search for cubes in a list of directories
authorsylvain.thenault@logilab.fr
Mon, 09 Mar 2009 13:04:32 +0100
changeset 1015 b5fdad9208f8
parent 1004 625e59773119
child 1018 7c1976a108dd
search for cubes in a list of directories
cwconfig.py
cwctl.py
devtools/devctl.py
goa/goactl.py
test/unittest_cwconfig.py
--- a/cwconfig.py	Wed Mar 04 16:53:10 2009 +0100
+++ b/cwconfig.py	Mon Mar 09 13:04:32 2009 +0100
@@ -10,7 +10,7 @@
 import sys
 import os
 import logging
-from os.path import exists, join, expanduser, abspath, basename
+from os.path import exists, join, expanduser, abspath, normpath, basename, isdir
 
 from logilab.common.decorators import cached
 from logilab.common.logging_ext import set_log_methods, init_log
@@ -152,7 +152,7 @@
         file(join(CUBES_DIR, '__init__.py'), 'w').close()
     elif exists(join(CW_SOFTWARE_ROOT, '.hg')):
         mode = 'dev'
-        CUBES_DIR = join(CW_SOFTWARE_ROOT, '../cubes')
+        CUBES_DIR = abspath(normpath(join(CW_SOFTWARE_ROOT, '../cubes')))
     else:
         mode = 'installed'
         CUBES_DIR = '/usr/share/cubicweb/cubes/'
@@ -225,7 +225,7 @@
         """
         if cls.mode in ('dev', 'test') and not os.environ.get('APYCOT_ROOT'):
             return join(CW_SOFTWARE_ROOT, 'web')
-        return join(cls.cubes_dir(), 'shared')
+        return self.cube_dir('shared')
         
     @classmethod
     def i18n_lib_dir(cls):
@@ -236,26 +236,38 @@
 
     @classmethod
     def available_cubes(cls):
-        cubes_dir = cls.cubes_dir()
-        return sorted(cube for cube in os.listdir(cubes_dir)
-                      if os.path.isdir(os.path.join(cubes_dir, cube))
-                      and not cube in ('CVS', '.svn', 'shared', '.hg'))
+        cubes = set()
+        for directory in cls.cubes_search_path():
+            for cube in os.listdir(directory):
+                if isdir(join(directory, cube)) and not cube in ('CVS', '.svn', 'shared', '.hg'):
+                    cubes.add(cube)
+        return sorted(cubes)
     
     @classmethod
-    def cubes_dir(cls):
-        """return the application cubes directory"""
-        return env_path('CW_CUBES', cls.CUBES_DIR, 'cubes')
+    def cubes_search_path(cls):
+        """return the path of directories where cubes should be searched"""
+        path = []
+        try:
+            for directory in os.environ['CW_CUBES_PATH'].split(os.pathsep):
+                directory = abspath(normpath(directory))
+                if exists(directory) and not directory in path:
+                    path.append(directory)
+        except KeyError:
+            pass
+        if not cls.CUBES_DIR in path:
+            path.append(cls.CUBES_DIR)
+        return path
     
     @classmethod
     def cube_dir(cls, cube):
         """return the cube directory for the given cube id,
         raise ConfigurationError if it doesn't exists
         """
-        cube_dir = join(cls.cubes_dir(), cube)
-        if not exists(cube_dir):
-            raise ConfigurationError('no cube %s in %s' % (
-                cube, cls.cubes_dir()))
-        return cube_dir
+        for directory in cls.cubes_search_path():
+            cubedir = join(directory, cube)
+            if exists(cubedir):
+                return cubedir
+        raise ConfigurationError('no cube %s in %s' % (cube, cls.cubes_search_path()))
 
     @classmethod
     def cube_migration_scripts_dir(cls, cube):
@@ -341,12 +353,13 @@
     @classmethod
     def cls_adjust_sys_path(cls):
         """update python path if necessary"""
+        if not cls.CUBES_DIR in sys.path:
+            sys.path.insert(0, cls.CUBES_DIR)
         try:
-            templdir = abspath(join(cls.cubes_dir(), '..'))
-            if not templdir in sys.path:
-                sys.path.insert(0, templdir)
-        except ConfigurationError:
-            return # cube dir doesn't exists
+            import cubes
+            cubes.__path__ = cls.cubes_search_path()
+        except ImportError:
+            return # cubes dir doesn't exists
 
     @classmethod
     def load_cwctl_plugins(cls):
@@ -358,10 +371,9 @@
             if exists(join(CW_SOFTWARE_ROOT, ctlfile)):
                 load_module_from_file(join(CW_SOFTWARE_ROOT, ctlfile))
                 cls.info('loaded cubicweb-ctl plugin %s', ctlfile)
-        templdir = cls.cubes_dir()
         for cube in cls.available_cubes():
-            pluginfile = join(templdir, cube, 'ecplugin.py')
-            initfile = join(templdir, cube, '__init__.py')
+            pluginfile = join(cls.cube_dir(cube), 'ecplugin.py')
+            initfile = join(cls.cube_dir(cube), '__init__.py')
             if exists(pluginfile):
                 try:
                     __import__('cubes.%s.ecplugin' % cube)
--- a/cwctl.py	Wed Mar 04 16:53:10 2009 +0100
+++ b/cwctl.py	Mon Mar 09 13:04:32 2009 +0100
@@ -173,19 +173,18 @@
                     continue
                 print '   ', line
         print 
+        cubesdirs = ', '.join(CubicWebConfiguration.cubes_search_path())
         try:
-            cubesdir = CubicWebConfiguration.cubes_dir()
             namesize = max(len(x) for x in CubicWebConfiguration.available_cubes())
         except ConfigurationError, ex:
             print 'No cubes available:', ex
         except ValueError:
-            print 'No cubes available in %s' % cubesdir
+            print 'No cubes available in %s' % cubesdirs
         else:
-            print 'Available cubes (%s):' % cubesdir
+            print 'Available cubes (%s):' % cubesdirs
             for cube in CubicWebConfiguration.available_cubes():
                 if cube in ('CVS', '.svn', 'shared', '.hg'):
                     continue
-                templdir = join(cubesdir, cube)
                 try:
                     tinfo = CubicWebConfiguration.cube_pkginfo(cube)
                     tversion = tinfo.version
@@ -198,7 +197,7 @@
                                            or tinfo.__doc__)
                     if shortdesc:
                         print '    '+ '    \n'.join(shortdesc.splitlines())
-                    modes = detect_available_modes(templdir)
+                    modes = detect_available_modes(CubicWebConfiguration.cube_dir(cube))
                     print '    available modes: %s' % ', '.join(modes)
         print
         try:
--- a/devtools/devctl.py	Wed Mar 04 16:53:10 2009 +0100
+++ b/devtools/devctl.py	Mon Mar 09 13:04:32 2009 +0100
@@ -286,10 +286,10 @@
         """run the command with its specific arguments"""
         CUBEDIR = DevCubeConfiguration.cubes_dir()
         if args:
-            cubes = [join(CUBEDIR, app) for app in args]
+            cubes = [DevCubeConfiguration.cube_dir(cube) for cube in args]
         else:
-            cubes = [join(CUBEDIR, app) for app in listdir(CUBEDIR)
-                         if exists(join(CUBEDIR, app, 'i18n'))]
+            cubes = [DevCubeConfiguration.cube_dir(cube) for cube in DevCubeConfiguration.available_cubes()]
+            cubes = [cubepath for cubepath in cubes if exists(join(cubepath, 'i18n'))]
         update_cubes_catalogs(cubes)
 
 def update_cubes_catalogs(cubes):
--- a/goa/goactl.py	Wed Mar 04 16:53:10 2009 +0100
+++ b/goa/goactl.py	Mon Mar 09 13:04:32 2009 +0100
@@ -211,12 +211,12 @@
         # link every supported components
         packagesdir = join(appldir, 'cubes')
         create_init_file(join(appldir, 'cubes'), 'cubes')
-        cubesdir = CubicWebConfiguration.cubes_dir()
-        for include in ('addressbook','basket', 'blog','classfolders',
-                        'classtags', 'comment', 'file', 'link',
+        for include in ('addressbook','basket', 'blog','folder',
+                        'tag', 'comment', 'file', 'link',
                         'mailinglist', 'person', 'task', 'zone',
                         ):
-            create_symlink(join(cubesdir, include), join(packagesdir, include))
+            create_symlink(CubicWebConfiguration.cube_dir(include),
+                           join(packagesdir, include))
         # generate sample config
         from cubicweb.goa.goaconfig import GAEConfiguration
         from cubicweb.common.migration import MigrationHelper
--- a/test/unittest_cwconfig.py	Wed Mar 04 16:53:10 2009 +0100
+++ b/test/unittest_cwconfig.py	Mon Mar 09 13:04:32 2009 +0100
@@ -1,4 +1,6 @@
+import sys
 import os
+from os.path import dirname, join, abspath
 from tempfile import mktemp
 
 from logilab.common.testlib import TestCase, unittest_main
@@ -69,6 +71,33 @@
                           ['entities', 'web/views', 'sobjects',
                            'file/entities.py', 'file/views', 'file/hooks.py',
                            'email/entities.py', 'email/views', 'email/hooks.py'])
-            
+
+    def test_cubes_path(self):
+        os.environ['CW_CUBES_PATH'] = join(dirname(__file__), 'data', 'cubes')
+        self.assertEquals(self.config.cubes_search_path(),
+                          [abspath(join(dirname(__file__), 'data', 'cubes')),
+                           self.config.CUBES_DIR])
+        os.environ['CW_CUBES_PATH'] = '%s%s%s%s%s' % (join(dirname(__file__), 'data', 'cubes'),
+                                                      os.pathsep, self.config.CUBES_DIR,
+                                                      os.pathsep, 'unexistant')
+        # filter out unexistant and duplicates
+        self.assertEquals(self.config.cubes_search_path(),
+                          [abspath(join(dirname(__file__), 'data', 'cubes')),
+                           self.config.CUBES_DIR])
+        self.failUnless('mycube' in self.config.available_cubes())
+        # test cubes python path
+        self.config.adjust_sys_path()
+        import cubes
+        self.assertEquals(cubes.__path__, self.config.cubes_search_path())
+        # this import should succeed once path is adjusted
+        from cubes import mycube
+        self.assertEquals(mycube.__path__, [abspath(join(dirname(__file__), 'data', 'cubes', 'mycube'))])
+        # file cube should be overriden by the one found in data/cubes
+        sys.modules.pop('cubes.file', None)
+        del cubes.file
+        from cubes import file
+        self.assertEquals(file.__path__, [abspath(join(dirname(__file__), 'data', 'cubes', 'file'))])
+                                       
+                          
 if __name__ == '__main__':
     unittest_main()