def on_success(): # A new local feed may have been registered, so reload it from the disk cache info(_("0compile command completed successfully. Reloading interface details.")) reader.update_from_cache(interface) for feed in interface.extra_feeds: self.policy.config.iface_cache.get_feed(feed.uri, force = True) self.policy.recalculate()
def add_feed(): # A new local feed may have been registered, so update the interface from the cache info( _("0compile command completed successfully. Reloading interface details." )) reader.update_from_cache(interface) policy.recalculate()
def action_run(self, uri): iface = self.iface_cache.get_interface(uri) reader.update_from_cache(iface) if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')): if gtk.pygtk_version >= (2,16,0) and gtk.gdk.WINDOWING == 'quartz': script = ['0launch', '--', uri] osascript = support.find_in_path('osascript') subprocess.Popen([osascript, '-e', 'tell app "Terminal"', '-e', 'activate', '-e', 'do script "%s"' % ' '.join(script), '-e', 'end tell']) return for terminal in ['x-terminal-emulator', 'xterm', 'gnome-terminal', 'rxvt', 'konsole']: exe = support.find_in_path(terminal) if exe: if terminal == 'gnome-terminal': flag = '-x' else: flag = '-e' subprocess.Popen([terminal, flag, '0launch', '--', uri]) break else: box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Can't find a suitable terminal emulator")) box.run() box.destroy() else: subprocess.Popen(['0launch', '--', uri])
def action_run(self, uri): iface = self.iface_cache.get_interface(uri) reader.update_from_cache(iface) if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')): if gtk.pygtk_version >= (2, 16, 0) and gtk.gdk.WINDOWING == 'quartz': script = ['0launch', '--', uri] osascript = support.find_in_path('osascript') subprocess.Popen([ osascript, '-e', 'tell app "Terminal"', '-e', 'activate', '-e', 'do script "%s"' % ' '.join(script), '-e', 'end tell' ]) return for terminal in [ 'x-terminal-emulator', 'xterm', 'gnome-terminal', 'rxvt', 'konsole' ]: exe = support.find_in_path(terminal) if exe: if terminal == 'gnome-terminal': flag = '-x' else: flag = '-e' subprocess.Popen([terminal, flag, '0launch', '--', uri]) break else: box = gtk.MessageDialog( self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Can't find a suitable terminal emulator")) box.run() box.destroy() else: subprocess.Popen(['0launch', '--', uri])
def action_help(self, uri): p = policy.Policy(uri) policy.network_use = model.network_offline if p.need_download(): child = subprocess.Popen(['0launch', '-d', '--', uri]) child.wait() if child.returncode: return iface = self.iface_cache.get_interface(uri) reader.update_from_cache(iface) p.solve_with_downloads() impl = p.solver.selections[iface] assert impl, "Failed to choose an implementation of %s" % uri help_dir = impl.metadata.get('doc-dir') path = p.get_implementation_path(impl) assert path, "Chosen implementation is not cached!" if help_dir: path = os.path.join(path, help_dir) else: main = impl.main if main: # Hack for ROX applications. They should be updated to # set doc-dir. help_dir = os.path.join(path, os.path.dirname(main), 'Help') if os.path.isdir(help_dir): path = help_dir # xdg-open has no "safe" mode, so check we're not "opening" an application. if os.path.exists(os.path.join(path, 'AppRun')): raise Exception( _("Documentation directory '%s' is an AppDir; refusing to open" ) % path) subprocess.Popen(['xdg-open', path])
def action_help(self, uri): p = policy.Policy(uri) policy.network_use = model.network_offline if p.need_download(): child = subprocess.Popen(['0launch', '-d', '--', uri]) child.wait() if child.returncode: return iface = self.iface_cache.get_interface(uri) reader.update_from_cache(iface) p.solve_with_downloads() impl = p.solver.selections[iface] assert impl, "Failed to choose an implementation of %s" % uri help_dir = impl.metadata.get('doc-dir') path = p.get_implementation_path(impl) assert path, "Chosen implementation is not cached!" if help_dir: path = os.path.join(path, help_dir) else: main = impl.main if main: # Hack for ROX applications. They should be updated to # set doc-dir. help_dir = os.path.join(path, os.path.dirname(main), 'Help') if os.path.isdir(help_dir): path = help_dir # xdg-open has no "safe" mode, so check we're not "opening" an application. if os.path.exists(os.path.join(path, 'AppRun')): raise Exception(_("Documentation directory '%s' is an AppDir; refusing to open") % path) subprocess.Popen(['xdg-open', path])
def ok(feed): from zeroinstall.injector import reader try: feed_targets = policy.get_feed_targets(feed) if interface not in feed_targets: raise Exception( _("Not a valid feed for '%(uri)s'; this is a feed for:\n%(feed_for)s" ) % { 'uri': interface.uri, 'feed_for': '\n'.join([f.uri for f in feed_targets]) }) if interface.get_feed(feed): dialog.alert(None, _('This feed is already registered.')) else: interface.extra_feeds.append( Feed(feed, user_override=True, arch=None)) writer.save_interface(interface) chooser.destroy() reader.update_from_cache(interface) policy.recalculate() except Exception, ex: dialog.alert( None, _("Error in feed file '%(feed)s':\n\n%(exception)s") % { 'feed': feed, 'exception': str(ex) })
def testSitePackages(self): # The old system (0install < 1.9): # - 0compile stores implementations to ~/.cache, and # - adds to extra_feeds # # The middle system (0install 1.9..1.12) # - 0compile stores implementations to ~/.local/0install.net/site-packages # but using an obsolete escaping scheme, and # - modern 0install finds them via extra_feeds # # The new system (0install >= 1.13): # - 0compile stores implementations to ~/.local/0install.net/site-packages, and # - 0install finds them automatically # For backwards compatibility, 0install >= 1.9: # - writes discovered feeds to extra_feeds # - skips such entries in extra_feeds when loading expected_escape = 'section__prog_5f_1.xml' meta_dir = basedir.save_data_path('0install.net', 'site-packages', 'http', 'example.com', expected_escape, '1.0', '0install') feed = os.path.join(meta_dir, 'feed.xml') shutil.copyfile(os.path.join(mydir, 'Local.xml'), feed) # Check that we find the feed without us having to register it iface = self.config.iface_cache.get_interface('http://example.com/section/prog_1.xml') self.assertEqual(1, len(iface.extra_feeds)) site_feed, = iface.extra_feeds self.assertEqual(True, site_feed.site_package) # Check that we write it out, so that older 0installs can find it writer.save_interface(iface) config_file = basedir.load_first_config('0install.net', 'injector', 'interfaces', 'http:##example.com#section#prog_1.xml') with open(config_file, 'rb') as s: doc = qdom.parse(s) feed_node = None for item in doc.childNodes: if item.name == 'feed': feed_node = item self.assertEqual('True', feed_node.getAttribute('is-site-package')) # Check we ignore this element iface.reset() self.assertEqual([], iface.extra_feeds) reader.update_user_overrides(iface) self.assertEqual([], iface.extra_feeds) # Check feeds are automatically removed again reader.update_from_cache(iface, iface_cache = self.config.iface_cache) self.assertEqual(1, len(iface.extra_feeds)) shutil.rmtree(basedir.load_first_data('0install.net', 'site-packages', 'http', 'example.com', expected_escape)) reader.update_from_cache(iface, iface_cache = self.config.iface_cache) self.assertEqual(0, len(iface.extra_feeds))
def on_success(): # A new local feed may have been registered, so reload it from the disk cache info(_("0compile command completed successfully. Reloading interface details.")) reader.update_from_cache(interface) for feed in interface.extra_feeds: self.config.iface_cache.get_feed(feed.uri, force = True) import main main.recalculate()
def _import_new_interface(self, interface, new_xml, modified_time): """Write new_xml into the cache. @param interface: updated once the new XML is written @param new_xml: the data to write @param modified_time: when new_xml was modified @raises ReplayAttack: if the new mtime is older than the current one """ assert modified_time upstream_dir = basedir.save_cache_path(config_site, 'interfaces') cached = os.path.join(upstream_dir, escape(interface.uri)) if os.path.exists(cached): old_xml = file(cached).read() if old_xml == new_xml: debug(_("No change")) reader.update_from_cache(interface) return stream = file(cached + '.new', 'w') stream.write(new_xml) stream.close() os.utime(cached + '.new', (modified_time, modified_time)) new_mtime = reader.check_readable(interface.uri, cached + '.new') assert new_mtime == modified_time old_modified = self._get_signature_date(interface.uri) if old_modified is None: old_modified = interface.last_modified if old_modified: if new_mtime < old_modified: os.unlink(cached + '.new') raise ReplayAttack( _("New interface's modification time is " "before old version!\nOld time: %(old_time)s\nNew time: %(new_time)s\n" "Refusing update.") % { 'old_time': _pretty_time(old_modified), 'new_time': _pretty_time(new_mtime) }) if new_mtime == old_modified: # You used to have to update the modification time manually. # Now it comes from the signature, this check isn't useful # and often causes problems when the stored format changes # (e.g., when we stopped writing last-modified attributes) pass #raise SafeException("Interface has changed, but modification time " # "hasn't! Refusing update.") os.rename(cached + '.new', cached) debug(_("Saved as %s") % cached) reader.update_from_cache(interface)
def testSitePackages(self): # The old system (0install < 1.9): # - 0compile stores implementations to ~/.cache, and # - adds to extra_feeds # The new system (0install >= 1.9): # - 0compile stores implementations to ~/.local/0install.net/site-packages, and # - 0install finds them automatically # For backwards compatibility, 0install >= 1.9: # - writes discovered feeds to extra_feeds # - skips such entries in extra_feeds when loading meta_dir = basedir.save_data_path('0install.net', 'site-packages', 'http:##example.com#prog.xml', '1.0', '0install') feed = os.path.join(meta_dir, 'feed.xml') shutil.copyfile(os.path.join(mydir, 'Local.xml'), feed) # Check that we find the feed without us having to register it iface = self.config.iface_cache.get_interface('http://example.com/prog.xml') self.assertEqual(1, len(iface.extra_feeds)) site_feed, = iface.extra_feeds self.assertEqual(True, site_feed.site_package) # Check that we write it out, so that older 0installs can find it writer.save_interface(iface) config_file = basedir.load_first_config('0install.net', 'injector', 'interfaces', 'http:##example.com#prog.xml') with open(config_file, 'rb') as s: doc = qdom.parse(s) feed_node = None for item in doc.childNodes: if item.name == 'feed': feed_node = item self.assertEqual('True', feed_node.getAttribute('site-package')) # Check we ignore this element iface.reset() self.assertEqual([], iface.extra_feeds) reader.update_user_overrides(iface) self.assertEqual([], iface.extra_feeds) # Check feeds are automatically removed again reader.update_from_cache(iface, iface_cache = self.config.iface_cache) self.assertEqual(1, len(iface.extra_feeds)) shutil.rmtree(basedir.load_first_data('0install.net', 'site-packages', 'http:##example.com#prog.xml')) reader.update_from_cache(iface, iface_cache = self.config.iface_cache) self.assertEqual(0, len(iface.extra_feeds))
def get_interface(self, uri): """Get the interface for uri, creating a new one if required. New interfaces are initialised from the disk cache, but not from the network. @param uri: the URI of the interface to find @rtype: L{model.Interface} """ if type(uri) == str: uri = unicode(uri) assert isinstance(uri, unicode) if uri in self._interfaces: return self._interfaces[uri] debug(_("Initialising new interface object for %s"), uri) self._interfaces[uri] = Interface(uri) reader.update_from_cache(self._interfaces[uri]) return self._interfaces[uri]
def get_interface(self, uri): """Get the interface for uri, creating a new one if required. New interfaces are initialised from the disk cache, but not from the network. @param uri: the URI of the interface to find @type uri: str @rtype: L{model.Interface}""" if type(uri) == str: uri = unicode(uri) assert isinstance(uri, unicode) if uri in self._interfaces: return self._interfaces[uri] logger.debug(_("Initialising new interface object for %s"), uri) self._interfaces[uri] = Interface(uri) reader.update_from_cache(self._interfaces[uri], iface_cache = self) return self._interfaces[uri]
def action_run(self, uri): iface = self.iface_cache.get_interface(uri) reader.update_from_cache(iface) if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')): for terminal in ['xterm', 'gnome-terminal', 'rxvt', 'konsole']: exe = support.find_in_path(terminal) if exe: if terminal == 'gnome-terminal': flag = '-x' else: flag = '-e' subprocess.Popen([terminal, flag, '0launch', '--', uri]) break else: box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Can't find a suitable terminal emulator")) box.run() box.destroy() else: subprocess.Popen(['0launch', '--', uri])
def ok(feed): from zeroinstall.injector import reader try: feed_targets = policy.get_feed_targets(feed) if interface not in feed_targets: raise Exception(_("Not a valid feed for '%(uri)s'; this is a feed for:\n%(feed_for)s") % {'uri': interface.uri, 'feed_for': '\n'.join([f.uri for f in feed_targets])}) if feed in [f.uri for f in interface.extra_feeds]: dialog.alert(None, _('This feed is already registered.')) else: interface.extra_feeds.append(Feed(feed, user_override = True, arch = None)) writer.save_interface(interface) chooser.destroy() reader.update_from_cache(interface) import main main.recalculate() except Exception as ex: dialog.alert(None, _("Error in feed file '%(feed)s':\n\n%(exception)s") % {'feed': feed, 'exception': str(ex)})
def response(box, resp): if resp == RESPONSE_SETUP: def done_setup(): self.add_msg('Now use Build to compile the chosen source code.') self.run_command((sys.executable, main_path, 'setup'), done_setup) elif resp == RESPONSE_BUILD: def done_build(): self.add_msg('\nBuild successful. Now register or publish the build.') def build_failed(): self.add_msg('\nIf the messages displayed above indicate a missing dependency (e.g. no C compiler ' "or a library that isn't available through Zero Install) then install it using your " 'normal package manager and click on Build again. Note that for libraries you often ' 'need the -dev version of the package. ' '\nOtherwise, please notify the developers of this problem (this will transmit ' 'the contents of the build/build-failure.log file):') end = self.buffer.get_end_iter() anchor = self.buffer.create_child_anchor(end) align = gtk.Alignment(0.0, 0.0, 1.0, 1.0) button = ButtonMixed(gtk.STOCK_YES, 'Notify developers') align.add(button) align.set_padding(8, 8, 8, 8) align.show_all() self.tv.add_child_at_anchor(align, anchor) self.add_msg('\n') def report_bug(button): def done_notify(): self.add_msg("\nReport sent. Thank you! (note: you won't get a reply, as " "no contact details were sent; write to the project's mailing " "list if you want to discuss the problem)") self.run_command((sys.executable, main_path, 'report-bug'), done_notify) button.connect('clicked', report_bug) buildenv = BuildEnv() changes = buildenv.get_build_changes() if changes: options = get_build_options(box, '\n'.join(changes) + '\n\nIt would be best to do a clean (full) build.') else: options = [] if options is not None: box.run_command([sys.executable, main_path, 'build'] + options, done_build, build_failed) elif resp == RESPONSE_REGISTER: buildenv = BuildEnv() iface = iface_cache.get_interface(interface) reader.update_from_cache(iface) # Register using the feed-for, if available real_iface = iface for uri in iface.feed_for or []: real_iface = iface_cache.get_interface(uri) self.add_msg("Registering as a feed for %s" % real_iface.uri) break else: if os.path.isabs(iface.uri): self.add_msg("Warning: no <feed-for> in local feed %s!" % iface.uri) feed = buildenv.local_iface_file for f in real_iface.feeds or []: if f.uri == feed: self.add_msg("Feed '%s' is already registered for interface '%s'!\n" % (feed, real_iface.uri)) return box.buffer.insert_at_cursor("Registering feed '%s'\n" % feed) real_iface.extra_feeds.append(model.Feed(feed, arch = None, user_override = True)) writer.save_interface(real_iface) box.buffer.insert_at_cursor("Done. You can now close this window.\n") elif resp == RESPONSE_PUBLISH: buildenv = BuildEnv() box = PublishBox(self, buildenv) resp = box.run() box.destroy() if resp == gtk.RESPONSE_OK: def done_publish(): self.add_msg("\nYou can use '0publish --local' to add this " "into the main feed. If you don't have a main feed then this " "will create one. See " "http://0install.net/injector-packagers.html for more information.") self.run_command((sys.executable, main_path, 'publish', box.archive_dir.get_text()), done_publish) elif resp == gtk.RESPONSE_CANCEL or resp == gtk.RESPONSE_DELETE_EVENT: if self.kill_child(): return self.destroy() else: self.add_msg('Unknown response: %s' % resp)
def compile_and_register(self, sels, forced_iface_uri=None): """If forced_iface_uri, register as an implementation of this interface, ignoring the any <feed-for>, etc.""" buildenv = BuildEnv(need_config=False) buildenv.config.set('compile', 'interface', sels.interface) buildenv.config.set('compile', 'selections', 'selections.xml') # Download any required packages now, so we can use the GUI to request confirmation, etc download_missing = sels.download_missing(self.config, include_packages=True) if download_missing: yield download_missing tasks.check(download_missing) tmpdir = tempfile.mkdtemp(prefix='0compile-') try: os.chdir(tmpdir) # Write configuration for build... buildenv.save() sel_file = open('selections.xml', 'w') try: doc = sels.toDOM() doc.writexml(sel_file) sel_file.write('\n') finally: sel_file.close() # Do the build... build = self.spawn_build(buildenv.iface_name) if build: yield build tasks.check(build) # Register the result... dom = minidom.parse(buildenv.local_iface_file) feed_for_elem, = dom.getElementsByTagNameNS( namespaces.XMLNS_IFACE, 'feed-for') claimed_iface = feed_for_elem.getAttribute('interface') if forced_iface_uri is not None: if forced_iface_uri != claimed_iface: self.note( "WARNING: registering as feed for {forced}, though feed claims to be for {claimed}" .format(forced=forced_iface_uri, claimed=claimed_iface)) else: forced_iface_uri = claimed_iface # (the top-level interface being built) version = sels.selections[sels.interface].version site_package_versions_dir = basedir.save_data_path( '0install.net', 'site-packages', *model.escape_interface_uri(forced_iface_uri)) leaf = '%s-%s' % (version, build_target_machine_type) site_package_dir = os.path.join(site_package_versions_dir, leaf) self.note("Storing build in %s" % site_package_dir) # 1. Copy new version in under a temporary name. Names starting with '.' are ignored by 0install. tmp_distdir = os.path.join(site_package_versions_dir, '.new-' + leaf) shutil.copytree(buildenv.distdir, tmp_distdir, symlinks=True) # 2. Rename the previous build to .old-VERSION (deleting that if it already existed) if os.path.exists(site_package_dir): self.note("(moving previous build out of the way)") previous_build_dir = os.path.join(site_package_versions_dir, '.old-' + leaf) if os.path.exists(previous_build_dir): shutil.rmtree(previous_build_dir) os.rename(site_package_dir, previous_build_dir) else: previous_build_dir = None # 3. Rename the new version immediately after renaming away the old one to minimise time when there's # no version. os.rename(tmp_distdir, site_package_dir) # 4. Delete the old version. if previous_build_dir: self.note("(deleting previous build)") shutil.rmtree(previous_build_dir) local_feed = os.path.join(site_package_dir, '0install', 'feed.xml') assert os.path.exists( local_feed), "Feed %s not found!" % local_feed # Reload - our 0install will detect the new feed automatically iface = self.config.iface_cache.get_interface(forced_iface_uri) reader.update_from_cache(iface, iface_cache=self.config.iface_cache) self.config.iface_cache.get_feed(local_feed, force=True) # Write it out - 0install will add the feed so that older 0install versions can find it writer.save_interface(iface) seen_key = (forced_iface_uri, sels.selections[sels.interface].id) assert seen_key not in self.seen, seen_key self.seen[seen_key] = site_package_dir except: self.note( "\nBuild failed: leaving build directory %s for inspection...\n" % tmpdir) raise else: # Can't delete current directory on Windows, so move to parent first os.chdir(os.path.join(tmpdir, os.path.pardir)) ro_rmtree(tmpdir)
def compile_and_register(self, sels, forced_iface_uri = None): """If forced_iface_uri, register as an implementation of this interface, ignoring the any <feed-for>, etc.""" buildenv = BuildEnv(need_config = False) buildenv.config.set('compile', 'interface', sels.interface) buildenv.config.set('compile', 'selections', 'selections.xml') # Download any required packages now, so we can use the GUI to request confirmation, etc download_missing = sels.download_missing(self.config, include_packages = True) if download_missing: yield download_missing tasks.check(download_missing) tmpdir = tempfile.mkdtemp(prefix = '0compile-') try: os.chdir(tmpdir) # Write configuration for build... buildenv.save() sel_file = open('selections.xml', 'w') try: doc = sels.toDOM() doc.writexml(sel_file) sel_file.write('\n') finally: sel_file.close() # Do the build... build = self.spawn_build(buildenv.iface_name) if build: yield build tasks.check(build) # Register the result... dom = minidom.parse(buildenv.local_iface_file) feed_for_elem, = dom.getElementsByTagNameNS(namespaces.XMLNS_IFACE, 'feed-for') claimed_iface = feed_for_elem.getAttribute('interface') if forced_iface_uri is not None: if forced_iface_uri != claimed_iface: self.note("WARNING: registering as feed for {forced}, though feed claims to be for {claimed}".format( forced = forced_iface_uri, claimed = claimed_iface)) else: forced_iface_uri = claimed_iface # (the top-level interface being built) version = sels.selections[sels.interface].version site_package_versions_dir = basedir.save_data_path('0install.net', 'site-packages', *model.escape_interface_uri(forced_iface_uri)) leaf = '%s-%s' % (version, uname[4]) site_package_dir = os.path.join(site_package_versions_dir, leaf) self.note("Storing build in %s" % site_package_dir) # 1. Copy new version in under a temporary name. Names starting with '.' are ignored by 0install. tmp_distdir = os.path.join(site_package_versions_dir, '.new-' + leaf) shutil.copytree(buildenv.distdir, tmp_distdir, symlinks = True) # 2. Rename the previous build to .old-VERSION (deleting that if it already existed) if os.path.exists(site_package_dir): self.note("(moving previous build out of the way)") previous_build_dir = os.path.join(site_package_versions_dir, '.old-' + leaf) if os.path.exists(previous_build_dir): shutil.rmtree(previous_build_dir) os.rename(site_package_dir, previous_build_dir) else: previous_build_dir = None # 3. Rename the new version immediately after renaming away the old one to minimise time when there's # no version. os.rename(tmp_distdir, site_package_dir) # 4. Delete the old version. if previous_build_dir: self.note("(deleting previous build)") shutil.rmtree(previous_build_dir) local_feed = os.path.join(site_package_dir, '0install', 'feed.xml') assert os.path.exists(local_feed), "Feed %s not found!" % local_feed # Reload - our 0install will detect the new feed automatically iface = self.config.iface_cache.get_interface(forced_iface_uri) reader.update_from_cache(iface, iface_cache = self.config.iface_cache) self.config.iface_cache.get_feed(local_feed, force = True) # Write it out - 0install will add the feed so that older 0install versions can find it writer.save_interface(iface) except: self.note("\nBuild failed: leaving build directory %s for inspection...\n" % tmpdir) raise else: # Can't delete current directory on Windows, so move to parent first os.chdir(os.path.join(tmpdir, os.path.pardir)) ro_rmtree(tmpdir)