/[collab-qa]/udd/udd/ftpnew_gatherer.py
ViewVC logotype

Contents of /udd/udd/ftpnew_gatherer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1561 - (hide annotations) (download) (as text)
Fri Aug 21 06:22:23 2009 UTC (3 years, 9 months ago) by tille
File MIME type: text/x-python
File size: 23952 byte(s)
Do not crash if deb822 stumbles upon unknown keys
1 tille 1406 #!/usr/bin/env python
2    
3     """
4     This script imports information from ftp new queue into the database
5     See http://ftp-master.debian.org/new.822 and
6     http://ftp-master.debian.org/new.html
7     """
8    
9     from debian_bundle import deb822
10     from os import access, mkdir, unlink, W_OK
11     from sys import stderr
12     import aux
13     from aux import quote
14     from gatherer import gatherer
15     import email.Utils
16     import re
17     from time import ctime
18     from psycopg2 import IntegrityError
19    
20     def get_gatherer(connection, config, source):
21     return ftpnew_gatherer(connection, config, source)
22    
23 tille 1408 DEBUG=0
24    
25 tille 1406 # When parsing src html pages we have to get rid of certain html strings
26     def de_html(string):
27 tille 1408 string= re.sub("</?span[^>]*>", '', string)
28     string= re.sub("&quot;", '"', string)
29     string= re.sub("&amp;", '&', string)
30     string= re.sub("&lt;", '<', string)
31     string= re.sub("&gt;", '>', string)
32     string= re.sub("</?pre>", '', string)
33 tille 1406 return string
34    
35     # These fields are not forewarded to UDD tables for the moment
36     fields_to_pass = ('Format',
37     'Date',
38     'Changed-By',
39     'Files',
40     'Uploaders',
41     'Standards-Version',
42     'Priority',
43     'Urgency',
44     'Dm-Upload-Allowed',
45     'Autobuild',
46     'Build-Depends',
47     'Build-Depends-Indep',
48     'Build-Conflicts',
49     'Python-Version')
50     # + startswith('Npp-')
51    
52     dependencies_to_accept = ( 'Depends', 'Recommends', 'Suggests', 'Enhances', 'Pre-Depends',
53     'Breaks', 'Replaces', 'Provides', 'Conflicts')
54    
55     class src_pkg():
56     def __init__(self, source):
57     self.s = {}
58     self.s['Source'] = source
59     self.has_several_versions = 0
60     # self.bin = () # comma separated list of binaries created from the source
61     self.s['Bin'] = () # comma separated list of binaries created from the source
62     self.s['Architecture'] = () # architecture(s separated by blanks)
63     # Just define Vcs fields in case it is not provided in the control
64     self.s['Vcs-Type'] = None
65     self.s['Vcs-Url'] = None
66     # preset WNPP bug
67     self.s['Closes'] = 0
68    
69     def check_dict(self):
70     "Make sure that non-mandatory fields at least get a '' value"
71     for field in ftpnew_gatherer.s_non_mandatory:
72     if not self.s.has_key(field):
73     self.s[field] = ''
74    
75     def __str__(self):
76     str = "Source %(Source)s: %(Version)s, (%(Architecture)s), %(Last_modified)s, %(Queue)s, %(Distribution)s" % \
77     (self.s)
78     str += " %(maintainer_name)s <%(maintainer_email)s>, %(Closes)i" % (self.s)
79     return str
80    
81     class bin_pkg():
82     def __init__(self, package, source):
83     self.b = {}
84     self.b['Package'] = package
85     self.b['Source'] = source
86     self.b['Installed-Size'] = 0
87     self.b['License'] = ''
88    
89     def check_dict(self):
90     "Make sure that non-mandatory fields at least get a '' value"
91     for field in ftpnew_gatherer.b_non_mandatory:
92     if not self.b.has_key(field):
93     self.b[field] = ''
94    
95     def __str__(self):
96     return "Package %s: %s, %s, %s, %s, %s" % \
97     (self.b['Package'], self.b['Version'], self.b['Architecture'], self.b['Maintainer'],
98     self.b['Description'], self.b['Long_Description'])
99    
100     class ftpnew_gatherer(gatherer):
101     "This class imports the data from New queue into the database"
102     s_mandatory = {'Source': 0, 'Format': 0, 'Maintainer': 0, 'Package': 0, 'Version': 0, 'Files': 0,
103     'Queue': 0, 'Last_modified': 0}
104     s_non_mandatory = {'Uploaders': 0, 'Bin': 0, 'Architecture': 0,
105     'Homepage': 0, 'Build-Depends': 0, 'Vcs-Arch': 0, 'Vcs-Bzr': 0,
106     'Vcs-Cvs': 0, 'Vcs-Darcs': 0, 'Vcs-Git': 0, 'Vcs-Hg': 0, 'Vcs-Svn': 0,
107 tille 1474 'Vcs-Mtn':0, 'Vcs-Browser': 0, 'License': 0, 'Section': 0
108 tille 1406 }
109     s_ignorable = {'X-Vcs-Browser': 0, 'X-Vcs-Bzr': 0, 'X-Vcs-Darcs': 0, 'X-Vcs-Svn': 0, 'X-Vcs-Hg':0, 'X-Vcs-Git':0,
110     'Directory':0, 'Comment':0, 'Origin':0, 'Url':0, 'X-Collab-Maint':0, 'Autobuild':0, 'Vcs-Cvs:':0,
111     'Python-Standards-Version':0, 'url':0, 'originalmaintainer':0, 'Originalmaintainer':0,
112     'Build-Recommends':0,
113     'Build-Depends-Indep': 0, 'Build-Conflicts': 0, 'Build-Conflicts-Indep': 0,
114 tille 1474 'Priority': 0, 'Python-Version': 0, 'Checksums-Sha1':0,
115 tille 1406 'Checksums-Sha256':0, 'Original-Maintainer':0, 'Dm-Upload-Allowed':0,
116     'Standards-Version': 0,
117     }
118    
119     b_non_mandatory = {'Source': 0, 'Essential': 0, 'Depends': 0, 'Recommends': 0,
120     'Suggests': 0, 'Enhances': 0, 'Pre-Depends': 0, 'Breaks':0, 'Installed-Size': 0,
121     'Homepage': 0, 'Size': 0, 'Build-Essential':0, 'Origin':0,
122     'SHA1':0, 'Replaces':0, 'Section':0, 'MD5sum':0, 'Bugs':0, 'Priority':0,
123     'Tag':0, 'Task':0, 'Python-Version':0, 'Provides':0, 'Conflicts':0,
124     'SHA256':0, 'Original-Maintainer':0}
125    
126     s_ignorable_re = re.compile("^(Original-|Origianl-|Orginal-|Debian-|X-Original-|Upstream-)")
127     s_vcs = { 'Arch':0, 'Bzr':0, 'Cvs':0, 'Darcs':0, 'Git':0, 'Hg':0, 'Svn':0, 'Mtn':0}
128    
129     src_html_failed_re = re.compile("^<p>The requested URL /new/.+\.html was not found on this server\.</p>")
130     src_html_has_tag_re = re.compile('^\s*<tr><td class="key">([-\w]+):</td><td class="val">(.+)</td></tr>$')
131     src_html_has_description_start_re = re.compile('^\s*<tr><td class="key">Description:</td><td class="val"><pre>(.+)')
132     src_html_has_description_end_re = re.compile('(.+)</pre></td></tr>')
133 tille 1559 closes_is_itp_re = re.compile('^[\s"]*(ITP|RFP|ITA)')
134 tille 1406 vcs_type_re = re.compile('Vcs-(Svn|Git|Bzr|Darcs|Hg|Cvs|Arch|Mtn)')
135    
136     def __init__(self, connection, config, source):
137     gatherer.__init__(self, connection, config, source)
138     self.assert_my_config('path', 'table_sources', 'table_packages', 'ftpmasterURL', 'releases_ignore')
139    
140    
141     def check_existing_binaries(self, values, queue):
142     # Sometimes the source package name has changed, but the binary package name is known in UDD
143     # we are not interested in these packages
144    
145     cur = self.cursor()
146     for value in values:
147     # query = "SELECT count(*) FROM packages WHERE package = '%s'" % (value)
148     query = "EXECUTE ftpnew_check_existing_package ('%s')" % (value)
149     cur.execute(query)
150     in_udd = cur.fetchone()[0]
151     if in_udd:
152 tille 1408 if DEBUG != 0:
153     print >>stderr, "Binary package %s is %i times in UDD - no interest in just known binaries (queue = %s)" \
154     % (value, int(in_udd), queue)
155 tille 1406 return 1
156     return 0
157    
158     def run(self):
159     my_config = self.my_config
160    
161     #start harassing the DB, preparing the final inserts and making place
162     #for the new data:
163     cur = self.cursor()
164    
165     # if we check whether a package just exists in UDD we ignore oldstable which is currently etch but other
166     # dists might have to be ignored as well
167     cur.execute("PREPARE ftpnew_check_existing_package AS SELECT COUNT(*) FROM packages WHERE package = $1 AND release NOT IN (%s)" \
168     % self.my_config["releases_ignore"])
169     # For some reason the code tries to add binary packages twice - just verify whether the package is
170     # just included to make sure we do not trigger conflicting primary keys
171     cur.execute("PREPARE ftpnew_check_just_added_package AS SELECT COUNT(*) FROM new_packages WHERE package = $1 AND version = $2 AND architecture = $3")
172    
173     cur.execute("DELETE FROM %s" % my_config["table_sources"])
174     cur.execute("DELETE FROM %s" % my_config["table_packages"])
175    
176     query = """PREPARE ftpnew_insert_source
177     AS INSERT INTO %s (source, version, maintainer, maintainer_name, maintainer_email, binaries,
178     changed_by, architecture, homepage,
179 tille 1474 vcs_type, vcs_url, vcs_browser,
180     section, distribution, component, closes, license, last_modified, queue)
181     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)""" % (my_config['table_sources'])
182 tille 1406 cur.execute(query)
183     query = """PREPARE ftpnew_insert_package
184     AS INSERT INTO %s (package, version, architecture, maintainer, description, source,
185     depends, recommends, suggests, enhances, pre_depends, breaks, replaces, provides, conflicts,
186 tille 1474 installed_size, homepage, section, long_description, distribution, component, license)
187     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22)""" \
188     % (my_config['table_packages'])
189 tille 1406 cur.execute(query)
190    
191 tille 1561 ftpnew822file = my_config['path']+'/new.822'
192     ftpnew_data = open(ftpnew822file)
193 tille 1406
194 tille 1474 has_warned_about_missing_section_key = 0
195 tille 1561 try:
196     for stanza in deb822.Sources.iter_paragraphs(ftpnew_data, shared_storage=False):
197     try:
198     if stanza['queue'] == 'accepted' or stanza['queue'] == 'proposedupdates' :
199     continue
200     except KeyError, err:
201     print >>stderr, "No key queue found (%s), %s" % (err, str(stanza))
202 tille 1560 continue
203 tille 1561 srcpkg = src_pkg(stanza['source'])
204     versions = stanza['version'].split(' ') # the page lists more than one version
205     srcpkg.has_several_versions = len(versions)-1 # some tests below fail if more than one version in in queue
206     srcpkg.s['Version'] = versions[srcpkg.has_several_versions]
207     srcpkg.s['Architecture'] = stanza['architectures']
208     srcpkg.s['Queue'] = stanza['queue']
209     srcpkg.s['Last_modified'] = ctime(int(stanza['last-modified'])) # We want a real time object instead of an epoch
210     srcpkg.s['Distribution'] = stanza['distribution']
211     srcpkg.s['Changed-By'] = stanza['changed-by']
212     try:
213     srcpkg.s['Section'] = stanza['section']
214     if stanza['section'].startswith('non-free'):
215     srcpkg.s['Component'] = 'non-free'
216     elif stanza['section'].startswith('contrib'):
217     srcpkg.s['Component'] = 'contrib'
218     else:
219     srcpkg.s['Component'] = 'main'
220     except KeyError:
221     srcpkg.s['Section'] = ''
222     srcpkg.s['Component'] = ''
223     if has_warned_about_missing_section_key == 0:
224     has_warned_about_missing_section_key = 1
225     print >>stderr, "Warning: Because of a bug in DAK code the Section field is currently missing."
226 tille 1406
227 tille 1561 # Check UDD for existing source packages of this name
228     query = "SELECT count(*) FROM sources WHERE source = '%s'" % (srcpkg.s['Source'])
229     cur.execute(query)
230     in_udd = cur.fetchone()[0]
231     if in_udd:
232     if DEBUG != 0:
233     print >>stderr, "%s is %i times in UDD - no interest in just known sources (queue = %s)" \
234     % (srcpkg.s['Source'], int(in_udd), srcpkg.s['Queue'])
235     continue
236 tille 1406
237 tille 1561 src_info_base = srcpkg.s['Source'] + '_' + srcpkg.s['Version']
238     src_info_html = my_config['path'] + '/' + src_info_base + '.html'
239     src_info_822 = my_config['path'] + '/' + src_info_base + '.822'
240 tille 1406
241 tille 1561 try:
242     srci = open(src_info_html, 'r')
243     except IOError, err:
244     print >>stderr, "No html info for package %s in queue %s (%s)." % (srcpkg.s['Source'], stanza['queue'], err)
245     continue
246     srco = open(src_info_822, 'w')
247     in_description = 0
248     in_source = 1
249     binpkgs = []
250     binpkg = None
251     binpkg_changes = None # In case we have only information about changes file which sometimes might happen
252     for line in srci.readlines():
253     if ftpnew_gatherer.src_html_failed_re.match(line):
254     print >>stderr, "File %s not found." % (src_info_html)
255     src_info_not_found = 1
256     break
257     match = ftpnew_gatherer.src_html_has_tag_re.match(line)
258     if match:
259     field = match.groups()[0]
260     value = de_html(match.groups()[1])
261     if field == 'Package':
262     # Here begins a new binary package
263     if self.check_existing_binaries((value,), srcpkg.s['Queue']):
264     srcpkg.s['Queue'] = 'ignore'
265     break
266     if in_source:
267     in_source = 0
268     if binpkg:
269     binpkgs.append(binpkg)
270     binpkg = bin_pkg(value, srcpkg.s['Source'])
271     print >>srco, "\nPackage: %s" % (value)
272     binpkg.b['Distribution'] = srcpkg.s['Distribution']
273     elif field == 'Maintainer':
274     # print "DEBUG %s: %s" % (field, value)
275     if in_source:
276     srcpkg.s[field] = value
277     srcpkg.s['maintainer_name'], srcpkg.s['maintainer_email'] = email.Utils.parseaddr(srcpkg.s['Maintainer'])
278     binpkg_changes.b[field] = value
279 tille 1406 else:
280 tille 1561 binpkg.b[field] = value
281 tille 1406 print >>srco, "%s: %s" % (field, value)
282 tille 1561 elif field == 'Description':
283     # This does not seem to be executed because description is parsed when src_html_has_description_start_re matches (see below)
284     if in_source:
285     srcpkg.s[field] = de_html(value)
286     else:
287     binpkg.b[field] = de_html(value)
288 tille 1406 print >>srco, "%s: %s" % (field, value)
289 tille 1561 elif field == 'Architecture':
290     if in_source:
291     srcpkg.s[field] = value
292     binpkg_changes.b[field] = value
293 tille 1474 else:
294     binpkg.b[field] = value
295 tille 1406 print >>srco, "%s: %s" % (field, value)
296 tille 1561 elif field == 'Source':
297     if in_source:
298     if value != srcpkg.s['Source']:
299     print >>stderr, "Incompatible source names between new.822(%s) and %s.html (%s)" % \
300     (srcpkg.s['Source'], src_info_base, value)
301     srcpkg.s['Source'] = value
302     print >>srco, "%s: %s" % (field, value)
303     elif field == 'Version':
304     if in_source:
305     if srcpkg.has_several_versions == 0 and value != srcpkg.s[field]:
306     print >>stderr, "Incompatible version numbers between new.822(%s) and %s.html (%s)" % \
307     (srcpkg.s[field], src_info_base, value)
308     srcpkg.s[field] = value
309     binpkg_changes.b[field] = value
310     else:
311     binpkg.b[field] = value
312     print >>srco, "%s: %s" % (field, value)
313     elif field == 'Closes':
314     values = value.split(' ')
315     found_itp = 0
316     for val in values:
317     ival = int(val)
318     query = "SELECT title from bugs where id = %i and package = 'wnpp' and source = 'wnpp'" % (ival)
319     cur.execute(query)
320     try:
321     wnpp_title = cur.fetchone()[0]
322     except TypeError, err:
323     query = "SELECT id, package, source, title FROM bugs WHERE id = %i" % (ival)
324     cur.execute(query)
325     bug_info = cur.fetchone()
326     if DEBUG != 0:
327     if not bug_info:
328     print >>stderr, "Bug %i which source package %s claims to close does not exist." % (ival, srcpkg.s['Source'])
329     else:
330     print >>stderr, "Bug #%i of package %s and source %s is not against pseudopackage 'wnpp' and hast title '%s'" % bug_info
331     if not ftpnew_gatherer.closes_is_itp_re.match(wnpp_title):
332     print >>stderr, "Closed bug %i seems to be not ITPed (queue = %s; title = %s)" % (ival, srcpkg.s['Queue'], wnpp_title)
333     else:
334     if found_itp:
335     if DEBUG != 0:
336     print >>stderr, "Warning: Package %s seems to have more than one ITP bugs (%i, %i). Only %i is stored in UDD (title = %s)" % \
337     (srcpkg.s['Source'], srcpkg.s['Closes'], ival, srcpkg.s['Closes'], wnpp_title)
338     query = "SELECT count(*) FROM bugs_merged_with WHERE id = %i OR id = %i" % (srcpkg.s['Closes'], ival)
339     cur.execute(query)
340     is_merged = cur.fetchone()[0]
341     if is_merged != 2:
342     print >>stderr, " --> Please verify whether bugs should could be merged in BTS!"
343     else: # stay with the ITP found first
344     srcpkg.s[field] = int(ival)
345     found_itp = 1
346     if not found_itp and DEBUG != 0:
347     print >>stderr, "Most probably %s is not new." % (srcpkg.s['Source'])
348     print >>srco, "%s: %s\n" % (field, value)
349     elif field == 'Distribution':
350     if in_source:
351     if srcpkg.has_several_versions == 0 and value != srcpkg.s['Distribution']:
352     print >>stderr, "Incompatible distributions between new.822(%s) and %s.html (%s)" % \
353     (srcpkg.s['Distribution'], src_info_base, value)
354     srcpkg.s[field] = value
355     print >>srco, "%s: %s" % (field, value)
356     else:
357     print >>stderr, "Binary should not mention distribution field in %s.html (%s)" % \
358     (src_info_base, value)
359     elif field == 'Binary':
360     if in_source:
361     # Binaries are mentioned in different syntax in *.changes and *.dsc
362     value = re.sub(", +", " ", value)
363     if self.check_existing_binaries(value.split(' '), srcpkg.s['Queue']):
364     srcpkg.s['Queue'] = 'ignore'
365     break
366     if in_source:
367     if srcpkg.s['Bin'] != () and value != srcpkg.s['Bin']:
368     print >>stderr, "Incompatible binaries between new.822(%s) and %s.html (%s)" % \
369     (srcpkg.s['Bin'], src_info_base, value)
370     srcpkg.s['Bin'] = value
371     print >>srco, "%s: %s" % (field, value)
372     binpkg_changes = bin_pkg(value.split(' ')[0], srcpkg.s['Source'])
373     binpkg_changes.b['Distribution'] = srcpkg.s['Distribution']
374     binpkg_changes.b['Description'] = 'binary package information is missing in new queue'
375     binpkg_changes.b['Long_Description'] = '' # no long description available in *.changes file
376     binpkg_changes.b['Component'] = srcpkg.s['Component']
377     else:
378     print >>stderr, "Binary should not mention Binary field in %s.html (%s)" % \
379     (src_info_base, value)
380     elif field == 'Installed-Size':
381     if not in_source:
382     binpkg.b[field] = int(value)
383     elif field == 'Homepage':
384     if not in_source:
385     binpkg.b[field] = value
386     elif field == 'Section':
387     if not in_source:
388     if not binpkg:
389     print >>stderr, "This should not happen", srcpkg, field, value
390     exit(-1)
391     else:
392     binpkg.b[field] = value
393     binpkg.b['Component'] = srcpkg.s['Component']
394     elif field == 'Vcs-Browser':
395     srcpkg.s[field] = value
396     elif binpkg != None and field in dependencies_to_accept:
397     binpkg.b[field] = value
398     print >>srco, "%s: %s" % (field, value)
399     elif field in fields_to_pass or field.startswith('Npp-'):
400     print >>srco, "%s: %s" % (field, value)
401 tille 1406 else:
402 tille 1561 matchvcs = ftpnew_gatherer.vcs_type_re.match(field)
403     if matchvcs:
404     srcpkg.s['Vcs-Type'] = matchvcs.groups()[0]
405     srcpkg.s['Vcs-Url'] = value
406     print >>srco, "%s: %s" % (field, value)
407     else:
408     print >>stderr, "Unknown field in %s: %s" % (srcpkg.s['Source'], field)
409     print >>srco, "*%s: %s" % (field, value)
410     continue
411     if in_description:
412     match = ftpnew_gatherer.src_html_has_description_end_re.match(line)
413     if match:
414     if match.groups()[0][0] != ' ':
415     description += ' '
416     description += de_html(match.groups()[0])
417     in_description = 0
418     if not in_source: # binpkg and binpkg.b:
419     (binpkg.b['Description'], binpkg.b['Long_Description']) = description.split("\n",1)
420     print >>srco, "Description: %s\n%s" % (binpkg.b['Description'], binpkg.b['Long_Description'])
421     else:
422     if line[0] != ' ':
423     description += ' '
424     description += de_html(line)
425 tille 1406 else:
426 tille 1561 match = ftpnew_gatherer.src_html_has_description_start_re.match(line)
427     if match:
428     in_description = 1
429     description = de_html(match.groups()[0]) + "\n"
430     srci.close()
431     srco.close()
432     # Append last read binary package to list of binary packages
433     if binpkg != None:
434     binpkgs.append(binpkg)
435     else: # ... if only .changes information available (for whatever reason other information might be missing in new queue
436     if srcpkg.s['Queue'] != 'ignore':
437     # fall back to some basic information
438     binpkgs.append(binpkg_changes)
439     print >>stderr, "Package %s is missing information for binary packages" % (binpkg_changes.b['Package'])
440 tille 1555 if srcpkg.s['Queue'] != 'ignore':
441 tille 1561 # print srcpkg
442     srcpkg.check_dict()
443     query = """EXECUTE ftpnew_insert_source (%(Source)s, %(Version)s,
444     %(Maintainer)s, %(maintainer_name)s, %(maintainer_email)s,
445     %(Bin)s, %(Changed-By)s, %(Architecture)s, %(Homepage)s,
446     %(Vcs-Type)s, %(Vcs-Url)s, %(Vcs-Browser)s,
447     %(Section)s, %(Distribution)s, %(Component)s, %(Closes)s, %(License)s,
448     %(Last_modified)s, %(Queue)s)"""
449     cur.execute(query, srcpkg.s)
450     for binpkg in binpkgs:
451     # print binpkg
452     if not binpkg:
453     print >>stderr, "Undefined binpkg. This is the info from changes:", str(binpkg_changes)
454     continue
455     binpkg.check_dict()
456     query = """EXECUTE ftpnew_insert_package (%(Package)s, %(Version)s,
457     %(Architecture)s, %(Maintainer)s, %(Description)s, %(Source)s,
458     %(Depends)s, %(Recommends)s, %(Suggests)s, %(Enhances)s,
459     %(Pre-Depends)s, %(Breaks)s, %(Replaces)s, %(Provides)s, %(Conflicts)s,
460     %(Installed-Size)s, %(Homepage)s, %(Section)s,
461     %(Long_Description)s, %(Distribution)s, %(Component)s, %(License)s)"""
462     try:
463     cur.execute(query, binpkg.b)
464     except IntegrityError, err:
465     print >>stderr, err, src_info_html
466     print >>stderr, binpkg
467     print >>stderr, binpkg.b
468     continue
469     except KeyError, err:
470     print >>stderr, "Missing information field for binary package %s: %s" % (binpkg.b['Package'], err)
471     continue
472     except KeyError, err:
473     print >>stderr, "Unable to finish parsing %s: %s" % (ftpnew822file, err)
474 tille 1406
475     cur.execute("DEALLOCATE ftpnew_insert_source")
476     cur.execute("DEALLOCATE ftpnew_insert_package")
477     cur.execute("DEALLOCATE ftpnew_check_existing_package")
478 lucas 1531 cur.execute("ANALYZE %s" % my_config["table_sources"])
479     cur.execute("ANALYZE %s" % my_config["table_packages"])
480 tille 1406
481     if __name__ == '__main__':
482     main()
483    
484     # vim:set et tabstop=2:

  ViewVC Help
Powered by ViewVC 1.1.5