]> git.decadent.org.uk Git - dak.git/blob - dak/override.py
Merge branch 'master' of ssh://ftp-master.debian.org/srv/ftp.debian.org/git/dak
[dak.git] / dak / override.py
1 #!/usr/bin/env python
2
3 """ Microscopic modification and query tool for overrides in projectb """
4 # Copyright (C) 2004, 2006  Daniel Silverstone <dsilvers@digital-scurf.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 ## 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 ################################################################################
27
28 import os
29 import sys
30 import apt_pkg
31
32 from daklib.config import Config
33 from daklib.dbconn import *
34 from daklib import daklog
35 from daklib import utils
36
37 ################################################################################
38
39 # Shamelessly stolen from 'dak rm'. Should probably end up in utils.py
40 def game_over():
41     answer = utils.our_raw_input("Continue (y/N)? ").lower()
42     if answer != "y":
43         print "Aborted."
44         sys.exit(1)
45
46
47 def usage (exit_code=0):
48     print """Usage: dak override [OPTIONS] package [section] [priority]
49 Make microchanges or microqueries of the binary overrides
50
51   -h, --help                 show this help and exit
52   -d, --done=BUG#            send priority/section change as closure to bug#
53   -n, --no-action            don't do anything
54   -s, --suite                specify the suite to use
55 """
56     sys.exit(exit_code)
57
58 def main ():
59     cnf = Config()
60
61     Arguments = [('h',"help","Override::Options::Help"),
62                  ('d',"done","Override::Options::Done", "HasArg"),
63                  ('n',"no-action","Override::Options::No-Action"),
64                  ('s',"suite","Override::Options::Suite", "HasArg"),
65                  ]
66     for i in ["help", "no-action"]:
67         if not cnf.has_key("Override::Options::%s" % (i)):
68             cnf["Override::Options::%s" % (i)] = ""
69     if not cnf.has_key("Override::Options::Suite"):
70         cnf["Override::Options::Suite"] = "unstable"
71
72     arguments = apt_pkg.ParseCommandLine(cnf.Cnf, Arguments, sys.argv)
73     Options = cnf.SubTree("Override::Options")
74
75     if Options["Help"]:
76         usage()
77
78     session = DBConn().session()
79
80     if not arguments:
81         utils.fubar("package name is a required argument.")
82
83     package = arguments.pop(0)
84     suite = Options["Suite"]
85     if arguments and len(arguments) > 2:
86         utils.fubar("Too many arguments")
87
88     if arguments and len(arguments) == 1:
89         # Determine if the argument is a priority or a section...
90         arg = arguments.pop()
91         q = session.execute("""
92         SELECT ( SELECT COUNT(*) FROM section WHERE section = :arg ) AS secs,
93                ( SELECT COUNT(*) FROM priority WHERE priority = :arg ) AS prios
94                """, {'arg': arg})
95         r = q.fetchall()
96         if r[0][0] == 1:
97             arguments = (arg, ".")
98         elif r[0][1] == 1:
99             arguments = (".", arg)
100         else:
101             utils.fubar("%s is not a valid section or priority" % (arg))
102
103     # Retrieve current section/priority...
104     oldsection, oldsourcesection, oldpriority = None, None, None
105     for packagetype in ['source', 'binary']:
106         eqdsc = '!='
107         if packagetype == 'source':
108             eqdsc = '='
109         q = session.execute("""
110     SELECT priority.priority AS prio, section.section AS sect, override_type.type AS type
111       FROM override, priority, section, suite, override_type
112      WHERE override.priority = priority.id
113        AND override.type = override_type.id
114        AND override_type.type %s 'dsc'
115        AND override.section = section.id
116        AND override.package = :package
117        AND override.suite = suite.id
118        AND suite.suite_name = :suite
119         """ % (eqdsc), {'package': package, 'suite': suite})
120
121         if q.rowcount == 0:
122             continue
123         if q.rowcount > 1:
124             utils.fubar("%s is ambiguous. Matches %d packages" % (package,q.rowcount))
125
126         r = q.fetchone()
127         if packagetype == 'binary':
128             oldsection = r[1]
129             oldpriority = r[0]
130         else:
131             oldsourcesection = r[1]
132             oldpriority = 'source'
133
134     if not oldpriority and not oldsourcesection:
135         utils.fubar("Unable to find package %s" % (package))
136
137     if oldsection and oldsourcesection and oldsection != oldsourcesection:
138         # When setting overrides, both source & binary will become the same section
139         utils.warn("Source is in section '%s' instead of '%s'" % (oldsourcesection, oldsection))
140
141     if not oldsection:
142         oldsection = oldsourcesection
143
144     if not arguments:
145         print "%s is in section '%s' at priority '%s'" % (
146             package, oldsection, oldpriority)
147         sys.exit(0)
148
149     # At this point, we have a new section and priority... check they're valid...
150     newsection, newpriority = arguments
151
152     if newsection == ".":
153         newsection = oldsection
154     if newpriority == ".":
155         newpriority = oldpriority
156
157     s = get_section(newsection, session)
158     if s is None:
159         utils.fubar("Supplied section %s is invalid" % (newsection))
160     newsecid = s.section_id
161
162     p = get_priority(newpriority, session)
163     if p is None:
164         utils.fubar("Supplied priority %s is invalid" % (newpriority))
165     newprioid = p.priority_id
166
167     if newpriority == oldpriority and newsection == oldsection:
168         print "I: Doing nothing"
169         sys.exit(0)
170
171     if oldpriority == 'source' and newpriority != 'source':
172         utils.fubar("Trying to change priority of a source-only package")
173
174     # If we're in no-action mode
175     if Options["No-Action"]:
176         if newpriority != oldpriority:
177             print "I: Would change priority from %s to %s" % (oldpriority,newpriority)
178         if newsection != oldsection:
179             print "I: Would change section from %s to %s" % (oldsection,newsection)
180         if Options.has_key("Done"):
181             print "I: Would also close bug(s): %s" % (Options["Done"])
182
183         sys.exit(0)
184
185     if newpriority != oldpriority:
186         print "I: Will change priority from %s to %s" % (oldpriority,newpriority)
187
188     if newsection != oldsection:
189         print "I: Will change section from %s to %s" % (oldsection,newsection)
190
191     if not Options.has_key("Done"):
192         pass
193         #utils.warn("No bugs to close have been specified. Noone will know you have done this.")
194     else:
195         print "I: Will close bug(s): %s" % (Options["Done"])
196
197     game_over()
198
199     Logger = daklog.Logger(cnf.Cnf, "override")
200
201     dsc_otype_id = get_override_type('dsc').overridetype_id
202
203     # We're already in a transaction
204     # We're in "do it" mode, we have something to do... do it
205     if newpriority != oldpriority:
206         session.execute("""
207         UPDATE override
208            SET priority = :newprioid
209          WHERE package = :package
210            AND override.type != :otypedsc
211            AND suite = (SELECT id FROM suite WHERE suite_name = :suite)""",
212            {'newprioid': newprioid, 'package': package,
213             'otypedsc':  dsc_otype_id, 'suite': suite})
214
215         Logger.log(["changed priority", package, oldpriority, newpriority])
216
217     if newsection != oldsection:
218         q = session.execute("""
219         UPDATE override
220            SET section = :newsecid
221          WHERE package = :package
222            AND suite = (SELECT id FROM suite WHERE suite_name = :suite)""",
223            {'newsecid': newsecid, 'package': package,
224             'suite': suite})
225
226         Logger.log(["changed section", package, oldsection, newsection])
227
228     session.commit()
229
230     if Options.has_key("Done"):
231         Subst = {}
232         Subst["__OVERRIDE_ADDRESS__"] = cnf["Dinstall::MyEmailAddress"]
233         Subst["__BUG_SERVER__"] = cnf["Dinstall::BugServer"]
234         bcc = []
235         if cnf.Find("Dinstall::Bcc") != "":
236             bcc.append(cnf["Dinstall::Bcc"])
237         if bcc:
238             Subst["__BCC__"] = "Bcc: " + ", ".join(bcc)
239         else:
240             Subst["__BCC__"] = "X-Filler: 42"
241         Subst["__CC__"] = "Cc: " + package + "@" + cnf["Dinstall::PackagesServer"] + "\nX-DAK: dak override"
242         Subst["__ADMIN_ADDRESS__"] = cnf["Dinstall::MyAdminAddress"]
243         Subst["__DISTRO__"] = cnf["Dinstall::MyDistribution"]
244         Subst["__WHOAMI__"] = utils.whoami()
245         Subst["__SOURCE__"] = package
246
247         summary = "Concerning package %s...\n" % (package)
248         summary += "Operating on the %s suite\n" % (suite)
249         if newpriority != oldpriority:
250             summary += "Changed priority from %s to %s\n" % (oldpriority,newpriority)
251         if newsection != oldsection:
252             summary += "Changed section from %s to %s\n" % (oldsection,newsection)
253         Subst["__SUMMARY__"] = summary
254
255         template = os.path.join(cnf["Dir::Templates"], "override.bug-close")
256         for bug in utils.split_args(Options["Done"]):
257             Subst["__BUG_NUMBER__"] = bug
258             mail_message = utils.TemplateSubst(Subst, template)
259             utils.send_mail(mail_message)
260             Logger.log(["closed bug", bug])
261
262     Logger.close()
263
264 #################################################################################
265
266 if __name__ == '__main__':
267     main()