Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db15.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db15.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db15.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db15.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index, DatabaseManager def do_upgrade(env, ver, cursor):
Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db16.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db16.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db16.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db16.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db17.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db17.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db17.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db17.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index, DatabaseManager def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db18.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db18.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db18.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db18.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index, DatabaseManager def do_upgrade(env, ver, cursor): @@ -61,4 +74,3 @@ def do_upgrade(env, ver, cursor): cursor.execute("DROP TABLE session_old") cursor.execute("DROP TABLE ticket_change_old") - Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db19.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db19.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db19.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db19.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2006-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index, DatabaseManager def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db20.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db20.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db20.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db20.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.versioncontrol.cache import CACHE_YOUNGEST_REV def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db21.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db21.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db21.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db21.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2007-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + def do_upgrade(env, ver, cursor): """Upgrade the reports to better handle the new workflow capabilities""" Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db22.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db22.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db22.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db22.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2009-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, DatabaseManager def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db23.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db23.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db23.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db23.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2009-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index, DatabaseManager def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db24.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db24.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db24.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db24.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2009-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, Index, DatabaseManager def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db25.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db25.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db25.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db25.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2010-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import DatabaseManager Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db26.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db26.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db26.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db26.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2010-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + def do_upgrade(env, ver, cursor): """Zero-pad Subversion revision numbers in the cache.""" Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db27.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db27.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db27.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db27.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2012-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + from trac.db import Table, Column, DatabaseManager def do_upgrade(env, ver, cursor): Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db28.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db28.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db28.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db28.py Sat Nov 15 01:14:46 2014 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2012 Edgewall Software +# Copyright (C) 2012-2013 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db29.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db29.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db29.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db29.py Sat Nov 15 01:14:46 2014 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2012 Edgewall Software +# Copyright (C) 2012-2013 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db3.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db3.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db3.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db3.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2004-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + sql = """ CREATE TABLE attachment ( type text, Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db4.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db4.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db4.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db4.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2004-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + sql = [ """CREATE TABLE session ( sid text, Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db5.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db5.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db5.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db5.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2004-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + sql = [ #-- Add unique id, descr to 'milestone' """CREATE TEMPORARY TABLE milestone_old AS SELECT * FROM milestone;""", Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db6.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db6.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db6.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db6.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2004-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + sql = """ CREATE TABLE ticket_custom ( ticket integer, @@ -9,4 +22,3 @@ CREATE TABLE ticket_custom ( def do_upgrade(env, ver, cursor): cursor.execute(sql) - Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db7.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db7.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db7.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db7.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2004-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + sql = [ #-- Add readonly flag to 'wiki' """CREATE TEMPORARY TABLE wiki_old AS SELECT * FROM wiki;""", Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db8.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db8.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db8.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db8.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + import time d = {'now':time.time()} @@ -17,6 +30,7 @@ SELECT name,time,time,descr FROM milesto SELECT name,time,descr FROM milestone_old WHERE time > %(now)s;""" % d ] + def do_upgrade(env, ver, cursor): for s in sql: cursor.execute(s) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db9.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db9.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db9.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/upgrades/db9.py Sat Nov 15 01:14:46 2014 @@ -1,3 +1,16 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2005-2013 Edgewall Software +# All rights reserved. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at http://trac.edgewall.com/license.html. +# +# This software consists of voluntary contributions made by many +# individuals. For the exact contribution history, see the revision +# history and logs, available at http://trac.edgewall.org/. + import time sql = [ @@ -17,6 +30,7 @@ sql = [ """DROP TABLE session_old;""" ] + def do_upgrade(env, ver, cursor): for s in sql: cursor.execute(s) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/__init__.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/__init__.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/__init__.py Sat Nov 15 01:14:46 2014 @@ -20,6 +20,7 @@ from __future__ import with_statement import errno +import functools import inspect from itertools import izip, tee import locale @@ -29,11 +30,13 @@ import random import re import shutil import sys +import struct import tempfile import time from urllib import quote, unquote, urlencode from .compat import any, md5, sha1, sorted +from .datefmt import to_datetime, to_timestamp, utc from .text import exception_to_unicode, to_unicode, getpreferredencoding # -- req, session and web utils @@ -255,6 +258,68 @@ def create_unique_file(path): path = '%s.%d%s' % (parts[0], idx, parts[1]) +def create_zipinfo(filename, mtime=None, dir=False, executable=False, symlink=False, + comment=None): + """Create a instance of `ZipInfo`. + + :param filename: file name of the entry + :param mtime: modified time of the entry + :param dir: if `True`, the entry is a directory + :param executable: if `True`, the entry is a executable file + :param symlink: if `True`, the entry is a symbolic link + :param comment: comment of the entry + """ + from zipfile import ZipInfo, ZIP_DEFLATED, ZIP_STORED + zipinfo = ZipInfo() + + # The general purpose bit flag 11 is used to denote + # UTF-8 encoding for path and comment. Only set it for + # non-ascii files for increased portability. + # See http://www.pkware.com/documents/casestudies/APPNOTE.TXT + if any(ord(c) >= 128 for c in filename): + zipinfo.flag_bits |= 0x0800 + zipinfo.filename = filename.encode('utf-8') + + if mtime is not None: + mtime = to_datetime(mtime, utc) + zipinfo.date_time = mtime.utctimetuple()[:6] + # The "extended-timestamp" extra field is used for the + # modified time of the entry in unix time. It avoids + # extracting wrong modified time if non-GMT timezone. + # See http://www.opensource.apple.com/source/zip/zip-6/unzip/unzip + # /proginfo/extra.fld + zipinfo.extra += struct.pack( + '<hhBl', + 0x5455, # extended-timestamp extra block type + 1 + 4, # size of this block + 1, # modification time is present + to_timestamp(mtime)) # time of last modification + + # external_attr is 4 bytes in size. The high order two + # bytes represent UNIX permission and file type bits, + # while the low order two contain MS-DOS FAT file + # attributes, most notably bit 4 marking directories. + if dir: + if not zipinfo.filename.endswith('/'): + zipinfo.filename += '/' + zipinfo.compress_type = ZIP_STORED + zipinfo.external_attr = 040755 << 16L # permissions drwxr-xr-x + zipinfo.external_attr |= 0x10 # MS-DOS directory flag + else: + zipinfo.compress_type = ZIP_DEFLATED + zipinfo.external_attr = 0644 << 16L # permissions -r-wr--r-- + if executable: + zipinfo.external_attr |= 0755 << 16L # -rwxr-xr-x + if symlink: + zipinfo.compress_type = ZIP_STORED + zipinfo.external_attr |= 0120000 << 16L # symlink file type + + if comment: + zipinfo.comment = comment.encode('utf-8') + + return zipinfo + + class NaivePopen: """This is a deadlock-safe version of popen that returns an object with errorlevel, out (a string) and err (a string). @@ -299,6 +364,39 @@ class NaivePopen: os.remove(errfile) +def terminate(process): + """Python 2.5 compatibility method. + os.kill is not available on Windows before Python 2.7. + In Python 2.6 subprocess.Popen has a terminate method. + (It also seems to have some issues on Windows though.) + """ + + def terminate_win(process): + import ctypes + PROCESS_TERMINATE = 1 + handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, + False, + process.pid) + ctypes.windll.kernel32.TerminateProcess(handle, -1) + ctypes.windll.kernel32.CloseHandle(handle) + + def terminate_nix(process): + import os + import signal + try: + os.kill(process.pid, signal.SIGTERM) + except OSError, e: + # If the process has already finished and has not been + # waited for, killing it raises an ESRCH error on Cygwin + import errno + if e.errno != errno.ESRCH: + raise + + if sys.platform == 'win32': + return terminate_win(process) + return terminate_nix(process) + + def makedirs(path, overwrite=False): """Create as many directories as necessary to make `path` exist. @@ -513,7 +611,7 @@ def safe__import__(module_name): return __import__(module_name, globals(), locals(), []) except Exception, e: for modname in sys.modules.copy(): - if not already_imported.has_key(modname): + if modname not in already_imported: del(sys.modules[modname]) raise e @@ -611,11 +709,33 @@ def get_pkginfo(dist): """ import types if isinstance(dist, types.ModuleType): + def has_resource(dist, resource_name): + if dist.location.endswith('.egg'): # installed by easy_install + return dist.has_resource(resource_name) + if dist.has_metadata('installed-files.txt'): # installed by pip + resource_name = os.path.normpath('../' + resource_name) + return any(resource_name == os.path.normpath(name) + for name + in dist.get_metadata_lines('installed-files.txt')) + if dist.has_metadata('SOURCES.txt'): + resource_name = os.path.normpath(resource_name) + return any(resource_name == os.path.normpath(name) + for name in dist.get_metadata_lines('SOURCES.txt')) + toplevel = resource_name.split('/')[0] + if dist.has_metadata('top_level.txt'): + return toplevel in dist.get_metadata_lines('top_level.txt') + return dist.key == toplevel.lower() module = dist module_path = get_module_path(module) + resource_name = module.__name__.replace('.', '/') + if os.path.basename(module.__file__) in ('__init__.py', '__init__.pyc', + '__init__.pyo'): + resource_name += '/__init__.py' + else: + resource_name += '.py' for dist in find_distributions(module_path, only=True): if os.path.isfile(module_path) or \ - dist.key == module.__name__.lower(): + has_resource(dist, resource_name): break else: return {} @@ -639,6 +759,20 @@ def get_pkginfo(dist): info[normalize(attr)] = err return info + +def warn_setuptools_issue(out=None): + if not out: + out = sys.stderr + import setuptools + from pkg_resources import parse_version as parse + if parse('5.4') <= parse(setuptools.__version__) < parse('5.7') and \ + not os.environ.get('PKG_RESOURCES_CACHE_ZIP_MANIFESTS'): + out.write("Warning: Detected setuptools version %s. The environment " + "variable 'PKG_RESOURCES_CACHE_ZIP_MANIFESTS' must be set " + "to avoid significant performance degradation.\n" + % setuptools.__version__) + + # -- crypto utils try: @@ -983,18 +1117,30 @@ def to_ranges(revs): class lazy(object): - """A lazily-evaluated attribute""" + """A lazily-evaluated attribute. + + :since: 1.0 + """ def __init__(self, fn): self.fn = fn + functools.update_wrapper(self, fn) def __get__(self, instance, owner): if instance is None: return self + if self.fn.__name__ in instance.__dict__: + return instance.__dict__[self.fn.__name__] result = self.fn(instance) - setattr(instance, self.fn.__name__, result) + instance.__dict__[self.fn.__name__] = result return result + def __set__(self, instance, value): + instance.__dict__[self.fn.__name__] = value + + def __delete__(self, instance): + del instance.__dict__[self.fn.__name__] + # -- algorithmic utilities Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/compat.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/compat.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/compat.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/compat.py Sat Nov 15 01:14:46 2014 @@ -17,7 +17,9 @@ previous versions of Python from 2.5 onward. """ +import math import os +import time # Import symbols previously defined here, kept around so that plugins importing # them don't suddenly stop working @@ -95,3 +97,19 @@ except ImportError: while lines and not lines[0]: lines.pop(0) return '\n'.join(lines) + + +def wait_for_file_mtime_change(filename): + """This function is typically called before a file save operation, + waiting if necessary for the file modification time to change. The + purpose is to avoid successive file updates going undetected by the + caching mechanism that depends on a change in the file modification + time to know when the file should be reparsed.""" + try: + mtime = os.stat(filename).st_mtime + os.utime(filename, None) + while mtime == os.stat(filename).st_mtime: + time.sleep(1e-3) + os.utime(filename, None) + except OSError: + pass # file doesn't exist (yet) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/daemon.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/daemon.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/daemon.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/daemon.py Sat Nov 15 01:14:46 2014 @@ -19,6 +19,7 @@ import os import signal import sys + def daemonize(pidfile=None, progname=None, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', umask=022): """Fork a daemon process.""" Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/datefmt.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/datefmt.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/datefmt.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/datefmt.py Sat Nov 15 01:14:46 2014 @@ -26,8 +26,11 @@ from locale import getlocale, LC_TIME try: import babel +except ImportError: + babel = None +else: from babel import Locale - from babel.core import LOCALE_ALIASES + from babel.core import LOCALE_ALIASES, UnknownLocaleError from babel.dates import ( format_datetime as babel_format_datetime, format_date as babel_format_date, @@ -36,12 +39,10 @@ try: get_time_format, get_month_names, get_period_names, get_day_names ) -except ImportError: - babel = None from trac.core import TracError from trac.util.text import to_unicode, getpreferredencoding -from trac.util.translation import _, ngettext, get_available_locales +from trac.util.translation import _, ngettext # Date/time utilities @@ -54,12 +55,14 @@ def to_datetime(t, tzinfo=None): ``t`` is converted using the following rules: - - If ``t`` is already a `datetime` object, - - if it is timezone-"naive", it is localized to ``tzinfo`` - - if it is already timezone-aware, ``t`` is mapped to the given - timezone (`datetime.datetime.astimezone`) - - If ``t`` is None, the current time will be used. - - If ``t`` is a number, it is interpreted as a timestamp. + * If ``t`` is already a `datetime` object, + + * if it is timezone-"naive", it is localized to ``tzinfo`` + * if it is already timezone-aware, ``t`` is mapped to the given + timezone (`datetime.datetime.astimezone`) + + * If ``t`` is None, the current time will be used. + * If ``t`` is a number, it is interpreted as a timestamp. Any other input will trigger a `TypeError`. @@ -87,6 +90,8 @@ def to_datetime(t, tzinfo=None): timedelta(seconds=frac + 1) else: dt = datetime.fromtimestamp(t, tz) + else: + dt = None if dt: return tz.normalize(dt) raise TypeError('expecting datetime, int, long, float, or None; got %s' % @@ -154,51 +159,45 @@ _BABEL_FORMATS = { 'date': {'short': '%x', 'medium': '%x', 'long': '%x', 'full': '%x'}, 'time': {'short': '%H:%M', 'medium': '%X', 'long': '%X', 'full': '%X'}, } -_ISO8601_FORMATS = { - 'datetime': { - '%x %X': 'iso8601', '%x': 'iso8601date', '%X': 'iso8601time', - 'short': '%Y-%m-%dT%H:%M', 'medium': '%Y-%m-%dT%H:%M:%S', - 'long': 'iso8601', 'full': 'iso8601', - 'iso8601': 'iso8601', None: 'iso8601'}, - 'date': { - '%x %X': 'iso8601', '%x': 'iso8601date', '%X': 'iso8601time', - 'short': 'iso8601date', 'medium': 'iso8601date', - 'long': 'iso8601date', 'full': 'iso8601date', - 'iso8601': 'iso8601date', None: 'iso8601date'}, - 'time': { - '%x %X': 'iso8601', '%x': 'iso8601date', '%X': 'iso8601time', - 'short': '%H:%M', 'medium': '%H:%M:%S', - 'long': 'iso8601time', 'full': 'iso8601time', - 'iso8601': 'iso8601time', None: 'iso8601time'}, -} _STRFTIME_HINTS = {'%x %X': 'datetime', '%x': 'date', '%X': 'time'} def _format_datetime_without_babel(t, format): - normalize_Z = False - if format.lower().startswith('iso8601'): - if 'date' in format: - format = '%Y-%m-%d' - elif 'time' in format: - format = '%H:%M:%S%z' - normalize_Z = True - else: - format = '%Y-%m-%dT%H:%M:%S%z' - normalize_Z = True text = t.strftime(str(format)) - if normalize_Z: - text = text.replace('+0000', 'Z') - if not text.endswith('Z'): - text = text[:-2] + ":" + text[-2:] encoding = getlocale(LC_TIME)[1] or getpreferredencoding() \ or sys.getdefaultencoding() return unicode(text, encoding, 'replace') +def _format_datetime_iso8601(t, format, hint): + if format != 'full': + t = t.replace(microsecond=0) + text = t.isoformat() # YYYY-MM-DDThh:mm:ss.SSSSSS±hh:mm + if format == 'short': + text = text[:16] # YYYY-MM-DDThh:mm + elif format == 'medium': + text = text[:19] # YYYY-MM-DDThh:mm:ss + elif text.endswith('+00:00'): + text = text[:-6] + 'Z' + if hint == 'date': + text = text.split('T', 1)[0] + elif hint == 'time': + text = text.split('T', 1)[1] + return unicode(text, 'ascii') + def _format_datetime(t, format, tzinfo, locale, hint): t = to_datetime(t, tzinfo or localtz) - if (format in ('iso8601', 'iso8601date', 'iso8601time') or - locale == 'iso8601'): - format = _ISO8601_FORMATS[hint].get(format, format) + if format == 'iso8601': + return _format_datetime_iso8601(t, 'long', hint) + if format in ('iso8601date', 'iso8601time'): + return _format_datetime_iso8601(t, 'long', format[7:]) + if locale == 'iso8601': + if format is None: + format = 'long' + elif format in _STRFTIME_HINTS: + hint = _STRFTIME_HINTS[format] + format = 'long' + if format in ('short', 'medium', 'long', 'full'): + return _format_datetime_iso8601(t, format, hint) return _format_datetime_without_babel(t, format) if babel and locale: @@ -254,11 +253,17 @@ def get_date_format_hint(locale=None): if babel and locale: format = get_date_format('medium', locale=locale) return format.pattern + return _libc_get_date_format_hint() +def _libc_get_date_format_hint(format=None): t = datetime(1999, 10, 29, tzinfo=utc) tmpl = format_date(t, tzinfo=utc) - return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \ - .replace('10', 'MM', 1).replace('29', 'DD', 1) + units = [('1999', 'YYYY'), ('99', 'YY'), ('10', 'MM'), ('29', 'dd')] + if format: + units = [(unit[0], '%(' + unit[1] + ')s') for unit in units] + for unit in units: + tmpl = tmpl.replace(unit[0], unit[1], 1) + return tmpl def get_datetime_format_hint(locale=None): """Present the default format used by `format_datetime` in a human readable @@ -274,16 +279,22 @@ def get_datetime_format_hint(locale=None format = get_datetime_format('medium', locale=locale) return format.replace('{0}', time_pattern) \ .replace('{1}', date_pattern) + return _libc_get_datetime_format_hint() +def _libc_get_datetime_format_hint(format=None): t = datetime(1999, 10, 29, 23, 59, 58, tzinfo=utc) tmpl = format_datetime(t, tzinfo=utc) ampm = format_time(t, '%p', tzinfo=utc) + units = [] if ampm: - tmpl = tmpl.replace(ampm, 'a', 1) - return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \ - .replace('10', 'MM', 1).replace('29', 'DD', 1) \ - .replace('23', 'hh', 1).replace('11', 'hh', 1) \ - .replace('59', 'mm', 1).replace('58', 'ss', 1) + units.append((ampm, 'a')) + units.extend([('1999', 'YYYY'), ('99', 'YY'), ('10', 'MM'), ('29', 'dd'), + ('23', 'hh'), ('11', 'hh'), ('59', 'mm'), ('58', 'ss')]) + if format: + units = [(unit[0], '%(' + unit[1] + ')s') for unit in units] + for unit in units: + tmpl = tmpl.replace(unit[0], unit[1], 1) + return tmpl def get_month_names_jquery_ui(req): """Get the month names for the jQuery UI datepicker library""" @@ -372,6 +383,19 @@ def get_first_week_day_jquery_ui(req): if locale == 'iso8601': return 1 # Monday if babel and locale: + if not locale.territory: + # search first locale which has the same `langauge` and territory + # in preferred languages + for l in req.languages: + l = l.replace('-', '_').lower() + if l.startswith(locale.language.lower() + '_'): + try: + l = Locale.parse(l) + if l.territory: + locale = l + break + except UnknownLocaleError: + pass if not locale.territory and locale.language in LOCALE_ALIASES: locale = Locale.parse(LOCALE_ALIASES[locale.language]) return (locale.first_week_day + 1) % 7 @@ -437,6 +461,21 @@ def _parse_date_iso8601(text, tzinfo): return None +def _libc_parse_date(text, tzinfo): + for format in ('%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c', + '%b %d, %Y'): + try: + tm = time.strptime(text, format) + dt = tzinfo.localize(datetime(*tm[0:6])) + return tzinfo.normalize(dt) + except ValueError: + continue + try: + return _i18n_parse_date(text, tzinfo, None) + except ValueError: + pass + return + def parse_date(text, tzinfo=None, locale=None, hint='date'): tzinfo = tzinfo or localtz text = text.strip() @@ -446,24 +485,25 @@ def parse_date(text, tzinfo=None, locale if babel and locale: dt = _i18n_parse_date(text, tzinfo, locale) else: - for format in ['%x %X', '%x, %X', '%X %x', '%X, %x', '%x', '%c', - '%b %d, %Y']: - try: - tm = time.strptime(text, format) - dt = tzinfo.localize(datetime(*tm[0:6])) - dt = tzinfo.normalize(dt) - break - except ValueError: - continue + dt = _libc_parse_date(text, tzinfo) if dt is None: dt = _parse_relative_time(text, tzinfo) if dt is None: - hint = {'datetime': get_datetime_format_hint, - 'date': get_date_format_hint - }.get(hint, lambda(l): hint)(locale) - raise TracError(_('"%(date)s" is an invalid date, or the date format ' - 'is not known. Try "%(hint)s" instead.', - date=text, hint=hint), _('Invalid Date')) + formatted_hint = { + 'datetime': get_datetime_format_hint, + 'date': get_date_format_hint, + 'iso8601': lambda l: get_datetime_format_hint('iso8601'), + }.get(hint, lambda(l): hint)(locale) + if hint != 'iso8601': + msg = _('"%(date)s" is an invalid date, or the date format ' + 'is not known. Try "%(hint)s" or "%(isohint)s" instead.', + date=text, hint=formatted_hint, + isohint=get_datetime_format_hint('iso8601')) + else: + msg = _('"%(date)s" is an invalid date, or the date format ' + 'is not known. Try "%(hint)s" instead.', + date=text, hint=formatted_hint) + raise TracError(msg, _('Invalid Date')) # Make sure we can convert it to a timestamp and back - fromtimestamp() # may raise ValueError if larger than platform C localtime() or gmtime() try: @@ -483,15 +523,17 @@ def _i18n_parse_date_pattern(locale): 'm': ('m',), 's': ('s',), } - regexp = [r'[0-9]+'] - date_format = get_date_format('medium', locale=locale) - time_format = get_time_format('medium', locale=locale) - datetime_format = get_datetime_format('medium', locale=locale) - formats = ( - datetime_format.replace('{0}', time_format.format) \ - .replace('{1}', date_format.format), - date_format.format) + if locale is None: + formats = (_libc_get_datetime_format_hint(format=True), + _libc_get_date_format_hint(format=True)) + else: + date_format = get_date_format('medium', locale=locale) + time_format = get_time_format('medium', locale=locale) + datetime_format = get_datetime_format('medium', locale=locale) + formats = (datetime_format.replace('{0}', time_format.format) \ + .replace('{1}', date_format.format), + date_format.format) orders = [] for format in formats: @@ -503,49 +545,64 @@ def _i18n_parse_date_pattern(locale): order.append((idx, key)) break order.sort() - order = dict((key, idx) for idx, (_, key) in enumerate(order)) - orders.append(order) - - month_names = { - 'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6, - 'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12, - } - if formats[0].find('%(MMM)s') != -1: - for width in ('wide', 'abbreviated'): - names = get_month_names(width, locale=locale) - for num, name in names.iteritems(): - name = name.lower() - month_names[name] = num - regexp.extend(month_names.iterkeys()) + orders.append(dict((key, idx) for idx, (_, key) in enumerate(order))) + # always allow using English names regardless of locale + month_names = dict(zip(('jan', 'feb', 'mar', 'apr', 'may', 'jun', + 'jul', 'aug', 'sep', 'oct', 'nov', 'dec',), + xrange(1, 13))) period_names = {'am': 'am', 'pm': 'pm'} - if formats[0].find('%(a)s') != -1: - names = get_period_names(locale=locale) - for period, name in names.iteritems(): - name = name.lower() - period_names[name] = period - regexp.extend(period_names.iterkeys()) + + if locale is None: + for num in xrange(1, 13): + t = datetime(1999, num, 1, tzinfo=utc) + names = format_date(t, '%b\t%B', utc).split('\t') + month_names.update((name.lower(), num) for name in names + if str(num) not in name) + for num, period in ((11, 'am'), (23, 'pm')): + t = datetime(1999, 1, 1, num, tzinfo=utc) + name = format_datetime(t, '%p', utc) + if name: + period_names[name.lower()] = period + else: + if formats[0].find('%(MMM)s') != -1: + for width in ('wide', 'abbreviated'): + names = get_month_names(width, locale=locale) + month_names.update((name.lower(), num) + for num, name in names.iteritems()) + if formats[0].find('%(a)s') != -1: + names = get_period_names(locale=locale) + period_names.update((name.lower(), period) + for period, name in names.iteritems() + if period in ('am', 'pm')) + + regexp = ['[0-9]+'] + regexp.extend(re.escape(name) for name in month_names) + regexp.extend(re.escape(name) for name in period_names) return { 'orders': orders, - 'regexp': re.compile('(%s)' % '|'.join(regexp), - re.IGNORECASE | re.UNICODE), + 'regexp': re.compile('(%s)' % '|'.join(regexp), re.IGNORECASE), 'month_names': month_names, 'period_names': period_names, } -_I18N_PARSE_DATE_PATTERNS = dict(map(lambda l: (l, False), - get_available_locales())) +_I18N_PARSE_DATE_PATTERNS = {} +_I18N_PARSE_DATE_PATTERNS_LIBC = {} def _i18n_parse_date(text, tzinfo, locale): - locale = Locale.parse(locale) - key = str(locale) - pattern = _I18N_PARSE_DATE_PATTERNS.get(key) - if pattern is False: - pattern = _i18n_parse_date_pattern(locale) - _I18N_PARSE_DATE_PATTERNS[key] = pattern + if locale is None: + key = getlocale(LC_TIME)[0] + patterns = _I18N_PARSE_DATE_PATTERNS_LIBC + else: + locale = Locale.parse(locale) + key = str(locale) + patterns = _I18N_PARSE_DATE_PATTERNS + + pattern = patterns.get(key) if pattern is None: - return None + pattern = _i18n_parse_date_pattern(locale) + patterns[key] = pattern regexp = pattern['regexp'] period_names = pattern['period_names'] @@ -749,67 +806,103 @@ class LocalTimezone(tzinfo): @classmethod def _initialize(cls): - cls._std_tz = cls(False) cls._std_offset = timedelta(seconds=-time.timezone) + cls._std_tz = cls(cls._std_offset) if time.daylight: - cls._dst_tz = cls(True) cls._dst_offset = timedelta(seconds=-time.altzone) + cls._dst_tz = cls(cls._dst_offset) else: - cls._dst_tz = cls._std_tz cls._dst_offset = cls._std_offset + cls._dst_tz = cls._std_tz cls._dst_diff = cls._dst_offset - cls._std_offset - def __init__(self, is_dst=None): - self.is_dst = is_dst + def __init__(self, offset=None): + self._offset = offset def __str__(self): - offset = self.utcoffset(datetime.now()) - secs = offset.days * 3600 * 24 + offset.seconds - hours, rem = divmod(abs(secs), 3600) - return 'UTC%c%02d:%02d' % ('-' if secs < 0 else '+', hours, rem / 60) + return self._tzname_offset(self.utcoffset(datetime.now())) def __repr__(self): - if self.is_dst is None: + if self._offset is None: return '<LocalTimezone "%s" %s "%s" %s>' % \ (time.tzname[False], self._std_offset, time.tzname[True], self._dst_offset) - if self.is_dst: - offset = self._dst_offset + return '<LocalTimezone "%s" %s>' % (self._tzname(), self._offset) + + def _tzname(self): + if self is self._std_tz: + return time.tzname[False] + elif self is self._dst_tz: + return time.tzname[True] + elif self._offset is not None: + return self._tzname_offset(self._offset) else: - offset = self._std_offset - return '<LocalTimezone "%s" %s>' % (time.tzname[self.is_dst], offset) + return '%s, %s' % time.tzname - def _is_dst(self, dt, is_dst=False): - if self.is_dst is not None: - return self.is_dst + def _tzname_offset(self, offset): + secs = offset.days * 3600 * 24 + offset.seconds + hours, rem = divmod(abs(secs), 3600) + return 'UTC%c%02d:%02d' % ('+-'[secs < 0], hours, rem / 60) - tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, - dt.weekday(), 0) - try: - std_tt = time.localtime(time.mktime(tt + (0,))) - dst_tt = time.localtime(time.mktime(tt + (1,))) - except (ValueError, OverflowError): - return False - - std_correct = std_tt.tm_isdst == 0 - dst_correct = dst_tt.tm_isdst == 1 - if std_correct is dst_correct: - if is_dst is None: - if std_correct is True: - raise ValueError('Ambiguous time "%s"' % dt) - if std_correct is False: - raise ValueError('Non existent time "%s"' % dt) - return is_dst - if std_correct: - return False - if dst_correct: + def _tzinfo(self, dt, is_dst=False): + tzinfo = dt.tzinfo + if isinstance(tzinfo, LocalTimezone) and tzinfo._offset is not None: + return tzinfo + + base_tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, + dt.weekday(), 0) + local_tt = [None, None] + for idx in (0, 1): + try: + local_tt[idx] = time.localtime(time.mktime(base_tt + (idx,))) + except (ValueError, OverflowError): + pass + if local_tt[0] is local_tt[1] is None: + return self._std_tz + + std_correct = local_tt[0] and local_tt[0].tm_isdst == 0 + dst_correct = local_tt[1] and local_tt[1].tm_isdst == 1 + if is_dst is None and std_correct is dst_correct: + if std_correct: + raise ValueError('Ambiguous time "%s"' % dt) + if not std_correct: + raise ValueError('Non existent time "%s"' % dt) + tt = None + if std_correct is dst_correct is True: + tt = local_tt[bool(is_dst)] + elif std_correct is True: + tt = local_tt[0] + elif dst_correct is True: + tt = local_tt[1] + if tt: + utc_ts = to_timestamp(datetime(tzinfo=utc, *tt[:6])) + tz_offset = timedelta(seconds=utc_ts - time.mktime(tt)) + else: + dt = dt.replace(tzinfo=utc) + utc_ts = to_timestamp(dt) + dt -= timedelta(hours=6) + tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + tz_offset = timedelta(seconds=utc_ts - time.mktime(tt) - 6 * 3600) + + # if UTC offset doesn't match timezone offset, create a + # LocalTimezone instance with the UTC offset (#11563) + if tz_offset == self._std_offset: + tz = self._std_tz + elif tz_offset == self._dst_offset: + tz = self._dst_tz + else: + tz = LocalTimezone(tz_offset) + return tz + + def _is_dst(self, dt, is_dst=False): + tz = self._tzinfo(dt, is_dst) + if tz is self._dst_tz: return True + return False def utcoffset(self, dt): - if self._is_dst(dt): - return self._dst_offset - else: - return self._std_offset + return self._tzinfo(dt)._offset def dst(self, dt): if self._is_dst(dt): @@ -818,16 +911,12 @@ class LocalTimezone(tzinfo): return _zero def tzname(self, dt): - return time.tzname[self._is_dst(dt)] + return self._tzinfo(dt)._tzname() def localize(self, dt, is_dst=False): if dt.tzinfo is not None: raise ValueError('Not naive datetime (tzinfo is already set)') - if self._is_dst(dt, is_dst): - tz = self._dst_tz - else: - tz = self._std_tz - return dt.replace(tzinfo=tz) + return dt.replace(tzinfo=self._tzinfo(dt, is_dst)) def normalize(self, dt, is_dst=False): if dt.tzinfo is None: @@ -839,12 +928,22 @@ class LocalTimezone(tzinfo): def fromutc(self, dt): if dt.tzinfo is None or dt.tzinfo is not self: raise ValueError('fromutc: dt.tzinfo is not self') - tt = time.localtime(to_timestamp(dt.replace(tzinfo=utc))) - if tt.tm_isdst > 0: + dt = dt.replace(tzinfo=utc) + try: + tt = time.localtime(to_timestamp(dt)) + except ValueError: + return dt.replace(tzinfo=self._std_tz) + self._std_offset + # if UTC offset from localtime() doesn't match timezone offset, + # create a LocalTimezone instance with the UTC offset (#11563) + new_dt = datetime(*(tt[:6] + (dt.microsecond, utc))) + tz_offset = new_dt - dt + if tz_offset == self._std_offset: + tz = self._std_tz + elif tz_offset == self._dst_offset: tz = self._dst_tz else: - tz = self._std_tz - return datetime(microsecond=dt.microsecond, tzinfo=tz, *tt[0:6]) + tz = LocalTimezone(tz_offset) + return new_dt.replace(tzinfo=tz) utc = FixedOffset(0, 'UTC') Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/dist.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/dist.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/dist.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/dist.py Sat Nov 15 01:14:46 2014 @@ -17,4 +17,3 @@ try: from trac.dist import extract_javascript_script except ImportError: pass - Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/html.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/html.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/html.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/html.py Sat Nov 15 01:14:46 2014 @@ -16,12 +16,19 @@ import re from genshi import Markup, HTML, escape, unescape from genshi.core import stripentities, striptags, START, END -from genshi.builder import Element, ElementFactory, Fragment +from genshi.builder import Element, ElementFactory, Fragment, tag from genshi.filters.html import HTMLSanitizer from genshi.input import ParseError +try: + from babel.support import LazyProxy +except ImportError: + LazyProxy = None -__all__ = ['escape', 'unescape', 'html', 'plaintext', 'find_element', - 'TracHTMLSanitizer', 'Deuglifier', 'FormTokenInjector'] +from trac.core import TracError +from trac.util.text import to_unicode + +__all__ = ['Deuglifier', 'FormTokenInjector', 'TracHTMLSanitizer', 'escape', + 'find_element', 'html', 'plaintext', 'to_fragment', 'unescape'] class TracHTMLSanitizer(HTMLSanitizer): @@ -39,15 +46,17 @@ class TracHTMLSanitizer(HTMLSanitizer): 'background', 'background-attachment', 'background-color', 'background-image', 'background-position', 'background-repeat', 'border', 'border-bottom', 'border-bottom-color', - 'border-bottom-style', 'border-bottom-width', 'border-collapse', - 'border-color', 'border-left', 'border-left-color', - 'border-left-style', 'border-left-width', 'border-right', - 'border-right-color', 'border-right-style', 'border-right-width', - 'border-spacing', 'border-style', 'border-top', 'border-top-color', + 'border-bottom-style', 'border-bottom-left-radius', + 'border-bottom-right-radius', 'border-bottom-width', + 'border-collapse', 'border-color', 'border-left', 'border-left-color', + 'border-left-style', 'border-left-width', 'border-radius', + 'border-right', 'border-right-color', 'border-right-style', + 'border-right-width', 'border-spacing', 'border-style', 'border-top', + 'border-top-color', 'border-top-left-radius', 'border-top-right-radius', 'border-top-style', 'border-top-width', 'border-width', 'bottom', 'caption-side', 'clear', 'clip', 'color', 'content', - 'counter-increment', 'counter-reset', 'cursor', 'direction', 'display', - 'empty-cells', 'float', 'font', 'font-family', 'font-size', + 'counter-increment', 'counter-reset', 'cursor', 'direction', + 'display', 'empty-cells', 'float', 'font', 'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'height', 'left', 'letter-spacing', 'line-height', 'list-style', 'list-style-image', 'list-style-position', 'list-style-type', 'margin', 'margin-bottom', @@ -297,18 +306,20 @@ def plaintext(text, keeplinebreaks=True) return text -def find_element(frag, attr=None, cls=None): - """Return the first element in the fragment having the given attribute or - class, using a preorder depth-first search. +def find_element(frag, attr=None, cls=None, tag=None): + """Return the first element in the fragment having the given attribute, + class or tag, using a preorder depth-first search. """ if isinstance(frag, Element): if attr is not None and attr in frag.attrib: return frag if cls is not None and cls in frag.attrib.get('class', '').split(): return frag + if tag is not None and tag == frag.tag: + return frag if isinstance(frag, Fragment): for child in frag.children: - elt = find_element(child, attr, cls) + elt = find_element(child, attr, cls, tag) if elt is not None: return elt @@ -328,3 +339,15 @@ def expand_markup(stream, ctxt=None): yield event else: yield event + + +def to_fragment(input): + """Convert input to a `Fragment` object.""" + + if isinstance(input, TracError): + input = input.message + if LazyProxy and isinstance(input, LazyProxy): + input = input.value + if isinstance(input, Fragment): + return input + return tag(to_unicode(input)) Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/__init__.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/__init__.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/__init__.py Sat Nov 15 01:14:46 2014 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2009 Edgewall Software +# Copyright (C) 2006-2013 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which @@ -15,13 +15,18 @@ from __future__ import with_statement import doctest import os.path +import pkg_resources import random import re +import sys import tempfile import unittest +import trac +import trac.tests.compat from trac import util -from trac.util.tests import concurrency, datefmt, presentation, text, html +from trac.util.tests import concurrency, datefmt, presentation, text, \ + translation, html class AtomicFileTestCase(unittest.TestCase): @@ -38,7 +43,7 @@ class AtomicFileTestCase(unittest.TestCa def test_non_existing(self): with util.AtomicFile(self.path) as f: f.write('test content') - self.assertEqual(True, f.closed) + self.assertTrue(f.closed) self.assertEqual('test content', util.read_file(self.path)) def test_existing(self): @@ -46,7 +51,7 @@ class AtomicFileTestCase(unittest.TestCa self.assertEqual('Some content', util.read_file(self.path)) with util.AtomicFile(self.path) as f: f.write('Some new content') - self.assertEqual(True, f.closed) + self.assertTrue(f.closed) self.assertEqual('Some new content', util.read_file(self.path)) if util.can_rename_open_file: @@ -56,8 +61,8 @@ class AtomicFileTestCase(unittest.TestCa with open(self.path) as rf: with util.AtomicFile(self.path) as f: f.write('Replaced content') - self.assertEqual(True, rf.closed) - self.assertEqual(True, f.closed) + self.assertTrue(rf.closed) + self.assertTrue(f.closed) self.assertEqual('Replaced content', util.read_file(self.path)) # FIXME: It is currently not possible to make this test pass on all @@ -70,18 +75,18 @@ class AtomicFileTestCase(unittest.TestCa self.path = os.path.join(tempfile.gettempdir(), u'träc-témpfilè') with util.AtomicFile(self.path) as f: f.write('test content') - self.assertEqual(True, f.closed) + self.assertTrue(f.closed) self.assertEqual('test content', util.read_file(self.path)) class PathTestCase(unittest.TestCase): def assert_below(self, path, parent): - self.assert_(util.is_path_below(path.replace('/', os.sep), - parent.replace('/', os.sep))) + self.assertTrue(util.is_path_below(path.replace('/', os.sep), + parent.replace('/', os.sep))) def assert_not_below(self, path, parent): - self.assert_(not util.is_path_below(path.replace('/', os.sep), + self.assertFalse(util.is_path_below(path.replace('/', os.sep), parent.replace('/', os.sep))) def test_is_path_below(self): @@ -93,8 +98,8 @@ class PathTestCase(unittest.TestCase): self.assert_not_below('/svn/project2/sub/repos', '/svn/project1') self.assert_not_below('/svn/project1/../project2/repos', '/svn/project1') - self.assert_(util.is_path_below('repos', os.path.join(os.getcwd()))) - self.assert_(not util.is_path_below('../sub/repos', + self.assertTrue(util.is_path_below('repos', os.path.join(os.getcwd()))) + self.assertFalse(util.is_path_below('../sub/repos', os.path.join(os.getcwd()))) @@ -168,19 +173,118 @@ class SafeReprTestCase(unittest.TestCase "type(s) for +: 'int' and 'str')>", sr) +class SetuptoolsUtilsTestCase(unittest.TestCase): + + def test_get_module_path(self): + self.assertEqual(util.get_module_path(trac), + util.get_module_path(util)) + + def test_get_pkginfo_trac(self): + pkginfo = util.get_pkginfo(trac) + self.assertEqual(trac.__version__, pkginfo.get('version')) + self.assertNotEqual({}, pkginfo) + + def test_get_pkginfo_non_toplevel(self): + from trac import core + import tracopt + pkginfo = util.get_pkginfo(trac) + self.assertEqual(pkginfo, util.get_pkginfo(util)) + self.assertEqual(pkginfo, util.get_pkginfo(core)) + self.assertEqual(pkginfo, util.get_pkginfo(tracopt)) + + def test_get_pkginfo_genshi(self): + try: + import genshi + import genshi.core + dist = pkg_resources.get_distribution('Genshi') + except: + pass + else: + pkginfo = util.get_pkginfo(genshi) + self.assertNotEqual({}, pkginfo) + self.assertEqual(pkginfo, util.get_pkginfo(genshi.core)) + + def test_get_pkginfo_babel(self): + try: + import babel + import babel.core + dist = pkg_resources.get_distribution('Babel') + except: + pass + else: + pkginfo = util.get_pkginfo(babel) + self.assertNotEqual({}, pkginfo) + self.assertEqual(pkginfo, util.get_pkginfo(babel.core)) + + def test_get_pkginfo_mysqldb(self): + # MySQLdb's package name is "MySQL-Python" + try: + import MySQLdb + import MySQLdb.cursors + dist = pkg_resources.get_distribution('MySQL-Python') + dist.get_metadata('top_level.txt') + except: + pass + else: + pkginfo = util.get_pkginfo(MySQLdb) + self.assertNotEqual({}, pkginfo) + self.assertEqual(pkginfo, util.get_pkginfo(MySQLdb.cursors)) + + def test_get_pkginfo_psycopg2(self): + # python-psycopg2 deb package doesn't provide SOURCES.txt and + # top_level.txt + try: + import psycopg2 + import psycopg2.extensions + dist = pkg_resources.get_distribution('psycopg2') + except: + pass + else: + pkginfo = util.get_pkginfo(psycopg2) + self.assertNotEqual({}, pkginfo) + self.assertEqual(pkginfo, util.get_pkginfo(psycopg2.extensions)) + + +class LazyClass(object): + @util.lazy + def f(self): + return object() + + +class LazyTestCase(unittest.TestCase): + + def setUp(self): + self.obj = LazyClass() + + def test_lazy_get(self): + f = self.obj.f + self.assertTrue(self.obj.f is f) + + def test_lazy_set(self): + self.obj.f = 2 + self.assertEqual(2, self.obj.f) + + def test_lazy_del(self): + f = self.obj.f + del self.obj.f + self.assertFalse(self.obj.f is f) + def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(AtomicFileTestCase, 'test')) - suite.addTest(unittest.makeSuite(PathTestCase, 'test')) - suite.addTest(unittest.makeSuite(RandomTestCase, 'test')) - suite.addTest(unittest.makeSuite(ContentDispositionTestCase, 'test')) - suite.addTest(unittest.makeSuite(SafeReprTestCase, 'test')) + suite.addTest(unittest.makeSuite(AtomicFileTestCase)) + suite.addTest(unittest.makeSuite(PathTestCase)) + suite.addTest(unittest.makeSuite(RandomTestCase)) + suite.addTest(unittest.makeSuite(ContentDispositionTestCase)) + suite.addTest(unittest.makeSuite(SafeReprTestCase)) + suite.addTest(unittest.makeSuite(SetuptoolsUtilsTestCase)) + suite.addTest(unittest.makeSuite(LazyTestCase)) suite.addTest(concurrency.suite()) suite.addTest(datefmt.suite()) suite.addTest(presentation.suite()) suite.addTest(doctest.DocTestSuite(util)) suite.addTest(text.suite()) + suite.addTest(translation.suite()) suite.addTest(html.suite()) return suite Modified: bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/concurrency.py URL: http://svn.apache.org/viewvc/bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/concurrency.py?rev=1639823&r1=1639822&r2=1639823&view=diff ============================================================================== --- bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/concurrency.py (original) +++ bloodhound/branches/trac-1.0.2-integration/trac/trac/util/tests/concurrency.py Sat Nov 15 01:14:46 2014 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (C) 2010 Edgewall Software +# Copyright (C) 2010-2013 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which @@ -37,7 +37,7 @@ class ThreadLocalTestCase(unittest.TestC def suite(): suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(ThreadLocalTestCase, 'test')) + suite.addTest(unittest.makeSuite(ThreadLocalTestCase)) return suite if __name__ == '__main__':