--- a/.hgtags Mon Apr 23 13:50:50 2018 +0200
+++ b/.hgtags Mon Apr 23 15:23:55 2018 +0200
@@ -614,3 +614,14 @@
b8567725c473b701fe9352e578ad6e05c523c1f2 3.25.4
b8567725c473b701fe9352e578ad6e05c523c1f2 centos/3.25.4-1
b8567725c473b701fe9352e578ad6e05c523c1f2 debian/3.25.4-1
+199851fcddd4b45e3d7f40efcd1739134c33db2a 3.26.0
+199851fcddd4b45e3d7f40efcd1739134c33db2a debian/3.26.0-1
+199851fcddd4b45e3d7f40efcd1739134c33db2a centos/3.26.0-1
+027676243aaa6895492ecd31918f12d221fd503d 3.26.1
+027676243aaa6895492ecd31918f12d221fd503d debian/3.26.1-1
+027676243aaa6895492ecd31918f12d221fd503d centos/3.26.1-1
+9bee3134d304f6cc51ab728b4ca84d464d1b3fd8 3.26.2
+9bee3134d304f6cc51ab728b4ca84d464d1b3fd8 centos/3.26.2-1
+9bee3134d304f6cc51ab728b4ca84d464d1b3fd8 debian/3.26.2-1
+f7067be5f69cd05f34ce99fbb534e4674b3a782d 3.26.3
+f7067be5f69cd05f34ce99fbb534e4674b3a782d debian/3.26.3-1
--- a/MANIFEST.in Mon Apr 23 13:50:50 2018 +0200
+++ b/MANIFEST.in Mon Apr 23 15:23:55 2018 +0200
@@ -1,5 +1,4 @@
include README
-include README.pyramid.rst
include COPYING
include COPYING.LESSER
include pylintrc
@@ -31,7 +30,7 @@
recursive-include cubicweb/misc *.py *.png *.display
include cubicweb/web/views/*.pt
-recursive-include cubicweb/web/data external_resources *.js *.css *.py *.png *.gif *.ico *.ttf *.svg *.woff *.eot
+recursive-include cubicweb/web/data *.js *.css *.py *.png *.gif *.ico *.ttf *.svg *.woff *.eot
recursive-include cubicweb/web/wdoc *.rst *.png *.xml
recursive-include cubicweb/devtools/data *.js *.css *.sh
--- a/README Mon Apr 23 13:50:50 2018 +0200
+++ b/README Mon Apr 23 15:23:55 2018 +0200
@@ -14,7 +14,7 @@
Install
-------
-More details at https://cubicweb.readthedocs.io/en/3.25/book/admin/setup
+More details at https://cubicweb.readthedocs.io/en/3.26/book/admin/setup
Getting started
---------------
@@ -26,12 +26,12 @@
cubicweb-ctl start -D myblog
sensible-browser http://localhost:8080/
-Details at https://cubicweb.readthedocs.io/en/3.25/tutorials/base/blog-in-five-minutes
+Details at https://cubicweb.readthedocs.io/en/3.26/tutorials/base/blog-in-five-minutes
Documentation
-------------
-Look in the doc/ subdirectory or read https://cubicweb.readthedocs.io/en/3.25/
+Look in the doc/ subdirectory or read https://cubicweb.readthedocs.io/en/3.26/
CubicWeb includes the Entypo pictograms by Daniel Bruce — http://www.entypo.com
--- a/cubicweb.spec Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb.spec Mon Apr 23 15:23:55 2018 +0200
@@ -8,7 +8,7 @@
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
Name: cubicweb
-Version: 3.25.4
+Version: 3.26.3
Release: logilab.1%{?dist}
Summary: CubicWeb is a semantic web application framework
Source0: https://pypi.python.org/packages/source/c/cubicweb/cubicweb-%{version}.tar.gz
--- a/cubicweb/__pkginfo__.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/__pkginfo__.py Mon Apr 23 15:23:55 2018 +0200
@@ -19,11 +19,6 @@
"""cubicweb global packaging information for the cubicweb knowledge management
software
"""
-import sys
-from os import listdir
-from os.path import join, isdir
-import glob
-
modname = distname = "cubicweb"
@@ -43,54 +38,8 @@
'Programming Language :: JavaScript',
]
-_server_migration_dir = join(modname, 'misc', 'migration')
-_data_dir = join(modname, 'web', 'data')
-_wdoc_dir = join(modname, 'web', 'wdoc')
-_wdocimages_dir = join(_wdoc_dir, 'images')
-_views_dir = join(modname, 'web', 'views')
-_i18n_dir = join(modname, 'i18n')
-
-_pyversion = '.'.join(str(num) for num in sys.version_info[0:2])
-if '--home' in sys.argv:
- # --home install
- pydir = 'python' + _pyversion
-else:
- pydir = join('python' + _pyversion, 'site-packages')
-
# data files that shall be copied into the main package directory
package_data = {
'cubicweb.web.views': ['*.pt'],
'cubicweb.pyramid': ['development.ini.tmpl'],
}
-
-try:
- # data files that shall be copied outside the main package directory
- data_files = [
- # server data
- [join('share', 'cubicweb', 'migration'),
- [join(_server_migration_dir, filename)
- for filename in listdir(_server_migration_dir)]],
- # web data
- [join('share', 'cubicweb', 'cubes', 'shared', 'data'),
- [join(_data_dir, fname) for fname in listdir(_data_dir)
- if not isdir(join(_data_dir, fname))]],
- [join('share', 'cubicweb', 'cubes', 'shared', 'data', 'images'),
- [join(_data_dir, 'images', fname) for fname in listdir(join(_data_dir, 'images'))]],
- [join('share', 'cubicweb', 'cubes', 'shared', 'data', 'jquery-treeview'),
- [join(_data_dir, 'jquery-treeview', fname) for fname in listdir(join(_data_dir, 'jquery-treeview'))
- if not isdir(join(_data_dir, 'jquery-treeview', fname))]],
- [join('share', 'cubicweb', 'cubes', 'shared', 'data', 'jquery-treeview', 'images'),
- [join(_data_dir, 'jquery-treeview', 'images', fname)
- for fname in listdir(join(_data_dir, 'jquery-treeview', 'images'))]],
- [join('share', 'cubicweb', 'cubes', 'shared', 'wdoc'),
- [join(_wdoc_dir, fname) for fname in listdir(_wdoc_dir)
- if not isdir(join(_wdoc_dir, fname))]],
- [join('share', 'cubicweb', 'cubes', 'shared', 'wdoc', 'images'),
- [join(_wdocimages_dir, fname) for fname in listdir(_wdocimages_dir)]],
- [join('share', 'cubicweb', 'cubes', 'shared', 'i18n'),
- glob.glob(join(_i18n_dir, '*.po'))],
- # skeleton
- ]
-except OSError:
- # we are in an installed directory, don't care about this
- pass
--- a/cubicweb/cwconfig.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/cwconfig.py Mon Apr 23 15:23:55 2018 +0200
@@ -240,36 +240,6 @@
return modes[0]
-def _find_prefix(start_path=None):
- """Return the prefix path of CubicWeb installation.
-
- Walk parent directories of `start_path` looking for one containing a
- 'share/cubicweb' directory. The first matching directory is assumed as the
- prefix installation of CubicWeb.
-
- If run from within a virtualenv, the virtualenv root is used as
- `start_path`. Otherwise, `start_path` defaults to cubicweb package
- directory path.
- """
- if start_path is None:
- try:
- prefix = os.environ['VIRTUAL_ENV']
- except KeyError:
- prefix = CW_SOFTWARE_ROOT
- else:
- prefix = start_path
- if not isdir(prefix):
- prefix = dirname(prefix)
- old_prefix = None
- while (not isdir(join(prefix, 'share', 'cubicweb'))
- or prefix.endswith('.egg')):
- if prefix == old_prefix:
- return sys.prefix
- old_prefix = prefix
- prefix = dirname(prefix)
- return prefix
-
-
def _cube_pkgname(cube):
if not cube.startswith('cubicweb_'):
return 'cubicweb_' + cube
@@ -391,18 +361,8 @@
'float' : 'Float',
}
-_forced_mode = os.environ.get('CW_MODE')
-assert _forced_mode in (None, 'system', 'user')
-# CWDEV tells whether directories such as i18n/, web/data/, etc. (ie containing
-# some other resources than python libraries) are located with the python code
-# or as a 'shared' cube
-CWDEV = exists(join(CW_SOFTWARE_ROOT, 'i18n'))
-
-try:
- _INSTALL_PREFIX = os.environ['CW_INSTALL_PREFIX']
-except KeyError:
- _INSTALL_PREFIX = _find_prefix()
+_INSTALL_PREFIX = os.environ.get('CW_INSTALL_PREFIX', sys.prefix)
_USR_INSTALL = _INSTALL_PREFIX == '/usr'
class CubicWebNoAppConfiguration(ConfigurationMixIn):
@@ -420,15 +380,13 @@
quick_start = False
if 'VIRTUAL_ENV' in os.environ:
- mode = _forced_mode or 'user'
- _CUBES_DIR = join(_INSTALL_PREFIX, 'share', 'cubicweb', 'cubes')
- elif CWDEV and _forced_mode != 'system':
- mode = 'user'
- _CUBES_DIR = join(CW_SOFTWARE_ROOT, '../../cubes')
+ mode = os.environ.get('CW_MODE', 'user')
else:
- mode = _forced_mode or 'system'
- _CUBES_DIR = join(_INSTALL_PREFIX, 'share', 'cubicweb', 'cubes')
+ mode = os.environ.get('CW_MODE', 'system')
+ assert mode in ('system', 'user'), '"CW_MODE" should be either "user" or "system"'
+ _CUBES_DIR = join(_INSTALL_PREFIX, 'share', 'cubicweb', 'cubes')
+ assert _CUBES_DIR # XXX only meaningful if CW_CUBES_DIR is not set
CUBES_DIR = realpath(abspath(os.environ.get('CW_CUBES_DIR', _CUBES_DIR)))
CUBES_PATH = os.environ.get('CW_CUBES_PATH', '').split(os.pathsep)
@@ -493,20 +451,9 @@
return Configuration(options=PERSISTENT_OPTIONS)
@classmethod
- def shared_dir(cls):
- """return the shared data directory (i.e. directory where standard
- library views and data may be found)
- """
- if CWDEV:
- return join(CW_SOFTWARE_ROOT, 'web')
- return cls.cube_dir('shared')
-
- @classmethod
def i18n_lib_dir(cls):
"""return instance's i18n directory"""
- if CWDEV:
- return join(CW_SOFTWARE_ROOT, 'i18n')
- return join(cls.shared_dir(), 'i18n')
+ return join(dirname(__file__), 'i18n')
@classmethod
def cw_languages(cls):
@@ -1031,11 +978,8 @@
@classmethod
def migration_scripts_dir(cls):
"""cubicweb migration scripts directory"""
- if CWDEV:
- return join(CW_SOFTWARE_ROOT, 'misc', 'migration')
- mdir = join(_INSTALL_PREFIX, 'share', 'cubicweb', 'migration')
- if not exists(mdir):
- raise ConfigurationError('migration path %s doesn\'t exist' % mdir)
+ mdir = join(dirname(__file__), 'misc', 'migration')
+ assert exists(mdir), 'migration path %s does not exist' % mdir
return mdir
@classmethod
--- a/cubicweb/cwctl.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/cwctl.py Mon Apr 23 15:23:55 2018 +0200
@@ -44,7 +44,7 @@
from logilab.common.decorators import clear_cache
from cubicweb import ConfigurationError, ExecutionError, BadCommandUsage
-from cubicweb.cwconfig import CubicWebConfiguration as cwcfg, CWDEV, CONFIGURATIONS
+from cubicweb.cwconfig import CubicWebConfiguration as cwcfg, CONFIGURATIONS
from cubicweb.toolsutils import Command, rm, create_dir, underline_title
from cubicweb.__pkginfo__ import version
@@ -760,7 +760,7 @@
if cubicwebversion > applcubicwebversion:
toupgrade.append(('cubicweb', applcubicwebversion, cubicwebversion))
# only stop once we're sure we have something to do
- if instance_running and not (CWDEV or self.config.nostartstop):
+ if instance_running and not self.config.nostartstop:
StopInstanceCommand(self.logger).stop_instance(appid)
# run cubicweb/componants migration scripts
if self.config.fs_only or toupgrade:
@@ -783,7 +783,7 @@
if helper:
helper.postupgrade(repo)
print('-> instance migrated.')
- if instance_running and not (CWDEV or self.config.nostartstop):
+ if instance_running and not self.config.nostartstop:
# restart instance through fork to get a proper environment, avoid
# uicfg pb (and probably gettext catalogs, to check...)
forkcmd = '%s start %s' % (sys.argv[0], appid)
--- a/cubicweb/pyramid/session.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/pyramid/session.py Mon Apr 23 15:23:55 2018 +0200
@@ -91,7 +91,10 @@
from pyramid.compat import pickle
from pyramid.session import SignedCookieSessionFactory
-from cubicweb import Binary
+from cubicweb import (
+ Binary,
+ UnknownEid,
+)
log = logging.getLogger(__name__)
@@ -228,8 +231,16 @@
'CWSession', cwsessiondata=data)
sessioneid = session.eid
else:
- session = cnx.entity_from_eid(sessioneid)
- session.cw_set(cwsessiondata=data)
+ try:
+ session = cnx.entity_from_eid(sessioneid)
+ except UnknownEid:
+ # Might occur if CWSession entity got dropped (e.g.
+ # the whole db got recreated) while user's cookie is
+ # still valid. We recreate the CWSession in this case.
+ sessioneid = cnx.create_entity(
+ 'CWSession', cwsessiondata=data).eid
+ else:
+ session.cw_set(cwsessiondata=data)
cnx.commit()
# Only if needed actually set the cookie
--- a/cubicweb/server/sources/native.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/server/sources/native.py Mon Apr 23 15:23:55 2018 +0200
@@ -1261,6 +1261,8 @@
def fti_unindex_entities(self, cnx, entities):
"""remove text content for entities from the full text index
"""
+ if not cnx.repo.system_source.do_fti:
+ return
cursor = cnx.cnxset.cu
cursor_unindex_object = self.dbhelper.cursor_unindex_object
try:
@@ -1272,6 +1274,8 @@
def fti_index_entities(self, cnx, entities):
"""add text content of created/modified entities to the full text index
"""
+ if not cnx.repo.system_source.do_fti:
+ return
cursor_index_object = self.dbhelper.cursor_index_object
cursor = cnx.cnxset.cu
try:
@@ -1296,6 +1300,8 @@
def precommit_event(self):
cnx = self.cnx
source = cnx.repo.system_source
+ if not source.do_fti:
+ return
pendingeids = cnx.transaction_data.get('pendingeids', ())
done = cnx.transaction_data.setdefault('indexedeids', set())
to_reindex = set()
--- a/cubicweb/server/sqlutils.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/server/sqlutils.py Mon Apr 23 15:23:55 2018 +0200
@@ -19,6 +19,7 @@
from __future__ import print_function
+import os
import sys
import re
import subprocess
@@ -48,13 +49,16 @@
SQL_PREFIX = 'cw_'
-def _run_command(cmd):
+def _run_command(cmd, extra_env=None):
+ env = os.environ.copy()
+ for key, value in (extra_env or {}).items():
+ env.setdefault(key, value)
if isinstance(cmd, string_types):
print(cmd)
- return subprocess.call(cmd, shell=True)
+ return subprocess.call(cmd, shell=True, env=env)
else:
print(' '.join(cmd))
- return subprocess.call(cmd)
+ return subprocess.call(cmd, env=env)
def sqlexec(sqlstmts, cursor_or_execute, withpb=True,
@@ -342,18 +346,25 @@
"""open and return a connection to the database"""
return self.dbhelper.get_connection()
+ def _backup_restore_env(self):
+ if (self.config['db-driver'] == 'postgres'
+ and self.config['db-password'] is not None):
+ return {'PGPASSWORD': self.config['db-password']}
+
def backup_to_file(self, backupfile, confirm):
+ extra_env = self._backup_restore_env()
for cmd in self.dbhelper.backup_commands(backupfile,
keepownership=False):
- if _run_command(cmd):
+ if _run_command(cmd, extra_env=extra_env):
if not confirm(' [Failed] Continue anyway?', default='n'):
raise Exception('Failed command: %s' % cmd)
def restore_from_file(self, backupfile, confirm, drop=True):
+ extra_env = self._backup_restore_env()
for cmd in self.dbhelper.restore_commands(backupfile,
keepownership=False,
drop=drop):
- if _run_command(cmd):
+ if _run_command(cmd, extra_env=extra_env):
if not confirm(' [Failed] Continue anyway?', default='n'):
raise Exception('Failed command: %s' % cmd)
--- a/cubicweb/server/utils.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/server/utils.py Mon Apr 23 15:23:55 2018 +0200
@@ -26,7 +26,7 @@
from threading import Thread
from getpass import getpass
-from six import PY2
+from six import PY2, text_type
from six.moves import input
from passlib.utils import handlers as uh, to_hash_str
@@ -106,7 +106,7 @@
while not user:
user = input('login: ')
if PY2:
- user = unicode(user, sys.stdin.encoding)
+ user = text_type(user, sys.stdin.encoding)
passwd = getpass('%s: ' % passwdmsg)
if confirm:
while True:
--- a/cubicweb/statsd_logger.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/statsd_logger.py Mon Apr 23 15:23:55 2018 +0200
@@ -47,7 +47,7 @@
There is also a decorator (``statsd_timeit``) that may be used to
measure and send to the statsd_ server the time passed in a function
or a method and the number of calls. It will send a message like::
-
+
<bucket>.<funcname>:<ms>|ms\n<bucket>.<funcname>:1|c\n
@@ -56,7 +56,6 @@
"""
-
import time
import socket
@@ -112,10 +111,11 @@
@property
def __doc__(self):
return self.callable.__doc__
+
@property
def __name__(self):
return self.callable.__name__
-
+
def __call__(self, *args, **kw):
if _address is None:
return self.callable(*args, **kw)
@@ -123,13 +123,14 @@
try:
return self.callable(*args, **kw)
finally:
- dt = 1000*(time.time()-t0)
- msg = '{0}.{1}:{2:.4f}|ms\n{0}.{1}:1|c\n'.format(_bucket, self.__name__, dt)
+ dt = 1000 * (time.time() - t0)
+ msg = '{0}.{1}:{2:.4f}|ms\n{0}.{1}:1|c\n'.format(
+ _bucket, self.__name__, dt)
_socket.sendto(msg, _address)
-
+
def __get__(self, obj, objtype):
"""Support instance methods."""
- if obj is None: # class method or some already wrapped method
+ if obj is None: # class method or some already wrapped method
return self
import functools
return functools.partial(self.__call__, obj)
--- a/cubicweb/test/unittest_cwconfig.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/test/unittest_cwconfig.py Mon Apr 23 15:23:55 2018 +0200
@@ -35,17 +35,7 @@
from cubicweb.devtools import ApptestConfiguration
from cubicweb.devtools.testlib import BaseTestCase, TemporaryDirectory
from cubicweb.cwconfig import (
- CubicWebConfiguration, _find_prefix, _expand_modname)
-
-
-def unabsolutize(path):
- parts = path.split(os.sep)
- for i, part in reversed(tuple(enumerate(parts))):
- if part.startswith('cubicweb_'):
- return os.sep.join([part[len('cubicweb_'):]] + parts[i + 1:])
- if part.startswith('cubicweb') or part == 'legacy_cubes':
- return os.sep.join(parts[i + 1:])
- raise Exception('duh? %s' % path)
+ CubicWebConfiguration, _expand_modname)
def templibdir(func):
@@ -125,6 +115,12 @@
ApptestConfiguration.CUBES_PATH = []
cleanup_sys_modules([self.datapath('libpython')])
+ def test_migration_scripts_dir(self):
+ mscripts = os.listdir(self.config.migration_scripts_dir())
+ self.assertIn('bootstrapmigration_repository.py', mscripts)
+ self.assertIn('postcreate.py', mscripts)
+ self.assertIn('3.24.0_Any.py', mscripts)
+
@patch('pkg_resources.iter_entry_points', side_effect=iter_entry_points)
def test_available_cubes(self, mock_iter_entry_points):
expected_cubes = [
@@ -289,101 +285,6 @@
self.assertNotIn('cubicweb_mycube.ccplugin', sys.modules, sorted(sys.modules))
-class FindPrefixTC(unittest.TestCase):
-
- def make_dirs(self, basedir, *args):
- path = join(basedir, *args)
- if not os.path.exists(path):
- os.makedirs(path)
- return path
-
- def make_file(self, basedir, *args):
- self.make_dirs(basedir, *args[:-1])
- file_path = join(basedir, *args)
- with open(file_path, 'w') as f:
- f.write('""" None """')
- return file_path
-
- def test_samedir(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- self.assertEqual(_find_prefix(prefix), prefix)
-
- def test_samedir_filepath(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- file_path = self.make_file(prefix, 'bob.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_dir_inside_prefix(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- dir_path = self.make_dirs(prefix, 'bob')
- self.assertEqual(_find_prefix(dir_path), prefix)
-
- def test_file_in_dir_inside_prefix(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- file_path = self.make_file(prefix, 'bob', 'toto.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_file_in_deeper_dir_inside_prefix(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- file_path = self.make_file(prefix, 'bob', 'pyves', 'alain',
- 'adim', 'syt', 'toto.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_multiple_candidate_prefix(self):
- with TemporaryDirectory() as tempdir:
- self.make_dirs(tempdir, 'share', 'cubicweb')
- prefix = self.make_dirs(tempdir, 'bob')
- self.make_dirs(prefix, 'share', 'cubicweb')
- file_path = self.make_file(prefix, 'pyves', 'alain',
- 'adim', 'syt', 'toto.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_sister_candidate_prefix(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- self.make_dirs(prefix, 'bob', 'share', 'cubicweb')
- file_path = self.make_file(prefix, 'bell', 'toto.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_multiple_parent_candidate_prefix(self):
- with TemporaryDirectory() as tempdir:
- self.make_dirs(tempdir, 'share', 'cubicweb')
- prefix = self.make_dirs(tempdir, 'share', 'cubicweb', 'bob')
- self.make_dirs(tempdir, 'share', 'cubicweb', 'bob', 'share',
- 'cubicweb')
- file_path = self.make_file(tempdir, 'share', 'cubicweb', 'bob',
- 'pyves', 'alain', 'adim', 'syt',
- 'toto.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_upper_candidate_prefix(self):
- with TemporaryDirectory() as prefix:
- self.make_dirs(prefix, 'share', 'cubicweb')
- self.make_dirs(prefix, 'bell', 'bob', 'share', 'cubicweb')
- file_path = self.make_file(prefix, 'bell', 'toto.py')
- self.assertEqual(_find_prefix(file_path), prefix)
-
- def test_no_prefix(self):
- with TemporaryDirectory() as prefix:
- self.assertEqual(_find_prefix(prefix), sys.prefix)
-
- def test_virtualenv(self):
- venv = os.environ.get('VIRTUAL_ENV')
- try:
- with TemporaryDirectory() as prefix:
- os.environ['VIRTUAL_ENV'] = prefix
- self.make_dirs(prefix, 'share', 'cubicweb')
- self.assertEqual(_find_prefix(), prefix)
- finally:
- if venv:
- os.environ['VIRTUAL_ENV'] = venv
-
-
class ModnamesTC(unittest.TestCase):
@templibdir
--- a/cubicweb/web/propertysheet.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/propertysheet.py Mon Apr 23 15:23:55 2018 +0200
@@ -109,6 +109,12 @@
with os.fdopen(tmpfd, 'w') as stream:
stream.write(content)
try:
+ mode = os.stat(sourcefile).st_mode
+ os.chmod(tmpfile, mode)
+ except IOError:
+ self.warning('Cannot set access mode for %s; you may encouter '
+ 'file permissions issues', cachefile)
+ try:
os.rename(tmpfile, cachefile)
except OSError as err:
if err.errno != errno.EEXIST:
--- a/cubicweb/web/test/unittest_propertysheet.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/test/unittest_propertysheet.py Mon Apr 23 15:23:55 2018 +0200
@@ -40,13 +40,13 @@
self.assertEqual(ps['fontcolor'], 'black')
# defined by sheet1, extended by sheet2
self.assertEqual(ps['stylesheets'], ['http://cwtest.com/cubicweb.css',
- 'http://cwtest.com/mycube.css'])
+ 'http://cwtest.com/mycube.css'])
# lazy string defined by sheet1
self.assertIsInstance(ps['lazy'], lazystr)
self.assertEqual(str(ps['lazy']), '#FFFFFF')
# test compilation
self.assertEqual(ps.compile('a {bgcolor: %(bgcolor)s; size: 1%;}'),
- 'a {bgcolor: #FFFFFF; size: 1%;}')
+ 'a {bgcolor: #FFFFFF; size: 1%;}')
self.assertEqual(ps.process_resource(DATADIR, 'pouet.css'),
self.cachedir)
self.assertFalse(ps.need_reload())
@@ -54,10 +54,17 @@
self.assertTrue(ps.need_reload())
ps.reload()
self.assertFalse(ps.need_reload())
- ps.process_resource(DATADIR, 'pouet.css') # put in cache
+ ps.process_resource(DATADIR, 'pouet.css') # put in cache
os.utime(self.data('pouet.css'), None)
self.assertFalse(ps.need_reload())
+ def test_chmod(self):
+ ps = PropertySheet(self.cachedir, datadir_url='http://cwtest.com')
+ ps.load(self.data('sheet1.py'))
+ rdir = ps.process_resource(DATADIR, 'pouet.css')
+ mode = os.stat(join(rdir, 'pouet.css')).st_mode
+ self.assertEqual(('%o' % mode)[-4:], '0644')
+
if __name__ == '__main__':
main()
--- a/cubicweb/web/test/unittest_webconfig.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/test/unittest_webconfig.py Mon Apr 23 15:23:55 2018 +0200
@@ -19,6 +19,7 @@
"""cubicweb.web.webconfig unit tests"""
import os
+from os import path
from unittest import TestCase
from cubicweb.devtools import ApptestConfiguration, fake
@@ -52,6 +53,18 @@
'neither "web" nor "shared" found in cubicwebcsspath (%s)'
% cubicwebcsspath)
+ def test_locate_all_files(self):
+ wdocfiles = list(self.config.locate_all_files('toc.xml'))
+ for fpath in wdocfiles:
+ self.assertTrue(path.exists(fpath), fpath)
+ for expected in [path.join('cubes', 'file', 'wdoc', 'toc.xml'),
+ path.join('cubicweb', 'web', 'wdoc', 'toc.xml')]:
+ for fpath in wdocfiles:
+ if fpath.endswith(expected):
+ break
+ else:
+ raise AssertionError('%s not found in %s' % (expected, wdocfiles))
+
def test_sign_text(self):
signature = self.config.sign_text(u'hôp')
self.assertTrue(self.config.check_text_sign(u'hôp', signature))
--- a/cubicweb/web/views/ajaxcontroller.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/views/ajaxcontroller.py Mon Apr 23 15:23:55 2018 +0200
@@ -153,7 +153,7 @@
result = func(*args)
except (RemoteCallFailed, DirectResponse):
raise
- except ValidationError:
+ except ValidationError as exc:
raise RemoteCallFailed(exc_message(exc, self._cw.encoding),
status=http_client.BAD_REQUEST)
except Exception as exc:
--- a/cubicweb/web/views/authentication.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/views/authentication.py Mon Apr 23 15:23:55 2018 +0200
@@ -17,6 +17,8 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""user authentication component"""
+from six import text_type
+
from logilab.common.deprecation import class_renamed
from logilab.common.textutils import unormalize
@@ -113,7 +115,7 @@
self.data = {}
def __unicode__(self):
- return '<session %s (0x%x)>' % (unicode(self.user.login), id(self))
+ return '<session %s (0x%x)>' % (text_type(self.user.login), id(self))
@property
def anonymous_session(self):
--- a/cubicweb/web/webconfig.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/webconfig.py Mon Apr 23 15:23:55 2018 +0200
@@ -23,7 +23,7 @@
import os
import hmac
from uuid import uuid4
-from os.path import join, exists, split, isdir
+from os.path import dirname, join, exists, split, isdir
from warnings import warn
from six import text_type
@@ -37,6 +37,9 @@
from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options
+_DATA_DIR = join(dirname(__file__), 'data')
+
+
register_persistent_options( (
# site-wide only web ui configuration
('site-title',
@@ -204,7 +207,7 @@
('captcha-font-file',
{'type' : 'string',
- 'default': join(CubicWebConfiguration.shared_dir(), 'data', 'porkys.ttf'),
+ 'default': join(_DATA_DIR, 'porkys.ttf'),
'help': 'True type font to use for captcha image generation (you \
must have the python imaging library installed to use captcha)',
'group': 'web', 'level': 3,
@@ -327,7 +330,7 @@
@cached
def _fs_path_locate(self, rid, rdirectory):
"""return the directory where the given resource may be found"""
- path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())]
+ path = [self.apphome] + self.cubes_path() + [dirname(__file__)]
for directory in path:
if exists(join(directory, rdirectory, rid)):
return directory
@@ -352,7 +355,7 @@
def locate_all_files(self, rid, rdirectory='wdoc'):
"""return all files corresponding to the given resource"""
- path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())]
+ path = [self.apphome] + self.cubes_path() + [dirname(__file__)]
for directory in path:
fpath = join(directory, rdirectory, rid)
if exists(fpath):
@@ -399,7 +402,7 @@
self._init_uiprops(self.uiprops)
def _init_uiprops(self, uiprops):
- libuiprops = join(self.shared_dir(), 'data', 'uiprops.py')
+ libuiprops = join(_DATA_DIR, 'uiprops.py')
uiprops.load(libuiprops)
for path in reversed([self.apphome] + self.cubes_path()):
self._load_ui_properties_file(uiprops, path)
--- a/cubicweb/web/webctl.py Mon Apr 23 13:50:50 2018 +0200
+++ b/cubicweb/web/webctl.py Mon Apr 23 15:23:55 2018 +0200
@@ -20,9 +20,8 @@
"""
from __future__ import print_function
-
-
-import os, os.path as osp
+import os
+import os.path as osp
from shutil import copy, rmtree
from logilab.common.shellutils import ASK
@@ -31,6 +30,7 @@
from cubicweb.cwctl import CWCTL
from cubicweb.cwconfig import CubicWebConfiguration as cwcfg
from cubicweb.toolsutils import Command, CommandHandler, underline_title
+from cubicweb.web.webconfig import _DATA_DIR
try:
@@ -76,18 +76,19 @@
if not dest:
dest = osp.join(config.appdatahome, 'data')
if osp.exists(dest):
- if config.verbosity and (not ask_clean or
- not (config.verbosity and
- ASK.confirm('Remove existing data directory %s?' % dest))):
+ if (config.verbosity
+ and (not ask_clean
+ or not (config.verbosity
+ and ASK.confirm('Remove existing data directory %s?' % dest)))):
raise ExecutionError('Directory %s already exists. '
'Remove it first.' % dest)
rmtreecontent(dest)
- config.quick_start = True # notify this is not a regular start
+ config.quick_start = True # notify this is not a regular start
# list all resources (no matter their order)
resources = set()
for datadir in self._datadirs(config, repo=repo):
for dirpath, dirnames, filenames in os.walk(datadir):
- rel_dirpath = dirpath[len(datadir)+1:]
+ rel_dirpath = dirpath[len(datadir) + 1:]
resources.update(osp.join(rel_dirpath, f) for f in filenames)
# locate resources and copy them to destination
@@ -115,7 +116,7 @@
cube_datadir = osp.join(cwcfg.cube_dir(cube), 'data')
if osp.isdir(cube_datadir):
yield cube_datadir
- yield osp.join(config.shared_dir(), 'data')
+ yield _DATA_DIR
class WebUpgradeHandler(CommandHandler, GenStaticDataDirMixIn):
--- a/debian/changelog Mon Apr 23 13:50:50 2018 +0200
+++ b/debian/changelog Mon Apr 23 15:23:55 2018 +0200
@@ -1,3 +1,27 @@
+cubicweb (3.26.3-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Denis Laxalde <denis.laxalde@logilab.fr> Mon, 23 Apr 2018 15:18:55 +0200
+
+cubicweb (3.26.2-1) unstable; urgency=medium
+
+ * new upstream release.
+
+ -- Denis Laxalde <denis.laxalde@logilab.fr> Thu, 22 Mar 2018 13:52:54 +0100
+
+cubicweb (3.26.1-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Denis Laxalde <denis.laxalde@logilab.fr> Wed, 21 Feb 2018 18:06:54 +0100
+
+cubicweb (3.26.0-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Denis Laxalde <denis.laxalde@logilab.fr> Thu, 01 Feb 2018 09:24:01 +0100
+
cubicweb (3.25.4-1) unstable; urgency=medium
* New upstream release.
--- a/doc/changes/3.26.rst Mon Apr 23 13:50:50 2018 +0200
+++ b/doc/changes/3.26.rst Mon Apr 23 15:23:55 2018 +0200
@@ -1,5 +1,5 @@
-3.26 (unreleased)
-=================
+3.26 (1 February 2018)
+======================
New features
------------
@@ -7,3 +7,8 @@
* For ``pyramid`` instance configuration kind, logging is not handled anymore
by CubicWeb but should be configured through ``development.ini`` file
following https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html.
+
+Backwards incompatible changes
+------------------------------
+
+* CubicWebConfiguration method 'shared_dir' got dropped.
--- a/doc/changes/changelog.rst Mon Apr 23 13:50:50 2018 +0200
+++ b/doc/changes/changelog.rst Mon Apr 23 15:23:55 2018 +0200
@@ -2,6 +2,7 @@
Changelog history
===================
+.. include:: 3.26.rst
.. include:: 3.25.rst
.. include:: 3.24.rst
.. include:: 3.23.rst
--- a/flake8-ok-files.txt Mon Apr 23 13:50:50 2018 +0200
+++ b/flake8-ok-files.txt Mon Apr 23 15:23:55 2018 +0200
@@ -73,6 +73,7 @@
cubicweb/sobjects/test/unittest_notification.py
cubicweb/sobjects/test/unittest_register_user.py
cubicweb/sobjects/textparsers.py
+cubicweb/statsd_logger.py
cubicweb/test/data/libpython/cubicweb_comment/__init__.py
cubicweb/test/data/libpython/cubicweb_comment/__pkginfo__.py
cubicweb/test/data/libpython/cubicweb_email/entities.py
@@ -110,6 +111,7 @@
cubicweb/web/test/data/entities.py
cubicweb/web/test/unittest_application.py
cubicweb/web/test/unittest_http_headers.py
+cubicweb/web/test/unittest_propertysheet.py
cubicweb/web/test/unittest_uicfg.py
cubicweb/web/test/unittest_views_basetemplates.py
cubicweb/web/test/unittest_views_cwsources.py
@@ -122,6 +124,7 @@
cubicweb/web/views/staticcontrollers.py
cubicweb/web/views/workflow.py
cubicweb/web/views/uicfg.py
+cubicweb/web/webctl.py
cubicweb/xy.py
cubicweb/pyramid/auth.py
cubicweb/pyramid/bwcompat.py
--- a/setup.py Mon Apr 23 13:50:50 2018 +0200
+++ b/setup.py Mon Apr 23 15:23:55 2018 +0200
@@ -47,7 +47,6 @@
# import optional features
distname = __pkginfo__['distname']
-data_files = __pkginfo__['data_files']
package_data = __pkginfo__['package_data']
@@ -62,7 +61,6 @@
author_email=author_email,
packages=find_packages(),
package_data=package_data,
- data_files=data_files,
include_package_data=True,
install_requires=[
'six >= 1.4.0',