From 254bfc008a78e71ee9b07c3e6aaac0f254c41208 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 9 Jan 2011 18:57:35 +0000 Subject: [PATCH] Store configuration in a separate object Solver now takes a ConfigParser object rather than storing individual settings. --- tests/testsat.py | 9 +++++- tests/testsolver.py | 19 +++++++---- zeroinstall/injector/policy.py | 72 ++++++++++++++++++++++-------------------- zeroinstall/injector/solver.py | 17 +++++++--- 4 files changed, 70 insertions(+), 47 deletions(-) diff --git a/tests/testsat.py b/tests/testsat.py index 86ca39d..3848182 100755 --- a/tests/testsat.py +++ b/tests/testsat.py @@ -1,5 +1,6 @@ #!/usr/bin/env python from basetest import BaseTest +import ConfigParser import sys, os import unittest @@ -130,7 +131,13 @@ def assertSelection(expected, repo): cache.get_prog(prog).get_version(str(prog_version)).add_requires(lib, min_v, max_v) root = uri_prefix + expected[0][0] - s = Solver(model.network_offline, cache, stores) + + test_config = ConfigParser.RawConfigParser() + test_config.add_section('global') + test_config.set('global', 'help_with_testing', 'False') + test_config.set('global', 'network_use', model.network_offline) + + s = Solver(test_config, cache, stores) s.solve(root, arch.get_architecture('Linux', 'x86_64')) if expected[0][1] == 'FAIL': diff --git a/tests/testsolver.py b/tests/testsolver.py index b479e6b..5ab6af8 100755 --- a/tests/testsolver.py +++ b/tests/testsolver.py @@ -1,6 +1,7 @@ #!/usr/bin/env python from basetest import BaseTest import sys, os, locale +import ConfigParser import unittest sys.path.insert(0, '..') @@ -12,9 +13,15 @@ import logging logger = logging.getLogger() #logger.setLevel(logging.DEBUG) +test_config = ConfigParser.ConfigParser() +test_config.add_section('global') +test_config.set('global', 'help_with_testing', 'False') +test_config.set('global', 'freshness', str(60 * 60 * 24 * 30)) # One month +test_config.set('global', 'network_use', 'full') + class TestSolver(BaseTest): def testSimple(self): - s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + s = solver.DefaultSolver(test_config, iface_cache, Stores()) foo = iface_cache.get_interface('http://foo/Binary.xml') reader.update(foo, 'Binary.xml') @@ -43,7 +50,7 @@ class TestSolver(BaseTest): assert not s.details def testDetails(self): - s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + s = solver.DefaultSolver(test_config, iface_cache, Stores()) foo = iface_cache.get_interface('http://foo/Binary.xml') reader.update(foo, 'Binary.xml') @@ -68,7 +75,7 @@ class TestSolver(BaseTest): assert s.details[compiler] == [(compiler_impls['sha1=345'], None)] def testRecursive(self): - s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + s = solver.DefaultSolver(test_config, iface_cache, Stores()) foo = iface_cache.get_interface('http://foo/Recursive.xml') reader.update(foo, 'Recursive.xml') @@ -84,7 +91,7 @@ class TestSolver(BaseTest): assert s.details[foo] == [(foo_impls['sha1=abc'], None)] def testMultiArch(self): - s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + s = solver.DefaultSolver(test_config, iface_cache, Stores()) foo = iface_cache.get_interface('http://foo/MultiArch.xml') reader.update(foo, 'MultiArch.xml') @@ -124,7 +131,7 @@ class TestSolver(BaseTest): assert 'ppc' not in other.machine_ranks def testRanking(self): - s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + s = solver.DefaultSolver(test_config, iface_cache, Stores()) ranking = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'Ranking.xml') iface = iface_cache.get_interface(ranking) @@ -147,7 +154,7 @@ class TestSolver(BaseTest): try: locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') - s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + s = solver.DefaultSolver(test_config, iface_cache, Stores()) iface = iface_cache.get_interface('http://foo/Langs.xml') reader.update(iface, 'Langs.xml') diff --git a/zeroinstall/injector/policy.py b/zeroinstall/injector/policy.py index cc13c38..55653c6 100644 --- a/zeroinstall/injector/policy.py +++ b/zeroinstall/injector/policy.py @@ -23,6 +23,23 @@ from zeroinstall.injector.iface_cache import iface_cache # If we started a check within this period, don't start another one: FAILED_CHECK_DELAY = 60 * 60 # 1 Hour +def load_config(): + config = ConfigParser.RawConfigParser() + config.add_section('global') + config.set('global', 'help_with_testing', 'False') + config.set('global', 'freshness', str(60 * 60 * 24 * 30)) # One month + config.set('global', 'network_use', 'full') + + path = basedir.load_first_config(config_site, config_prog, 'global') + if path: + info("Loading configuration from %s", path) + try: + config.read(path) + except Exception, ex: + warn(_("Error loading config: %s"), str(ex) or repr(ex)) + + return config + class Policy(object): """Chooses a set of implementations based on a policy. Typical use: @@ -50,21 +67,24 @@ class Policy(object): @ivar stale_feeds: set of feeds which are present but haven't been checked for a long time @type stale_feeds: set """ - __slots__ = ['root', 'watchers', 'command', - 'freshness', 'handler', '_warned_offline', + __slots__ = ['root', 'watchers', 'command', 'config', + 'handler', '_warned_offline', '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)) + help_with_testing = property(lambda self: self.config.getboolean('global', 'help_with_testing'), + lambda self, value: self.config.set('global', 'help_with_testing', bool(value))) - network_use = property(lambda self: self.solver.network_use, - lambda self, value: setattr(self.solver, 'network_use', value)) + network_use = property(lambda self: self.config.get('global', 'network_use'), + lambda self, value: self.config.set('global', 'network_use', value)) + + freshness = property(lambda self: int(self.config.get('global', 'freshness')), + lambda self, value: self.config.set('global', 'freshness', str(value))) implementation = property(lambda self: self.solver.selections) ready = property(lambda self: self.solver.ready) - def __init__(self, root, handler = None, src = False, command = -1): + def __init__(self, root, handler = None, src = False, command = -1, config = None): """ @param root: The URI of the root interface (the program we want to run). @param handler: A handler for main-loop integration. @@ -73,6 +93,8 @@ class Policy(object): @type src: bool @param command: The name of the command to run (e.g. 'run', 'test', 'compile', etc) @type command: str + @param config: The configuration settings to use, or None to load from disk. + @type config: L{ConfigParser.ConfigParser} """ self.watchers = [] self.src = src # Root impl must be a "src" machine type @@ -84,8 +106,13 @@ class Policy(object): command = 'run' self.command = command + if config is None: + self.config = load_config() + else: + self.config = config + from zeroinstall.injector.solver import DefaultSolver - self.solver = DefaultSolver(network_full, iface_cache, iface_cache.stores) + self.solver = DefaultSolver(self.config, iface_cache, iface_cache.stores) # If we need to download something but can't because we are offline, # warn the user. But only the first time. @@ -98,25 +125,7 @@ class Policy(object): debug(_("Supported systems: '%s'"), arch.os_ranks) debug(_("Supported processors: '%s'"), arch.machine_ranks) - config = ConfigParser.ConfigParser() - config.add_section('global') - config.set('global', 'help_with_testing', 'False') - config.set('global', 'freshness', str(60 * 60 * 24 * 30)) # One month - config.set('global', 'network_use', 'full') - - path = basedir.load_first_config(config_site, config_prog, 'global') - if path: - info("Loading configuration from %s", path) - try: - config.read(path) - except Exception, ex: - warn(_("Error loading config: %s"), str(ex) or repr(ex)) - - self.solver.help_with_testing = config.getboolean('global', 'help_with_testing') - self.solver.network_use = config.get('global', 'network_use') - self.freshness = int(config.get('global', 'freshness')) - assert self.solver.network_use in network_levels, self.solver.network_use - + assert self.network_use in network_levels, self.network_use self.set_root(root) self.target_arch = arch.get_host_architecture() @@ -136,16 +145,9 @@ class Policy(object): def save_config(self): """Write global settings.""" - config = ConfigParser.ConfigParser() - config.add_section('global') - - config.set('global', 'help_with_testing', self.help_with_testing) - config.set('global', 'network_use', self.network_use) - config.set('global', 'freshness', self.freshness) - path = basedir.save_config_path(config_site, config_prog) path = os.path.join(path, 'global') - config.write(file(path + '.new', 'w')) + self.config.write(file(path + '.new', 'w')) os.rename(path + '.new', path) def recalculate(self, fetch_stale_interfaces = True): diff --git a/zeroinstall/injector/solver.py b/zeroinstall/injector/solver.py index aa32ba2..21d5369 100644 --- a/zeroinstall/injector/solver.py +++ b/zeroinstall/injector/solver.py @@ -119,13 +119,12 @@ class Solver(object): raise NotImplementedError("Abstract") class SATSolver(Solver): - __slots__ = ['_failure_reason', 'network_use', 'iface_cache', 'stores', 'help_with_testing', 'extra_restrictions', - 'langs'] + __slots__ = ['_failure_reason', 'config', 'iface_cache', 'stores', 'extra_restrictions', 'langs'] """Converts the problem to a set of pseudo-boolean constraints and uses a PB solver to solve them. @ivar langs: the preferred languages (e.g. ["es_ES", "en"]). Initialised to the current locale. @type langs: str""" - def __init__(self, network_use, iface_cache, stores, extra_restrictions = None): + def __init__(self, config, iface_cache, stores, extra_restrictions = None): """ @param network_use: how much use to make of the network @type network_use: L{model.network_levels} @@ -137,14 +136,22 @@ class SATSolver(Solver): @type extra_restrictions: {L{model.Interface}: [L{model.Restriction}]} """ Solver.__init__(self) - self.network_use = network_use + assert not isinstance(config, str), "API change!" + self.config = config self.iface_cache = iface_cache self.stores = stores - self.help_with_testing = False self.extra_restrictions = extra_restrictions or {} self.langs = [locale.getlocale()[0] or 'en'] + @property + def network_use(self): + return self.config.get('global', 'network_use') + + @property + def help_with_testing(self): + return self.config.getboolean('global', 'help_with_testing') + def compare(self, interface, b, a, arch): """Compare a and b to see which would be chosen first. Does not consider whether the implementations are usable (check for that yourself first). -- 2.11.4.GIT