File: deltas_queue.py

package info (click to toggle)
debdelta 0.70%2Bnmu2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 984 kB
  • sloc: python: 6,511; perl: 1,398; sh: 965; xml: 736; ansic: 215; makefile: 116; awk: 21
file content (217 lines) | stat: -rw-r--r-- 7,392 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/usr/bin/python

#Copyright (c) 2018 A. Mennucci
#License: GNU GPL v2 

import os, sys, atexit, tempfile, subprocess
from os.path import join
from copy import copy
import time, string, shutil, pickle, lockfile, logging, logging.handlers

if sys.version_info.major == 2:
    string_types = (str, unicode)  # python2
    from urllib import quote as urllib_quote
else:
    string_types = (str, bytes)  # python3
    import urllib, urllib.parse
    from urllib.parse import quote as urllib_quote

import sqlite3 as dbapi

logger=logging.getLogger(__name__)

#http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python
#from enum import Enum
class Enum(object):
    def __init__(self, *k):
        pass

def enum(*enums):
    d=dict([ (enums[k],k)    for k in range(len(enums)) ])
    return type('Enum', (object,), d)

if dbapi != None:
    pass
    # ===== sqlite machinery
    #def convert_blob(s):
    #   return s #this is always a string
    #
    # Register the adapter
    #sqlite.register_adapter(StringType, adapt_blob)
    #
    # Register the converter
    #dbapi.register_converter("blob", convert_blob)
    #dbapi.register_converter("text", convert_blob)

class SQL_queue(object):
    dbname=None
    sql_connection=None
    sql_connection_add=None
    fields=('id','priority','old_name','new_name','delta','forensic','other_info','ctime')
    fields_enum=enum(*fields)

    schema="""
    create table deltas_queue (
    id integer unique primary key autoincrement,
    priority integer,
    old_name text,
    new_name text,
    delta text,
    forensic text,
    other_info text,
    ctime integer
    ) ;
    CREATE INDEX IF NOT EXISTS deltas_queue_priority ON deltas_queue ( priority );
    CREATE INDEX IF NOT EXISTS deltas_queue_delta ON deltas_queue ( delta ) ;
    CREATE INDEX IF NOT EXISTS deltas_queue_ctime ON deltas_queue ( ctime ) ;
    CREATE INDEX IF NOT EXISTS deltas_queue_priority_ctime ON deltas_queue ( priority, ctime ) ;
    """

    def __init__(self,dbname):
        assert type(dbname) in string_types
        if not os.path.exists(dbname):
            r=my_subprocess_Popen(['sqlite3',dbname], stdin=subprocess.PIPE)
            r.stdin.write(self.schema)
            r.stdin.close()
            r.wait()
            assert 0 == r.returncode
        assert os.path.exists(dbname)
        self.dbname=dbname
        self.sql_connection = self._connect()
        # will be created when needed
        self.sql_connection_add = None
    
    def _connect(self):
        return dbapi.connect(self.dbname, isolation_level='EXCLUSIVE')   # detect_types=dbapi.PARSE_DECLTYPES | dbapi.PARSE_COLNAMES)
    
    def __del__(self):
        if self.sql_connection != None:
            self.sql_connection.close()
        if self.sql_connection_add != None:
            self.sql_connection_add.close()

    def _get_connection_cursor(self):
        connection =  self.sql_connection
        cursor = connection.cursor()
        return connection, cursor
    
    def queue_add_begin(self):
        assert self.sql_connection_add == None
        self.sql_connection_add = self._connect()

    def queue_add(self, priority, old_name, new_name, delta, forensic, other_info='', ctime=None):
        if self.sql_connection_add == None:
            raise Exception(' should use queue_add_begin() before ')
        if ctime==None:
            ctime=int(time.time())
        with self.sql_connection_add as S:
            S.execute('INSERT INTO deltas_queue VALUES (null, ?, ?, ?, ?, ?, ?, ?)',\
                                    (priority, old_name, new_name, delta, forensic, other_info, ctime))
            S.commit()

    def queue_add_commit(self):
        self.sql_connection_add = None

    def queue_peek(self):
        conn,cursor = self._get_connection_cursor()
        cursor.execute('SELECT * FROM deltas_queue ORDER BY priority , ctime  LIMIT 1')
        return cursor.fetchone()
    
    def queue_get(self, id_):
        conn,cursor = self._get_connection_cursor()
        cursor.execute('SELECT * FROM deltas_queue WHERE id = ? ', (id_,))
        return cursor.fetchone()
    
    def queue_pop(self, id_=None):
        "pop one value, if 'id' is set that value"
        #http://stackoverflow.com/questions/15856976/transactions-with-python-sqlite3
        connection, cursor = self._get_connection_cursor()
        try:
            connection.execute('begin exclusive transaction')
            if id_ == None:
                cursor.execute('SELECT * FROM deltas_queue ORDER BY priority , ctime LIMIT 1 ')
            else:
                cursor.execute('SELECT * FROM deltas_queue WHERE id = ? ', (id_,))
            x=cursor.fetchone()
            if x is not None:
                id_ = x[0]
                connection.execute('DELETE FROM deltas_queue where id = ? ', (id_,))
            connection.commit()
            #cursor.execute('commit transaction')
        except:
            connection.rollback() 
            #cursor.execute('rollback')
            raise
        return x

    def queue_del(self, id_):
        "delete queued item by 'id'"
        connection, cursor = self._get_connection_cursor()
        try:
            cursor.execute('DELETE FROM deltas_queue where id = ? ', (id_,))
            connection.commit() #cursor.executescript('commit transaction')
        except:
            connection.rollback() #cursor.executescript('rollback')
            raise
    
    def iterate(self):
        "returns a cursor onto the database"
        connection, cursor = self._get_connection_cursor()
        cursor.execute('SELECT * FROM deltas_queue ORDER BY priority , ctime')
        return cursor
    
    def queue_peek_delta(self, delta):
        conn,cursor = self._get_connection_cursor()
        cursor.execute('SELECT * FROM deltas_queue WHERE delta = ?', (delta, ))
        return cursor.fetchone()
        


_html_top="""<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <link rel="StyleSheet" href="style.css" type="text/css">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>debdeltas Server History Page</title>
</head>
<body>
"""

def html(db,W):
    s=SQL_queue(db)
    if type(W) in string_types:
        W=open(W,'w').write
    W(_html_top)
    W('Queue state at '+time.ctime()+'\n')
    F=list(SQL_queue.fields)
    FE=SQL_queue.fields_enum
    W('<table class="queue"><tr>')
    for j in F:
        W('<th>' + j.replace('_',' ')+'</th>')
    W('</tr>\n')
    count=0
    for x in s.iterate():
        count+=1
        x=list(x)
        x=[('%.3f' % j) if isinstance(j,float) else j for j in x]
        x=[(j.split('/')[-1]) if (type(j) in string_types) else j for j in x]
        x=['' if (j == None) else j for j in x]
        x[FE.ctime]=time.ctime(x[FE.ctime])
        W('<tr>')
        for j in x:
            W('<td>'+str(j)+'</td>')
        W('</tr>\n')
        if (count % 40)  == 0:
            W('<tr>')
            for j in F:
                W('<th>'+j.replace('_',' ')+'</th>')
            W('</tr>\n')
    W('</table></body></html>\n')
    W('total %d elements in queue\n' % count)


if __name__ == '__main__' and len(sys.argv) > 1:
    if sys.argv[1] == 'html' :
        W= sys.argv[3] if (len(sys.argv) > 3)  else sys.stdout.write
        html(sys.argv[2],W)
    else: raise ValueError('unknown command %r' % sys.argv[1])