def testMultiArch(self): iface_cache = self.config.iface_cache s = solver.DefaultSolver(self.config) foo = iface_cache.get_interface('http://foo/MultiArch.xml') self.import_feed(foo.uri, 'MultiArch.xml') lib = iface_cache.get_interface('http://foo/MultiArchLib.xml') self.import_feed(lib.uri, 'MultiArchLib.xml') # On an i686 system we can only use the i486 implementation binary_arch = arch.get_architecture('Linux', 'i686') s.solve('http://foo/MultiArch.xml', binary_arch) assert s.ready assert s.selections[foo].machine == 'i486' assert s.selections[lib].machine == 'i486' # On an 64 bit system we could use either, but we prefer the 64 # bit implementation. The i486 version of the library is newer, # but we must pick one that is compatible with the main binary. binary_arch = arch.get_architecture('Linux', 'x86_64') s.solve('http://foo/MultiArch.xml', binary_arch) assert s.ready assert s.selections[foo].machine == 'x86_64' assert s.selections[lib].machine == 'x86_64'
def testLangs(self): iface_cache = self.config.iface_cache try: locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') s = solver.DefaultSolver(self.config) iface = iface_cache.get_interface('http://foo/Langs.xml') self.import_feed(iface.uri, 'Langs.xml') # 1 is the oldest, but the only one in our language binary_arch = arch.get_architecture(None, 'arch_1') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals('sha1=1', s.selections[iface].id) # 6 is the newest, and close enough, even though not # quite the right locale binary_arch = arch.get_architecture(None, 'arch_2') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals('sha1=6', s.selections[iface].id) # 9 is the newest, although 7 is a closer match binary_arch = arch.get_architecture(None, 'arch_3') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals('sha1=9', s.selections[iface].id) # 11 is the newest we understand binary_arch = arch.get_architecture(None, 'arch_4') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals('sha1=11', s.selections[iface].id) # 13 is the newest we understand binary_arch = arch.get_architecture(None, 'arch_5') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals('sha1=13', s.selections[iface].id) def check(target_arch, langs, expected): s.langs = langs binary_arch = arch.get_architecture(None, target_arch) s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals(expected, s.selections[iface].id) # We don't understand any, so pick the newest check('arch_2', ['es_ES'], 'sha1=6') # These two have the same version number. Choose the # one most appropriate to our country check('arch_6', ['zh_CN'], 'sha1=15') check('arch_6', ['zh_TW'], 'sha1=16') # Same, but one doesn't have a country code check('arch_7', ['bn'], 'sha1=17') check('arch_7', ['bn_IN'], 'sha1=18') finally: locale.setlocale(locale.LC_ALL, '')
def testLangs(self): iface_cache = self.config.iface_cache try: locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') s = solver.DefaultSolver(self.config) iface = iface_cache.get_interface('http://foo/Langs.xml') self.import_feed(iface.uri, 'Langs.xml') # 1 is the oldest, but the only one in our language binary_arch = arch.get_architecture(None, 'arch_1') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual('sha1=1', s.selections[iface].id) # 6 is the newest, and close enough, even though not # quite the right locale binary_arch = arch.get_architecture(None, 'arch_2') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual('sha1=6', s.selections[iface].id) # 9 is the newest, although 7 is a closer match binary_arch = arch.get_architecture(None, 'arch_3') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual('sha1=9', s.selections[iface].id) # 11 is the newest we understand binary_arch = arch.get_architecture(None, 'arch_4') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual('sha1=11', s.selections[iface].id) # 13 is the newest we understand binary_arch = arch.get_architecture(None, 'arch_5') s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual('sha1=13', s.selections[iface].id) def check(target_arch, langs, expected): s.langs = langs binary_arch = arch.get_architecture(None, target_arch) s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual(expected, s.selections[iface].id) # We don't understand any, so pick the newest check('arch_2', ['es_ES'], 'sha1=6') # These two have the same version number. Choose the # one most appropriate to our country check('arch_6', ['zh_CN'], 'sha1=15') check('arch_6', ['zh_TW'], 'sha1=16') # Same, but one doesn't have a country code check('arch_7', ['bn'], 'sha1=17') check('arch_7', ['bn_IN'], 'sha1=18') finally: locale.setlocale(locale.LC_ALL, '')
def testArch(self): host_arch = arch.get_host_architecture() host_arch2 = arch.get_architecture(None, None) self.assertEquals(host_arch.os_ranks, host_arch2.os_ranks) self.assertEquals(host_arch.machine_ranks, host_arch2.machine_ranks) other = arch.get_architecture('FooBar', 'i486') self.assertEquals(2, len(other.os_ranks)) assert 'FooBar' in other.os_ranks assert None in other.os_ranks assert 'i486' in other.machine_ranks assert 'ppc' not in other.machine_ranks
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 get_arch_for(self, requirements, interface=None): """Return the Architecture we would use when solving for this interface. Normally, this architecture is constructed from the OS and CPU type in the requirements, using the host platform's settings if these are not given. If interface is the root, then we wrap this in a SourceArchitecture if looking for source code and (for backwards compatibility) we enable use="testing" dependencies if the command is "test". @param requirements: the overall requirements for the solve @type requirements: L{requirements.Requirements} @param interface: the interface of interest @type interface: L{model.Interface} @return: the architecture that would be used @rtype: L{architecture.Architecture} @since: 1.9""" root_arch = arch.get_architecture(requirements.os, requirements.cpu) if interface is None or interface.uri == requirements.interface_uri: if requirements.source: root_arch = arch.SourceArchitecture(root_arch) if requirements.command == 'test': # This is for old feeds that have use='testing' instead of the newer # 'test' command for giving test-only dependencies. root_arch = arch.Architecture(root_arch.os_ranks, root_arch.machine_ranks) root_arch.use = frozenset([None, "testing"]) return root_arch # Assume we use the same arch for all descendants return root_arch.child_arch
def check(target_arch, langs, expected): s.langs = langs binary_arch = arch.get_architecture(None, target_arch) s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEqual(expected, s.selections.selections[iface.uri].id)
def get_arch_for(self, requirements, interface = None): """Return the Architecture we would use when solving for this interface. Normally, this architecture is constructed from the OS and CPU type in the requirements, using the host platform's settings if these are not given. If interface is the root, then we wrap this in a SourceArchitecture if looking for source code and (for backwards compatibility) we enable use="testing" dependencies if the command is "test". @param requirements: the overall requirements for the solve @type requirements: L{requirements.Requirements} @param interface: the interface of interest @type interface: L{model.Interface} @return: the architecture that would be used @rtype: L{architecture.Architecture} @since: 1.9""" root_arch = arch.get_architecture(requirements.os, requirements.cpu) if interface is None or interface.uri == requirements.interface_uri: if requirements.source: root_arch = arch.SourceArchitecture(root_arch) if requirements.command == 'test': # This is for old feeds that have use='testing' instead of the newer # 'test' command for giving test-only dependencies. root_arch = arch.Architecture(root_arch.os_ranks, root_arch.machine_ranks) root_arch.use = frozenset([None, "testing"]) return root_arch # Assume we use the same arch for all descendants return root_arch.child_arch
def testRanking(self): iface_cache = self.config.iface_cache s = solver.DefaultSolver(self.config) ranking = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Ranking.xml') iface = iface_cache.get_interface(ranking) binary_arch = arch.get_architecture('Linux', 'x86_64') selected = [] while True: s.solve(ranking, binary_arch) if not s.ready: break impl = s.selections[iface] selected.append(impl.get_version() + ' ' + impl.arch) impl.arch = 'Foo-odd' # prevent reselection self.assertEqual( [ '0.2 Linux-i386', # poor arch, but newest version '0.1 Linux-x86_64', # 64-bit is best match for host arch '0.1 Linux-i686', '0.1 Linux-i586', '0.1 Linux-i486' ], # ordering of x86 versions selected)
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) self.solver.extra_restrictions = requirements.get_extra_restrictions( self.config.iface_cache)
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) 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 testDecideBug(self): s = solver.DefaultSolver(self.config) watch_xml = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'watchdog.xml') s.solve(watch_xml, arch.get_architecture(None, None), command_name='test')
def testRecommendBug(self): s = solver.DefaultSolver(self.config) optional_missing_xml = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'OptionalMissing.xml') s.solve(optional_missing_xml, arch.get_architecture(None, None), command_name=None)
def testFeedBug(self): self.import_feed('http://foo/Build.xml', 'Build.xml') self.import_feed('http://foo/Compiler.xml', 'Compiler.xml') self.import_feed('http://foo/Compiler-new.xml', 'Compiler-new.xml') s = solver.DefaultSolver(self.config) s.solve('http://foo/Build.xml', arch.get_architecture(None, None)) assert s.ready, s.get_failure_reason() assert s.selections
def assertSelection(expected, repo): cache = TestCache() expected = [tuple(e.strip().split('-')) for e in expected.split(",")] for line in repo.split('\n'): line = line.strip() if not line: continue if ':' in line: prog, versions = line.split(':') prog = prog.strip() if ' ' in prog: prog, prog_arch = prog.split() else: prog_arch = None for v in versions.split(): cache.get_prog(prog).get_version(v).arch = prog_arch elif '=>' in line: prog, requires = line.split('=>') prog, version_range = prog.strip().split('[') lib, min_v, max_v = requires.split() assert version_range.endswith(']') version_range = version_range[:-1] if ',' in version_range: min_p, max_p = map(int, version_range.split(',')) prog_versions = range(min_p, max_p + 1) else: prog_versions = [int(version_range)] for prog_version in prog_versions: cache.get_prog(prog).get_version( str(prog_version)).add_requires(lib, min_v, max_v) root = uri_prefix + expected[0][0] class TestConfig: help_with_testing = False network_use = model.network_offline stores = stores iface_cache = cache s = Solver(TestConfig()) s.solve(root, arch.get_architecture('Linux', 'x86_64')) if expected[0][1] == 'FAIL': assert not s.ready else: assert s.ready actual = [] for iface_uri, impl in s.selections.selections.iteritems(): actual.append(((iface_uri.rsplit('/', 1)[1]), impl.version)) expected.sort() actual.sort() if expected != actual: raise Exception("Solve failed:\nExpected: %s\n Actual: %s" % (expected, actual)) return s
def assertSelection(expected, repo): cache = TestCache() expected = [tuple(e.strip().split('-')) for e in expected.split(",")] for line in repo.split('\n'): line = line.strip() if not line: continue if ':' in line: prog, versions = line.split(':') prog = prog.strip() if ' ' in prog: prog, prog_arch = prog.split() else: prog_arch = None for v in versions.split(): cache.get_prog(prog).get_version(v).arch = prog_arch elif '=>' in line: prog, requires = line.split('=>') prog, version_range = prog.strip().split('[') lib, min_v, max_v = requires.split() assert version_range.endswith(']') version_range = version_range[:-1] if ',' in version_range: min_p, max_p = map(int, version_range.split(',')) prog_versions = range(min_p, max_p + 1) else: prog_versions = [int(version_range)] for prog_version in prog_versions: cache.get_prog(prog).get_version(str(prog_version)).add_requires(lib, min_v, max_v) root = uri_prefix + expected[0][0] class TestConfig: help_with_testing = False network_use = model.network_offline stores = stores iface_cache = cache s = Solver(TestConfig()) s.solve(root, arch.get_architecture('Linux', 'x86_64')) if expected[0][1] == 'FAIL': assert not s.ready else: assert s.ready actual = [] for iface_uri, impl in s.selections.selections.items(): actual.append(((iface_uri.rsplit('/', 1)[1]), impl.version)) expected.sort() actual.sort() if expected != actual: raise Exception("Solve failed:\nExpected: %s\n Actual: %s" % (expected, actual)) return s
def solve_for(self, requirements): """Solve for given requirements. @param requirements: the interface, architecture and command to solve for @type requirements: L{requirements.Requirements} @postcondition: self.ready, self.selections and self.feeds_used are updated @since: 1.8""" root_arch = arch.get_architecture(requirements.os, requirements.cpu) if requirements.source: root_arch = arch.SourceArchitecture(root_arch) return self.solve(requirements.interface_uri, root_arch, requirements.command)
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 testRanking(self): iface_cache = self.config.iface_cache s = solver.DefaultSolver(self.config) ranking = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Ranking.xml') binary_arch = arch.get_architecture('Linux', 'x86_64') selected = [] while True: s.solve(ranking, binary_arch) if not s.ready: break impl = s.selections.selections[ranking] selected.append(impl.version + ' ' + impl.attrs['arch']) iface_cache.get_feed(ranking).implementations[impl.id].arch = 'Foo-odd' # prevent reselection self.assertEqual([ '0.2 Linux-i386', # poor arch, but newest version '0.1 Linux-x86_64', # 64-bit is best match for host arch '0.1 Linux-i686', '0.1 Linux-i586', '0.1 Linux-i486'], # ordering of x86 versions selected)
def justify_decision(self, requirements, iface, impl): """Run a solve with impl_id forced to be selected, and explain why it wasn't (or was) selected in the normal case.""" assert isinstance(iface, model.Interface), iface restrictions = self.extra_restrictions.copy() restrictions[iface] = restrictions.get(iface, []) + [_ForceImpl(impl)] s = SATSolver(self.config, restrictions) s.record_details = True s.solve_for(requirements) wanted = "{iface} {version}".format(iface=iface.get_name(), version=impl.get_version()) # Could a selection involving impl even be valid? if not s.ready or iface.uri not in s.selections.selections: reasons = s.details.get(iface, []) for (rid, rstr) in reasons: if rid.id == impl.id and rstr is not None: return _( "{wanted} cannot be used (regardless of other components): {reason}" ).format(wanted=wanted, reason=rstr) if not s.ready: return _( "There is no possible selection using {wanted}.\n{reason}" ).format(wanted=wanted, reason=s.get_failure_reason()) actual_selection = self.selections.get(iface, None) if actual_selection is not None: # Was impl actually selected anyway? if actual_selection.id == impl.id: return _("{wanted} was selected as the preferred version." ).format(wanted=wanted) # Was impl ranked below the selected version? iface_arch = arch.get_architecture(requirements.os, requirements.cpu) if requirements.source and iface.uri == requirements.interface_uri: iface_arch = arch.SourceArchitecture(iface_arch) wanted_rating = self.get_rating(iface, impl, arch) selected_rating = self.get_rating(iface, actual_selection, arch) if wanted_rating < selected_rating: _ranking_component_reason = [ _("natural languages we understand are preferred"), _("preferred versions come first"), _("locally-available versions are preferred when network use is limited" ), _("packages that don't require admin access to install are preferred" ), _("more stable versions preferred"), _("newer versions are preferred"), _("native packages are preferred"), _("newer versions are preferred"), _("better OS match"), _("better CPU match"), _("better locale match"), _("is locally available"), _("better ID (tie-breaker)"), ] actual = actual_selection.get_version() if impl.get_version() == actual: def detail(i): if len(i.id) < 18: return " (" + i.id + ")" else: return " (" + i.id[:16] + "...)" wanted += detail(impl) actual += detail(actual_selection) for i in range(len(wanted_rating)): if wanted_rating[i] < selected_rating[i]: return _( "{wanted} is ranked lower than {actual}: {why}" ).format(wanted=wanted, actual=actual, why=_ranking_component_reason[i]) used_impl = iface.uri in s.selections.selections # Impl is selectable and ranked higher than the selected version. Selecting it would cause # a problem elsewhere. changes = [] for old_iface, old_sel in self.selections.selections.items(): if old_iface == iface.uri and used_impl: continue new_sel = s.selections.selections.get(old_iface, None) if new_sel is None: changes.append( _("{interface}: no longer used").format( interface=old_iface)) elif old_sel.version != new_sel.version: changes.append( _("{interface}: {old} to {new}").format( interface=old_iface, old=old_sel.version, new=new_sel.version)) elif old_sel.id != new_sel.id: changes.append( _("{interface}: {old} to {new}").format( interface=old_iface, old=old_sel.id, new=new_sel.id)) if changes: changes_text = '\n\n' + _( 'The changes would be:') + '\n\n' + '\n'.join(changes) else: changes_text = '' if used_impl: return _( "{wanted} is selectable, but using it would produce a less optimal solution overall." ).format(wanted=wanted) + changes_text else: return _( "If {wanted} were the only option, the best available solution wouldn't use it." ).format(wanted=wanted) + changes_text
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 testOs(self): arch = get_architecture('MacOSX', 'ppc') assert ('Darwin' in arch.os_ranks)
def testDefault(self): arch = get_architecture(None, None) assert arch
def testDecideBug(self): s = solver.DefaultSolver(self.config) watch_xml = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'watchdog.xml') s.solve(watch_xml, arch.get_architecture(None, None), command_name = 'test')
def testMachine(self): arch = get_architecture('Linux', 'i686') assert ('i386' in arch.machine_ranks)
def testRecommendBug(self): s = solver.DefaultSolver(self.config) optional_missing_xml = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'OptionalMissing.xml') s.solve(optional_missing_xml, arch.get_architecture(None, None), command_name = None)
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 justify_decision(self, requirements, iface, impl): """Run a solve with impl_id forced to be selected, and explain why it wasn't (or was) selected in the normal case. @type requirements: L{zeroinstall.injector.requirements.Requirements} @type iface: L{zeroinstall.injector.model.Interface} @type impl: L{zeroinstall.injector.model.Implementation} @rtype: str""" assert isinstance(iface, model.Interface), iface restrictions = self.extra_restrictions.copy() restrictions[iface] = restrictions.get(iface, []) + [_ForceImpl(impl)] s = SATSolver(self.config, restrictions) s.record_details = True s.solve_for(requirements) wanted = "{iface} {version}".format(iface = iface.get_name(), version = impl.get_version()) # Could a selection involving impl even be valid? if not s.ready or iface.uri not in s.selections.selections: reasons = s.details.get(iface, []) for (rid, rstr) in reasons: if rid.id == impl.id and rstr is not None: return _("{wanted} cannot be used (regardless of other components): {reason}").format( wanted = wanted, reason = rstr) if not s.ready: return _("There is no possible selection using {wanted}.\n{reason}").format( wanted = wanted, reason = s.get_failure_reason()) actual_selection = self.selections.get(iface, None) if actual_selection is not None: # Was impl actually selected anyway? if actual_selection.id == impl.id: return _("{wanted} was selected as the preferred version.").format(wanted = wanted) # Was impl ranked below the selected version? iface_arch = arch.get_architecture(requirements.os, requirements.cpu) if requirements.source and iface.uri == requirements.interface_uri: iface_arch = arch.SourceArchitecture(iface_arch) wanted_rating = self.get_rating(iface, impl, arch) selected_rating = self.get_rating(iface, actual_selection, arch) if wanted_rating < selected_rating: _ranking_component_reason = [ _("natural languages we understand are preferred"), _("preferred versions come first"), _("locally-available versions are preferred when network use is limited"), _("packages that don't require admin access to install are preferred"), _("more stable versions preferred"), _("newer versions are preferred"), _("native packages are preferred"), _("newer versions are preferred"), _("better OS match"), _("better CPU match"), _("better locale match"), _("is locally available"), _("better ID (tie-breaker)"), ] actual = actual_selection.get_version() if impl.get_version() == actual: def detail(i): if len(i.id) < 18: return " (" + i.id + ")" else: return " (" + i.id[:16] + "...)" wanted += detail(impl) actual += detail(actual_selection) for i in range(len(wanted_rating)): if wanted_rating[i] < selected_rating[i]: return _("{wanted} is ranked lower than {actual}: {why}").format( wanted = wanted, actual = actual, why = _ranking_component_reason[i]) used_impl = iface.uri in s.selections.selections # Impl is selectable and ranked higher than the selected version. Selecting it would cause # a problem elsewhere. changes = [] for old_iface, old_sel in self.selections.selections.items(): if old_iface == iface.uri and used_impl: continue new_sel = s.selections.selections.get(old_iface, None) if new_sel is None: changes.append(_("{interface}: no longer used").format(interface = old_iface)) elif old_sel.version != new_sel.version: changes.append(_("{interface}: {old} to {new}").format(interface = old_iface, old = old_sel.version, new = new_sel.version)) elif old_sel.id != new_sel.id: changes.append(_("{interface}: {old} to {new}").format(interface = old_iface, old = old_sel.id, new = new_sel.id)) if changes: changes_text = '\n\n' + _('The changes would be:') + '\n\n' + '\n'.join(changes) else: changes_text = '' if used_impl: return _("{wanted} is selectable, but using it would produce a less optimal solution overall.").format(wanted = wanted) + changes_text else: return _("If {wanted} were the only option, the best available solution wouldn't use it.").format(wanted = wanted) + changes_text
def check(target_arch, langs, expected): s.langs = langs binary_arch = arch.get_architecture(None, target_arch) s.solve('http://foo/Langs.xml', binary_arch) assert s.ready self.assertEquals(expected, s.selections[iface].id)