]> git.decadent.org.uk Git - dak.git/blob - daklib/metadata.py
config/debian/dak.conf: add suite map for {wheezy,testing}-updates
[dak.git] / daklib / metadata.py
1 #!/usr/bin/env python
2 """
3 Helper code for packages and sources generation.
4
5 @contact: Debian FTPMaster <ftpmaster@debian.org>
6 @copyright: 2011 Torsten Werner <twerner@debian.org>
7 @copyright: 2011 Mark Hymers <mhy@debian.org>
8 @license: GNU General Public License version 2 or later
9 """
10
11 ################################################################################
12
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 2 of the License, or
16 # (at your option) any later version.
17
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 # GNU General Public License for more details.
22
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
27 ################################################################################
28
29 from daklib.dbconn import *
30 from daklib.config import Config
31
32 from multiprocessing import Pool
33 from subprocess import Popen, PIPE
34
35 import os.path
36
37 class MetadataScanner(object):
38     '''
39     MetadataScanner provides a threadsafe method scan() to scan the metadata of
40     a DBSource or DBBinary object depending on what is passed as dbclass'''
41
42     def __init__(self, dbclass, pkid, verbose=True):
43         '''
44         The argument binary_id is the id of the DBBinary object that
45
46         should be scanned.
47         '''
48         self.verbose = True
49         self.dbclass = dbclass
50         self.pkid = pkid
51
52     def scan(self, dummy_arg = None):
53         '''
54         This method does the actual scan and fills in the associated metadata
55         property. It commits any changes to the database. The argument dummy_arg
56         is ignored but needed by our threadpool implementation.
57         '''
58         obj = None
59         fullpath = 'UNKNOWN PATH'
60
61         session = DBConn().session()
62         try:
63             obj = session.query(self.dbclass).get(self.pkid)
64             fullpath = obj.poolfile.fullpath
65             import_metadata_into_db(obj, session=session)
66             if self.verbose:
67                 print "Imported %s (%s)" % (self.pkid, fullpath)
68             session.commit()
69         except Exception as e:
70             print "Failed to import %s [id=%s; fullpath=%s]" % (self.dbclass.__name__, self.pkid, fullpath)
71             print "Exception: ", e
72             session.rollback()
73
74         session.close()
75
76     @classmethod
77     def scan_all(class_, scantype='source', limit = None):
78         '''
79         The class method scan_all() scans all sources using multiple threads.
80         The number of sources to be scanned can be limited with the limit
81         argument. Returns the number of processed and remaining files as a
82         dict.
83         '''
84         session = DBConn().session()
85         if scantype == 'source':
86             dbclass = DBSource
87             query = session.query(DBSource).filter(~DBSource.source_id.in_(session.query(SourceMetadata.source_id.distinct())))
88             t = 'sources'
89         else:
90             # Otherwise binary
91             dbclass = DBBinary
92             query = session.query(DBBinary).filter(~DBBinary.binary_id.in_(session.query(BinaryMetadata.binary_id.distinct())))
93             t = 'binaries'
94
95         remaining = query.count
96         if limit is not None:
97             query = query.limit(limit)
98         processed = query.count()
99         pool = Pool(processes=10)
100         for obj in query.yield_per(100):
101             pool.apply_async(scan_helper, (dbclass, obj.pkid, ))
102         pool.close()
103         pool.join()
104         remaining = remaining()
105         session.close()
106         return { 'processed': processed, 'remaining': remaining , 'type': t}
107
108 def scan_helper(dbclass, source_id):
109     '''
110     This function runs in a subprocess.
111     '''
112     scanner = MetadataScanner(dbclass, source_id)
113     scanner.scan()