]> git.decadent.org.uk Git - dak.git/blob - dak/manage_build_queues.py
Debug suites might also miss the source package
[dak.git] / dak / manage_build_queues.py
1 #!/usr/bin/env python
2
3 """ Manage build queues
4
5 @contact: Debian FTPMaster <ftpmaster@debian.org>
6 @copyright: 2000, 2001, 2002, 2006  James Troup <james@nocrew.org>
7 @copyright: 2009  Mark Hymers <mhy@debian.org>
8 @copyright: 2012, Ansgar Burchardt <ansgar@debian.org>
9
10 """
11
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
16
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 # GNU General Public License for more details.
21
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
26 ################################################################################
27
28 import apt_pkg
29 from datetime import datetime, timedelta
30 import sys
31
32 from daklib import daklog
33 from daklib.archive import ArchiveTransaction
34 from daklib.dbconn import *
35 from daklib.config import Config
36
37 ################################################################################
38
39 Options = None
40 Logger = None
41
42 ################################################################################
43
44 def usage (exit_code=0):
45     print """Usage: dak manage-build-queues [OPTIONS] buildqueue1 buildqueue2
46 Manage the contents of one or more build queues
47
48   -a, --all                  run on all known build queues
49   -n, --no-action            don't do anything
50   -h, --help                 show this help and exit"""
51
52     sys.exit(exit_code)
53
54 ################################################################################
55
56 def clean(build_queue, transaction, now=None):
57     session = transaction.session
58     if now is None:
59         now = datetime.now()
60
61     delete_before = now - timedelta(seconds=build_queue.stay_of_execution)
62     suite = build_queue.suite
63
64     # Remove binaries subject to the following conditions:
65     # 1. Keep binaries that are in policy queues.
66     # 2. Remove binaries that are not in suites.
67     # 3. Remove binaries that have been in the build queue for some time.
68     query = """
69         SELECT b.*
70           FROM binaries b
71           JOIN bin_associations ba ON b.id = ba.bin
72          WHERE ba.suite = :suite_id
73            AND NOT EXISTS
74                (SELECT 1 FROM policy_queue_upload_binaries_map pqubm
75                          JOIN policy_queue_upload pqu ON pqu.id = pqubm.policy_queue_upload_id
76                          JOIN policy_queue pq ON pq.id = pqu.policy_queue_id
77                          JOIN suite s ON s.policy_queue_id = pq.id
78                          JOIN suite_build_queue_copy sbqc ON sbqc.suite = s.id
79                         WHERE pqubm.binary_id = ba.bin AND pq.send_to_build_queues
80                           AND sbqc.build_queue_id = :build_queue_id)
81            AND (ba.created < :delete_before
82                 OR NOT EXISTS
83                    (SELECT 1 FROM bin_associations ba2
84                              JOIN suite_build_queue_copy sbqc ON sbqc.suite = ba2.suite
85                             WHERE ba2.bin = ba.bin AND sbqc.build_queue_id = :build_queue_id))"""
86     binaries = session.query(DBBinary).from_statement(query) \
87         .params({'build_queue_id': build_queue.queue_id, 'suite_id': suite.suite_id, 'delete_before': delete_before})
88     for binary in binaries:
89         Logger.log(["removed binary from build queue", build_queue.queue_name, binary.package, binary.version])
90         transaction.remove_binary(binary, suite)
91
92     # Remove sources
93     # Conditions are similar as for binaries, but we also keep sources
94     # if there is a binary in the build queue that uses it.
95     query = """
96         SELECT s.*
97           FROM source s
98           JOIN src_associations sa ON s.id = sa.source
99          WHERE sa.suite = :suite_id
100            AND NOT EXISTS
101                (SELECT 1 FROM policy_queue_upload pqu
102                          JOIN policy_queue pq ON pq.id = pqu.policy_queue_id
103                          JOIN suite s ON s.policy_queue_id = pq.id
104                          JOIN suite_build_queue_copy sbqc ON sbqc.suite = s.id
105                         WHERE pqu.source_id = sa.source AND pq.send_to_build_queues
106                           AND sbqc.build_queue_id = :build_queue_id)
107            AND (sa.created < :delete_before
108                 OR NOT EXISTS
109                    (SELECT 1 FROM src_associations sa2
110                              JOIN suite_build_queue_copy sbqc ON sbqc.suite = sa2.suite
111                             WHERE sbqc.build_queue_id = :build_queue_id
112                               AND sa2.source = sa.source))
113            AND NOT EXISTS
114                (SELECT 1 FROM bin_associations ba
115                          JOIN binaries b ON ba.bin = b.id
116                         WHERE ba.suite = :suite_id
117                           AND b.source = s.id)"""
118     sources = session.query(DBSource).from_statement(query) \
119         .params({'build_queue_id': build_queue.queue_id, 'suite_id': suite.suite_id, 'delete_before': delete_before})
120     for source in sources:
121         Logger.log(["removed source from build queue", build_queue.queue_name, source.source, source.version])
122         transaction.remove_source(source, suite)
123
124 def main ():
125     global Options, Logger
126
127     cnf = Config()
128
129     for i in ["Help", "No-Action", "All"]:
130         if not cnf.has_key("Manage-Build-Queues::Options::%s" % (i)):
131             cnf["Manage-Build-Queues::Options::%s" % (i)] = ""
132
133     Arguments = [('h',"help","Manage-Build-Queues::Options::Help"),
134                  ('n',"no-action","Manage-Build-Queues::Options::No-Action"),
135                  ('a',"all","Manage-Build-Queues::Options::All")]
136
137     queue_names = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
138     Options = cnf.subtree("Manage-Build-Queues::Options")
139
140     if Options["Help"]:
141         usage()
142
143     Logger = daklog.Logger('manage-build-queues', Options['No-Action'])
144
145     starttime = datetime.now()
146
147     with ArchiveTransaction() as transaction:
148         session = transaction.session
149         if Options['All']:
150             if len(queue_names) != 0:
151                 print "E: Cannot use both -a and a queue name"
152                 sys.exit(1)
153             queues = session.query(BuildQueue)
154         else:
155             queues = session.query(BuildQueue).filter(BuildQueue.queue_name.in_(queue_names))
156
157         for q in queues:
158             Logger.log(['cleaning queue %s using datetime %s' % (q.queue_name, starttime)])
159             clean(q, transaction, now=starttime)
160         if not Options['No-Action']:
161             transaction.commit()
162         else:
163             transaction.rollback()
164
165     Logger.close()
166
167 #######################################################################################
168
169 if __name__ == '__main__':
170     main()