def get_package_info(self, package, factory): # Add any already-installed package... """@type package: str""" installed_cached_info = self._get_dpkg_info(package) if installed_cached_info != '-': installed_version, machine = installed_cached_info.split('\t') impl = factory('package:deb:%s:%s:%s' % (package, installed_version, machine)) impl.version = model.parse_version(installed_version) if machine != '*': impl.machine = machine else: installed_version = None # Add any uninstalled candidates (note: only one of these two methods will add anything) # From PackageKit... self.packagekit.get_candidates(package, factory, 'package:deb') # From apt-cache... cached = self.apt_cache.get(package, None) if cached: candidate_version = cached['version'] candidate_arch = cached['arch'] if candidate_version and candidate_version != installed_version: impl = factory('package:deb:%s:%s:%s' % (package, candidate_version, candidate_arch), installed = False) impl.version = model.parse_version(candidate_version) if candidate_arch != '*': impl.machine = candidate_arch impl.download_sources.append(model.DistributionSource(package, cached['size'], needs_confirmation = False))
def update_element(self, element, widgets): element.setAttribute('interface', widgets.get_widget('requires_uri').get_active_text()) before = widgets.get_widget('before').get_text() or None not_before = widgets.get_widget('not_before').get_text() or None if before: model.parse_version(before) if not_before: model.parse_version(not_before) if before or not_before: if not self.version_element: self.version_element = create_element(element, 'version') set_or_remove(self.version_element, 'before', before) set_or_remove(self.version_element, 'not-before', not_before) elif self.version_element: remove_element(self.version_element) self.version_element = None env_name = widgets.get_widget('env_name').get_active_text() env_insert = widgets.get_widget('env_insert').get_active_text() env_mode = widgets.get_widget('env_mode').get_active_text().lower() env_default = widgets.get_widget('env_default').get_text() if env_name: if not self.env_element: self.env_element = create_element(element, 'environment') self.env_element.setAttribute('name', env_name) self.env_element.setAttribute('insert', env_insert) self.env_element.setAttribute('mode', env_mode) set_or_remove(self.env_element, 'default', env_default) elif env_insert or env_default: raise Exception('Missing environment variable name!') elif self.env_element: remove_element(self.env_element) self.env_element = None
def get_package_info(self, package, factory): # Add any already-installed package... installed_cached_info = self._get_dpkg_info(package) if installed_cached_info != '-': installed_version, machine = installed_cached_info.split('\t') impl = factory('package:deb:%s:%s:%s' % (package, installed_version, machine)) impl.version = model.parse_version(installed_version) if machine != '*': impl.machine = machine else: installed_version = None # Add any uninstalled candidates (note: only one of these two methods will add anything) # From PackageKit... self.packagekit.get_candidates(package, factory, 'package:deb') # From apt-cache... cached = self.apt_cache.get(package, None) if cached: candidate_version = cached['version'] candidate_arch = cached['arch'] if candidate_version and candidate_version != installed_version: impl = factory('package:deb:%s:%s:%s' % (package, candidate_version, candidate_arch), installed = False) impl.version = model.parse_version(candidate_version) if candidate_arch != '*': impl.machine = candidate_arch def install(handler): raise model.SafeException(_("This program depends on '%s', which is a package that is available through your distribution. " "Please install it manually using your distribution's tools and try again. Or, install 'packagekit' and I can " "use that to install it.") % package) impl.download_sources.append(model.DistributionSource(package, cached['size'], install, needs_confirmation = False))
def __init__(self, config, requirements): """ @param config: The configuration settings to use @type config: L{config.Config} @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @since: 0.53 """ self.watchers = [] assert config self.config = config assert requirements self.requirements = requirements self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) logger.debug(_("Supported systems: '%s'"), arch.os_ranks) logger.debug(_("Supported processors: '%s'"), arch.machine_ranks) if requirements.before or requirements.not_before: self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [ model.VersionRangeRestriction( model.parse_version(requirements.before), model.parse_version(requirements.not_before) ) ]
def build(selections_xml): # Get the chosen versions sels = selections.Selections(qdom.parse(BytesIO(selections_xml))) impl = sels.selections[interface_uri] min_version = impl.attrs.get(XMLNS_0COMPILE + " min-version", our_min_version) # Check the syntax is valid and the version is high enough if model.parse_version(min_version) < model.parse_version(our_min_version): min_version = our_min_version # Do the whole build-and-register-feed c = Command() c.run( ( "0launch", "--message", _("Download the 0compile tool, to compile the source code"), "--not-before=" + min_version, "http://0install.net/2006/interfaces/0compile.xml", "gui", interface_uri, ), lambda unused: on_success(), )
def testConstraints(self): self.cache_iface('http://bar', """<?xml version="1.0" ?> <interface last-modified="1110752708" uri="http://bar" xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> <name>Bar</name> <summary>Bar</summary> <description>Bar</description> <implementation id='sha1=100' version='1.0'> <archive href='foo' size='10'/> </implementation> <implementation id='sha1=150' stability='developer' version='1.5'> <archive href='foo' size='10'/> </implementation> <implementation id='sha1=200' version='2.0'> <archive href='foo' size='10'/> </implementation> </interface>""") self.cache_iface(foo_iface_uri, """<?xml version="1.0" ?> <interface last-modified="1110752708" uri="%s" xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> <name>Foo</name> <summary>Foo</summary> <description>Foo</description> <group main='dummy'> <requires interface='http://bar'> <version/> </requires> <implementation id='sha1=123' version='1.0'> <archive href='foo' size='10'/> </implementation> </group> </interface>""" % foo_iface_uri) policy = Policy(foo_iface_uri, config = self.config) policy.network_use = model.network_full policy.freshness = 0 #logger.setLevel(logging.DEBUG) recalculate(policy) #logger.setLevel(logging.WARN) foo_iface = self.config.iface_cache.get_interface(foo_iface_uri) bar_iface = self.config.iface_cache.get_interface('http://bar') assert policy.implementation[bar_iface].id == 'sha1=200' dep = policy.implementation[foo_iface].dependencies['http://bar'] assert len(dep.restrictions) == 1 restriction = dep.restrictions[0] restriction.before = model.parse_version('2.0') recalculate(policy) assert policy.implementation[bar_iface].id == 'sha1=100' restriction.not_before = model.parse_version('1.5') recalculate(policy) assert policy.implementation[bar_iface].id == 'sha1=150'
def get_previous_release(this_version): """Return the highest numbered verison in the master feed before this_version. @return: version, or None if there wasn't one""" parsed_release_version = model.parse_version(this_version) versions = [model.parse_version(version) for version in scm.get_tagged_versions()] versions = [version for version in versions if version < parsed_release_version] if versions: return model.format_version(max(versions)) return None
def __init__(self, root = None, handler = None, src = None, command = -1, config = None, requirements = None): """ @param requirements: Details about the program we want to run @type requirements: L{requirements.Requirements} @param config: The configuration settings to use, or None to load from disk. @type config: L{ConfigParser.ConfigParser} Note: all other arguments are deprecated (since 0launch 0.52) """ self.watchers = [] if requirements is None: from zeroinstall.injector.requirements import Requirements requirements = Requirements(root) requirements.source = bool(src) # Root impl must be a "src" machine type if command == -1: if src: command = 'compile' else: command = 'run' requirements.command = command self.target_arch = arch.get_host_architecture() else: assert root == src == None assert command == -1 self.target_arch = arch.get_architecture(requirements.os, requirements.cpu) self.requirements = requirements self.stale_feeds = set() if config is None: self.config = load_config(handler or Handler()) else: assert handler is None, "can't pass a handler and a config" self.config = config from zeroinstall.injector.solver import DefaultSolver self.solver = DefaultSolver(self.config) # If we need to download something but can't because we are offline, # warn the user. But only the first time. self._warned_offline = False debug(_("Supported systems: '%s'"), arch.os_ranks) debug(_("Supported processors: '%s'"), arch.machine_ranks) if requirements.before or requirements.not_before: self.solver.extra_restrictions[config.iface_cache.get_interface(requirements.interface_uri)] = [ model.VersionRangeRestriction(model.parse_version(requirements.before), model.parse_version(requirements.not_before))]
def testLocalPath(self): # 0launch --get-selections Local.xml iface = os.path.join(mydir, "Local.xml") driver = Driver(requirements = Requirements(iface), config = self.config) driver.need_download() assert driver.solver.ready s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") # Reload selections and check they're the same root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) local_path = s2.selections[iface].local_path assert os.path.isdir(local_path), local_path assert not s2.selections[iface].digests, s2.selections[iface].digests # Add a newer implementation and try again feed = self.config.iface_cache.get_feed(iface) impl = model.ZeroInstallImplementation(feed, "foo bar=123", local_path = None) impl.version = model.parse_version('1.0') impl.commands["run"] = model.Command(qdom.Element(namespaces.XMLNS_IFACE, 'command', {'path': 'dummy', 'name': 'run'}), None) impl.add_download_source('http://localhost/bar.tgz', 1000, None) feed.implementations = {impl.id: impl} assert driver.need_download() assert driver.solver.ready, driver.solver.get_failure_reason() s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) xml = s2.toDOM().toxml("utf-8") qdom.parse(BytesIO(xml)) assert s2.selections[iface].local_path is None assert not s2.selections[iface].digests, s2.selections[iface].digests assert s2.selections[iface].id == 'foo bar=123'
def get_candidates(self, package_name, factory, prefix): """Add any cached candidates. The candidates are those discovered by a previous call to L{fetch_candidates}. @param package_name: the distribution's name for the package @type package_name: str @param factory: a function to add a new implementation to the feed @param prefix: the prefix for the implementation's ID @type prefix: str""" candidates = self._candidates.get(package_name, None) if candidates is None: return if isinstance(candidates, tasks.Blocker): return # Fetch still in progress for candidate in candidates: impl_name = '%s:%s:%s:%s' % (prefix, package_name, candidate['version'], candidate['arch']) impl = factory(impl_name, only_if_missing = True, installed = candidate['installed']) if impl is None: # (checking this way because the cached candidate['installed'] may be stale) return # Already installed impl.version = model.parse_version(candidate['version']) if candidate['arch'] != '*': impl.machine = candidate['arch'] impl.download_sources.append(model.DistributionSource(package_name, candidate['size'], packagekit_id = candidate['packagekit_id']))
def ask_if_previous_still_testing(master_doc, new_version): new_version_parsed = model.parse_version(new_version) xml = master_doc.toxml(encoding = 'utf-8') master = model.ZeroInstallFeed(qdom.parse(BytesIO(xml))) previous_versions = [impl.version for impl in master.implementations.values() if impl.version < new_version_parsed] if not previous_versions: return previous_version = max(previous_versions) # (all the <implementations> with this version number) previous_testing_impls = [impl for impl in master.implementations.values() if impl.version == previous_version and impl.upstream_stability == model.testing] if not previous_testing_impls: return print("The previous release, version {version}, is still marked as 'testing'. Set to stable?".format( version = model.format_version(previous_version))) if get_choice(['Yes', 'No']) != 'Yes': return ids_to_change = frozenset(impl.id for impl in previous_testing_impls) for impl in master_doc.getElementsByTagNameNS(XMLNS_IFACE, 'implementation'): if impl.getAttribute('id') in ids_to_change: impl.setAttribute('stability', 'stable')
def testLocalPath(self): # 0launch --get-selections Local.xml iface = os.path.join(mydir, "Local.xml") p = policy.Policy(iface, config=self.config) p.need_download() assert p.ready s1 = selections.Selections(p) xml = s1.toDOM().toxml("utf-8") # Reload selections and check they're the same root = qdom.parse(StringIO(xml)) s2 = selections.Selections(root) local_path = s2.selections[iface].local_path assert os.path.isdir(local_path), local_path assert not s2.selections[iface].digests, s2.selections[iface].digests # Add a newer implementation and try again feed = self.config.iface_cache.get_feed(iface) impl = model.ZeroInstallImplementation(feed, "foo bar=123", local_path=None) impl.version = model.parse_version("1.0") impl.commands["run"] = model.Command(qdom.Element(namespaces.XMLNS_IFACE, "command", {"path": "dummy"}), None) impl.add_download_source("http://localhost/bar.tgz", 1000, None) feed.implementations = {impl.id: impl} assert p.need_download() assert p.ready, p.solver.get_failure_reason() s1 = selections.Selections(p) xml = s1.toDOM().toxml("utf-8") root = qdom.parse(StringIO(xml)) s2 = selections.Selections(root) xml = s2.toDOM().toxml("utf-8") qdom.parse(StringIO(xml)) assert s2.selections[iface].local_path is None assert not s2.selections[iface].digests, s2.selections[iface].digests assert s2.selections[iface].id == "foo bar=123"
def get_candidates(self, package_name, factory, prefix): """Add any cached candidates. The candidates are those discovered by a previous call to L{fetch_candidates}. @param package_name: the distribution's name for the package @param factory: a function to add a new implementation to the feed @param prefix: the prefix for the implementation's ID """ candidate = self._candidates.get(package_name, None) if candidate is None: return if isinstance(candidate, tasks.Blocker): return # Fetch still in progress impl_name = '%s:%s:%s:%s' % (prefix, package_name, candidate['version'], candidate['arch']) impl = factory(impl_name, only_if_missing = True, installed = candidate['installed']) if impl is None: # (checking this way because the cached candidate['installed'] may be stale) return # Already installed impl.version = model.parse_version(candidate['version']) if candidate['arch'] != '*': impl.machine = candidate['arch'] def install(handler): packagekit_id = candidate['packagekit_id'] def download_factory(url, hint): return PackageKitDownload(url, hint, pk = self.pk, packagekit_id = packagekit_id) dl = handler.get_download('packagekit:' + packagekit_id, factory = download_factory, hint = impl) dl.expected_size = candidate['size'] return dl.downloaded impl.download_sources.append(model.DistributionSource(package_name, candidate['size'], install))
def get_package_info(self, package, factory): # Add installed versions... """@type package: str""" for entry in os.listdir(self._packages_dir): name, version, build = entry.rsplit('-', 2) if name == package: gotarch = False # (read in binary mode to avoid unicode errors in C locale) with open(os.path.join(self._packages_dir, entry, "desc"), 'rb') as stream: for line in stream: if line == b"%ARCH%\n": gotarch = True continue if gotarch: arch = line.strip().decode('utf-8') break zi_arch = canonical_machine(arch) clean_version = try_cleanup_distro_version("%s-%s" % (version, build)) if not clean_version: logger.warning(_("Can't parse distribution version '%(version)s' for package '%(package)s'"), {'version': version, 'package': name}) continue impl = factory('package:arch:%s:%s:%s' % \ (package, clean_version, zi_arch)) impl.version = model.parse_version(clean_version) if zi_arch != '*': impl.machine = zi_arch impl.quick_test_file = os.path.join(self._packages_dir, entry, 'desc') # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:arch')
def get_package_info(self, package, factory): """@type package: str""" _name_version_regexp = '^(.+)-([^-]+)$' nameversion = re.compile(_name_version_regexp) for pkgname in os.listdir(self._pkgdir): pkgdir = os.path.join(self._pkgdir, pkgname) if not os.path.isdir(pkgdir): continue #contents = open(os.path.join(pkgdir, '+CONTENTS')).readline().strip() match = nameversion.search(pkgname) if match is None: logger.warning(_('Cannot parse version from Ports package named "%(pkgname)s"'), {'pkgname': pkgname}) continue else: name = match.group(1) if name != package: continue version = try_cleanup_distro_version(match.group(2)) machine = host_machine impl = factory('package:ports:%s:%s:%s' % \ (package, version, machine)) impl.version = model.parse_version(version) impl.machine = machine
def get_package_info(self, package, factory): # Add installed versions... for entry in os.listdir(self._packages_dir): name, version, build = entry.rsplit('-', 2) if name == package: gotarch = False with open(os.path.join(self._packages_dir, entry, "desc"), 'rt') as stream: for line in stream: if line == "%ARCH%\n": gotarch = True continue if gotarch: arch = line.strip() break zi_arch = canonical_machine(arch) clean_version = try_cleanup_distro_version("%s-%s" % (version, build)) if not clean_version: logger.warn(_("Can't parse distribution version '%(version)s' for package '%(package)s'"), {'version': version, 'package': name}) continue impl = factory('package:arch:%s:%s:%s' % \ (package, clean_version, zi_arch)) impl.version = model.parse_version(clean_version) if zi_arch != '*': impl.machine = zi_arch # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:arch')
def get_feed(self, master_feed): """Generate a feed containing information about distribution packages. This should immediately return a feed containing an implementation for the package if it's already installed. Information about versions that could be installed using the distribution's package manager can be added asynchronously later (see L{fetch_candidates}). @param master_feed: feed containing the <package-implementation> elements @type master_feed: L{model.ZeroInstallFeed} @rtype: L{model.ZeroInstallFeed}""" feed = model.ZeroInstallFeed(None) feed.url = 'distribution:' + master_feed.url for item, item_attrs in master_feed.get_package_impls(self): package = item_attrs.get('package', None) if package is None: raise model.InvalidInterface(_("Missing 'package' attribute on %s") % item) def factory(id, only_if_missing = False, installed = True): assert id.startswith('package:') if id in feed.implementations: if only_if_missing: return None warn(_("Duplicate ID '%s' for DistributionImplementation"), id) impl = model.DistributionImplementation(feed, id, self, item) feed.implementations[id] = impl impl.installed = installed impl.metadata = item_attrs if 'run' not in impl.commands: item_main = item_attrs.get('main', None) if item_main: if item_main.startswith('/'): impl.main = item_main else: raise model.InvalidInterface(_("'main' attribute must be absolute, but '%s' doesn't start with '/'!") % item_main) impl.upstream_stability = model.packaged return impl self.get_package_info(package, factory) if master_feed.url == 'http://repo.roscidus.com/python/python' and all(not impl.installed for impl in feed.implementations.values()): # Hack: we can support Python on platforms with unsupported package managers # by adding the implementation of Python running us now to the list. python_version = '.'.join([str(v) for v in sys.version_info if isinstance(v, int)]) impl_id = 'package:host:python:' + python_version assert impl_id not in feed.implementations impl = model.DistributionImplementation(feed, impl_id, self) impl.installed = True impl.version = model.parse_version(python_version) impl.main = sys.executable impl.upstream_stability = model.packaged impl.machine = host_machine # (hopefully) feed.implementations[impl_id] = impl return feed
def fixup(self, package, impl): """@type package: str @type impl: L{zeroinstall.injector.model.DistributionImplementation}""" if impl.id.startswith('package:deb:openjdk-6-jre:') or \ impl.id.startswith('package:deb:openjdk-7-jre:'): # Debian marks all Java versions as pre-releases # See: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=685276 impl.version = model.parse_version(impl.get_version().replace('-pre', '.'))
def add_versions(parent, version): for x in child_elements(parent): if x.namespaceURI != XMLNS_INTERFACE: continue if x.hasAttribute('version'): version = x.getAttribute('version') if x.localName == 'group': add_versions(x, version) elif x.localName == 'implementation': versions.append((model.parse_version(version), x))
def find_java(part, jvm_version, zero_version): for arch in ['i386', 'x86_64']: home = java_home(jvm_version, arch) if os.path.isfile(home + "/bin/java"): impl = factory('package:darwin:%s:%s:%s' % (package, zero_version, arch)) impl.machine = arch impl.version = model.parse_version(zero_version) impl.upstream_stability = model.packaged impl.main = home + "/bin/java"
def get_package_info(self, package, factory): # Add installed versions... versions = self.versions.get(package, []) for version, machine in versions: impl = factory('package:cygwin:%s:%s:%s' % (package, version, machine)) impl.version = model.parse_version(version) if machine != '*': impl.machine = machine
def find_program(file): if os.path.isfile(file) and os.access(file, os.X_OK): program_version = try_cleanup_distro_version(get_version(file)) impl = factory('package:darwin:%s:%s' % (package, program_version), True) if impl: impl.installed = True impl.version = model.parse_version(program_version) impl.upstream_stability = model.packaged impl.machine = host_machine # (hopefully) impl.main = file
def get_version(x): root = x.ownerDocument.documentElement while x is not root: version = x.getAttribute('version') if version: mod = x.getAttribute('version-modifier') if mod: version += mod return model.parse_version(version) x = x.parentNode raise Exception("No version on %s" % x)
def find_java(part, win_version, zero_version): reg_path = r"SOFTWARE\JavaSoft\{part}\{win_version}".format(part = part, win_version = win_version) (java32_home, java64_home) = _read_hklm_reg(reg_path, "JavaHome") for (home, arch) in [(java32_home, 'i486'), (java64_home, 'x86_64')]: if os.path.isfile(home + r"\bin\java.exe"): impl = factory('package:windows:%s:%s:%s' % (package, zero_version, arch)) impl.machine = arch impl.version = model.parse_version(zero_version) impl.upstream_stability = model.packaged impl.main = home + r"\bin\java.exe"
def find_netfx(win_version, zero_version): reg_path = r"SOFTWARE\Microsoft\NET Framework Setup\NDP\{win_version}".format(win_version = win_version) (netfx32_install, netfx64_install) = _read_hklm_reg(reg_path, "Install") for (install, arch) in [(netfx32_install, 'i486'), (netfx64_install, 'x86_64')]: impl = factory('package:windows:%s:%s:%s' % (package, zero_version, arch)) impl.installed = (install == 1) impl.machine = arch impl.version = model.parse_version(zero_version) impl.upstream_stability = model.packaged impl.main = "" # .NET executables do not need a runner on Windows but they need one elsewhere
def get_package_info(self, package, factory): """@type package: str""" self.darwin.get_package_info(package, factory) # Add installed versions... versions = self.versions.get(package, []) for version, machine in versions: impl = factory('package:macports:%s:%s:%s' % (package, version, machine)) impl.version = model.parse_version(version) if machine != '*': impl.machine = machine
def get_package_info(self, package, factory): # Add installed versions... versions = self.versions.get(package, []) for version, machine in versions: impl = factory('package:rpm:%s:%s:%s' % (package, version, machine)) impl.version = model.parse_version(version) if machine != '*': impl.machine = machine # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:rpm')
def testImpl(self): i = model.Interface('http://foo') a = model.ZeroInstallImplementation(i, 'foo', None) assert a.id == 'foo' assert a.size == a.version == a.user_stability == None assert a.arch == a.upstream_stability == None assert a.dependencies == {} assert a.download_sources == [] assert a.get_stability() is model.testing a.upstream_stability = model.stable assert a.get_stability() is model.stable a.user_stability = model.buggy assert a.get_stability() is model.buggy a.version = model.parse_version('1.2.3') self.assertEqual('1.2.3', a.get_version()) a.version = model.parse_version('1.2.3-rc2-post') self.assertEqual('1.2.3-rc2-post', a.get_version()) assert str(a) == 'foo' b = model.ZeroInstallImplementation(i, 'foo', None) b.version = model.parse_version("1.2.1") assert b > a
def testRestricts(self): iface_cache = self.config.iface_cache s = solver.DefaultSolver(self.config) uri = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Conflicts.xml') versions = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Versions.xml') iface = iface_cache.get_interface(uri) r = Requirements(uri) # Selects 0.2 as the highest version, applying the restriction to versions < 4. s.solve_for(r) assert s.ready self.assertEqual("0.2", s.selections.selections[uri].version) self.assertEqual("3", s.selections.selections[versions].version) s.extra_restrictions[iface] = [model.VersionRestriction(model.parse_version('0.1'))] s.solve_for(r) assert s.ready self.assertEqual("0.1", s.selections.selections[uri].version) self.assertEqual(None, s.selections.selections.get(versions, None)) s.extra_restrictions[iface] = [model.VersionRestriction(model.parse_version('0.3'))] s.solve_for(r) assert not s.ready
def get_package_info(self, package, factory): # Add installed versions... for entry in os.listdir(self._packages_dir): name, version, arch, build = entry.rsplit('-', 3) if name == package: zi_arch = canonical_machine(arch) clean_version = try_cleanup_distro_version("%s-%s" % (version, build)) if not clean_version: logger.warning(_("Can't parse distribution version '%(version)s' for package '%(package)s'"), {'version': version, 'package': name}) continue impl = factory('package:slack:%s:%s:%s' % \ (package, clean_version, zi_arch)) impl.version = model.parse_version(clean_version) if zi_arch != '*': impl.machine = zi_arch # Add any uninstalled candidates found by PackageKit self.packagekit.get_candidates(package, factory, 'package:slack')
def testLocalPath(self): # 0launch --get-selections Local.xml iface = os.path.join(mydir, "Local.xml") driver = Driver(requirements=Requirements(iface), config=self.config) driver.need_download() assert driver.solver.ready s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") # Reload selections and check they're the same root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) local_path = s2.selections[iface].local_path assert os.path.isdir(local_path), local_path assert not s2.selections[iface].digests, s2.selections[iface].digests # Add a newer implementation and try again feed = self.config.iface_cache.get_feed(iface) impl = model.ZeroInstallImplementation(feed, "foo bar=123", local_path=None) impl.version = model.parse_version('1.0') impl.commands["run"] = model.Command( qdom.Element(namespaces.XMLNS_IFACE, 'command', { 'path': 'dummy', 'name': 'run' }), None) impl.add_download_source('http://localhost/bar.tgz', 1000, None) feed.implementations = {impl.id: impl} assert driver.need_download() assert driver.solver.ready, driver.solver.get_failure_reason() s1 = driver.solver.selections xml = s1.toDOM().toxml("utf-8") root = qdom.parse(BytesIO(xml)) s2 = selections.Selections(root) xml = s2.toDOM().toxml("utf-8") qdom.parse(BytesIO(xml)) assert s2.selections[iface].local_path is None assert not s2.selections[iface].digests, s2.selections[iface].digests assert s2.selections[iface].id == 'foo bar=123'
def suggest_release_version(snapshot_version): """Given a snapshot version, suggest a suitable release version. >>> suggest_release_version('1.0-pre') '1.0' >>> suggest_release_version('0.9-post') '0.10' >>> suggest_release_version('3') Traceback (most recent call last): ... SafeException: Version '3' is not a snapshot version (should end in -pre or -post) """ version = model.parse_version(snapshot_version) mod = version[-1] if mod == 0: raise SafeException( "Version '%s' is not a snapshot version (should end in -pre or -post)" % snapshot_version) if mod > 0: # -post, so increment the number version[-2][-1] += 1 version[-1] = 0 # Remove the modifier return model.format_version(version)
def get_package_info(self, package, factory): _version_start_reqexp = '-[0-9]' if package.count('/') != 1: return False category, leafname = package.split('/') category_dir = os.path.join(self._pkgdir, category) match_prefix = leafname + '-' if not os.path.isdir(category_dir): return False found = False for filename in os.listdir(category_dir): if filename.startswith(match_prefix) and filename[len( match_prefix)].isdigit(): name = file(os.path.join(category_dir, filename, 'PF')).readline().strip() match = re.search(_version_start_reqexp, name) if match is None: warn( _('Cannot parse version from Gentoo package named "%(name)s"' ), {'name': name}) continue else: version = try_cleanup_distro_version(name[match.start() + 1:]) machine = file(os.path.join(category_dir, filename, 'CHOST')).readline().split('-')[0] impl = factory('package:gentoo:%s:%s:%s' % \ (package, version, machine)) impl.version = model.parse_version(version) found = True return found
def testConstraints(self): self.cache_iface( 'http://bar', """<?xml version="1.0" ?> <interface last-modified="1110752708" uri="http://bar" xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> <name>Bar</name> <summary>Bar</summary> <description>Bar</description> <implementation id='sha1=100' version='1.0'> <archive href='foo' size='10'/> </implementation> <implementation id='sha1=150' stability='developer' version='1.5'> <archive href='foo' size='10'/> </implementation> <implementation id='sha1=200' version='2.0'> <archive href='foo' size='10'/> </implementation> </interface>""") self.cache_iface( foo_iface_uri, """<?xml version="1.0" ?> <interface last-modified="1110752708" uri="%s" xmlns="http://zero-install.sourceforge.net/2004/injector/interface"> <name>Foo</name> <summary>Foo</summary> <description>Foo</description> <group main='dummy'> <requires interface='http://bar'> <version/> </requires> <implementation id='sha1=123' version='1.0'> <archive href='foo' size='10'/> </implementation> </group> </interface>""" % foo_iface_uri) driver = Driver(requirements=Requirements(foo_iface_uri), config=self.config) self.config.network_use = model.network_full #logger.setLevel(logging.DEBUG) recalculate(driver) #logger.setLevel(logging.WARN) foo_iface = self.config.iface_cache.get_interface(foo_iface_uri) bar_iface = self.config.iface_cache.get_interface('http://bar') assert driver.solver.selections.selections[ bar_iface.uri].id == 'sha1=200' dep, = driver.solver.selections.selections[foo_iface.uri].dependencies assert dep.interface == 'http://bar' assert len(dep.restrictions) == 1 restriction = dep.restrictions[0] restriction.before = model.parse_version('2.0') recalculate(driver) assert driver.solver.selections.selections[ bar_iface.uri].id == 'sha1=100' restriction.not_before = model.parse_version('1.5') recalculate(driver) assert driver.solver.selections.selections[ bar_iface.uri].id == 'sha1=150'
def testUpdate(self): out, err = self.run_0install(['update']) assert out.lower().startswith("usage:") assert '--message' in out, out # Updating a local feed with no dependencies out, err = self.run_0install(['update', 'Local.xml']) assert not err, err assert 'No updates found' in out, out # Using a remote feed for the first time self.config.stores = TestStores() binary_feed = reader.load_feed('Binary.xml') self.config.fetcher.allow_download('sha1=123') self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed) out, err = self.run_0install(['update', 'http://foo/Binary.xml']) assert not err, err assert 'Binary.xml: new -> 1.0' in out, out # No updates. self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed) out, err = self.run_0install(['update', 'http://foo/Binary.xml']) assert not err, err assert 'No updates found' in out, out # New binary release available. new_binary_feed = reader.load_feed('Binary.xml') new_binary_feed.implementations[ 'sha1=123'].version = model.parse_version('1.1') self.config.fetcher.allow_feed_download('http://foo/Binary.xml', new_binary_feed) out, err = self.run_0install(['update', 'http://foo/Binary.xml']) assert not err, err assert 'Binary.xml: 1.0 -> 1.1' in out, out # Compiling from source for the first time. source_feed = reader.load_feed('Source.xml') compiler_feed = reader.load_feed('Compiler.xml') self.config.fetcher.allow_download('sha1=234') self.config.fetcher.allow_download('sha1=345') self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', compiler_feed) self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed) self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed) out, err = self.run_0install( ['update', 'http://foo/Binary.xml', '--source']) assert not err, err assert 'Binary.xml: new -> 1.0' in out, out assert 'Compiler.xml: new -> 1.0' in out, out # New compiler released. new_compiler_feed = reader.load_feed('Compiler.xml') new_compiler_feed.implementations[ 'sha1=345'].version = model.parse_version('1.1') self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', new_compiler_feed) self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed) self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed) out, err = self.run_0install( ['update', 'http://foo/Binary.xml', '--source']) assert not err, err assert 'Compiler.xml: 1.0 -> 1.1' in out, out # A dependency disappears. new_source_feed = reader.load_feed('Source.xml') new_source_feed.implementations['sha1=234'].requires = [] self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', new_compiler_feed) self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed) self.config.fetcher.allow_feed_download('http://foo/Source.xml', new_source_feed) out, err = self.run_0install( ['update', 'http://foo/Binary.xml', '--source']) assert not err, err assert 'No longer used: http://foo/Compiler.xml' in out, out
def get_package_info(self, package, factory): def _is_64bit_windows(): p = sys.platform from win32process import IsWow64Process if p == 'win64' or (p == 'win32' and IsWow64Process()): return True elif p == 'win32': return False else: raise Exception( _("WindowsDistribution may only be used on the Windows platform" )) def _read_hklm_reg(key_name, value_name): from win32api import RegOpenKeyEx, RegQueryValueEx, RegCloseKey from win32con import HKEY_LOCAL_MACHINE, KEY_READ KEY_WOW64_64KEY = 0x0100 KEY_WOW64_32KEY = 0x0200 if _is_64bit_windows(): try: key32 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ | KEY_WOW64_32KEY) (value32, _) = RegQueryValueEx(key32, value_name) RegCloseKey(key32) except: value32 = '' try: key64 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ | KEY_WOW64_64KEY) (value64, _) = RegQueryValueEx(key64, value_name) RegCloseKey(key64) except: value64 = '' else: try: key32 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ) (value32, _) = RegQueryValueEx(key32, value_name) RegCloseKey(key32) except: value32 = '' value64 = '' return (value32, value64) if package == 'openjdk-6-jre': (java32_home, java64_home) = _read_hklm_reg( r"SOFTWARE\JavaSoft\Java Runtime Environment\1.6", "JavaHome") if os.path.isfile(java32_home + r"\bin\java.exe"): impl = factory('package:windows:%s:%s:%s' % (package, '6', 'i486')) impl.machine = 'i486' impl.version = model.parse_version('6') impl.upstream_stability = model.packaged impl.main = java32_home + r"\bin\java.exe" if os.path.isfile(java64_home + r"\bin\java.exe"): impl = factory('package:windows:%s:%s:%s' % (package, '6', 'x86_64')) impl.machine = 'x86_64' impl.version = model.parse_version('6') impl.upstream_stability = model.packaged impl.main = java64_home + r"\bin\java.exe" if package == 'openjdk-6-jdk': (java32_home, java64_home) = _read_hklm_reg( r"SOFTWARE\JavaSoft\Java Development Kit\1.6", "JavaHome") if os.path.isfile(java32_home + r"\bin\java.exe"): impl = factory('package:windows:%s:%s:%s' % (package, '6', 'i486')) impl.machine = 'i486' impl.version = model.parse_version('6') impl.upstream_stability = model.packaged impl.main = java32_home + r"\bin\java.exe" if os.path.isfile(java64_home + r"\bin\java.exe"): impl = factory('package:windows:%s:%s:%s' % (package, '6', 'x86_64')) impl.machine = 'x86_64' impl.version = model.parse_version('6') impl.upstream_stability = model.packaged impl.main = java64_home + r"\bin\java.exe"
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 run_test_combinations(config, spec): r = requirements.Requirements(spec.test_iface) r.command = spec.command d = driver.Driver(config=config, requirements=r) solver = d.solver # Explore all combinations... tested_iface = config.iface_cache.get_interface(spec.test_iface) results = Results(spec) for combo in spec.get_combos(spec.test_ifaces): key = set() restrictions = {} selections = {} for (uri, version) in combo.iteritems(): iface = config.iface_cache.get_interface(uri) selections[iface] = version if version.startswith('%'): if version == '%nonlocal': restrictions[iface] = [NonlocalRestriction()] else: raise model.SafeException( "Unknown special '{special}'".format(special=version)) elif ',' in version: not_before, before = [ model.parse_version(v) if v != "" else None for v in version.split(',') ] if (not_before and before) and not_before >= before: raise model.SafeException( "Low version >= high version in %s!" % version) restrictions[iface] = [ model.VersionRangeRestriction(before, not_before) ] else: restrictions[iface] = [ model.VersionExpressionRestriction(version) ] key.add((uri, version)) solver.extra_restrictions = restrictions solve = d.solve_with_downloads() tasks.wait_for_blocker(solve) if not solver.ready: logging.info("Can't select combination %s: %s", combo, solver.get_failure_reason()) result = 'skipped' for uri, impl in solver.selections.iteritems(): if impl is None: selections[uri] = selections.get(uri, None) or '?' else: selections[uri] = impl.get_version() if not selections: selections = solver.get_failure_reason() else: selections = {} for iface, impl in solver.selections.iteritems(): if impl: version = impl.get_version() else: impl = None selections[iface] = version download = d.download_uncached_implementations() if download: config.handler.wait_for_blocker(download) print format_combo(selections) result = run_tests(config, tested_iface, solver.selections, spec) results.by_status[result].append(selections) results.by_combo[frozenset(key)] = (result, selections) return results
class DummyImpl: version = model.parse_version(v)
def pv(v): parsed = model.parse_version(v) assert model.format_version(parsed) == v return parsed
def handle(config, options, args): if len(args) != 1: raise UsageError() assert not options.offline iface_uri = model.canonical_iface_uri(args[0]) old_gui = options.gui # Select once in offline console mode to get the old values options.offline = True options.gui = False options.refresh = False try: old_sels = select.get_selections(config, options, iface_uri, select_only=True, download_only=False, test_callback=None) except SafeException: old_selections = {} else: if old_sels is None: old_selections = {} else: old_selections = old_sels.selections # Download in online mode to get the new values config.network_use = model.network_full options.offline = False options.gui = old_gui options.refresh = True sels = select.get_selections(config, options, iface_uri, select_only=False, download_only=True, test_callback=None) if not sels: sys.exit(1) # Aborted by user changes = False for iface, old_sel in old_selections.iteritems(): new_sel = sels.selections.get(iface, None) if new_sel is None: print(_("No longer used: %s") % iface) changes = True elif old_sel.version != new_sel.version: print( _("%s: %s -> %s") % (iface, old_sel.version, new_sel.version)) changes = True for iface, new_sel in sels.selections.iteritems(): if iface not in old_selections: print(_("%s: new -> %s") % (iface, new_sel.version)) changes = True root_sel = sels[iface_uri] root_iface = config.iface_cache.get_interface(iface_uri) latest = max((impl.version, impl) for impl in root_iface.implementations.values())[1] if latest.version > model.parse_version(sels[iface_uri].version): print( _("A later version ({name} {latest}) exists but was not selected. Using {version} instead." ).format(latest=latest.get_version(), name=root_iface.get_name(), version=root_sel.version)) if not config.help_with_testing and latest.get_stability( ) < model.stable: print( _('To select "testing" versions, use:\n0install config help_with_testing True' )) else: if not changes: print( _("No updates found. Continuing with version {version}."). format(version=root_sel.version))
def run_gui(args): parser = OptionParser(usage=_("usage: %prog [options] interface")) parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION') parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU') parser.add_option("-c", "--cache", help=_("show the cache"), action='store_true') parser.add_option("-d", "--download-only", help=_("fetch but don't run"), action='store_true') parser.add_option("", "--message", help=_("message to display when interacting with user")) parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION') parser.add_option("", "--os", help=_("target operation system type"), metavar='OS') parser.add_option("-r", "--refresh", help=_("check for updates of all interfaces"), action='store_true') parser.add_option("-s", "--source", help=_("select source code"), action='store_true') parser.add_option("", "--systray", help=_("download in the background"), action='store_true') parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count') parser.add_option("-V", "--version", help=_("display version information"), action='store_true') parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR') parser.disable_interspersed_args() (options, args) = parser.parse_args(args) if options.verbose: import logging logger = logging.getLogger() if options.verbose == 1: logger.setLevel(logging.INFO) else: logger.setLevel(logging.DEBUG) if options.cache: # Must fork before importing gtk, or ATK dies if os.fork(): # We exit, so our parent can call waitpid and unblock. sys.exit(0) # The grandchild continues... if options.with_store: from zeroinstall import zerostore for x in options.with_store: iface_cache.stores.stores.append(zerostore.Store(os.path.abspath(x))) import gui if options.version: print "0launch-gui (zero-install) " + gui.version print "Copyright (C) 2009 Thomas Leonard" print _("This program comes with ABSOLUTELY NO WARRANTY," "\nto the extent permitted by law." "\nYou may redistribute copies of this program" "\nunder the terms of the GNU Lesser General Public License." "\nFor more information about these matters, see the file named COPYING.") sys.exit(0) import gtk if gtk.gdk.get_display() is None: print >>sys.stderr, "Failed to connect to display. Aborting." sys.exit(1) if not hasattr(gtk, 'combo_box_new_text'): import combo_compat if options.cache: import cache cache_explorer = cache.CacheExplorer() cache_explorer.show() cache_explorer.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) gtk.gdk.flush() cache_explorer.populate_model() cache_explorer.window.set_cursor(None) gtk.main() sys.exit(0) handler = gui.GUIHandler() if len(args) < 1: import preferences # Once we separate configuration from Policy, this hack can go away class DummyPolicy(Policy): def recalculate(fetch_stale_interfaces = True): pass def solve_with_downloads(force = False): pass box = preferences.show_preferences(DummyPolicy('http://localhost/dummy', handler)) box.connect('destroy', gtk.main_quit) gtk.main() sys.exit(0) interface_uri = args[0] if len(args) > 1: parser.print_help() sys.exit(1) import mainwindow, dialog restrictions = [] if options.before or options.not_before: restrictions.append(model.VersionRangeRestriction(model.parse_version(options.before), model.parse_version(options.not_before))) widgets = dialog.Template('main') policy = Policy(interface_uri, handler, src = bool(options.source)) policy.target_arch = arch.get_architecture(options.os, options.cpu) root_iface = iface_cache.get_interface(interface_uri) policy.solver.extra_restrictions[root_iface] = restrictions policy.solver.record_details = True window = mainwindow.MainWindow(policy, widgets, download_only = bool(options.download_only)) handler.mainwindow = window if options.message: window.set_message(options.message) root = iface_cache.get_interface(policy.root) window.browser.set_root(root) window.window.connect('destroy', lambda w: handler.abort_all_downloads()) if options.systray: window.use_systray_icon() @tasks.async def main(): force_refresh = bool(options.refresh) while True: window.refresh_button.set_sensitive(False) window.browser.set_update_icons(force_refresh) solved = policy.solve_with_downloads(force = force_refresh) if not window.systray_icon: window.show() yield solved try: window.refresh_button.set_sensitive(True) tasks.check(solved) except Exception, ex: window.report_exception(ex) if window.systray_icon and window.systray_icon.get_visible() and \ window.systray_icon.is_embedded(): if policy.ready: window.systray_icon.set_tooltip(_('Downloading updates for %s') % root_iface.get_name()) window.run_button.set_active(True) else: # Should already be reporting an error, but # blink it again just in case window.systray_icon.set_blinking(True) yield dialog.ButtonClickedBlocker(window.refresh_button) force_refresh = True
def __init__(self, version, distro): self.version = model.parse_version(version) self.distro_name = distro
def write_sample_feed(buildenv, master_feed, src_impl): path = buildenv.local_iface_file old_path = os.path.join(buildenv.metadir, buildenv.iface_name + '.xml') if os.path.exists(old_path): warn("Removing old %s file: use %s instead now", old_path, path) os.unlink(old_path) impl = minidom.getDOMImplementation() XMLNS_IFACE = namespaces.XMLNS_IFACE doc = impl.createDocument(XMLNS_IFACE, "interface", None) root = doc.documentElement root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns', XMLNS_IFACE) prefixes = Prefixes(XMLNS_IFACE) def addSimple(parent, name, text=None): elem = doc.createElementNS(XMLNS_IFACE, name) parent.appendChild( doc.createTextNode('\n' + ' ' * (1 + depth(parent)))) parent.appendChild(elem) if text: elem.appendChild(doc.createTextNode(text)) return elem def close(element): element.appendChild(doc.createTextNode('\n' + ' ' * depth(element))) addSimple(root, 'name', master_feed.name) addSimple(root, 'summary', master_feed.summary) addSimple(root, 'description', master_feed.description) feed_for = addSimple(root, 'feed-for') feed_for.setAttributeNS(None, 'interface', find_feed_for(master_feed)) group = addSimple(root, 'group') main = src_impl.attrs.get(XMLNS_0COMPILE + ' binary-main', None) if main: group.setAttributeNS(None, 'main', main) lib_mappings = src_impl.attrs.get(XMLNS_0COMPILE + ' binary-lib-mappings', None) if lib_mappings: prefixes.setAttributeNS(group, XMLNS_0COMPILE, 'lib-mappings', lib_mappings) for d in src_impl.dependencies: if parse_bool( d.metadata.get(XMLNS_0COMPILE + ' include-binary', 'false')): requires = d.qdom.toDOM(doc, prefixes) requires.removeAttributeNS(XMLNS_0COMPILE, 'include-binary') group.appendChild(requires) set_arch = True impl_elem = addSimple(group, 'implementation') impl_template = buildenv.get_binary_template() if impl_template: arm_if_0install_attrs(impl_template) # Copy attributes from template for fullname, value in impl_template.attrs.iteritems(): if fullname == 'arch': set_arch = False if value == '*-*': continue if ' ' in fullname: ns, localName = fullname.split(' ', 1) else: ns, localName = None, fullname prefixes.setAttributeNS(impl_elem, ns, localName, value) # Copy child nodes for child in impl_template.childNodes: impl_elem.appendChild(child.toDOM(doc, prefixes)) if impl_template.content: impl_elem.appendChild(doc.createTextNode(impl_template.content)) for version_elem in itertools.chain( impl_elem.getElementsByTagName('version'), ): pin_components = version_elem.getAttributeNS( XMLNS_0COMPILE, "pin-components") if pin_components: pin_components = int(pin_components) iface = version_elem.parentNode.getAttribute("interface") assert iface dep_impl = buildenv.chosen_impl(iface) impl_version = model.parse_version( dep_impl.attrs.get('version')) pinned_components = [impl_version[0][:pin_components]] # (for -pre versions) min_version = min(pinned_components, impl_version) # clone and increment max_version = [pinned_components[0][:]] max_version[0][-1] += 1 version_elem.setAttribute("not-before", model.format_version(min_version)) version_elem.setAttribute("before", model.format_version(max_version)) if set_arch: group.setAttributeNS(None, 'arch', buildenv.target_arch) impl_elem.setAttributeNS(None, 'version', src_impl.version) if not impl_elem.hasAttribute('license'): license = src_impl.attrs.get('license') if license: impl_elem.setAttributeNS(None, 'license', license) version_modifier = buildenv.version_modifier if version_modifier: impl_elem.setAttributeNS(None, 'version-modifier', version_modifier) impl_elem.setAttributeNS(None, 'id', '..') impl_elem.setAttributeNS(None, 'released', time.strftime('%Y-%m-%d')) close(group) close(root) for ns, prefix in prefixes.prefixes.items(): root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns:' + prefix, ns) stream = codecs.open(path, 'w', encoding='utf-8') try: doc.writexml(stream) finally: stream.close()
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 handle(config, options, args): if len(args) != 1: raise UsageError() assert not options.offline old_gui = options.gui app = config.app_mgr.lookup_app(args[0], missing_ok=True) if app is not None: old_sels = app.get_selections() old_selections = old_sels.selections iface_uri = old_sels.interface r = app.get_requirements() r.parse_update_options(options) else: iface_uri = model.canonical_iface_uri(args[0]) r = requirements.Requirements(iface_uri) r.parse_options(options) # Select once in offline console mode to get the old values options.offline = True options.gui = False options.refresh = False try: old_sels = select.get_selections_for(r, config, options, select_only=True, download_only=False, test_callback=None) except SafeException: old_selections = {} else: if old_sels is None: old_selections = {} else: old_selections = old_sels.selections # Download in online mode to get the new values config.network_use = model.network_full options.offline = False options.gui = old_gui options.refresh = True sels = select.get_selections_for(r, config, options, select_only=False, download_only=True, test_callback=None) if not sels: sys.exit(1) # Aborted by user root_feed = config.iface_cache.get_feed(iface_uri) if root_feed: target = root_feed.get_replaced_by() if target is not None: print( _("Warning: interface {old} has been replaced by {new}".format( old=iface_uri, new=target))) from zeroinstall.cmd import whatchanged changes = whatchanged.show_changes(old_selections, sels.selections) root_sel = sels[iface_uri] if not changes: from zeroinstall.support import xmltools # No obvious changes, but check for more subtle updates. if not xmltools.nodes_equal(sels.toDOM(), old_sels.toDOM()): changes = True print( _("Updates to metadata found, but no change to version ({version})." ).format(version=root_sel.version)) root_iface = config.iface_cache.get_interface(iface_uri) # Force a reload, since we may have used the GUI to update it for feed in config.iface_cache.get_feeds(root_iface): config.iface_cache.get_feed(feed, force=True) root_impls = config.iface_cache.get_implementations(root_iface) latest = max((impl.version, impl) for impl in root_impls)[1] if latest.version > model.parse_version(sels[iface_uri].version): print( _("A later version ({name} {latest}) exists but was not selected. Using {version} instead." ).format(latest=latest.get_version(), name=root_iface.get_name(), version=root_sel.version)) if not config.help_with_testing and latest.get_stability( ) < model.stable: print( _('To select "testing" versions, use:\n0install config help_with_testing True' )) elif not changes: print( _("No updates found. Continuing with version {version}.").format( version=root_sel.version)) if app is not None: if changes: app.set_selections(sels) app.set_requirements(r)
def get_feed(self, master_feed): """Generate a feed containing information about distribution packages. This should immediately return a feed containing an implementation for the package if it's already installed. Information about versions that could be installed using the distribution's package manager can be added asynchronously later (see L{fetch_candidates}). @param master_feed: feed containing the <package-implementation> elements @type master_feed: L{model.ZeroInstallFeed} @rtype: L{model.ZeroInstallFeed}""" feed = model.ZeroInstallFeed(None) feed.url = 'distribution:' + master_feed.url for item, item_attrs in master_feed.get_package_impls(self): package = item_attrs.get('package', None) if package is None: raise model.InvalidInterface( _("Missing 'package' attribute on %s") % item) def factory(id, only_if_missing=False, installed=True): assert id.startswith('package:') if id in feed.implementations: if only_if_missing: return None warn(_("Duplicate ID '%s' for DistributionImplementation"), id) impl = model.DistributionImplementation(feed, id, self) feed.implementations[id] = impl impl.installed = installed impl.metadata = item_attrs item_main = item_attrs.get('main', None) if item_main and not item_main.startswith('/'): raise model.InvalidInterface( _("'main' attribute must be absolute, but '%s' doesn't start with '/'!" ) % item_main) impl.main = item_main impl.upstream_stability = model.packaged return impl self.get_package_info(package, factory) if master_feed.url == 'http://repo.roscidus.com/python/python' and all( not impl.installed for impl in feed.implementations.values()): # Hack: we can support Python on platforms with unsupported package managers # by adding the implementation of Python running us now to the list. python_version = '.'.join( [str(v) for v in sys.version_info if isinstance(v, int)]) impl_id = 'package:host:python:' + python_version assert impl_id not in feed.implementations impl = model.DistributionImplementation(feed, impl_id, self) impl.installed = True impl.version = model.parse_version(python_version) impl.main = sys.executable impl.upstream_stability = model.packaged impl.machine = host_machine # (hopefully) feed.implementations[impl_id] = impl return feed