From c4658d23d8a1d34bd5bfae81fecac249081c3b2a Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sat, 5 Jul 2008 15:01:38 +0100 Subject: [PATCH] Added --cpu and --os arguments to 0launch This allows you to choose a binary for a different host. It's also useful on an x86_64 machine to run an x86 binary. --- tests/testsolver.py | 13 +++++++++++++ zeroinstall/0launch-gui/main.py | 5 ++++- zeroinstall/injector/arch.py | 31 +++++++++++++++++++++++++------ zeroinstall/injector/cli.py | 12 ++++++++++++ zeroinstall/injector/policy.py | 12 ++++++++---- 5 files changed, 62 insertions(+), 11 deletions(-) diff --git a/tests/testsolver.py b/tests/testsolver.py index 39fabf0..39e7dc3 100755 --- a/tests/testsolver.py +++ b/tests/testsolver.py @@ -74,6 +74,19 @@ class TestSolver(BaseTest): assert len(s.details) == 1 assert s.details[foo] == [(foo._main_feed.implementations['sha1=abc'], None)] + 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 suite = unittest.makeSuite(TestSolver) if __name__ == '__main__': diff --git a/zeroinstall/0launch-gui/main.py b/zeroinstall/0launch-gui/main.py index 87d85f1..e030b2b 100644 --- a/zeroinstall/0launch-gui/main.py +++ b/zeroinstall/0launch-gui/main.py @@ -5,7 +5,7 @@ import os, sys from optparse import OptionParser -from zeroinstall.injector import model, autopolicy, namespaces +from zeroinstall.injector import model, autopolicy, namespaces, arch from zeroinstall.injector.policy import Policy from zeroinstall.injector.iface_cache import iface_cache from zeroinstall.support import tasks @@ -13,9 +13,11 @@ from zeroinstall.support import tasks 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("", "--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("-v", "--verbose", help="more verbose output", action='count') @@ -92,6 +94,7 @@ def run_gui(args): handler = gui.GUIHandler() 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 diff --git a/zeroinstall/injector/arch.py b/zeroinstall/injector/arch.py index d22e23e..f9c52ad 100644 --- a/zeroinstall/injector/arch.py +++ b/zeroinstall/injector/arch.py @@ -30,12 +30,11 @@ os_ranks = { _uname[0] : 1, # Current OS } -def _get_machine_ranks(): +def _get_machine_ranks(target_machine): # Binaries compiled for _this_machine are best... - this_machine = _uname[-1] - machine_ranks = {this_machine : 0} + machine_ranks = {target_machine : 0} - # If this_machine appears in the first column of this table, all + # If target_machine appears in the first column of this table, all # following machine types on the line will also run on this one # (earlier ones preferred): _machine_matrix = { @@ -44,14 +43,14 @@ def _get_machine_ranks(): 'i686': ['i586', 'i486', 'i386'], 'ppc64': ['ppc32'], } - for supported in _machine_matrix.get(this_machine, []): + for supported in _machine_matrix.get(target_machine, []): machine_ranks[supported] = len(machine_ranks) # At the lowest priority, try a machine-independant implementation machine_ranks[None] = len(machine_ranks) return machine_ranks -machine_ranks = _get_machine_ranks() +machine_ranks = _get_machine_ranks(_uname[-1]) #print machine_ranks class Architecture: @@ -84,3 +83,23 @@ def get_host_architecture(): """Get an Architecture that matches implementations that will run on the host machine. @rtype: L{Architecture}""" return Architecture(os_ranks, machine_ranks) + +def get_architecture(os, machine): + """Get an Architecture that matches binaries that will work on the given system. + @param os: OS type, or None for host's type + @param machine: CPU type, or None for host's type + @return: an Architecture object + @rtype: L{Architecture}""" + + if os: + target_os_ranks = { + os : 1, # Perfer binaries for target OS + None : 2, # Otherwise, generic OS is fine + } + else: + target_os_ranks = os_ranks + if machine: + target_machine_ranks = _get_machine_ranks(machine) + else: + target_machine_ranks = machine_ranks + return Architecture(target_os_ranks, target_machine_ranks) diff --git a/zeroinstall/injector/cli.py b/zeroinstall/injector/cli.py index 3a4ed6b..5cc772e 100644 --- a/zeroinstall/injector/cli.py +++ b/zeroinstall/injector/cli.py @@ -151,6 +151,10 @@ def _normal_mode(options, args): 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 @@ -225,6 +229,12 @@ def _normal_mode(options, args): 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') sels = _fork_gui(iface_uri, gui_args, prog_args, options) if not sels: sys.exit(1) # Aborted @@ -292,6 +302,7 @@ def main(command_args): " %prog --feed [interface]") parser.add_option("", "--before", help="choose a version before this", metavar='VERSION') parser.add_option("-c", "--console", help="never use GUI", action='store_false', dest='gui') + parser.add_option("", "--cpu", help="target CPU type", metavar='CPU') parser.add_option("-d", "--download-only", help="fetch but don't run", action='store_true') parser.add_option("-D", "--dry-run", help="just print actions", action='store_true') parser.add_option("-f", "--feed", help="add or remove a feed", action='store_true') @@ -301,6 +312,7 @@ def main(command_args): parser.add_option("-l", "--list", help="list all known interfaces", action='store_true') parser.add_option("-m", "--main", help="name of the file to execute") 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("-o", "--offline", help="try to avoid using the network", action='store_true') parser.add_option("-r", "--refresh", help="refresh all used interfaces", action='store_true') parser.add_option("", "--set-selections", help="run versions specified in XML file", metavar='FILE') diff --git a/zeroinstall/injector/policy.py b/zeroinstall/injector/policy.py index adf4f17..e91f937 100644 --- a/zeroinstall/injector/policy.py +++ b/zeroinstall/injector/policy.py @@ -31,6 +31,8 @@ class Policy(object): 4. Use L{get_uncached_implementations} to find where to get these versions and download them using L{download_uncached_implementations}. + @ivar target_arch: target architecture for binaries + @type target_arch: L{arch.Architecture} @ivar root: URI of the root interface @ivar solver: solver used to choose a set of implementations @type solver: L{solve.Solver} @@ -49,7 +51,7 @@ class Policy(object): """ __slots__ = ['root', 'watchers', 'freshness', 'handler', '_warned_offline', - 'src', 'stale_feeds', 'solver', '_fetcher'] + 'target_arch', 'src', 'stale_feeds', 'solver', '_fetcher'] help_with_testing = property(lambda self: self.solver.help_with_testing, lambda self, value: setattr(self.solver, 'help_with_testing', value)) @@ -103,6 +105,8 @@ class Policy(object): self.set_root(root) + self.target_arch = arch.get_host_architecture() + @property def fetcher(self): if not self._fetcher: @@ -134,7 +138,7 @@ class Policy(object): """@deprecated: see L{solve_with_downloads} """ self.stale_feeds = set() - host_arch = arch.get_host_architecture() + host_arch = self.target_arch if self.src: host_arch = arch.SourceArchitecture(host_arch) self.solver.solve(self.root, host_arch) @@ -310,7 +314,7 @@ class Policy(object): downloads_finished = set() # Successful or otherwise downloads_in_progress = {} # URL -> Download - host_arch = arch.get_host_architecture() + host_arch = self.target_arch if self.src: host_arch = arch.SourceArchitecture(host_arch) @@ -350,7 +354,7 @@ class Policy(object): """Decide whether we need to download anything (but don't do it!) @return: true if we MUST download something (feeds or implementations) @rtype: bool""" - host_arch = arch.get_host_architecture() + host_arch = self.target_arch if self.src: host_arch = arch.SourceArchitecture(host_arch) self.solver.solve(self.root, host_arch) -- 2.11.4.GIT