]> git.decadent.org.uk Git - dak.git/blob - dak/control_suite.py
Enmasse adaptation for removal of silly names.
[dak.git] / dak / control_suite.py
1 #!/usr/bin/env python
2
3 # Manipulate suite tags
4 # Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006  James Troup <james@nocrew.org>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 #######################################################################################
21
22 # 8to6Guy: "Wow, Bob, You look rough!"
23 # BTAF: "Mbblpmn..."
24 # BTAF <.oO>: "You moron! This is what you get for staying up all night drinking vodka and salad dressing!"
25 # BTAF <.oO>: "This coffee I.V. drip is barely even keeping me awake! I need something with more kick! But what?"
26 # BTAF: "OMIGOD! I OVERDOSED ON HEROIN"
27 # CoWorker#n: "Give him air!!"
28 # CoWorker#n+1: "We need a syringe full of adrenaline!"
29 # CoWorker#n+2: "Stab him in the heart!"
30 # BTAF: "*YES!*"
31 # CoWorker#n+3: "Bob's been overdosing quite a bit lately..."
32 # CoWorker#n+4: "Third time this week."
33
34 # -- http://www.angryflower.com/8to6.gif
35
36 #######################################################################################
37
38 # Adds or removes packages from a suite.  Takes the list of files
39 # either from stdin or as a command line argument.  Special action
40 # "set", will reset the suite (!) and add all packages from scratch.
41
42 #######################################################################################
43
44 import pg, sys
45 import apt_pkg
46 import dak.lib.utils, dak.lib.database, dak.lib.logging
47
48 #######################################################################################
49
50 Cnf = None
51 projectB = None
52 Logger = None
53
54 ################################################################################
55
56 def usage (exit_code=0):
57     print """Usage: dak control-suite [OPTIONS] [FILE]
58 Display or alter the contents of a suite using FILE(s), or stdin.
59
60   -a, --add=SUITE            add to SUITE
61   -h, --help                 show this help and exit
62   -l, --list=SUITE           list the contents of SUITE
63   -r, --remove=SUITE         remove from SUITE
64   -s, --set=SUITE            set SUITE"""
65
66     sys.exit(exit_code)
67
68 #######################################################################################
69
70 def get_id (package, version, architecture):
71     if architecture == "source":
72         q = projectB.query("SELECT id FROM source WHERE source = '%s' AND version = '%s'" % (package, version))
73     else:
74         q = projectB.query("SELECT b.id FROM binaries b, architecture a WHERE b.package = '%s' AND b.version = '%s' AND (a.arch_string = '%s' OR a.arch_string = 'all') AND b.architecture = a.id" % (package, version, architecture))
75
76     ql = q.getresult()
77     if not ql:
78         dak.lib.utils.warn("Couldn't find '%s~%s~%s'." % (package, version, architecture))
79         return None
80     if len(ql) > 1:
81         dak.lib.utils.warn("Found more than one match for '%s~%s~%s'." % (package, version, architecture))
82         return None
83     id = ql[0][0]
84     return id
85
86 #######################################################################################
87
88 def set_suite (file, suite_id):
89     lines = file.readlines()
90
91     projectB.query("BEGIN WORK")
92
93     # Build up a dictionary of what is currently in the suite
94     current = {}
95     q = projectB.query("SELECT b.package, b.version, a.arch_string, ba.id FROM binaries b, bin_associations ba, architecture a WHERE ba.suite = %s AND ba.bin = b.id AND b.architecture = a.id" % (suite_id))
96     ql = q.getresult()
97     for i in ql:
98         key = " ".join(i[:3])
99         current[key] = i[3]
100     q = projectB.query("SELECT s.source, s.version, sa.id FROM source s, src_associations sa WHERE sa.suite = %s AND sa.source = s.id" % (suite_id))
101     ql = q.getresult()
102     for i in ql:
103         key = " ".join(i[:2]) + " source"
104         current[key] = i[2]
105
106     # Build up a dictionary of what should be in the suite
107     desired = {}
108     for line in lines:
109         split_line = line.strip().split()
110         if len(split_line) != 3:
111             dak.lib.utils.warn("'%s' does not break into 'package version architecture'." % (line[:-1]))
112             continue
113         key = " ".join(split_line)
114         desired[key] = ""
115
116     # Check to see which packages need removed and remove them
117     for key in current.keys():
118         if not desired.has_key(key):
119             (package, version, architecture) = key.split()
120             id = current[key]
121             if architecture == "source":
122                 q = projectB.query("DELETE FROM src_associations WHERE id = %s" % (id))
123             else:
124                 q = projectB.query("DELETE FROM bin_associations WHERE id = %s" % (id))
125             Logger.log(["removed",key,id])
126
127     # Check to see which packages need added and add them
128     for key in desired.keys():
129         if not current.has_key(key):
130             (package, version, architecture) = key.split()
131             id = get_id (package, version, architecture)
132             if not id:
133                 continue
134             if architecture == "source":
135                 q = projectB.query("INSERT INTO src_associations (suite, source) VALUES (%s, %s)" % (suite_id, id))
136             else:
137                 q = projectB.query("INSERT INTO bin_associations (suite, bin) VALUES (%s, %s)" % (suite_id, id))
138             Logger.log(["added",key,id])
139
140     projectB.query("COMMIT WORK")
141
142 #######################################################################################
143
144 def process_file (file, suite, action):
145
146     suite_id = dak.lib.database.get_suite_id(suite)
147
148     if action == "set":
149         set_suite (file, suite_id)
150         return
151
152     lines = file.readlines()
153
154     projectB.query("BEGIN WORK")
155
156     for line in lines:
157         split_line = line.strip().split()
158         if len(split_line) != 3:
159             dak.lib.utils.warn("'%s' does not break into 'package version architecture'." % (line[:-1]))
160             continue
161
162         (package, version, architecture) = split_line
163
164         id = get_id(package, version, architecture)
165         if not id:
166             continue
167
168         if architecture == "source":
169             # Find the existing assoications ID, if any
170             q = projectB.query("SELECT id FROM src_associations WHERE suite = %s and source = %s" % (suite_id, id))
171             ql = q.getresult()
172             if not ql:
173                 assoication_id = None
174             else:
175                 assoication_id = ql[0][0]
176             # Take action
177             if action == "add":
178                 if assoication_id:
179                     dak.lib.utils.warn("'%s~%s~%s' already exists in suite %s." % (package, version, architecture, suite))
180                     continue
181                 else:
182                     q = projectB.query("INSERT INTO src_associations (suite, source) VALUES (%s, %s)" % (suite_id, id))
183             elif action == "remove":
184                 if assoication_id == None:
185                     dak.lib.utils.warn("'%s~%s~%s' doesn't exist in suite %s." % (package, version, architecture, suite))
186                     continue
187                 else:
188                     q = projectB.query("DELETE FROM src_associations WHERE id = %s" % (assoication_id))
189         else:
190             # Find the existing assoications ID, if any
191             q = projectB.query("SELECT id FROM bin_associations WHERE suite = %s and bin = %s" % (suite_id, id))
192             ql = q.getresult()
193             if not ql:
194                 assoication_id = None
195             else:
196                 assoication_id = ql[0][0]
197             # Take action
198             if action == "add":
199                 if assoication_id:
200                     dak.lib.utils.warn("'%s~%s~%s' already exists in suite %s." % (package, version, architecture, suite))
201                     continue
202                 else:
203                     q = projectB.query("INSERT INTO bin_associations (suite, bin) VALUES (%s, %s)" % (suite_id, id))
204             elif action == "remove":
205                 if assoication_id == None:
206                     dak.lib.utils.warn("'%s~%s~%s' doesn't exist in suite %s." % (package, version, architecture, suite))
207                     continue
208                 else:
209                     q = projectB.query("DELETE FROM bin_associations WHERE id = %s" % (assoication_id))
210
211     projectB.query("COMMIT WORK")
212
213 #######################################################################################
214
215 def get_list (suite):
216     suite_id = dak.lib.database.get_suite_id(suite)
217     # List binaries
218     q = projectB.query("SELECT b.package, b.version, a.arch_string FROM binaries b, bin_associations ba, architecture a WHERE ba.suite = %s AND ba.bin = b.id AND b.architecture = a.id" % (suite_id))
219     ql = q.getresult()
220     for i in ql:
221         print " ".join(i)
222
223     # List source
224     q = projectB.query("SELECT s.source, s.version FROM source s, src_associations sa WHERE sa.suite = %s AND sa.source = s.id" % (suite_id))
225     ql = q.getresult()
226     for i in ql:
227         print " ".join(i) + " source"
228
229 #######################################################################################
230
231 def main ():
232     global Cnf, projectB, Logger
233
234     Cnf = dak.lib.utils.get_conf()
235
236     Arguments = [('a',"add","Control-Suite::Options::Add", "HasArg"),
237                  ('h',"help","Control-Suite::Options::Help"),
238                  ('l',"list","Control-Suite::Options::List","HasArg"),
239                  ('r',"remove", "Control-Suite::Options::Remove", "HasArg"),
240                  ('s',"set", "Control-Suite::Options::Set", "HasArg")]
241
242     for i in ["add", "help", "list", "remove", "set", "version" ]:
243         if not Cnf.has_key("Control-Suite::Options::%s" % (i)):
244             Cnf["Control-Suite::Options::%s" % (i)] = ""
245
246     file_list = apt_pkg.ParseCommandLine(Cnf,Arguments,sys.argv)
247     Options = Cnf.SubTree("Control-Suite::Options")
248
249     if Options["Help"]:
250         usage()
251
252     projectB = pg.connect(Cnf["DB::Name"], Cnf["DB::Host"],int(Cnf["DB::Port"]))
253
254     dak.lib.database.init(Cnf, projectB)
255
256     action = None
257
258     for i in ("add", "list", "remove", "set"):
259         if Cnf["Control-Suite::Options::%s" % (i)] != "":
260             suite = Cnf["Control-Suite::Options::%s" % (i)]
261             if dak.lib.database.get_suite_id(suite) == -1:
262                 dak.lib.utils.fubar("Unknown suite '%s'." %(suite))
263             else:
264                 if action:
265                     dak.lib.utils.fubar("Can only perform one action at a time.")
266                 action = i
267
268     # Need an action...
269     if action == None:
270         dak.lib.utils.fubar("No action specified.")
271
272     # Safety/Sanity check
273     if action == "set" and suite != "testing":
274         dak.lib.utils.fubar("Will not reset a suite other than testing.")
275
276     if action == "list":
277         get_list(suite)
278     else:
279         Logger = dak.lib.logging.Logger(Cnf, "control-suite")
280         if file_list:
281             for file in file_list:
282                 process_file(dak.lib.utils.open_file(file), suite, action)
283         else:
284             process_file(sys.stdin, suite, action)
285         Logger.close()
286
287 #######################################################################################
288
289 if __name__ == '__main__':
290     main()
291