set up Configurator stuff

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1858 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-08-01 13:05:27 +00:00
parent 87d60fd415
commit 7ea411b923
4 changed files with 156 additions and 26 deletions

View file

@ -26,8 +26,92 @@ This means that all calls to services (like crawler, transporter, ...)
return a deferred that must be supplied with a callback method (and in return a deferred that must be supplied with a callback method (and in
most cases also an errback method). most cases also an errback method).
>>> from loops.agent.core import Agent >>> from loops.agent import core
>>> agent = Agent() >>> agent = core.Agent()
Configuration Management
========================
Functionality
- Storage of configuration parameters
- Interface to the browser-based user interface that allows the
editing of configuration parameters
All configuration parameters are always accessible via the ``config``
attribute of the agent object.
>>> config = agent.config
This already provides all needed sections (transport, crawl, ui), so
we can directly put information into these sections by loading a
string with the corresponding assignment.
>>> config.load('transport.url = "http://loops.cy55.de"')
>>> config.transport.url
'http://loops.cy55.de'
This setting may also contain indexed access; thus we can model
configuration parameters with multiple instances (like crawling
jobs).
>>> config.load('''
... crawl[0].type = "filesystem"
... crawl[0].directory = "documents/projects"
... ''')
>>> config.crawl[0].type
'filesystem'
>>> config.crawl[0].directory
'documents/projects'
Subsections are created automatically when they are first accessed.
>>> config.load('ui.web.port = 8081')
>>> config.ui.web.port
8081
The ``setdefault()`` method allows to retrieve a value and set
it with a default if not found, in one statement.
>>> config.ui.web.setdefault('port', 8080)
8081
>>> config.transport.setdefault('user', 'loops')
'loops'
We can output a configuration in a form that is ready for loading
just by converting it to a string representation.
>>> print config
crawl[0].directory = 'documents/projects'
crawl[0].type = 'filesystem'
transport.url = 'http://loops.cy55.de'
transport.user = 'loops'
ui.web.port = 8081
The configuration may also be saved to a file -
for testing purposes let's use the loops.agent package directory
for storage; normally it would be stored in the users home directory.
>>> import os
>>> os.environ['HOME'] = os.path.dirname(core.__file__)
>>> config.save()
>>> fn = config.getDefaultConfigFile()
>>> fn
'....loops.agent.cfg'
>>> print open(fn).read()
crawl[0].directory = 'documents/projects'
crawl[0].type = 'filesystem'
transport.url = 'http://loops.cy55.de'
transport.user = 'loops'
ui.web.port = 8081
Cleaning up up...
>>> os.unlink(fn)
Scheduling Scheduling
@ -185,16 +269,6 @@ Configuration (per install/update job)
- package names - package names
Configuration Management
========================
Functionality
- Storage of configuration parameters
- Interface to the browser-based user interface that allows the
editing of configuration parameters
Browser-based User Interface Browser-based User Interface
============================ ============================

View file

@ -22,6 +22,7 @@ Management of agent configuration.
$Id$ $Id$
""" """
import os
from zope.interface import implements from zope.interface import implements
from loops.agent.interfaces import IConfigurator from loops.agent.interfaces import IConfigurator
@ -30,21 +31,75 @@ class Configurator(object):
implements(IConfigurator) implements(IConfigurator)
def loadConfiguration(self): def __init__(self, *sections, **kw):
pass for s in sections:
setattr(self, s, ConfigSection())
self.filename = kw.get('filename')
def addConfigOption(self, key, value): def load(self, p=None, filename=None):
setattr(self, key, value) if p is None:
fn = self.getConfigFile(filename)
if fn is not None:
f = open(fn, 'r')
p = f.read()
f.close()
if p is None:
return
exec p in self.__dict__
def getConfigOption(self, key, value): def save(self, filename=None):
return getattr(self, key, None) fn = self.getConfigFile(filename)
if fn is None:
fn = self.getDefaultConfigFile()
if fn is not None:
f = open(fn, 'w')
f.write(repr(self))
f.close()
def __repr__(self):
result = []
for name, value in self.__dict__.items():
if isinstance(value, ConfigSection):
value.collect(name, result)
return '\n'.join(sorted(result))
def getConfigFile(self, filename=None):
if filename is not None:
self.filename = filename
if self.filename is None:
fn = self.getDefaultConfigFile()
if os.path.isfile(fn):
self.filename = fn
return self.filename
def getDefaultConfigFile(self):
return os.path.join(os.path.expanduser('~'), '.loops.agent.cfg')
conf = Configurator() class ConfigSection(list):
# this is just for convenience during the development phase, def __getattr__(self, attr):
# thus we can retrieve the port easily via ``conf.ui.web.port`` value = ConfigSection()
conf.addConfigOption('ui', Configurator()) setattr(self, attr, value)
conf.ui.addConfigOption('web', Configurator()) return value
conf.ui.web.addConfigOption('port', 10095)
def __getitem__(self, idx):
while idx >= len(self):
self.append(ConfigSection())
return list.__getitem__(self, idx)
def setdefault(self, attr, value):
if attr not in self.__dict__:
setattr(self, attr, value)
return value
return getattr(self, attr)
def collect(self, ident, result):
for idx, element in enumerate(self):
element.collect('%s[%i]' % (ident, idx), result)
for name, value in self.__dict__.items():
if isinstance(value, ConfigSection):
value.collect('%s.%s' % (ident, name), result)
elif isinstance(value, (str, int)):
result.append('%s.%s = %s' % (ident, name, repr(value)))

View file

@ -33,7 +33,7 @@ class Agent(object):
implements(IAgent) implements(IAgent)
def __init__(self): def __init__(self):
configurator = self.configurator = Configurator() config = self.config = Configurator('ui', 'crawl', 'transport')
configurator.loadConfiguration() config.load()
self.scheduler = Scheduler() self.scheduler = Scheduler()

View file

@ -1,3 +1,4 @@
#! /usr/bin/env python
# #
# Run with ``trial2.4 tests.py`` to execute the twisted unit tests. # Run with ``trial2.4 tests.py`` to execute the twisted unit tests.
# Run with ``python tests.py`` to execute the doctests. # Run with ``python tests.py`` to execute the doctests.