backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 10 Feb 2011 11:58:24 +0100
changeset 49 b3e20c6aae6e
parent 45 57a92eae8941 (current diff)
parent 48 2d0870c9ceea (diff)
child 50 9cbf5b822bef
backport stable
--- a/__pkginfo__.py	Thu Oct 21 16:22:05 2010 +0200
+++ b/__pkginfo__.py	Thu Feb 10 11:58:24 2011 +0100
@@ -8,18 +8,10 @@
 version = '.'.join(str(num) for num in numversion)
 
 license = 'LGPL'
-copyright = '''Copyright (c) 2008-2010 LOGILAB S.A. (Paris, FRANCE).
-http://www.logilab.fr/ -- mailto:contact@logilab.fr'''
-
 author = 'Logilab'
 author_email = 'contact@logilab.fr'
 
-short_desc = 'expense tracking application built on the CubicWeb framework'
-long_desc = '''\
-This cube provides a full-featured expense tracking application.
-'''
-
-ftp = ''
+description = 'expense tracking application built on the CubicWeb framework'
 web = 'http://www.cubicweb.org/project/%s' % distname
 
 classifiers = [
@@ -29,26 +21,18 @@
     'Programming Language :: JavaScript',
     ]
 
-pyversions = ['2.4']
-
-__depends_cubes__ = {'expense': '>= 0.4.4',
-                     'workcase': None,
-                     }
-__depends__ = {'cubicweb': '>= 3.6.0'}
-for key, value in __depends_cubes__.items():
-    __depends__['cubicweb-'+key] = value
-__use__ = tuple(__depends_cubes__)
-__recommend__ = ()
+__depends__ = {'cubicweb': '>= 3.10.0',
+               'cubicweb-expense': '>= 0.4.4',
+               'cubicweb-workcase': None,
+               }
 
 # packaging ###
 
-from glob import glob
 from os import listdir as _listdir
 from os.path import join, isdir
+from glob import glob
 
-#from cubicweb.devtools.pkginfo import get_distutils_datafiles
-CUBES_DIR = join('share', 'cubicweb', 'cubes')
-THIS_CUBE_DIR = join(CUBES_DIR, modname)
+THIS_CUBE_DIR = join('share', 'cubicweb', 'cubes', modname)
 
 def listdir(dirpath):
     return [join(dirpath, fname) for fname in _listdir(dirpath)
@@ -56,18 +40,13 @@
             and not fname.endswith('~')
             and not isdir(join(dirpath, fname))]
 
-from glob import glob
-try:
-    data_files = [
-        # common files
-        [THIS_CUBE_DIR, [fname for fname in glob('*.py') if fname != 'setup.py']],
-        ]
-    # check for possible extended cube layout
-    for dirname in ('entities', 'views', 'sobjects', 'hooks', 'schema', 'data', 'i18n', 'migration', 'wdoc'):
-        if isdir(dirname):
-            data_files.append([join(THIS_CUBE_DIR, dirname), listdir(dirname)])
-    # Note: here, you'll need to add subdirectories if you want
-    # them to be included in the debian package
-except OSError:
-    # we are in an installed directory
-    pass
+data_files = [
+    # common files
+    [THIS_CUBE_DIR, [fname for fname in glob('*.py') if fname != 'setup.py']],
+    ]
+# check for possible extended cube layout
+for dirname in ('entities', 'views', 'sobjects', 'hooks', 'schema', 'data', 'i18n', 'migration', 'wdoc'):
+    if isdir(dirname):
+        data_files.append([join(THIS_CUBE_DIR, dirname), listdir(dirname)])
+# Note: here, you'll need to add subdirectories if you want
+# them to be included in the debian package
--- a/debian/control	Thu Oct 21 16:22:05 2010 +0200
+++ b/debian/control	Thu Feb 10 11:58:24 2011 +0100
@@ -9,9 +9,7 @@
 
 Package: cubicweb-fresh
 Architecture: all
-Conflicts: cubicweb-fresh, erudi-fresh-client, erudi-fresh-server, erudi-fresh-comp
-Replaces: cubicweb-fresh, erudi-fresh-client, erudi-fresh-server, erudi-fresh-comp
-Depends: cubicweb-common (>= 3.6.0), cubicweb-expense (>= 0.4.4), cubicweb-workcase
+Depends: cubicweb-common (>= 3.10.0), cubicweb-expense (>= 0.4.4), cubicweb-workcase
 Description: expense tracking application built on the CubicWeb framework
  This CubicWeb component provides an expense tracking application.
  .
--- a/debian/rules	Thu Oct 21 16:22:05 2010 +0200
+++ b/debian/rules	Thu Feb 10 11:58:24 2011 +0100
@@ -7,7 +7,7 @@
 build: build-stamp
 build-stamp:
 	dh_testdir
-	python setup.py -q build
+	NO_SETUPTOOLS=1 python setup.py -q build
 	touch build-stamp
 
 clean:
@@ -23,7 +23,7 @@
 	dh_testroot
 	dh_clean -k
 	dh_installdirs -i
-	python setup.py -q install --no-compile --prefix=debian/cubicweb-fresh/usr/
+	NO_SETUPTOOLS=1 python setup.py -q install --no-compile --prefix=debian/cubicweb-fresh/usr/
 	# remove generated .egg-info file
 	rm -rf debian/cubicweb-comment/usr/lib/python*
 
--- a/entities.py	Thu Oct 21 16:22:05 2010 +0200
+++ b/entities.py	Thu Feb 10 11:58:24 2011 +0100
@@ -7,7 +7,7 @@
     @property
     def workcase(self):
         rql = 'Any R WHERE E has_lines EL, EL eid %(el)s, E spent_for W, W ref R'
-        rset = self._cw.execute(rql, {'el': self.eid}, 'el')
+        rset = self._cw.execute(rql, {'el': self.eid})
         if rset:
             return rset[0][0]
         return None
--- a/setup.py	Thu Oct 21 16:22:05 2010 +0200
+++ b/setup.py	Thu Feb 10 11:58:24 2011 +0100
@@ -1,44 +1,78 @@
 #!/usr/bin/env python
-# pylint: disable-msg=W0404,W0622,W0704,W0613,W0152
-# Copyright (c) 2003-2004 LOGILAB S.A. (Paris, FRANCE).
-# http://www.logilab.fr/ -- mailto:contact@logilab.fr
+# pylint: disable=W0142,W0403,W0404,W0613,W0622,W0622,W0704,R0904,C0103,E0611
+#
+# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb tag cube.
 #
-# 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.
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
 #
-# This program is distributed in the hope that it will be useful, but WITHOUT
+# CubicWeb 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.
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser 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.
-""" Generic Setup script, takes package info from __pkginfo__.py file """
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
+"""Generic Setup script, takes package info from __pkginfo__.py file
+"""
+__docformat__ = "restructuredtext en"
 
 import os
 import sys
 import shutil
-from distutils.core import setup
-from distutils import command
-from distutils.command import install_lib
 from os.path import isdir, exists, join, walk
 
+try:
+    if os.environ.get('NO_SETUPTOOLS'):
+        raise ImportError() # do as there is no setuptools
+    from setuptools import setup
+    from setuptools.command import install_lib
+    USE_SETUPTOOLS = True
+except ImportError:
+    from distutils.core import setup
+    from distutils.command import install_lib
+    USE_SETUPTOOLS = False
+from distutils.command import install_data
+
 # import required features
-from __pkginfo__ import distname, version, license, short_desc, long_desc, \
-     web, author, author_email
-try:
-    from __pkginfo__ import scripts
-except ImportError:
-    scripts = []
-try:
-    from __pkginfo__ import data_files
-except ImportError:
-    data_files = None
-    
+from __pkginfo__ import modname, version, license, description, web, \
+     author, author_email
+
+if exists('README'):
+    long_description = file('README').read()
+else:
+    long_description = ''
+
+# import optional features
+import __pkginfo__
+if USE_SETUPTOOLS:
+    requires = {}
+    for entry in ("__depends__",): # "__recommends__"):
+        requires.update(getattr(__pkginfo__, entry, {}))
+    install_requires = [("%s %s" % (d, v and v or "")).strip()
+                       for d, v in requires.iteritems()]
+else:
+    install_requires = []
+
+distname = getattr(__pkginfo__, 'distname', modname)
+scripts = getattr(__pkginfo__, 'scripts', ())
+include_dirs = getattr(__pkginfo__, 'include_dirs', ())
+data_files = getattr(__pkginfo__, 'data_files', None)
+ext_modules = getattr(__pkginfo__, 'ext_modules', None)
+dependency_links = getattr(__pkginfo__, 'dependency_links', ())
+
+BASE_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build')
+IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~')
+
+
 def ensure_scripts(linux_scripts):
-    """creates the proper script names required for each platform
+    """
+    Creates the proper script names required for each platform
     (taken from 4Suite)
     """
     from distutils import util
@@ -48,19 +82,119 @@
         scripts_ = linux_scripts
     return scripts_
 
+def export(from_dir, to_dir,
+           blacklist=BASE_BLACKLIST,
+           ignore_ext=IGNORED_EXTENSIONS,
+           verbose=True):
+    """make a mirror of from_dir in to_dir, omitting directories and files
+    listed in the black list
+    """
+    def make_mirror(arg, directory, fnames):
+        """walk handler"""
+        for norecurs in blacklist:
+            try:
+                fnames.remove(norecurs)
+            except ValueError:
+                pass
+        for filename in fnames:
+            # don't include binary files
+            if filename[-4:] in ignore_ext:
+                continue
+            if filename[-1] == '~':
+                continue
+            src = join(directory, filename)
+            dest = to_dir + src[len(from_dir):]
+            if verbose:
+                print >> sys.stderr, src, '->', dest
+            if os.path.isdir(src):
+                if not exists(dest):
+                    os.mkdir(dest)
+            else:
+                if exists(dest):
+                    os.remove(dest)
+                shutil.copy2(src, dest)
+    try:
+        os.mkdir(to_dir)
+    except OSError, ex:
+        # file exists ?
+        import errno
+        if ex.errno != errno.EEXIST:
+            raise
+    walk(from_dir, make_mirror, None)
+
+
+class MyInstallLib(install_lib.install_lib):
+    """extend install_lib command to handle  package __init__.py and
+    include_dirs variable if necessary
+    """
+    def run(self):
+        """overridden from install_lib class"""
+        install_lib.install_lib.run(self)
+        # manually install included directories if any
+        if include_dirs:
+            base = modname
+            for directory in include_dirs:
+                dest = join(self.install_dir, base, directory)
+                export(directory, dest, verbose=False)
+
+# re-enable copying data files in sys.prefix
+old_install_data = install_data.install_data
+if USE_SETUPTOOLS:
+    # overwrite InstallData to use sys.prefix instead of the egg directory
+    class MyInstallData(old_install_data):
+        """A class that manages data files installation"""
+        def run(self):
+            _old_install_dir = self.install_dir
+            if self.install_dir.endswith('egg'):
+                self.install_dir = sys.prefix
+            old_install_data.run(self)
+            self.install_dir = _old_install_dir
+    try:
+        import setuptools.command.easy_install # only if easy_install avaible
+        # monkey patch: Crack SandboxViolation verification
+        from setuptools.sandbox import DirectorySandbox as DS
+        old_ok = DS._ok
+        def _ok(self, path):
+            """Return True if ``path`` can be written during installation."""
+            out = old_ok(self, path) # here for side effect from setuptools
+            realpath = os.path.normcase(os.path.realpath(path))
+            allowed_path = os.path.normcase(sys.prefix)
+            if realpath.startswith(allowed_path):
+                out = True
+            return out
+        DS._ok = _ok
+    except ImportError:
+        pass
+
 def install(**kwargs):
     """setup entry point"""
-    return setup(name=distname,
-                 version=version,
-                 license =license,
-                 description=short_desc,
-                 long_description=long_desc,
-                 author=author,
-                 author_email=author_email,
-                 url=web,
-                 scripts=ensure_scripts(scripts),
-                 data_files=data_files,
-                 **kwargs)
-            
+    if USE_SETUPTOOLS:
+        if '--force-manifest' in sys.argv:
+            sys.argv.remove('--force-manifest')
+    # install-layout option was introduced in 2.5.3-1~exp1
+    elif sys.version_info < (2, 5, 4) and '--install-layout=deb' in sys.argv:
+        sys.argv.remove('--install-layout=deb')
+    cmdclass = {'install_lib': MyInstallLib}
+    if USE_SETUPTOOLS:
+        kwargs['install_requires'] = install_requires
+        kwargs['dependency_links'] = dependency_links
+        kwargs['zip_safe'] = False
+        cmdclass['install_data'] = MyInstallData
+
+    return setup(name = distname,
+                 version = version,
+                 license = license,
+                 description = description,
+                 long_description = long_description,
+                 author = author,
+                 author_email = author_email,
+                 url = web,
+                 scripts = ensure_scripts(scripts),
+                 data_files = data_files,
+                 ext_modules = ext_modules,
+                 cmdclass = cmdclass,
+                 **kwargs
+                 )
+
 if __name__ == '__main__' :
     install()
--- a/test/test_fresh.py	Thu Oct 21 16:22:05 2010 +0200
+++ b/test/test_fresh.py	Thu Feb 10 11:58:24 2011 +0100
@@ -5,9 +5,11 @@
 from cubicweb.devtools.htmlparser import SaxOnlyValidator
 from cubicweb.devtools.testlib import AutomaticWebTest
 
-AutomaticWebTest.vid_validators.update({
-    'accexpense': SaxOnlyValidator,
-    'accentry': SaxOnlyValidator,
+class AutomaticWebTest(AutomaticWebTest):
+    vid_validators = AutomaticWebTest.vid_validators.copy()
+    vid_validators.update({
+        'accexpense': SaxOnlyValidator,
+        'accentry': SaxOnlyValidator,
     })
 
 if __name__ == '__main__':
--- a/views/accounting.py	Thu Oct 21 16:22:05 2010 +0200
+++ b/views/accounting.py	Thu Feb 10 11:58:24 2011 +0100
@@ -9,13 +9,13 @@
 
 from logilab.mtconverter import xml_escape
 
-from cubicweb.selectors import implements
+from cubicweb.selectors import is_instance
 from cubicweb.view import EntityView
 
 
 class ExpenseAccountingXmlView(EntityView):
     __regid__ = 'accexpense'
-    __select__ = implements('Expense')
+    __select__ = is_instance('Expense')
 
     title = _('accounting entry view')
     templatable = False
@@ -41,7 +41,7 @@
 
 class ExpenseLineAccountingEntryXmlView(EntityView):
     __regid__ = 'accentry'
-    __select__ = implements('ExpenseLine',)
+    __select__ = is_instance('ExpenseLine',)
 
     title = _('accounting entry view')
     templatable = False
--- a/views/actions.py	Thu Oct 21 16:22:05 2010 +0200
+++ b/views/actions.py	Thu Feb 10 11:58:24 2011 +0100
@@ -6,12 +6,12 @@
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb.selectors import implements
+from cubicweb.selectors import is_instance
 from cubicweb.web.action import Action
 
 class AccountingAction(Action):
     __regid__ = 'accaction'
-    __select__ = implements('Expense')
+    __select__ = is_instance('Expense')
     title = _('generate accounting entries')
 
     def url(self):