diff --git a/agent/crawl/filesystem.py b/agent/crawl/filesystem.py index b85c475..45ac986 100644 --- a/agent/crawl/filesystem.py +++ b/agent/crawl/filesystem.py @@ -53,16 +53,19 @@ class CrawlingJob(BaseCrawlingJob): for path, dirs, files in os.walk(directory): if '.svn' in dirs: del dirs[dirs.index('.svn')] - for f in filter(files, pattern): - filename = os.path.join(path, f) - mtime = datetime.fromtimestamp(os.path.getmtime(filename)) - if mtime <= lastRun: # file not changed - continue - meta = dict( - path=filename, - ) - self.collected.append(FileResource(filename, Metadata(meta))) - yield None + self.loadFiles(files, pattern) + + def loadFiles(self, files, pattern): + for f in filter(files, pattern): + filename = os.path.join(path, f) + mtime = datetime.fromtimestamp(os.path.getmtime(filename)) + if mtime <= lastRun: # file not changed + continue + meta = dict( + path=filename, + ) + self.collected.append(FileResource(filename, Metadata(meta))) + yield None class FileResource(object): diff --git a/browser/common.py b/browser/common.py index 3f1033c..e7826b3 100644 --- a/browser/common.py +++ b/browser/common.py @@ -433,7 +433,8 @@ class BaseView(GenericView, I18NView): def registerDojoDateWidget(self): self.registerDojo() - jsCall = 'dojo.require("dijit.form.DateTextBox");' + jsCall = ('dojo.require("dijit.form.DateTextBox"); ' + 'dojo.require("dijit.form.TimeTextBox");') self.controller.macros.register('js-execute', jsCall, jsCall=jsCall) def registerDojoTextWidget(self): diff --git a/config/README.txt b/config/README.txt new file mode 100644 index 0000000..3287953 --- /dev/null +++ b/config/README.txt @@ -0,0 +1,73 @@ +=============================================================== +loops - Linked Objects for Organization and Processing Services +=============================================================== + +Management of configuration settings and preferences. + + ($Id$) + + +Setting up a loops Site and Utilities +===================================== + +Let's do some basic set up + + >>> from zope import component, interface + >>> from zope.traversing.api import getName + >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown + >>> site = placefulSetUp(True) + +and build a simple loops site with a concept manager and some concepts +(with a relation registry, a catalog, and all the type machinery - what +in real life is done via standard ZCML setup or via local utility +configuration): + + >>> from loops.integrator.testsetup import TestSite + >>> t = TestSite(site) + >>> concepts, resources, views = t.setup() + >>> loopsRoot = concepts.getLoopsRoot() + + +Options Adapters +================ + +Global and site options +----------------------- + + >>> from loops.config.base import LoopsOptions + >>> component.provideAdapter(LoopsOptions) + + >>> from cybertools.meta.interfaces import IOptions + >>> opt = IOptions(loopsRoot) + >>> opt + + >>> str(opt) + '' + +We now use the loops root object's options field to define +some options. + + >>> loopsRoot.options = ['useVersioning', 'organize.tracking:changes, access'] + >>> opt = IOptions(loopsRoot) + >>> print opt + organize(tracking=['changes', 'access']) + useVersioning=True + + >>> opt.organize.tracking + ['changes', 'access'] + >>> opt.useVersioning + True + +If we query an option that is not defined on the site level we get a +dummy element that corresponds to False. + + >>> opt.i18n.languages + + >>> bool(opt.i18n.languages) + False + + +Fin de partie +============= + + >>> placefulTearDown() diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..4bc90fb --- /dev/null +++ b/config/__init__.py @@ -0,0 +1,4 @@ +""" +$Id$ +""" + diff --git a/config/base.py b/config/base.py new file mode 100644 index 0000000..9bab435 --- /dev/null +++ b/config/base.py @@ -0,0 +1,68 @@ +# +# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +""" +Adapters and others classes for analyzing resources. + +$Id$ +""" + +from zope.cachedescriptors.property import Lazy +from zope import component +from zope.component import adapts +from zope.traversing.api import getName, getParent + +from cybertools.meta.config import Options +from cybertools.meta.namespace import Executor, ExecutionError +from cybertools.typology.interfaces import IType +from loops.interfaces import ILoops + + +class LoopsOptions(Options): + + adapts(ILoops) + + builtins = Options.builtins + ('True', 'False') + True, False = True, False + + def __init__(self, context, *args, **kw): + self.context = context + super(LoopsOptions, self).__init__(*args, **kw) + self.loadContextOptions() + + def parseContextOptions(self): + def result(): + for opt in self.context.options: + parts = opt.split(':', 1) + key = parts[0].strip() + if len(parts) == 1: + value = 'True' + else: + value = repr([p.strip() for p in parts[1].split(',')]) + yield '='.join((key, value)) + return '\n'.join(result()) + + def loadContextOptions(self): + code = self.parseContextOptions() + rc = Executor(self).execute(code) + if rc: + raise ExecutionError('\n' + result) + + #def __getitem__(self, key): + # opt = self.baseOptions.get(key) + # return opt diff --git a/config/tests.py b/config/tests.py new file mode 100755 index 0000000..1b3d044 --- /dev/null +++ b/config/tests.py @@ -0,0 +1,23 @@ +# $Id$ + +import unittest, doctest +from zope.testing.doctestunit import DocFileSuite +from zope.interface.verify import verifyClass + + +class Test(unittest.TestCase): + "Basic tests for the config sub-package." + + def testSomething(self): + pass + + +def test_suite(): + flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS + return unittest.TestSuite(( + unittest.makeSuite(Test), + DocFileSuite('README.txt', optionflags=flags), + )) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/i18n/browser.py b/i18n/browser.py index 717ba32..4f27b28 100644 --- a/i18n/browser.py +++ b/i18n/browser.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2007 Helmut Merz helmutm@cy55.de +# Copyright (c) 2008 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -54,6 +54,8 @@ class LanguageInfo(object): if opt.startswith('languages:'): return opt[len('languages:'):].split(',') return [] + # new implementation: + # return IOptions(self.context).i18n.languages @Lazy def defaultLanguage(self): diff --git a/i18n/common.py b/i18n/common.py index e7b2912..372a367 100644 --- a/i18n/common.py +++ b/i18n/common.py @@ -121,6 +121,8 @@ class I18NAdapterBase(AdapterBase): tp = IType(self.context) attrs = tp.optionsDict.get('i18nattributes', '') return [attr.strip() for attr in attrs.split(',')] + # new implementation: + # return self.options.i18n.attributes def __getattr__(self, attr): self.checkAttr(attr) diff --git a/organize/browser/event.py b/organize/browser/event.py index 94eb360..1c00fba 100644 --- a/organize/browser/event.py +++ b/organize/browser/event.py @@ -60,8 +60,8 @@ class Events(ConceptView): cm = self.loopsRoot.getConceptManager() tEvent = cm['event'] hasType = cm.getTypePredicate() - sort = lambda x: x.adapted.start now = datetime.today() + sort = lambda x: x.adapted.start or now relViews = (self.childViewFactory(r, self.request, contextIsSecond=True) for r in tEvent.getChildRelations([hasType], sort=None)) return sorted((rv for rv in relViews diff --git a/organize/tracking/change.py b/organize/tracking/change.py index 5a22ff7..4921801 100644 --- a/organize/tracking/change.py +++ b/organize/tracking/change.py @@ -47,11 +47,16 @@ class ChangeManager(object): return self.context = context + @Lazy + def options(self): + return IOptions(self.context) + @Lazy def valid(self): return not (self.context is None or self.storage is None or self.person is None) + # and 'changes' in self.options.tracking @Lazy def loopsRoot(self):