backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 14 Feb 2012 15:16:42 +0100
changeset 8236 cc70da744f43
parent 8230 00435a332502 (current diff)
parent 8235 c2a91d6639d8 (diff)
child 8237 f854cf9b089e
backport stable
__init__.py
debian/control
hooks/notification.py
server/migractions.py
server/repository.py
--- a/__init__.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/__init__.py	Tue Feb 14 15:16:42 2012 +0100
@@ -117,6 +117,7 @@
                     binary.write(chunk)
             else:
                 binary.write(fobj.read())
+        binary.seek(0)
         return binary
 
 
--- a/debian/control	Tue Feb 14 11:34:53 2012 +0100
+++ b/debian/control	Tue Feb 14 15:16:42 2012 +0100
@@ -127,7 +127,7 @@
 Architecture: all
 XB-Python-Version: ${python:Versions}
 Depends: ${misc:Depends}, ${python:Depends}, cubicweb-server (= ${source:Version}), cubicweb-web (= ${source:Version}), python-pysqlite2
-Suggests: w3c-dtd-xhtml
+Suggests: w3c-dtd-xhtml, xvfb
 Description: tests suite and development tools for the CubicWeb framework
  CubicWeb is a semantic web application framework.
  .
--- a/devtools/qunit.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/devtools/qunit.py	Tue Feb 14 15:16:42 2012 +0100
@@ -70,13 +70,16 @@
         fnull = open(os.devnull, 'w')
         stdout = TemporaryFile()
         stderr = TemporaryFile()
+        self.firefox_cmd = ['firefox', '-no-remote']
+        if os.name == 'posix':
+            self.firefox_cmd = ['xvfb-run', '-a'] + self.firefox_cmd
         try:
             home = osp.expanduser('~')
             user = getlogin()
             assert os.access(home, os.W_OK), \
                    'No write access to your home directory, Firefox will crash.'\
                    ' Are you sure "%s" is a valid home  for user "%s"' % (home, user)
-            check_call(['firefox', '-no-remote', '-CreateProfile',
+            check_call(self.firefox_cmd + ['-CreateProfile',
                         '%s %s' % (self._profile_name, self._tmp_dir)],
                                   stdout=stdout, stderr=stderr)
         except CalledProcessError, cpe:
@@ -87,7 +90,7 @@
     def start(self, url):
         self.stop()
         fnull = open(os.devnull, 'w')
-        self._process = Popen(['firefox', '-no-remote', '-P', self._profile_name, url],
+        self._process = Popen(self.firefox_cmd + ['-P', self._profile_name, url],
                               stdout=fnull, stderr=fnull)
 
     def stop(self):
--- a/hooks/notification.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/hooks/notification.py	Tue Feb 14 15:16:42 2012 +0100
@@ -30,7 +30,7 @@
     """delay rendering of notification view until precommit"""
     view = None # make pylint happy
 
-    def precommit_event(self):
+    def postcommit_event(self):
         view = self.view
         if view.cw_rset is not None and not view.cw_rset:
             return # entity added and deleted in the same transaction (cache effect)
--- a/i18n.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/i18n.py	Tue Feb 14 15:16:42 2012 +0100
@@ -60,7 +60,9 @@
     status != 0
     """
     from subprocess import call
-    print cmd.replace(os.getcwd() + os.sep, '')
+    # use getcwdu as cmd may be unicode and cwd may contains non-ascii
+    # characters
+    print cmd.replace(os.getcwdu() + os.sep, '')
     status = call(cmd, shell=True)
     if status != 0:
         raise Exception('status = %s' % status)
--- a/server/migractions.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/server/migractions.py	Tue Feb 14 15:16:42 2012 +0100
@@ -1352,7 +1352,7 @@
             getattr(entity, attribute)
             storage.migrate_entity(entity, attribute)
             # remove from entity cache to avoid memory exhaustion
-            del entity[attribute]
+            del entity.cw_attr_cache[attribute]
             pb.update()
         print
         source.set_storage(etype, attribute, storage)
--- a/server/repository.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/server/repository.py	Tue Feb 14 15:16:42 2012 +0100
@@ -509,6 +509,8 @@
             results['%s_cache_hit' % title] =  hits
             results['%s_cache_miss' % title] = misses
             results['%s_cache_hit_percent' % title] = (hits * 100) / (hits + misses)
+        results['type_source_cache_size'] = len(self._type_source_cache)
+        results['extid_cache_size'] = len(self._extid_cache)
         results['sql_no_cache'] = self.system_source.no_cache
         results['nb_open_sessions'] = len(self._sessions)
         results['nb_active_threads'] = threading.activeCount()
@@ -517,6 +519,43 @@
         results['threads'] = ', '.join(sorted(str(t) for t in threading.enumerate()))
         return results
 
+    def gc_stats(self, nmax=20):
+        """Return a dictionary containing some statistics about the repository
+        memory usage.
+
+        This is a public method, not requiring a session id.
+
+        nmax is the max number of (most) referenced object returned as
+        the 'referenced' result
+        """
+
+        from cubicweb._gcdebug import gc_info
+        from cubicweb.appobject import AppObject
+        from cubicweb.rset import ResultSet
+        from cubicweb.dbapi import Connection, Cursor
+        from cubicweb.web.request import CubicWebRequestBase
+        from rql.stmts import Union
+
+        lookupclasses = (AppObject,
+                         Union, ResultSet,
+                         Connection, Cursor,
+                         CubicWebRequestBase)
+        try:
+            from cubicweb.server.session import Session, InternalSession
+            lookupclasses += (InternalSession, Session)
+        except ImportError:
+            pass # no server part installed
+
+        results = {}
+        counters, ocounters, garbage = gc_info(lookupclasses,
+                                               viewreferrersclasses=())
+        values = sorted(counters.iteritems(), key=lambda x: x[1], reverse=True)
+        results['lookupclasses'] = values
+        values = sorted(ocounters.iteritems(), key=lambda x: x[1], reverse=True)[:nmax]
+        results['referenced'] = values
+        results['unreachable'] = len(garbage)
+        return results
+
     def get_schema(self):
         """Return the instance schema.
 
--- a/server/serverctl.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/server/serverctl.py	Tue Feb 14 15:16:42 2012 +0100
@@ -25,6 +25,7 @@
 import sys
 import os
 import logging
+import subprocess
 
 from logilab.common import nullobject
 from logilab.common.configuration import Configuration
@@ -258,12 +259,13 @@
     cfgname = 'repository'
 
     def start_server(self, config):
-        command = ['cubicweb-ctl start-repository ']
+        command = ['cubicweb-ctl', 'start-repository']
         if config.debugmode:
             command.append('--debug')
-        command.append('--loglevel %s' % config['log-threshold'].lower())
+        command.append('--loglevel')
+        command.append(config['log-threshold'].lower())
         command.append(config.appid)
-        os.system(' '.join(command))
+        subprocess.call(command)
         return 1
 
 
--- a/server/sources/__init__.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/server/sources/__init__.py	Tue Feb 14 15:16:42 2012 +0100
@@ -135,7 +135,8 @@
         source_config.pop('type')
 
     def __repr__(self):
-        return '<%s source %s @%#x>' % (self.uri, self.eid, id(self))
+        return '<%s %s source %s @%#x>' % (self.uri, self.__class__.__name__,
+                                           self.eid, id(self))
 
     def __cmp__(self, other):
         """simple comparison function to get predictable source order, with the
--- a/server/sources/native.py	Tue Feb 14 11:34:53 2012 +0100
+++ b/server/sources/native.py	Tue Feb 14 15:16:42 2012 +0100
@@ -1586,9 +1586,11 @@
                 pwd = rset[0][0]
             except IndexError:
                 raise AuthenticationError('bad login')
+            if pwd is None:
+                # if pwd is None but a password is provided, something is wrong
+                raise AuthenticationError('bad password')
             # passwords are stored using the Bytes type, so we get a StringIO
-            if pwd is not None:
-                args['pwd'] = Binary(crypt_password(password, pwd.getvalue()[:2]))
+            args['pwd'] = Binary(crypt_password(password, pwd.getvalue()[:2]))
         # get eid from login and (crypted) password
         rset = self.source.syntax_tree_search(session, self._auth_rqlst, args)
         try: