3 """ Microscopic modification and query tool for overrides in projectb """
4 # Copyright (C) 2004, 2006 Daniel Silverstone <dsilvers@digital-scurf.org>
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.
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.
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
21 ################################################################################
22 ## So line up your soldiers and she'll shoot them all down
23 ## Coz Alisha Rules The World
24 ## You think you found a dream, then it shatters and it seems,
25 ## That Alisha Rules The World
26 ################################################################################
33 from daklib.config import Config
34 from daklib.dbconn import *
35 from daklib import daklog
36 from daklib import utils
38 ################################################################################
40 # Shamelessly stolen from 'dak rm'. Should probably end up in utils.py
42 answer = utils.our_raw_input("Continue (y/N)? ").lower()
48 def usage (exit_code=0):
49 print """Usage: dak override [OPTIONS] package [section] [priority]
50 Make microchanges or microqueries of the binary overrides
52 -h, --help show this help and exit
53 -c, --check chech override compliance
54 -d, --done=BUG# send priority/section change as closure to bug#
55 -n, --no-action don't do anything
56 -s, --suite specify the suite to use
60 def check_override_compliance(package, priority, suite, cnf, session):
61 print "Checking compliance with related overrides..."
65 components = cnf.ValueList("Suite::%s::Components" % suite)
66 arches = set([x.arch_string for x in get_suite_architectures(suite)])
67 arches -= set(["source", "all"])
69 for component in components:
70 filename = "%s/dists/%s/%s/binary-%s/Packages.gz" % (cnf["Dir::Root"], suite, component, arch)
71 (fd, temp_filename) = utils.temp_filename()
72 (result, output) = commands.getstatusoutput("gunzip -c %s > %s" % (filename, temp_filename))
74 utils.fubar("Gunzip invocation failed!\n%s\n" % (output), result)
75 filename = "%s/dists/%s/%s/debian-installer/binary-%s/Packages.gz" % (cnf["Dir::Root"], suite, component, arch)
76 if os.path.exists(filename):
77 (result, output) = commands.getstatusoutput("gunzip -c %s >> %s" % (filename, temp_filename))
79 utils.fubar("Gunzip invocation failed!\n%s\n" % (output), result)
80 packages = utils.open_file(temp_filename)
81 Packages = apt_pkg.ParseTagFile(packages)
82 while Packages.Step():
83 package_name = Packages.Section.Find("Package")
84 dep_list = Packages.Section.Find("Depends")
86 if package_name == package:
87 for d in apt_pkg.ParseDepends(dep_list):
91 for d in apt_pkg.ParseDepends(dep_list):
94 rdepends.add(package_name)
95 os.unlink(temp_filename)
97 query = """SELECT o.package, p.level, p.priority
99 JOIN suite s ON s.id = o.suite
100 JOIN priority p ON p.id = o.priority
101 WHERE s.suite_name = '%s'
102 AND o.package in ('%s')""" \
103 % (suite, "', '".join(depends.union(rdepends)))
104 packages = session.execute(query)
108 if p[0] == package or not p[1]:
111 if priority.level < p[1]:
112 excuses.append("%s would have priority %s, its dependency %s has priority %s" \
113 % (package, priority.priority, p[0], p[2]))
115 if priority.level > p[1]:
116 excuses.append("%s would have priority %s, its reverse dependency %s has priority %s" \
117 % (package, priority.priority, p[0], p[2]))
123 print "Proposed override change complies with Debian Policy"
128 Arguments = [('h',"help","Override::Options::Help"),
129 ('c',"check","Override::Options::Check"),
130 ('d',"done","Override::Options::Done", "HasArg"),
131 ('n',"no-action","Override::Options::No-Action"),
132 ('s',"suite","Override::Options::Suite", "HasArg"),
134 for i in ["help", "check", "no-action"]:
135 if not cnf.has_key("Override::Options::%s" % (i)):
136 cnf["Override::Options::%s" % (i)] = ""
137 if not cnf.has_key("Override::Options::Suite"):
138 cnf["Override::Options::Suite"] = "unstable"
140 arguments = apt_pkg.ParseCommandLine(cnf.Cnf, Arguments, sys.argv)
141 Options = cnf.SubTree("Override::Options")
146 session = DBConn().session()
149 utils.fubar("package name is a required argument.")
151 package = arguments.pop(0)
152 suite = Options["Suite"]
153 if arguments and len(arguments) > 2:
154 utils.fubar("Too many arguments")
156 if arguments and len(arguments) == 1:
157 # Determine if the argument is a priority or a section...
158 arg = arguments.pop()
159 q = session.execute("""
160 SELECT ( SELECT COUNT(*) FROM section WHERE section = :arg ) AS secs,
161 ( SELECT COUNT(*) FROM priority WHERE priority = :arg ) AS prios
165 arguments = (arg, ".")
167 arguments = (".", arg)
169 utils.fubar("%s is not a valid section or priority" % (arg))
171 # Retrieve current section/priority...
172 oldsection, oldsourcesection, oldpriority = None, None, None
173 for packagetype in ['source', 'binary']:
175 if packagetype == 'source':
177 q = session.execute("""
178 SELECT priority.priority AS prio, section.section AS sect, override_type.type AS type
179 FROM override, priority, section, suite, override_type
180 WHERE override.priority = priority.id
181 AND override.type = override_type.id
182 AND override_type.type %s 'dsc'
183 AND override.section = section.id
184 AND override.package = :package
185 AND override.suite = suite.id
186 AND suite.suite_name = :suite
187 """ % (eqdsc), {'package': package, 'suite': suite})
192 utils.fubar("%s is ambiguous. Matches %d packages" % (package,q.rowcount))
195 if packagetype == 'binary':
199 oldsourcesection = r[1]
200 oldpriority = 'source'
202 if not oldpriority and not oldsourcesection:
203 utils.fubar("Unable to find package %s" % (package))
205 if oldsection and oldsourcesection and oldsection != oldsourcesection:
206 # When setting overrides, both source & binary will become the same section
207 utils.warn("Source is in section '%s' instead of '%s'" % (oldsourcesection, oldsection))
210 oldsection = oldsourcesection
213 print "%s is in section '%s' at priority '%s'" % (
214 package, oldsection, oldpriority)
217 # At this point, we have a new section and priority... check they're valid...
218 newsection, newpriority = arguments
220 if newsection == ".":
221 newsection = oldsection
222 if newpriority == ".":
223 newpriority = oldpriority
225 s = get_section(newsection, session)
227 utils.fubar("Supplied section %s is invalid" % (newsection))
228 newsecid = s.section_id
230 p = get_priority(newpriority, session)
232 utils.fubar("Supplied priority %s is invalid" % (newpriority))
233 newprioid = p.priority_id
235 if newpriority == oldpriority and newsection == oldsection:
236 print "I: Doing nothing"
239 if oldpriority == 'source' and newpriority != 'source':
240 utils.fubar("Trying to change priority of a source-only package")
242 if Options["Check"] and newpriority != oldpriority:
243 check_override_compliance(package, p, suite, cnf, session)
245 # If we're in no-action mode
246 if Options["No-Action"]:
247 if newpriority != oldpriority:
248 print "I: Would change priority from %s to %s" % (oldpriority,newpriority)
249 if newsection != oldsection:
250 print "I: Would change section from %s to %s" % (oldsection,newsection)
251 if Options.has_key("Done"):
252 print "I: Would also close bug(s): %s" % (Options["Done"])
256 if newpriority != oldpriority:
257 print "I: Will change priority from %s to %s" % (oldpriority,newpriority)
259 if newsection != oldsection:
260 print "I: Will change section from %s to %s" % (oldsection,newsection)
262 if not Options.has_key("Done"):
264 #utils.warn("No bugs to close have been specified. Noone will know you have done this.")
266 print "I: Will close bug(s): %s" % (Options["Done"])
270 Logger = daklog.Logger(cnf.Cnf, "override")
272 dsc_otype_id = get_override_type('dsc').overridetype_id
274 # We're already in a transaction
275 # We're in "do it" mode, we have something to do... do it
276 if newpriority != oldpriority:
279 SET priority = :newprioid
280 WHERE package = :package
281 AND override.type != :otypedsc
282 AND suite = (SELECT id FROM suite WHERE suite_name = :suite)""",
283 {'newprioid': newprioid, 'package': package,
284 'otypedsc': dsc_otype_id, 'suite': suite})
286 Logger.log(["changed priority", package, oldpriority, newpriority])
288 if newsection != oldsection:
289 q = session.execute("""
291 SET section = :newsecid
292 WHERE package = :package
293 AND suite = (SELECT id FROM suite WHERE suite_name = :suite)""",
294 {'newsecid': newsecid, 'package': package,
297 Logger.log(["changed section", package, oldsection, newsection])
301 if Options.has_key("Done"):
303 Subst["__OVERRIDE_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
304 Subst["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
306 if cnf.Find("Dinstall::Bcc") != "":
307 bcc.append(cnf["Dinstall::Bcc"])
309 Subst["__BCC__"] = "Bcc: " + ", ".join(bcc)
311 Subst["__BCC__"] = "X-Filler: 42"
312 Subst["__CC__"] = "Cc: " + package + "@" + cnf["Dinstall::PackagesServer"] + "\nX-DAK: dak override"
313 Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
314 Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
315 Subst["__WHOAMI__"] = utils.whoami()
316 Subst["__SOURCE__"] = package
318 summary = "Concerning package %s...\n" % (package)
319 summary += "Operating on the %s suite\n" % (suite)
320 if newpriority != oldpriority:
321 summary += "Changed priority from %s to %s\n" % (oldpriority,newpriority)
322 if newsection != oldsection:
323 summary += "Changed section from %s to %s\n" % (oldsection,newsection)
324 Subst["__SUMMARY__"] = summary
326 template = os.path.join(cnf["Dir::Templates"], "override.bug-close")
327 for bug in utils.split_args(Options["Done"]):
328 Subst["__BUG_NUMBER__"] = bug
329 mail_message = utils.TemplateSubst(Subst, template)
330 utils.send_mail(mail_message)
331 Logger.log(["closed bug", bug])
335 #################################################################################
337 if __name__ == '__main__':