Merge lp:~stub/pqm/config-reload into lp:pqm
- config-reload
- Merge into trunk
Proposed by
Stuart Bishop
Status: | Work in progress |
---|---|
Proposed branch: | lp:~stub/pqm/config-reload |
Merge into: | lp:pqm |
Diff against target: |
329 lines (has conflicts)
Text conflict in bin/pqm |
To merge this branch: | bzr merge lp:~stub/pqm/config-reload |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Robert Collins | Approve | ||
Review via email: mp+1757@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote : | # |
The intent looks good, and given the massive globals of the time, reload() looks roughly right. However Tim has been busily refactoring things to make this better, so this is conflicting with trunk. Minimally it needs conflicts resolved, but it may be deeper than that.
review:
Approve
Unmerged revisions
- 184. By Stuart Bishop
-
Reload config and all global state every job
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/pqm' |
2 | --- bin/pqm 2008-11-21 00:43:51 +0000 |
3 | +++ bin/pqm 2009-03-26 03:50:11 +0000 |
4 | @@ -72,7 +72,138 @@ |
5 | raise PQMTlaFailure(sender, ["VCS command %s %s failed (%s): %s" % (cmd, args, status, msg)] + output) |
6 | return output |
7 | |
8 | +<<<<<<< TREE |
9 | def do_read_mode(logger, options, mail_reply, mail_server, from_address, fromaddr): |
10 | +======= |
11 | +def do_run_mode(): |
12 | + (goodscripts, badscripts) = ([], []) |
13 | + scripts = find_patches( |
14 | + queuedir, logger, rev_optionhandler, configp, options) |
15 | + while scripts: |
16 | + if os.path.isfile("%s/stop.patch" % queuedir): |
17 | + break |
18 | + run_one_script(logger, script, logdir, goodscripts, badscripts, |
19 | + mail_reply, mail_server, from_address, fromaddr, options) |
20 | + reload() |
21 | + scripts = find_patches( |
22 | + queuedir, logger, rev_optionhandler, configp, options) |
23 | + |
24 | + if options.print_report: |
25 | + for (patchname, logname) in goodscripts: |
26 | + print "Patch: " + patchname |
27 | + print "Status: success" |
28 | + print "Log: " + logname |
29 | |
30 | + for (patchname, logname) in badscripts: |
31 | + print "Patch: " + patchname |
32 | + print "Status: failure" |
33 | + print "Log: " + logname |
34 | |
35 | + |
36 | +def run_one_script(logger, script, logdir, goodscripts, badscripts, |
37 | + mail_reply, mail_server, from_address, fromaddr, options): |
38 | + # FIXME: This is currently extremely hard to test. move it to the library, |
39 | + # and test it! |
40 | + try: |
41 | + success = False |
42 | + try: |
43 | + logger.info('trying script ' + script.filename) |
44 | + logname = os.path.join(logdir, os.path.basename(script.filename) + '.log') |
45 | + (sender, subject, msg, sig) = read_email(logger, open(script.filename)) |
46 | + if options.verify_sigs: |
47 | + sigid,siguid = verify_sig( |
48 | + script.getSender(), msg, sig, 0, logger, options.keyring) |
49 | + output = [] |
50 | + failedcmd=None |
51 | + |
52 | + # ugly transitional code |
53 | + pqm.logger = logger |
54 | + pqm.workdir = workdir |
55 | + pqm.runtla = runtla |
56 | + pqm.precommit_hook = precommit_hook |
57 | + (successes, unrecognized, output) = script.run() |
58 | + |
59 | + logger.info('successes: %s' % (successes,)) |
60 | + logger.info('unrecognized: %s' % (unrecognized,)) |
61 | + success = True |
62 | + goodscripts.append((script.filename, logname)) |
63 | + except PQMCmdFailure, e: |
64 | + badscripts.append((script.filename, logname)) |
65 | + successes = e.goodcmds |
66 | + failedcmd = e.badcmd |
67 | + output = e.output |
68 | + unrecognized=[] |
69 | + except PQMException, e: |
70 | + badscripts.append((script.filename, logname)) |
71 | + successes = [] |
72 | + failedcmd = [] |
73 | + output = [str(e)] |
74 | + unrecognized=[] |
75 | + except Exception, e: |
76 | + # catch all to ensure we get some output in uncaught failures |
77 | + output = [str(e)] |
78 | + raise |
79 | + if mail_reply: |
80 | + send_mail_reply(success, successes, unrecognized, |
81 | + mail_server, from_address, script.getSender(), |
82 | + fromaddr, failedcmd, output, script) |
83 | + else: |
84 | + logger.info('not sending mail reply') |
85 | + finally: |
86 | + # ensure we always unlink the script file. |
87 | + log_list(logname, output) |
88 | + os.unlink(script.filename) |
89 | + |
90 | +def send_mail_reply(success, successes, unrecognized, mail_server, from_address, sender, fromaddr, failedcmd, output, script): |
91 | + if success: |
92 | + retmesg = mail_format_successes(successes, "Command was successful.", unrecognized) |
93 | + if len(successes) > 0: |
94 | + statusmsg='success' |
95 | + else: |
96 | + statusmsg='no valid commands given' |
97 | + else: |
98 | + retmesg = mail_format_successes(successes, "Command passed checks, but was not committed.", unrecognized) |
99 | + retmesg+= "\n%s" % failedcmd |
100 | + retmesg+= '\nCommand failed!' |
101 | + if not script.debug: |
102 | + retmesg += '\nLast 20 lines of log output:' |
103 | + retmesg += ''.join(output[-20:]) |
104 | + else: |
105 | + retmesg += '\nAll lines of log output:' |
106 | + retmesg += ''.join(output) |
107 | + statusmsg='failure' |
108 | + server = smtplib.SMTP(mail_server) |
109 | + server.sendmail(from_address, [sender], 'From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s\n' % (fromaddr, sender, statusmsg, retmesg)) |
110 | + server.quit() |
111 | + |
112 | +def mail_format_successes(successes, command_msg, unrecognized): |
113 | + retmesg = [] |
114 | + for success in successes: |
115 | + retmesg.append('> ' + success) |
116 | + retmesg.append(command_msg) |
117 | + for line in unrecognized: |
118 | + retmesg.append('> ' + line) |
119 | + retmesg.append('Unrecognized command.') |
120 | + return string.join(retmesg, '\n') |
121 | + |
122 | +def log_list(logname, list): |
123 | + f = open(logname, 'w') |
124 | + for l in list: |
125 | + f.write(l) |
126 | + f.close() |
127 | + |
128 | +def run(): |
129 | + lockfile=LockFile(os.path.join(pqm_subdir, 'pqm.lock'), logger, |
130 | + options.no_act, options.cron_mode) |
131 | + lockfile.acquire() |
132 | + try: |
133 | + if options.run_mode: |
134 | + do_run_mode() |
135 | + finally: |
136 | + lockfile.release() |
137 | + |
138 | +def do_read_mode(): |
139 | +>>>>>>> MERGE-SOURCE |
140 | sender = None |
141 | try: |
142 | (sender, subject, msg, sig) = read_email(logger) |
143 | @@ -98,6 +229,7 @@ |
144 | sys.exit(1) |
145 | sys.exit(0) |
146 | |
147 | +<<<<<<< TREE |
148 | arch_path = 'baz' |
149 | arch_impl = None |
150 | logfile_name = 'pqm.log' |
151 | @@ -220,9 +352,151 @@ |
152 | filehandler.setLevel(logging.DEBUG) |
153 | logger.addHandler(filehandler) |
154 | filehandler.setFormatter(logging.Formatter( |
155 | +======= |
156 | +def reload(): |
157 | + """Load or reload all our configurable state.""" |
158 | + global pqm_subdir, queuedir, logger, logdir, mail_reply, mail_server |
159 | + global from_address, fromaddr, options, configp |
160 | + |
161 | + arch_path = 'baz' |
162 | + arch_impl = None |
163 | + logfile_name = 'pqm.log' |
164 | + default_mail_log_level = logging.ERROR |
165 | + mail_server = 'localhost' |
166 | + queuedir = None |
167 | + workdir = None |
168 | + logdir = None |
169 | + mail_reply = 1 |
170 | + from_address = None |
171 | + precommit_hook = [] |
172 | + |
173 | + (options, args) = parse_command_line(sys.argv[1:]) |
174 | + |
175 | + if options.show_version: |
176 | + print "pqm %s" % pqm.__version__ |
177 | + sys.exit(0) |
178 | + |
179 | + logger = logging.getLogger("pqm") |
180 | + # TODO: move the logging confuration somewhere else. |
181 | + logger.setLevel(logging.DEBUG) |
182 | + stderr_handler = logging.StreamHandler(strm=sys.stderr) |
183 | + stderr_handler.setLevel(options.loglevel) |
184 | + stderr_handler.setFormatter(logging.Formatter( |
185 | + fmt="%(name)s [%(thread)d] %(levelname)s: %(message)s")) |
186 | + logger.addHandler(stderr_handler) |
187 | + |
188 | + if not (options.read_mode or options.run_mode): |
189 | + logger.error("Either --read or --run must be specified") |
190 | + sys.exit(1) |
191 | + |
192 | + configp = ConfigParser() |
193 | + logger.debug("Reading config files: %s" % (options.configfile_names,)) |
194 | + configp.read(options.configfile_names) |
195 | + |
196 | + if configp.has_option('DEFAULT', 'arch_path'): |
197 | + arch_path = configp.get('DEFAULT', 'arch_path') |
198 | + elif configp.has_option('DEFAULT', 'tlapath'): |
199 | + logger.warn("Option 'tlapath' is deprecated") |
200 | + arch_path = configp.get('DEFAULT', 'tlapath') |
201 | + |
202 | + if os.access(arch_path, os.X_OK): |
203 | + logger.error( |
204 | + "Can't execute \"%s\", please fix arch_path" % (arch_path,)) |
205 | + sys.exit(1) |
206 | + |
207 | + # ugly transitional code |
208 | + pqm.logger = logger |
209 | + if configp.has_option('DEFAULT', 'arch_impl'): |
210 | + impl = configp.get('DEFAULT', 'arch_impl') |
211 | + if impl == 'tla': |
212 | + arch_impl = TlaHandler() |
213 | + elif impl == 'arx': |
214 | + arch_impl = ArXHandler() |
215 | + elif impl == 'baz': |
216 | + arch_impl = Baz1_1Handler() |
217 | + elif impl == 'baz1.0': |
218 | + arch_impl = Baz1_0Handler() |
219 | + else: |
220 | + logger.error("Unknown arch_impl \"%s\"" % (impl,)) |
221 | + sys.exit(1) |
222 | + # FIXME: move this into a nicer place. |
223 | + Command.arch_impl = arch_impl |
224 | + Command.arch_path = arch_path |
225 | + |
226 | + pqm.gpgv_path = configp.get_option('DEFAULT', 'gpgv_path', 'gpgv') |
227 | + myname = configp.get_option( |
228 | + 'DEFAULT', 'myname', 'Arch Patch Queue Manager') |
229 | + |
230 | + if configp.has_option('DEFAULT', 'from_address'): |
231 | + from_address = configp.get('DEFAULT', 'from_address') |
232 | + else: |
233 | + logger.error("No from_address specified") |
234 | + sys.exit(1) |
235 | + fromaddr = '%s <%s>' % (myname, from_address) |
236 | + |
237 | + mail_reply=configp.get_boolean_option('DEFAULT', 'mail_reply',1) |
238 | + # The command line parameter overrides the setting in the config file. |
239 | + if options.verify_sigs: |
240 | + options.verify_sigs = configp.get_boolean_option( |
241 | + 'DEFAULT', 'verify_sigs', True) |
242 | + |
243 | + if options.queuedir: |
244 | + queuedir = options.queuedir |
245 | + else: |
246 | + queuedir = get_queuedir(configp, logger, args) |
247 | + queuedir=os.path.abspath(queuedir) |
248 | + pqm_subdir = os.path.join(queuedir, 'pqm') |
249 | + pqm.pqm_subdir = pqm_subdir |
250 | + |
251 | + if not configp.has_option('DEFAULT', 'dont_set_home'): |
252 | + os.environ['HOME'] = queuedir |
253 | + |
254 | + workdir=dir_from_option(configp, 'workdir', 'workdir') |
255 | + logdir=dir_from_option(configp, 'logdir', 'logs') |
256 | + |
257 | + if not options.keyring: |
258 | + if configp.has_option('DEFAULT', 'keyring'): |
259 | + options.keyring = configp.get('DEFAULT', 'keyring') |
260 | + else: |
261 | + logger.error( |
262 | + "No keyring specified on command line or in config files.") |
263 | + sys.exit(1) |
264 | + if not os.access(options.keyring, os.R_OK): |
265 | + logger.error("Couldn't access keyring %s" % (options.keyring,)) |
266 | + sys.exit(1) |
267 | + |
268 | + do_mkdir(queuedir, options.no_act) |
269 | + os.chdir(queuedir) |
270 | + do_mkdir(workdir, options.no_act) |
271 | + do_mkdir(logdir, options.no_act) |
272 | + do_mkdir(pqm_subdir, options.no_act) |
273 | + |
274 | + rev_optionhandler = pqm.BranchSpecOptionHandler(configp, queuedir=queuedir) |
275 | + if len(rev_optionhandler._specs) == 0: |
276 | + logger.error("No branches to manage!") |
277 | + sys.exit(1) |
278 | + for spec in rev_optionhandler._specs: |
279 | + logger.info("managing branch(s): " + spec) |
280 | + |
281 | + if configp.has_option('DEFAULT', 'logfile'): |
282 | + logfile_name = configp.get('DEFAULT', 'logfile') |
283 | + |
284 | + if not options.no_log: |
285 | + if not os.path.isabs(logfile_name): |
286 | + logfile_name = os.path.join(pqm_subdir, logfile_name) |
287 | + logger.debug("Adding log file: %s" % (logfile_name,)) |
288 | + filehandler = logging.FileHandler(logfile_name) |
289 | + if options.loglevel >= logging.WARN: |
290 | + filehandler.setLevel(logging.INFO) |
291 | + else: |
292 | + filehandler.setLevel(logging.DEBUG) |
293 | + logger.addHandler(filehandler) |
294 | + filehandler.setFormatter(logging.Formatter( |
295 | +>>>>>>> MERGE-SOURCE |
296 | fmt="%(asctime)s %(name)s [%(thread)d] %(levelname)s: %(message)s", |
297 | datefmt="%b %d %H:%M:%S")) |
298 | |
299 | +<<<<<<< TREE |
300 | if not options.debug_mode: |
301 | # Don't log to stderr past this point |
302 | logger.removeHandler(stderr_handler) |
303 | @@ -246,4 +520,27 @@ |
304 | |
305 | logger.info("main thread exiting...") |
306 | sys.exit(0) |
307 | +======= |
308 | + if not options.debug_mode: |
309 | + # Don't log to stderr past this point |
310 | + logger.removeHandler(stderr_handler) |
311 | + |
312 | + transaction_file = os.path.join(queuedir, 'transactions-completed') |
313 | + if os.access(transaction_file, os.R_OK): |
314 | + lines = open(transaction_file).readlines() |
315 | + for line in lines: |
316 | + pqm.used_transactions[line[0:-1]] = 1 |
317 | + |
318 | +if __name__ == '__main__': |
319 | + reload() |
320 | + |
321 | + if options.read_mode: |
322 | + do_read_mode(logger, options, transaction_file) |
323 | + |
324 | + assert(options.run_mode) |
325 | + |
326 | + run() |
327 | + logger.info("main thread exiting...") |
328 | + sys.exit(0) |
329 | +>>>>>>> MERGE-SOURCE |
330 |
Reload config and global state after processing each job in --run mode.