def recalculate(self, fetch_stale_interfaces = True): """@deprecated: see L{solve_with_downloads} """ self.stale_feeds = set() host_arch = self.target_arch if self.src: host_arch = arch.SourceArchitecture(host_arch) self.solver.solve(self.root, host_arch) if self.network_use == network_offline: fetch_stale_interfaces = False blockers = [] for f in self.solver.feeds_used: if f.startswith('/'): continue feed = iface_cache.get_feed(f) if feed is None or feed.last_modified is None: self.download_and_import_feed_if_online(f) # Will start a download elif self.is_stale(feed): debug(_("Adding %s to stale set"), f) self.stale_feeds.add(iface_cache.get_interface(f)) # Legacy API if fetch_stale_interfaces: self.download_and_import_feed_if_online(f) # Will start a download for w in self.watchers: w() return blockers
def _main_feed(self): import warnings warnings.warn("use the feed instead", DeprecationWarning, 3) from zeroinstall.injector import policy iface_cache = policy.get_deprecated_singleton_config().iface_cache feed = iface_cache.get_feed(self.uri) if feed is None: return _dummy_feed return feed
def _manage_feeds(options, args): from zeroinstall.injector import writer from zeroinstall.injector.handler import Handler from zeroinstall.injector.policy import Policy handler = Handler(dry_run = options.dry_run) if not args: raise UsageError() for x in args: print _("Feed '%s':") % x + '\n' x = model.canonical_iface_uri(x) policy = Policy(x, handler) if options.offline: policy.network_use = model.network_offline feed = iface_cache.get_feed(x) if policy.network_use != model.network_offline and policy.is_stale(feed): blocker = policy.fetcher.download_and_import_feed(x, iface_cache.iface_cache) print _("Downloading feed; please wait...") handler.wait_for_blocker(blocker) print _("Done") interfaces = policy.get_feed_targets(x) for i in range(len(interfaces)): feed = interfaces[i].get_feed(x) if feed: print _("%(index)d) Remove as feed for '%(uri)s'") % {'index': i + 1, 'uri': interfaces[i].uri} else: print _("%(index)d) Add as feed for '%(uri)s'") % {'index': i + 1, 'uri': interfaces[i].uri} print while True: try: i = raw_input(_('Enter a number, or CTRL-C to cancel [1]: ')).strip() except KeyboardInterrupt: print raise SafeException(_("Aborted at user request.")) if i == '': i = 1 else: try: i = int(i) except ValueError: i = 0 if i > 0 and i <= len(interfaces): break print _("Invalid number. Try again. (1 to %d)") % len(interfaces) iface = interfaces[i - 1] feed = iface.get_feed(x) if feed: iface.extra_feeds.remove(feed) else: iface.extra_feeds.append(model.Feed(x, arch = None, user_override = True)) writer.save_interface(iface) print '\n' + _("Feed list for interface '%s' is now:") % iface.get_name() if iface.feeds: for f in iface.feeds: print "- " + f.uri else: print _("(no feeds)")
def is_stale(self): if self.policy is None: return False if self.policy.solver.feeds_used is None: # solve it at forst self.policy.need_download() for url in self.policy.solver.feeds_used: feed = iface_cache.get_feed(url) if self.policy.is_stale(feed): return True return False
def finish(): from . import xdgutils iface_uri = model.canonical_iface_uri(uri.get_text()) iface = iface_cache.get_interface(iface_uri) feed = iface_cache.get_feed(iface_uri) try: icon_path = iface_cache.get_icon_path(iface) xdgutils.add_to_menu(feed, icon_path, categories[category.get_active()]) except SafeException as ex: box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, str(ex)) box.run() box.destroy() else: self.window.destroy()
def finish(): from . import xdgutils iface_uri = model.canonical_iface_uri(uri.get_text()) iface = iface_cache.get_interface(iface_uri) feed = iface_cache.get_feed(iface_uri) try: icon_path = iface_cache.get_icon_path(iface) xdgutils.add_to_menu(feed, icon_path, categories[category.get_active()]) except SafeException as ex: box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, str(ex)) box.run() box.destroy() else: self.window.destroy()
def update_details_page(): iface_uri = model.canonical_iface_uri(uri.get_text()) iface = iface_cache.get_interface(iface_uri) feed = iface_cache.get_feed(iface_uri) assert feed, iface_uri about.set_text('%s - %s' % (feed.get_name(), feed.summary)) icon_path = iface_cache.get_icon_path(iface) from zeroinstall.gtkui import icon icon_pixbuf = icon.load_icon(icon_path) if icon_pixbuf: icon_widget.set_from_pixbuf(icon_pixbuf) feed_category = None for meta in feed.get_metadata(XMLNS_IFACE, 'category'): feed_category = meta.content break if feed_category: i = 0 for row in categories: if row.lower() == feed_category.lower(): category.set_active(i) break i += 1 self.window.set_response_sensitive(_RESPONSE_PREV, True)
def update_details_page(): iface_uri = model.canonical_iface_uri(uri.get_text()) iface = iface_cache.get_interface(iface_uri) feed = iface_cache.get_feed(iface_uri) assert feed, iface_uri about.set_text('%s - %s' % (feed.get_name(), feed.summary)) icon_path = iface_cache.get_icon_path(iface) from zeroinstall.gtkui import icon icon_pixbuf = icon.load_icon(icon_path) if icon_pixbuf: icon_widget.set_from_pixbuf(icon_pixbuf) feed_category = None for meta in feed.get_metadata(XMLNS_IFACE, 'category'): feed_category = meta.content break if feed_category: i = 0 for row in categories: if row.lower() == feed_category.lower(): category.set_active(i) break i += 1 self.window.set_response_sensitive(_RESPONSE_PREV, True)
def do_build_internal(options, args): """build-internal""" # If a sandbox is being used, we're in it now. import getpass, socket buildenv = BuildEnv() sels = buildenv.get_selections() builddir = os.path.realpath('build') ensure_dir(buildenv.metadir) build_env_xml = join(buildenv.metadir, 'build-environment.xml') buildenv_doc = sels.toDOM() # Create build-environment.xml file root = buildenv_doc.documentElement info = buildenv_doc.createElementNS(XMLNS_0COMPILE, 'build-info') root.appendChild(info) info.setAttributeNS(None, 'time', time.strftime('%Y-%m-%d %H:%M').strip()) info.setAttributeNS(None, 'host', socket.getfqdn()) info.setAttributeNS(None, 'user', getpass.getuser()) info.setAttributeNS(None, 'arch', '%s-%s' % (uname[0], uname[4])) stream = file(build_env_xml, 'w') buildenv_doc.writexml(stream, addindent=" ", newl="\n") stream.close() # Create local binary interface file. # We use the main feed for the interface as the template for the name, # summary, etc (note: this is not necessarily the feed that contained # the source code). master_feed = iface_cache.get_feed(buildenv.interface) src_impl = buildenv.chosen_impl(buildenv.interface) write_sample_feed(buildenv, master_feed, src_impl) # Check 0compile is new enough min_version = model.parse_version( src_impl.attrs.get(XMLNS_0COMPILE + ' min-version', None)) if min_version and min_version > model.parse_version(__main__.version): raise SafeException( "%s-%s requires 0compile >= %s, but we are only version %s" % (master_feed.get_name(), src_impl.version, model.format_version(min_version), __main__.version)) # Create the patch patch_file = join(buildenv.metadir, 'from-%s.patch' % src_impl.version) if buildenv.user_srcdir: with open(patch_file, 'w') as stream: # (ignore errors; will already be shown on stderr) try: subprocess.call(["diff", "-urN", buildenv.orig_srcdir, 'src'], stdout=stream) except OSError as ex: print >> sys.stderr, "WARNING: Failed to run 'diff': ", ex if os.path.getsize(patch_file) == 0: os.unlink(patch_file) elif os.path.exists(patch_file): os.unlink(patch_file) env('BUILDDIR', builddir) env('DISTDIR', buildenv.distdir) env('SRCDIR', buildenv.user_srcdir or buildenv.orig_srcdir) env('BINARYFEED', buildenv.local_iface_file) os.chdir(builddir) print "cd", builddir setup = CompileSetup(iface_cache.stores, sels) setup.prepare_env() # These mappings are needed when mixing Zero Install -dev packages with # native package binaries. mappings = {} for impl in sels.selections.values(): # Add mappings that have been set explicitly... new_mappings = impl.attrs.get(XMLNS_0COMPILE + ' lib-mappings', '') if new_mappings: new_mappings = new_mappings.split(' ') for mapping in new_mappings: assert ':' in mapping, "lib-mappings missing ':' in '%s' from '%s'" % ( mapping, impl.feed) name, major_version = mapping.split(':', 1) assert '/' not in mapping, "lib-mappings '%s' contains a / in the version number (from '%s')!" % ( mapping, impl.feed) if sys.platform == 'darwin': mappings[name] = 'lib%s.%s.dylib' % (name, major_version) else: mappings[name] = 'lib%s.so.%s' % (name, major_version) # Auto-detect required mappings where possible... # (if the -dev package is native, the symlinks will be OK) if not is_package_impl(impl): impl_path = lookup(impl) for libdirname in ['lib', 'usr/lib', 'lib64', 'usr/lib64']: libdir = os.path.join(impl_path, libdirname) if os.path.isdir(libdir): find_broken_version_symlinks(libdir, mappings) if mappings: set_up_mappings(mappings) overrides_dir = os.path.join(os.environ['TMPDIR'], PKG_CONFIG_OVERRIDES) if os.path.isdir(overrides_dir): add_overrides = model.EnvironmentBinding('PKG_CONFIG_PATH', PKG_CONFIG_OVERRIDES) do_env_binding(add_overrides, os.environ['TMPDIR']) # Some programs want to put temporary build files in the source directory. # Make a copy of the source if needed. dup_src_type = src_impl.attrs.get(XMLNS_0COMPILE + ' dup-src', None) if dup_src_type == 'true': dup_src(copy_file) env('SRCDIR', builddir) elif dup_src_type: raise Exception("Unknown dup-src value '%s'" % dup_src_type) if options.shell: spawn_and_check(find_in_path('cmd' if os.name == 'nt' else 'sh'), []) else: command = sels.commands[0].qdom.attrs.get('shell-command', None) if command is None: # New style <command> prog_args = setup.build_command(sels.interface, sels.command) + args else: # Old style shell-command='...' if os.name == 'nt': prog_args = [ os.environ['0COMPILE_BASH'], '-eux', '-c', command ] + args else: prog_args = ['/bin/sh', '-c', command + ' "$@"', '-'] + args assert len(sels.commands) == 1 # Remove any existing log files for log in ['build.log', 'build-success.log', 'build-failure.log']: if os.path.exists(log): os.unlink(log) # Run the command, copying output to a new log with open('build.log', 'w') as log: print >> log, "Build log for %s-%s" % (master_feed.get_name(), src_impl.version) print >> log, "\nBuilt using 0compile-%s" % __main__.version print >> log, "\nBuild system: " + ', '.join(uname) print >> log, "\n%s:\n" % ENV_FILE with open(os.path.join(os.pardir, ENV_FILE)) as properties_file: shutil.copyfileobj(properties_file, log) log.write('\n') if os.path.exists(patch_file): print >> log, "\nPatched with:\n" shutil.copyfileobj(file(patch_file), log) log.write('\n') if command: print "Executing: " + command, args print >> log, "Executing: " + command, args else: print "Executing: " + str(prog_args) print >> log, "Executing: " + str(prog_args) # Tee the output to the console and to the log child = subprocess.Popen(prog_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: data = os.read(child.stdout.fileno(), 100) if not data: break sys.stdout.write(data) log.write(data) status = child.wait() failure = None if status == 0: print >> log, "Build successful" shorten_dynamic_library_install_names() fixup_generated_pkgconfig_files() remove_la_files() elif status > 0: failure = "Build failed with exit code %d" % status else: failure = "Build failure: exited due to signal %d" % (-status) if failure: print >> log, failure if failure: os.rename('build.log', 'build-failure.log') raise SafeException("Command '%s': %s" % (prog_args, failure)) else: os.rename('build.log', 'build-success.log')
def get_name(self): from zeroinstall.injector.iface_cache import iface_cache feed = iface_cache.get_feed(self.uri) if feed: return feed.get_name() return '(' + os.path.basename(self.uri) + ')'
def testStale(self): self.httpd([ 'files/download.xml', 'files/25CE480645A8CA07.gpg', 'key-info/key/EC37EA199F9ADC3328EE338625CE480645A8CA07', 'files/HelloWorld.tgz', 'files/download.xml', 'files/download.xml', ]) flask = Flask() status = [] flask.connect('finished', lambda sender: (status.append(True), gtk.main_quit())) flask.connect('cancelled', lambda sender: (status.append(False), gtk.main_quit())) flask.connect('key_confirm', lambda sender, key: sender.accept(key)) flask.connect('verbose', lambda sender, message: self.logger.info(message)) flask.pull(HTTP + 'files/download.xml') gtk.main() self.assertEqual([True], status) self.assertEqual(HTTP + 'files/download.xml', flask.policy.root) self.assertEqual(True, flask.policy.solver.ready) self.assertEqual(False, flask.policy.need_download()) self.assertEqual(False, flask.is_stale()) self.assertEqual(1, flask.processed) self.assertEqual(0, flask.skipped) time.sleep(1) status = [] def refresh(): flask.refresh(HTTP + 'files/download.xml', freshness=10) gobject.idle_add(refresh) gtk.main() self.assertEqual([True], status) self.assertEqual(HTTP + 'files/download.xml', flask.policy.root) self.assertEqual(True, flask.policy.solver.ready) self.assertEqual(False, flask.is_stale()) self.assertEqual(1, flask.processed) self.assertEqual(0, flask.skipped) time.sleep(3) policy = Policy(HTTP + 'files/download.xml') policy.freshness = 1 policy.need_download() feed = [iface_cache.get_feed(i) for i in policy.solver.feeds_used][0] self.assertEqual(True, policy.is_stale(feed)) status = [] def refresh(): flask.refresh(HTTP + 'files/download.xml', freshness=1) gobject.idle_add(refresh) gtk.main() self.assertEqual([True], status) self.assertEqual(HTTP + 'files/download.xml', flask.policy.root) self.assertEqual(True, flask.policy.solver.ready) self.assertEqual(1, flask.processed) self.assertEqual(0, flask.skipped) policy = Policy(HTTP + 'files/download.xml') policy.freshness = 3 policy.need_download() feed = [iface_cache.get_feed(i) for i in policy.solver.feeds_used][0] self.assertEqual(False, policy.is_stale(feed))
def _normal_mode(options, args): from zeroinstall.injector import handler if len(args) < 1: if options.gui: from zeroinstall import helpers return helpers.get_selections_gui(None, []) else: raise UsageError() iface_uri = model.canonical_iface_uri(args[0]) root_iface = iface_cache.get_interface(iface_uri) if os.isatty(1): h = handler.ConsoleHandler() else: h = handler.Handler() h.dry_run = bool(options.dry_run) policy = autopolicy.AutoPolicy(iface_uri, handler = h, download_only = bool(options.download_only), src = options.source) if options.before or options.not_before: policy.solver.extra_restrictions[root_iface] = [model.VersionRangeRestriction(model.parse_version(options.before), model.parse_version(options.not_before))] if options.os or options.cpu: from zeroinstall.injector import arch policy.target_arch = arch.get_architecture(options.os, options.cpu) if options.offline: policy.network_use = model.network_offline if options.get_selections: if len(args) > 1: raise SafeException(_("Can't use arguments with --get-selections")) if options.main: raise SafeException(_("Can't use --main with --get-selections")) # Note that need_download() triggers a solve if options.refresh or options.gui: # We could run immediately, but the user asked us not to can_run_immediately = False else: can_run_immediately = (not policy.need_download()) and policy.ready stale_feeds = [feed for feed in policy.solver.feeds_used if policy.is_stale(iface_cache.get_feed(feed))] if options.download_only and stale_feeds: can_run_immediately = False if can_run_immediately: if stale_feeds: if policy.network_use == model.network_offline: logging.debug(_("No doing background update because we are in off-line mode.")) else: # There are feeds we should update, but we can run without them. # Do the update in the background while the program is running. import background background.spawn_background_update(policy, options.verbose > 0) if options.get_selections: _get_selections(policy) else: if not options.download_only: from zeroinstall.injector import run run.execute(policy, args[1:], dry_run = options.dry_run, main = options.main, wrapper = options.wrapper) else: logging.info(_("Downloads done (download-only mode)")) assert options.dry_run or options.download_only return # If the user didn't say whether to use the GUI, choose for them. if options.gui is None and os.environ.get('DISPLAY', None): options.gui = True # If we need to download anything, we might as well # refresh all the interfaces first. Also, this triggers # the 'checking for updates' box, which is non-interactive # when there are no changes to the selection. options.refresh = True logging.info(_("Switching to GUI mode... (use --console to disable)")) prog_args = args[1:] try: from zeroinstall.injector import run if options.gui: gui_args = [] if options.download_only: # Just changes the button's label gui_args.append('--download-only') if options.refresh: gui_args.append('--refresh') if options.systray: gui_args.append('--systray') if options.not_before: gui_args.insert(0, options.not_before) gui_args.insert(0, '--not-before') if options.before: gui_args.insert(0, options.before) gui_args.insert(0, '--before') if options.source: gui_args.insert(0, '--source') if options.message: gui_args.insert(0, options.message) gui_args.insert(0, '--message') if options.verbose: gui_args.insert(0, '--verbose') if options.verbose > 1: gui_args.insert(0, '--verbose') if options.cpu: gui_args.insert(0, options.cpu) gui_args.insert(0, '--cpu') if options.os: gui_args.insert(0, options.os) gui_args.insert(0, '--os') if options.with_store: for x in options.with_store: gui_args += ['--with-store', x] sels = _fork_gui(iface_uri, gui_args, prog_args, options) if not sels: sys.exit(1) # Aborted else: #program_log('download_and_execute ' + iface_uri) downloaded = policy.solve_and_download_impls(refresh = bool(options.refresh)) if downloaded: policy.handler.wait_for_blocker(downloaded) sels = selections.Selections(policy) if options.get_selections: doc = sels.toDOM() doc.writexml(sys.stdout) sys.stdout.write('\n') elif not options.download_only: run.execute_selections(sels, prog_args, options.dry_run, options.main, options.wrapper) except NeedDownload, ex: # This only happens for dry runs print ex
def do_build_internal(options, args): """build-internal""" # If a sandbox is being used, we're in it now. import getpass, socket buildenv = BuildEnv() sels = buildenv.get_selections() builddir = os.path.realpath('build') ensure_dir(buildenv.metadir) build_env_xml = join(buildenv.metadir, 'build-environment.xml') buildenv_doc = sels.toDOM() # Create build-environment.xml file root = buildenv_doc.documentElement info = buildenv_doc.createElementNS(XMLNS_0COMPILE, 'build-info') root.appendChild(info) info.setAttributeNS(None, 'time', time.strftime('%Y-%m-%d %H:%M').strip()) info.setAttributeNS(None, 'host', socket.getfqdn()) info.setAttributeNS(None, 'user', getpass.getuser()) info.setAttributeNS(None, 'arch', '%s-%s' % (uname[0], uname[4])) stream = file(build_env_xml, 'w') buildenv_doc.writexml(stream, addindent=" ", newl="\n") stream.close() # Create local binary interface file. # We use the main feed for the interface as the template for the name, # summary, etc (note: this is not necessarily the feed that contained # the source code). master_feed = iface_cache.get_feed(buildenv.interface) src_impl = buildenv.chosen_impl(buildenv.interface) write_sample_feed(buildenv, master_feed, src_impl) # Check 0compile is new enough min_version = model.parse_version(src_impl.attrs.get(XMLNS_0COMPILE + ' min-version', None)) if min_version and min_version > model.parse_version(__main__.version): raise SafeException("%s-%s requires 0compile >= %s, but we are only version %s" % (master_feed.get_name(), src_impl.version, model.format_version(min_version), __main__.version)) # Create the patch patch_file = join(buildenv.metadir, 'from-%s.patch' % src_impl.version) if buildenv.user_srcdir: with open(patch_file, 'w') as stream: # (ignore errors; will already be shown on stderr) try: subprocess.call(["diff", "-urN", buildenv.orig_srcdir, 'src'], stdout = stream) except OSError as ex: print >>sys.stderr, "WARNING: Failed to run 'diff': ", ex if os.path.getsize(patch_file) == 0: os.unlink(patch_file) elif os.path.exists(patch_file): os.unlink(patch_file) env('BUILDDIR', builddir) env('DISTDIR', buildenv.distdir) env('SRCDIR', buildenv.user_srcdir or buildenv.orig_srcdir) env('BINARYFEED', buildenv.local_iface_file) os.chdir(builddir) print "cd", builddir setup = CompileSetup(iface_cache.stores, sels) setup.prepare_env() # These mappings are needed when mixing Zero Install -dev packages with # native package binaries. mappings = {} for impl in sels.selections.values(): # Add mappings that have been set explicitly... new_mappings = impl.attrs.get(XMLNS_0COMPILE + ' lib-mappings', '') if new_mappings: new_mappings = new_mappings.split(' ') for mapping in new_mappings: assert ':' in mapping, "lib-mappings missing ':' in '%s' from '%s'" % (mapping, impl.feed) name, major_version = mapping.split(':', 1) assert '/' not in mapping, "lib-mappings '%s' contains a / in the version number (from '%s')!" % (mapping, impl.feed) if sys.platform == 'darwin': mappings[name] = 'lib%s.%s.dylib' % (name, major_version) else: mappings[name] = 'lib%s.so.%s' % (name, major_version) # Auto-detect required mappings where possible... # (if the -dev package is native, the symlinks will be OK) if not is_package_impl(impl): impl_path = lookup(impl) for libdirname in ['lib', 'usr/lib', 'lib64', 'usr/lib64']: libdir = os.path.join(impl_path, libdirname) if os.path.isdir(libdir): find_broken_version_symlinks(libdir, mappings) if mappings: set_up_mappings(mappings) overrides_dir = os.path.join(os.environ['TMPDIR'], PKG_CONFIG_OVERRIDES) if os.path.isdir(overrides_dir): add_overrides = model.EnvironmentBinding('PKG_CONFIG_PATH', PKG_CONFIG_OVERRIDES) do_env_binding(add_overrides, os.environ['TMPDIR']) # Some programs want to put temporary build files in the source directory. # Make a copy of the source if needed. dup_src_type = src_impl.attrs.get(XMLNS_0COMPILE + ' dup-src', None) if dup_src_type == 'true': dup_src(shutil.copy2) env('SRCDIR', builddir) elif dup_src_type: raise Exception("Unknown dup-src value '%s'" % dup_src_type) if options.shell: spawn_and_check(find_in_path('cmd' if os.name == 'nt' else 'sh'), []) else: command = sels.commands[0].qdom.attrs.get('shell-command', None) if command is None: # New style <command> prog_args = setup.build_command(sels.interface, sels.command) + args else: # Old style shell-command='...' if os.name == 'nt': prog_args = ['cmd', '/c', command] + args else: prog_args = ['/bin/sh', '-c', command + ' "$@"', '-'] + args assert len(sels.commands) == 1 # Remove any existing log files for log in ['build.log', 'build-success.log', 'build-failure.log']: if os.path.exists(log): os.unlink(log) # Run the command, copying output to a new log with open('build.log', 'w') as log: print >>log, "Build log for %s-%s" % (master_feed.get_name(), src_impl.version) print >>log, "\nBuilt using 0compile-%s" % __main__.version print >>log, "\nBuild system: " + ', '.join(uname) print >>log, "\n%s:\n" % ENV_FILE with open(os.path.join(os.pardir, ENV_FILE)) as properties_file: shutil.copyfileobj(properties_file, log) log.write('\n') if os.path.exists(patch_file): print >>log, "\nPatched with:\n" shutil.copyfileobj(file(patch_file), log) log.write('\n') if command: print "Executing: " + command, args print >>log, "Executing: " + command, args else: print "Executing: " + str(prog_args) print >>log, "Executing: " + str(prog_args) # Tee the output to the console and to the log child = subprocess.Popen(prog_args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) while True: data = os.read(child.stdout.fileno(), 100) if not data: break sys.stdout.write(data) log.write(data) status = child.wait() failure = None if status == 0: print >>log, "Build successful" shorten_dynamic_library_install_names() fixup_generated_pkgconfig_files() remove_la_files() elif status > 0: failure = "Build failed with exit code %d" % status else: failure = "Build failure: exited due to signal %d" % (-status) if failure: print >>log, failure if failure: os.rename('build.log', 'build-failure.log') raise SafeException("Command '%s': %s" % (prog_args, failure)) else: os.rename('build.log', 'build-success.log')