1#! /usr/bin/env python3
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################################################################################
28import os
29import sys
30import apt_pkg
32from daklib.config import Config
33from daklib.dbconn import *
34from daklib import daklog
35from daklib import utils
37################################################################################
39# Shamelessly stolen from 'dak rm'. Should probably end up in utils.py
42def game_over():
43 answer = utils.input_or_exit("Continue (y/N)? ").lower()
44 if answer != "y":
45 print("Aborted.")
46 sys.exit(1)
49def usage(exit_code=0):
50 print("""Usage: dak override [OPTIONS] package [section] [priority]
51Make microchanges or microqueries of the binary overrides
53 -h, --help show this help and exit
54 -c, --check check override compliance (deprecated)
55 -d, --done=BUG# send priority/section change as closure to bug#
56 -n, --no-action don't do anything
57 -s, --suite specify the suite to use
58""")
59 sys.exit(exit_code)
62def main():
63 cnf = Config()
65 Arguments = [('h', "help", "Override::Options::Help"),
66 ('c', "check", "Override::Options::Check"),
67 ('d', "done", "Override::Options::Done", "HasArg"),
68 ('n', "no-action", "Override::Options::No-Action"),
69 ('s', "suite", "Override::Options::Suite", "HasArg"),
70 ]
71 for i in ["help", "check", "no-action"]:
72 key = "Override::Options::%s" % i
73 if key not in cnf: 73 ↛ 71line 73 didn't jump to line 71, because the condition on line 73 was never false
74 cnf[key] = ""
75 if "Override::Options::Suite" not in cnf: 75 ↛ 78line 75 didn't jump to line 78, because the condition on line 75 was never false
76 cnf["Override::Options::Suite"] = "unstable"
78 arguments = apt_pkg.parse_commandline(cnf.Cnf, Arguments, sys.argv)
79 Options = cnf.subtree("Override::Options")
81 if Options["Help"]: 81 ↛ 84line 81 didn't jump to line 84, because the condition on line 81 was never false
82 usage()
84 session = DBConn().session()
86 if not arguments:
87 utils.fubar("package name is a required argument.")
89 package = arguments.pop(0)
90 suite_name = Options["Suite"]
91 if arguments and len(arguments) > 2:
92 utils.fubar("Too many arguments")
94 suite = get_suite(suite_name, session)
95 if suite is None:
96 utils.fubar("Unknown suite '{0}'".format(suite_name))
98 if arguments and len(arguments) == 1:
99 # Determine if the argument is a priority or a section...
100 arg = arguments.pop()
101 q = session.execute("""
102 SELECT ( SELECT COUNT(*) FROM section WHERE section = :arg ) AS secs,
103 ( SELECT COUNT(*) FROM priority WHERE priority = :arg ) AS prios
104 """, {'arg': arg})
105 r = q.fetchall()
106 if r[0][0] == 1:
107 arguments = (arg, ".")
108 elif r[0][1] == 1:
109 arguments = (".", arg)
110 else:
111 utils.fubar("%s is not a valid section or priority" % (arg))
113 # Retrieve current section/priority...
114 oldsection, oldsourcesection, oldpriority = None, None, None
115 for packagetype in ['source', 'binary']:
116 eqdsc = '!='
117 if packagetype == 'source':
118 eqdsc = '='
119 q = session.execute("""
120 SELECT priority.priority AS prio, section.section AS sect, override_type.type AS type
121 FROM override, priority, section, suite, override_type
122 WHERE override.priority = priority.id
123 AND override.type = override_type.id
124 AND override_type.type %s 'dsc'
125 AND override.section = section.id
126 AND override.package = :package
127 AND override.suite = suite.id
128 AND suite.suite_name = :suite_name
129 """ % (eqdsc), {'package': package, 'suite_name': suite_name})
131 if q.rowcount == 0:
132 continue
133 if q.rowcount > 1:
134 utils.fubar("%s is ambiguous. Matches %d packages" % (package, q.rowcount))
136 r = q.fetchone()
137 if packagetype == 'binary':
138 oldsection = r[1]
139 oldpriority = r[0]
140 else:
141 oldsourcesection = r[1]
142 oldpriority = 'optional'
144 if not oldpriority and not oldsourcesection:
145 utils.fubar("Unable to find package %s" % (package))
147 if oldsection and oldsourcesection and oldsection != oldsourcesection:
148 # When setting overrides, both source & binary will become the same section
149 utils.warn("Source is in section '%s' instead of '%s'" % (oldsourcesection, oldsection))
151 if not oldsection:
152 oldsection = oldsourcesection
154 if not arguments:
155 print("%s is in section '%s' at priority '%s'" % (
156 package, oldsection, oldpriority))
157 sys.exit(0)
159 # At this point, we have a new section and priority... check they're valid...
160 newsection, newpriority = arguments
162 if newsection == ".":
163 newsection = oldsection
164 if newpriority == ".":
165 newpriority = oldpriority
167 s = get_section(newsection, session)
168 if s is None:
169 utils.fubar("Supplied section %s is invalid" % (newsection))
170 newsecid = s.section_id
172 p = get_priority(newpriority, session)
173 if p is None:
174 utils.fubar("Supplied priority %s is invalid" % (newpriority))
175 newprioid = p.priority_id
177 if newpriority == oldpriority and newsection == oldsection:
178 print("I: Doing nothing")
179 sys.exit(0)
181 if Options["Check"]:
182 print("WARNING: Check option is deprecated by Debian Policy 4.0.1")
184 # If we're in no-action mode
185 if Options["No-Action"]:
186 if newpriority != oldpriority:
187 print("I: Would change priority from %s to %s" % (oldpriority, newpriority))
188 if newsection != oldsection:
189 print("I: Would change section from %s to %s" % (oldsection, newsection))
190 if "Done" in Options:
191 print("I: Would also close bug(s): %s" % (Options["Done"]))
193 sys.exit(0)
195 if newpriority != oldpriority:
196 print("I: Will change priority from %s to %s" % (oldpriority, newpriority))
198 if newsection != oldsection:
199 print("I: Will change section from %s to %s" % (oldsection, newsection))
201 if "Done" not in Options:
202 pass
203 # utils.warn("No bugs to close have been specified. Noone will know you have done this.")
204 else:
205 print("I: Will close bug(s): %s" % (Options["Done"]))
207 game_over()
209 Logger = daklog.Logger("override")
211 dsc_otype_id = get_override_type('dsc').overridetype_id
213 # We're already in a transaction
214 # We're in "do it" mode, we have something to do... do it
215 if newpriority != oldpriority:
216 session.execute("""
217 UPDATE override
218 SET priority = :newprioid
219 WHERE package = :package
220 AND override.type != :otypedsc
221 AND suite = (SELECT id FROM suite WHERE suite_name = :suite_name)""",
222 {'newprioid': newprioid, 'package': package,
223 'otypedsc': dsc_otype_id, 'suite_name': suite_name})
225 Logger.log(["changed priority", package, oldpriority, newpriority])
227 if newsection != oldsection:
228 q = session.execute("""
229 UPDATE override
230 SET section = :newsecid
231 WHERE package = :package
232 AND suite = (SELECT id FROM suite WHERE suite_name = :suite_name)""",
233 {'newsecid': newsecid, 'package': package,
234 'suite_name': suite_name})
236 Logger.log(["changed section", package, oldsection, newsection])
238 session.commit()
240 if "Done" in Options:
241 if "Dinstall::BugServer" not in cnf:
242 utils.warn("Asked to send Done message but Dinstall::BugServer is not configured")
243 Logger.close()
244 return
246 Subst = {}
247 Subst["__OVERRIDE_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
248 Subst["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
249 bcc = []
250 if cnf.find("Dinstall::Bcc") != "":
251 bcc.append(cnf["Dinstall::Bcc"])
252 if bcc:
253 Subst["__BCC__"] = "Bcc: " + ", ".join(bcc)
254 else:
255 Subst["__BCC__"] = "X-Filler: 42"
256 if "Dinstall::PackagesServer" in cnf:
257 Subst["__CC__"] = "Cc: " + package + "@" + cnf["Dinstall::PackagesServer"] + "\nX-DAK: dak override"
258 else:
259 Subst["__CC__"] = "X-DAK: dak override"
260 Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
261 Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
262 Subst["__WHOAMI__"] = utils.whoami()
263 Subst["__SOURCE__"] = package
265 summary = "Concerning package %s...\n" % (package)
266 summary += "Operating on the %s suite\n" % (suite_name)
267 if newpriority != oldpriority:
268 summary += "Changed priority from %s to %s\n" % (oldpriority, newpriority)
269 if newsection != oldsection:
270 summary += "Changed section from %s to %s\n" % (oldsection, newsection)
271 Subst["__SUMMARY__"] = summary
273 template = os.path.join(cnf["Dir::Templates"], "override.bug-close")
274 for bug in utils.split_args(Options["Done"]):
275 Subst["__BUG_NUMBER__"] = bug
276 mail_message = utils.TemplateSubst(Subst, template)
277 utils.send_mail(mail_message)
278 Logger.log(["closed bug", bug])
280 Logger.close()
282#################################################################################
285if __name__ == '__main__':
286 main()