summaryrefslogtreecommitdiff
path: root/patchtracker/DB.py
blob: 0913b24694b5af260a026e7097c65b6ec03bfe3a (plain)
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
from pysqlite2 import dbapi2 as sqlite
import Conf
import os
import errno

import patchtracker.SourceArchive as SourceArchive

def srcpkg_factory(cursor, row):
  d = {}
  for idx, col in enumerate(cursor.description):
    d[col[0]] = row[idx]

  info = {}
  info['Files'] = []
  if d['diffgz_name']:
    diffgz = {'name':d['diffgz_name'], 'size':d['diffgz_size'], 
              'md5sum':d['diffgz_md5sum'] }
    info['Files'].append(diffgz)
  if d['debtar_name']:
    debtar = {'name':d['debtar_name'], 'size':d['debtar_size'], 
                'md5sum':d['debtar_md5sum'] }
    info['Files'].append(debtar)

  colmap = {'name':'Package','version':'Version','format':'Format',
            'loc':'Directory','maintainer':'Maintainer','uploaders':'Uploaders'}
            
  for col,field in colmap.iteritems():
    info[field] = d[col]
  return SourceArchive.SourcePackage(info)

def srcpkg_collection_factory(cursor, row):
  d = {}
  rest = {}
  for idx, col in enumerate(cursor.description):
    if not d.has_key(col[0]):
      d[col[0]] = row[idx]
    else:
      rest[col[0]] = row[idx]

  info = {}
  info['Files'] = []
  if d['diffgz_name']:
    diffgz = {'name':d['diffgz_name'], 'size':d['diffgz_size'], 
              'md5sum':d['diffgz_md5sum'] }
    info['Files'].append(diffgz)
  if d['debtar_name']:
    debtar = {'name':d['debtar_name'], 'size':d['debtar_size'], 
              'md5sum':d['debtar_md5sum'] }
    info['Files'].append(debtar)

  colmap = {'name':'Package','version':'Version','format':'Format',
            'loc':'Directory','maintainer':'Maintainer','uploaders':'Uploaders'}
            
  for col,field in colmap.iteritems():
    info[field] = d[col]
  return (SourceArchive.SourcePackage(info), rest)

class PackageWithoutDiffException(Exception):
  def __init__(self, msg):
    Exception.__init__(self, msg)

class PatchTrackerDB:
  def __init__(self, dbname=Conf.database):
    self.db = sqlite.connect(dbname)
    cursor = self.db.cursor()
    cursor.execute("SELECT * FROM sqlite_master WHERE name='packages'")
    if not cursor.fetchone():
      print "repopulating empty database..."
      nextcmd = ""
      for l in file(Conf.sqlschema).readlines():
        if len(l.strip()):
          nextcmd += " " + l.strip()
        else:
          cursor.execute(nextcmd)
          nextcmd = ""

  def setFactory(self, factory):
    self.db.row_factory = factory

  def saveSourcePackage(self, srcpkg):
    cursor = self.db.cursor()
    #print "creating new record for",srcpkg
    q = "INSERT OR IGNORE INTO packages \
           (name,format,loc,version,diffgz_name,diffgz_size,diffgz_md5sum,debtar_name,debtar_size,debtar_md5sum,maintainer,uploaders) \
           VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
    cursor.execute(q, (srcpkg.name,srcpkg.format,srcpkg.loc,
                       srcpkg.version,srcpkg.diffgz_name,srcpkg.diffgz_size,
                       srcpkg.diffgz_md5sum,
                       srcpkg.debtar_name,srcpkg.debtar_size,
                       srcpkg.debtar_md5sum,
                       srcpkg.maintainers,srcpkg.uploaders))

  def saveSuite(self, suite):
    q = "INSERT INTO suites (name) VALUES (?)"
    cursor = self.db.cursor()
    cursor.execute(q, (suite,))

  def saveComponent(self, component):
    q = "INSERT INTO components (name) VALUES (?)"
    cursor = self.db.cursor()
    cursor.execute(q, (component,))

  def findCollection(self, package="%", version=None, email=None):
    oldfactory = self.db.row_factory
    self.db.row_factory = srcpkg_collection_factory
    cursor = self.db.cursor()
    toc = SourceArchive.SourcePackageIndex()
    q = "SELECT * FROM packages AS p,package_rel_map AS m,suites AS s \
           WHERE p.name LIKE ? AND p.id = m.package_id AND m.suite_id = s.id"
    qargs = (package,)
    if version:
      q += " AND p.version = ?"
      qargs += (version,)
    if email:
      q += " AND ( p.maintainer like ? OR p.uploaders like ? )"
      qargs += ("%%%s%%"%(email),"%%%s%%"%(email))

    cursor.execute(q, qargs)
    # use srcpkg_factory to fetch sourcepackages, once per suite
    for srcpkg,rest in cursor.fetchall():
      toc.ins(srcpkg, rest["name"])
    self.db.row_factory = oldfactory
    return toc

  def findLetterToc(self, letter):
    return self.findCollection(package=letter+"%").getletter(letter)

  def findIndices(self):
    indices = []
    cursor = self.db.cursor()
    q1 = "SELECT DISTINCT SUBSTR(name,1,1) FROM packages \
            WHERE name NOT LIKE 'lib%'"
    q2 = "SELECT DISTINCT SUBSTR(name,1,4) FROM packages \
            WHERE name LIKE 'lib%'"

    for q in [q1, q2]:
      cursor.execute(q)
      for idx in cursor.fetchall():
        indices.append(idx[0])
    
    indices.sort()
    return indices
     
  def relateSourcePackage(self, name, version, suite, component):
    q = "INSERT INTO package_rel_map \
           (package_id,suite_id,component_id,marked) \
           VALUES ((SELECT id FROM packages WHERE name=? AND version=?), \
                  (SELECT id FROM suites WHERE name=?), \
                  (SELECT id FROM components WHERE name=?), 1)"
    cursor = self.db.cursor()
    cursor.execute(q, (name, version, suite, component))

  def findDiffGz(self, pkgname, version):
    q = "SELECT diffgz_name,loc FROM packages WHERE name=? AND version=?"
    cursor = self.db.cursor()
    cursor.execute(q, (pkgname, version))
    try:
      diffgz,loc = cursor.fetchone()
      return os.sep.join([Conf.archive_root, loc, diffgz])
    except:
      return None

  def findDebTar(self, pkgname, version):
    q = "SELECT debtar_name,loc FROM packages WHERE name=? AND version=?"
    cursor = self.db.cursor()
    cursor.execute(q, (pkgname, version))
    try:
      debtar,loc = cursor.fetchone()
      return os.sep.join([Conf.archive_root, loc, debtar])
    except:
      return None

  # XXX this is kinda ugly...
  def makeDiffHandler(self, pkgname, vers):
    dfile = self.findDiffGz(pkgname,vers)
    if dfile:
      from DiffGzHandler import DiffGzHandler
      return DiffGzHandler(dfile)
    else:
      dfile = self.findDebTar(pkgname, vers)
      if dfile:
        from DebTarHandler import DebTarHandler
        return DebTarHandler(dfile)
      else:
        raise PackageWithoutDiffException("can not find diff file for %s / %s"%(pkgname,vers))

  def prune(self):
    q = "DELETE FROM package_rel_map WHERE marked != 1"
    cursor = self.db.cursor()
    cursor.execute(q)

  def unmark(self):
    q = "UPDATE package_rel_map SET marked=0"
    cursor = self.db.cursor()
    cursor.execute(q)

  def finalize(self):
    self.db.commit()

  def __del__(self):
    self.finalize()
    

if __name__ == "__main__":
  print "patch tracker db testing"
  d = PatchTrackerDB(dbname="foo.db")
  sp = SourceArchive.SourcePackage({'Package':'foo','Format':'blah','Directory':'/foo','Version':'1.2.3.4','Files':[]})
  d.saveSourcePackage(sp)
  d.finalize()