PQM

Merge lp:~stub/pqm/config-reload into lp:pqm

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
Reviewer Review Type Date Requested Status
Robert Collins Approve
Review via email: mp+1757@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

Reload config and global state after processing each job in --run mode.

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
Revision history for this message
Robert Collins (lifeless) wrote :

Ping; still conflicts.

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+ print
30+ for (patchname, logname) in badscripts:
31+ print "Patch: " + patchname
32+ print "Status: failure"
33+ print "Log: " + logname
34+ print
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

Subscribers

People subscribed via source and target branches