# HG changeset patch # User Nicolas VINOT # Date 1318017444 -7200 # Node ID 10d117545a7e837578770fdaff33e8f9b618a02c # Parent 307ec693bdf23a7a15d84f8af60e7dc8e6050095# Parent 4cd5ea76648058ce4bc9705ccc63021d563b1bbf Merge with upstream diff -r 307ec693bdf2 -r 10d117545a7e README.rst --- a/README.rst Fri Oct 07 21:49:28 2011 +0200 +++ b/README.rst Fri Oct 07 21:57:24 2011 +0200 @@ -2,10 +2,11 @@ Welcome to RhodeCode (RhodiumCode) documentation! ================================================= -``RhodeCode`` (formerly hg-app) is a Pylons framework based Mercurial repository +``RhodeCode`` is a Pylons framework based Mercurial repository browser/management tool with a built in push/pull server and full text search. It works on http/https and has a built in permission/authentication system with -the ability to authenticate via LDAP. +the ability to authenticate via LDAP or ActiveDirectory. RhodeCode also supports +simple API so it's easy integrable with existing systems. RhodeCode is similar in some respects to github or bitbucket_, however RhodeCode can be run as standalone hosted application on your own server. diff -r 307ec693bdf2 -r 10d117545a7e docs/changelog.rst --- a/docs/changelog.rst Fri Oct 07 21:49:28 2011 +0200 +++ b/docs/changelog.rst Fri Oct 07 21:57:24 2011 +0200 @@ -3,7 +3,8 @@ Changelog ========= -1.2.0 (**2011-XX-XX**) + +1.3.0 (**XXXX-XX-XX**) ====================== :status: in-progress @@ -12,6 +13,18 @@ news ---- +fixes +----- + + + + +1.2.0 (**2011-10-07**) +====================== + +news +---- + - implemented #47 repository groups - implemented #89 Can setup google analytics code from settings menu - implemented #91 added nicer looking archive urls with more download options diff -r 307ec693bdf2 -r 10d117545a7e docs/images/screenshot1_main_page.png Binary file docs/images/screenshot1_main_page.png has changed diff -r 307ec693bdf2 -r 10d117545a7e docs/images/screenshot2_summary_page.png Binary file docs/images/screenshot2_summary_page.png has changed diff -r 307ec693bdf2 -r 10d117545a7e docs/images/screenshot3_changelog_page.png Binary file docs/images/screenshot3_changelog_page.png has changed diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/__init__.py --- a/rhodecode/__init__.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/__init__.py Fri Oct 07 21:57:24 2011 +0200 @@ -25,9 +25,9 @@ # along with this program. If not, see . import platform -VERSION = (1, 2, 0, 'beta') +VERSION = (1, 3, 0, 'beta') __version__ = '.'.join((str(each) for each in VERSION[:4])) -__dbversion__ = 3 #defines current db version for migrations +__dbversion__ = 4 #defines current db version for migrations __platform__ = platform.system() __license__ = 'GPLv3' diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/api/__init__.py --- a/rhodecode/controllers/api/__init__.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/api/__init__.py Fri Oct 07 21:57:24 2011 +0200 @@ -26,12 +26,12 @@ # MA 02110-1301, USA. import inspect -import json import logging import types import urllib import traceback -from itertools import izip_longest + +from rhodecode.lib.compat import izip_longest, json from paste.response import replace_header @@ -103,7 +103,7 @@ try: json_body = json.loads(urllib.unquote_plus(raw_body)) - except ValueError as e: + except ValueError, e: #catch JSON errors Here return jsonrpc_error(message="JSON parse error ERR:%s RAW:%r" \ % (e, urllib.unquote_plus(raw_body))) @@ -116,14 +116,14 @@ log.debug('method: %s, params: %s', self._req_method, self._req_params) - except KeyError as e: + except KeyError, e: return jsonrpc_error(message='Incorrect JSON query missing %s' % e) #check if we can find this session using api_key try: u = User.get_by_api_key(self._req_api_key) auth_u = AuthUser(u.user_id, self._req_api_key) - except Exception as e: + except Exception, e: return jsonrpc_error(message='Invalid API KEY') self._error = None @@ -138,8 +138,8 @@ arglist = argspec[0][1:] defaults = argspec[3] or [] default_empty = types.NotImplementedType - - kwarglist = list(izip_longest(reversed(arglist),reversed(defaults), + + kwarglist = list(izip_longest(reversed(arglist), reversed(defaults), fillvalue=default_empty)) # this is little trick to inject logged in user for @@ -157,12 +157,12 @@ (self._func.__name__, USER_SESSION_ATTR)) # get our arglist and check if we provided them as args - for arg,default in kwarglist: + for arg, default in kwarglist: if arg == USER_SESSION_ATTR: # USER_SESSION_ATTR is something translated from api key and # this is checked before so we don't need validate it continue - + # skip the required param check if it's default value is # NotImplementedType (default_empty) if not self._req_params or (type(default) == default_empty @@ -201,10 +201,11 @@ raw_response = self._inspect_call(self._func) if isinstance(raw_response, HTTPError): self._error = str(raw_response) - except JSONRPCError as e: + except JSONRPCError, e: self._error = str(e) - except Exception as e: - log.error('Encountered unhandled exception: %s' % traceback.format_exc()) + except Exception, e: + log.error('Encountered unhandled exception: %s' \ + % traceback.format_exc()) json_exc = JSONRPCError('Internal server error') self._error = str(json_exc) diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/branches.py --- a/rhodecode/controllers/branches.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/branches.py Fri Oct 07 21:57:24 2011 +0200 @@ -30,7 +30,7 @@ from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator from rhodecode.lib.base import BaseRepoController, render -from rhodecode.lib.odict import OrderedDict +from rhodecode.lib.compat import OrderedDict from rhodecode.lib import safe_unicode log = logging.getLogger(__name__) diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/changelog.py --- a/rhodecode/controllers/changelog.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/changelog.py Fri Oct 07 21:57:24 2011 +0200 @@ -25,18 +25,13 @@ import logging -try: - import json -except ImportError: - #python 2.5 compatibility - import simplejson as json - from mercurial import graphmod from pylons import request, session, tmpl_context as c from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator from rhodecode.lib.base import BaseRepoController, render from rhodecode.lib.helpers import RepoPage +from rhodecode.lib.compat import json log = logging.getLogger(__name__) diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/changeset.py --- a/rhodecode/controllers/changeset.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/changeset.py Fri Oct 07 21:57:24 2011 +0200 @@ -34,7 +34,7 @@ from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator from rhodecode.lib.base import BaseRepoController, render from rhodecode.lib.utils import EmptyChangeset -from rhodecode.lib.odict import OrderedDict +from rhodecode.lib.compat import OrderedDict from vcs.exceptions import RepositoryError, ChangesetError, \ ChangesetDoesNotExistError diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/files.py --- a/rhodecode/controllers/files.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/files.py Fri Oct 07 21:57:24 2011 +0200 @@ -316,6 +316,13 @@ filename = file_obj.filename content = file_obj.file + #TODO: REMOVE THIS !! + ################################ + import ipdb;ipdb.set_trace() + print 'setting ipdb debuggin for rhodecode.controllers.files.FilesController.add' + ################################ + + node_path = os.path.join(location, filename) author = self.rhodecode_user.full_contact diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/summary.py --- a/rhodecode/controllers/summary.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/summary.py Fri Oct 07 21:57:24 2011 +0200 @@ -39,19 +39,13 @@ from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator from rhodecode.lib.base import BaseRepoController, render from rhodecode.lib.utils import EmptyChangeset -from rhodecode.lib.odict import OrderedDict from rhodecode.lib.celerylib import run_task from rhodecode.lib.celerylib.tasks import get_commits_stats, \ LANGUAGES_EXTENSIONS_MAP from rhodecode.lib.helpers import RepoPage +from rhodecode.lib.compat import json, OrderedDict -try: - import json -except ImportError: - #python 2.5 compatibility - import simplejson as json - log = logging.getLogger(__name__) @@ -139,7 +133,7 @@ lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined - + lang_stats = ((x, {"count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) for x, y in lang_stats_d.items()) @@ -162,7 +156,7 @@ c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True - + c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/controllers/tags.py --- a/rhodecode/controllers/tags.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/controllers/tags.py Fri Oct 07 21:57:24 2011 +0200 @@ -28,7 +28,7 @@ from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator from rhodecode.lib.base import BaseRepoController, render -from rhodecode.lib.odict import OrderedDict +from rhodecode.lib.compat import OrderedDict log = logging.getLogger(__name__) diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/lib/__init__.py --- a/rhodecode/lib/__init__.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/lib/__init__.py Fri Oct 07 21:57:24 2011 +0200 @@ -23,14 +23,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - -try: - import json -except ImportError: - #python 2.5 compatibility - import simplejson as json - - def __get_lem(): from pygments import lexers from string import lower @@ -209,14 +201,14 @@ return unicode_.encode(to_encoding) except UnicodeEncodeError: pass - + try: import chardet encoding = chardet.detect(unicode_)['encoding'] print encoding if encoding is None: raise UnicodeEncodeError() - + return unicode_.encode(encoding) except (ImportError, UnicodeEncodeError): return unicode_.encode(to_encoding, 'replace') @@ -386,4 +378,4 @@ except RepositoryError: from rhodecode.lib.utils import EmptyChangeset cs = EmptyChangeset(requested_revision=rev) - return cs \ No newline at end of file + return cs diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/lib/celerylib/tasks.py --- a/rhodecode/lib/celerylib/tasks.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/lib/celerylib/tasks.py Fri Oct 07 21:57:24 2011 +0200 @@ -43,7 +43,8 @@ from rhodecode.lib.helpers import person from rhodecode.lib.smtp_mailer import SmtpMailer from rhodecode.lib.utils import add_cache -from rhodecode.lib.odict import OrderedDict +from rhodecode.lib.compat import json, OrderedDict + from rhodecode.model import init_model from rhodecode.model import meta from rhodecode.model.db import RhodeCodeUi, Statistics, Repository @@ -54,11 +55,7 @@ add_cache(config) -try: - import json -except ImportError: - #python 2.5 compatibility - import simplejson as json + __all__ = ['whoosh_index', 'get_commits_stats', 'reset_user_password', 'send_email'] diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/lib/compat.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rhodecode/lib/compat.py Fri Oct 07 21:57:24 2011 +0200 @@ -0,0 +1,360 @@ +# -*- coding: utf-8 -*- +""" + rhodecode.lib.compat + ~~~~~~~~~~~~~~~~~~~~ + + Python backward compatibility functions and common libs + + + :created_on: Oct 7, 2011 + :author: marcink + :copyright: (C) 2009-2010 Marcin Kuzminski + :license: GPLv3, see COPYING for more details. +""" +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +#============================================================================== +# json +#============================================================================== +try: + import json +except ImportError: + import simplejson as json + + +#============================================================================== +# izip_longest +#============================================================================== +try: + from itertools import izip_longest +except ImportError: + import itertools + + def izip_longest(*args, **kwds): # noqa + fillvalue = kwds.get("fillvalue") + + def sentinel(counter=([fillvalue] * (len(args) - 1)).pop): + yield counter() # yields the fillvalue, or raises IndexError + + fillers = itertools.repeat(fillvalue) + iters = [itertools.chain(it, sentinel(), fillers) + for it in args] + try: + for tup in itertools.izip(*iters): + yield tup + except IndexError: + pass + + +#============================================================================== +# OrderedDict +#============================================================================== + +# Python Software Foundation License + +# XXX: it feels like using the class with "is" and "is not" instead of "==" and +# "!=" should be faster. +class _Nil(object): + + def __repr__(self): + return "nil" + + def __eq__(self, other): + if (isinstance(other, _Nil)): + return True + else: + return NotImplemented + + def __ne__(self, other): + if (isinstance(other, _Nil)): + return False + else: + return NotImplemented + +_nil = _Nil() + +class _odict(object): + """Ordered dict data structure, with O(1) complexity for dict operations + that modify one element. + + Overwriting values doesn't change their original sequential order. + """ + + def _dict_impl(self): + return None + + def __init__(self, data=(), **kwds): + """This doesn't accept keyword initialization as normal dicts to avoid + a trap - inside a function or method the keyword args are accessible + only as a dict, without a defined order, so their original order is + lost. + """ + if kwds: + raise TypeError("__init__() of ordered dict takes no keyword " + "arguments to avoid an ordering trap.") + self._dict_impl().__init__(self) + # If you give a normal dict, then the order of elements is undefined + if hasattr(data, "iteritems"): + for key, val in data.iteritems(): + self[key] = val + else: + for key, val in data: + self[key] = val + + # Double-linked list header + def _get_lh(self): + dict_impl = self._dict_impl() + if not hasattr(self, '_lh'): + dict_impl.__setattr__(self, '_lh', _nil) + return dict_impl.__getattribute__(self, '_lh') + + def _set_lh(self, val): + self._dict_impl().__setattr__(self, '_lh', val) + + lh = property(_get_lh, _set_lh) + + # Double-linked list tail + def _get_lt(self): + dict_impl = self._dict_impl() + if not hasattr(self, '_lt'): + dict_impl.__setattr__(self, '_lt', _nil) + return dict_impl.__getattribute__(self, '_lt') + + def _set_lt(self, val): + self._dict_impl().__setattr__(self, '_lt', val) + + lt = property(_get_lt, _set_lt) + + def __getitem__(self, key): + return self._dict_impl().__getitem__(self, key)[1] + + def __setitem__(self, key, val): + dict_impl = self._dict_impl() + try: + dict_impl.__getitem__(self, key)[1] = val + except KeyError, e: + new = [dict_impl.__getattribute__(self, 'lt'), val, _nil] + dict_impl.__setitem__(self, key, new) + if dict_impl.__getattribute__(self, 'lt') == _nil: + dict_impl.__setattr__(self, 'lh', key) + else: + dict_impl.__getitem__( + self, dict_impl.__getattribute__(self, 'lt'))[2] = key + dict_impl.__setattr__(self, 'lt', key) + + def __delitem__(self, key): + dict_impl = self._dict_impl() + pred, _ , succ = self._dict_impl().__getitem__(self, key) + if pred == _nil: + dict_impl.__setattr__(self, 'lh', succ) + else: + dict_impl.__getitem__(self, pred)[2] = succ + if succ == _nil: + dict_impl.__setattr__(self, 'lt', pred) + else: + dict_impl.__getitem__(self, succ)[0] = pred + dict_impl.__delitem__(self, key) + + def __contains__(self, key): + return key in self.keys() + + def __len__(self): + return len(self.keys()) + + def __str__(self): + pairs = ("%r: %r" % (k, v) for k, v in self.iteritems()) + return "{%s}" % ", ".join(pairs) + + def __repr__(self): + if self: + pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems()) + return "odict([%s])" % ", ".join(pairs) + else: + return "odict()" + + def get(self, k, x=None): + if k in self: + return self._dict_impl().__getitem__(self, k)[1] + else: + return x + + def __iter__(self): + dict_impl = self._dict_impl() + curr_key = dict_impl.__getattribute__(self, 'lh') + while curr_key != _nil: + yield curr_key + curr_key = dict_impl.__getitem__(self, curr_key)[2] + + iterkeys = __iter__ + + def keys(self): + return list(self.iterkeys()) + + def itervalues(self): + dict_impl = self._dict_impl() + curr_key = dict_impl.__getattribute__(self, 'lh') + while curr_key != _nil: + _, val, curr_key = dict_impl.__getitem__(self, curr_key) + yield val + + def values(self): + return list(self.itervalues()) + + def iteritems(self): + dict_impl = self._dict_impl() + curr_key = dict_impl.__getattribute__(self, 'lh') + while curr_key != _nil: + _, val, next_key = dict_impl.__getitem__(self, curr_key) + yield curr_key, val + curr_key = next_key + + def items(self): + return list(self.iteritems()) + + def sort(self, cmp=None, key=None, reverse=False): + items = [(k, v) for k, v in self.items()] + if cmp is not None: + items = sorted(items, cmp=cmp) + elif key is not None: + items = sorted(items, key=key) + else: + items = sorted(items, key=lambda x: x[1]) + if reverse: + items.reverse() + self.clear() + self.__init__(items) + + def clear(self): + dict_impl = self._dict_impl() + dict_impl.clear(self) + dict_impl.__setattr__(self, 'lh', _nil) + dict_impl.__setattr__(self, 'lt', _nil) + + def copy(self): + return self.__class__(self) + + def update(self, data=(), **kwds): + if kwds: + raise TypeError("update() of ordered dict takes no keyword " + "arguments to avoid an ordering trap.") + if hasattr(data, "iteritems"): + data = data.iteritems() + for key, val in data: + self[key] = val + + def setdefault(self, k, x=None): + try: + return self[k] + except KeyError: + self[k] = x + return x + + def pop(self, k, x=_nil): + try: + val = self[k] + del self[k] + return val + except KeyError: + if x == _nil: + raise + return x + + def popitem(self): + try: + dict_impl = self._dict_impl() + key = dict_impl.__getattribute__(self, 'lt') + return key, self.pop(key) + except KeyError: + raise KeyError("'popitem(): ordered dictionary is empty'") + + def riterkeys(self): + """To iterate on keys in reversed order. + """ + dict_impl = self._dict_impl() + curr_key = dict_impl.__getattribute__(self, 'lt') + while curr_key != _nil: + yield curr_key + curr_key = dict_impl.__getitem__(self, curr_key)[0] + + __reversed__ = riterkeys + + def rkeys(self): + """List of the keys in reversed order. + """ + return list(self.riterkeys()) + + def ritervalues(self): + """To iterate on values in reversed order. + """ + dict_impl = self._dict_impl() + curr_key = dict_impl.__getattribute__(self, 'lt') + while curr_key != _nil: + curr_key, val, _ = dict_impl.__getitem__(self, curr_key) + yield val + + def rvalues(self): + """List of the values in reversed order. + """ + return list(self.ritervalues()) + + def riteritems(self): + """To iterate on (key, value) in reversed order. + """ + dict_impl = self._dict_impl() + curr_key = dict_impl.__getattribute__(self, 'lt') + while curr_key != _nil: + pred_key, val, _ = dict_impl.__getitem__(self, curr_key) + yield curr_key, val + curr_key = pred_key + + def ritems(self): + """List of the (key, value) in reversed order. + """ + return list(self.riteritems()) + + def firstkey(self): + if self: + return self._dict_impl().__getattribute__(self, 'lh') + else: + raise KeyError("'firstkey(): ordered dictionary is empty'") + + def lastkey(self): + if self: + return self._dict_impl().__getattribute__(self, 'lt') + else: + raise KeyError("'lastkey(): ordered dictionary is empty'") + + def as_dict(self): + return self._dict_impl()(self.items()) + + def _repr(self): + """_repr(): low level repr of the whole data contained in the odict. + Useful for debugging. + """ + dict_impl = self._dict_impl() + form = "odict low level repr lh,lt,data: %r, %r, %s" + return form % (dict_impl.__getattribute__(self, 'lh'), + dict_impl.__getattribute__(self, 'lt'), + dict_impl.__repr__(self)) + +class OrderedDict(_odict, dict): + + def _dict_impl(self): + return dict + + +#============================================================================== +# OrderedSet +#============================================================================== +from sqlalchemy.util import OrderedSet diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/lib/odict.py --- a/rhodecode/lib/odict.py Fri Oct 07 21:49:28 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -# Python Software Foundation License - -# XXX: it feels like using the class with "is" and "is not" instead of "==" and -# "!=" should be faster. -class _Nil(object): - - def __repr__(self): - return "nil" - - def __eq__(self, other): - if (isinstance(other, _Nil)): - return True - else: - return NotImplemented - - def __ne__(self, other): - if (isinstance(other, _Nil)): - return False - else: - return NotImplemented - -_nil = _Nil() - -class _odict(object): - """Ordered dict data structure, with O(1) complexity for dict operations - that modify one element. - - Overwriting values doesn't change their original sequential order. - """ - - def _dict_impl(self): - return None - - def __init__(self, data=(), **kwds): - """This doesn't accept keyword initialization as normal dicts to avoid - a trap - inside a function or method the keyword args are accessible - only as a dict, without a defined order, so their original order is - lost. - """ - if kwds: - raise TypeError("__init__() of ordered dict takes no keyword " - "arguments to avoid an ordering trap.") - self._dict_impl().__init__(self) - # If you give a normal dict, then the order of elements is undefined - if hasattr(data, "iteritems"): - for key, val in data.iteritems(): - self[key] = val - else: - for key, val in data: - self[key] = val - - # Double-linked list header - def _get_lh(self): - dict_impl = self._dict_impl() - if not hasattr(self, '_lh'): - dict_impl.__setattr__(self, '_lh', _nil) - return dict_impl.__getattribute__(self, '_lh') - - def _set_lh(self, val): - self._dict_impl().__setattr__(self, '_lh', val) - - lh = property(_get_lh, _set_lh) - - # Double-linked list tail - def _get_lt(self): - dict_impl = self._dict_impl() - if not hasattr(self, '_lt'): - dict_impl.__setattr__(self, '_lt', _nil) - return dict_impl.__getattribute__(self, '_lt') - - def _set_lt(self, val): - self._dict_impl().__setattr__(self, '_lt', val) - - lt = property(_get_lt, _set_lt) - - def __getitem__(self, key): - return self._dict_impl().__getitem__(self, key)[1] - - def __setitem__(self, key, val): - dict_impl = self._dict_impl() - try: - dict_impl.__getitem__(self, key)[1] = val - except KeyError, e: - new = [dict_impl.__getattribute__(self, 'lt'), val, _nil] - dict_impl.__setitem__(self, key, new) - if dict_impl.__getattribute__(self, 'lt') == _nil: - dict_impl.__setattr__(self, 'lh', key) - else: - dict_impl.__getitem__( - self, dict_impl.__getattribute__(self, 'lt'))[2] = key - dict_impl.__setattr__(self, 'lt', key) - - def __delitem__(self, key): - dict_impl = self._dict_impl() - pred, _ , succ = self._dict_impl().__getitem__(self, key) - if pred == _nil: - dict_impl.__setattr__(self, 'lh', succ) - else: - dict_impl.__getitem__(self, pred)[2] = succ - if succ == _nil: - dict_impl.__setattr__(self, 'lt', pred) - else: - dict_impl.__getitem__(self, succ)[0] = pred - dict_impl.__delitem__(self, key) - - def __contains__(self, key): - return key in self.keys() - - def __len__(self): - return len(self.keys()) - - def __str__(self): - pairs = ("%r: %r" % (k, v) for k, v in self.iteritems()) - return "{%s}" % ", ".join(pairs) - - def __repr__(self): - if self: - pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems()) - return "odict([%s])" % ", ".join(pairs) - else: - return "odict()" - - def get(self, k, x=None): - if k in self: - return self._dict_impl().__getitem__(self, k)[1] - else: - return x - - def __iter__(self): - dict_impl = self._dict_impl() - curr_key = dict_impl.__getattribute__(self, 'lh') - while curr_key != _nil: - yield curr_key - curr_key = dict_impl.__getitem__(self, curr_key)[2] - - iterkeys = __iter__ - - def keys(self): - return list(self.iterkeys()) - - def itervalues(self): - dict_impl = self._dict_impl() - curr_key = dict_impl.__getattribute__(self, 'lh') - while curr_key != _nil: - _, val, curr_key = dict_impl.__getitem__(self, curr_key) - yield val - - def values(self): - return list(self.itervalues()) - - def iteritems(self): - dict_impl = self._dict_impl() - curr_key = dict_impl.__getattribute__(self, 'lh') - while curr_key != _nil: - _, val, next_key = dict_impl.__getitem__(self, curr_key) - yield curr_key, val - curr_key = next_key - - def items(self): - return list(self.iteritems()) - - def sort(self, cmp=None, key=None, reverse=False): - items = [(k, v) for k, v in self.items()] - if cmp is not None: - items = sorted(items, cmp=cmp) - elif key is not None: - items = sorted(items, key=key) - else: - items = sorted(items, key=lambda x: x[1]) - if reverse: - items.reverse() - self.clear() - self.__init__(items) - - def clear(self): - dict_impl = self._dict_impl() - dict_impl.clear(self) - dict_impl.__setattr__(self, 'lh', _nil) - dict_impl.__setattr__(self, 'lt', _nil) - - def copy(self): - return self.__class__(self) - - def update(self, data=(), **kwds): - if kwds: - raise TypeError("update() of ordered dict takes no keyword " - "arguments to avoid an ordering trap.") - if hasattr(data, "iteritems"): - data = data.iteritems() - for key, val in data: - self[key] = val - - def setdefault(self, k, x=None): - try: - return self[k] - except KeyError: - self[k] = x - return x - - def pop(self, k, x=_nil): - try: - val = self[k] - del self[k] - return val - except KeyError: - if x == _nil: - raise - return x - - def popitem(self): - try: - dict_impl = self._dict_impl() - key = dict_impl.__getattribute__(self, 'lt') - return key, self.pop(key) - except KeyError: - raise KeyError("'popitem(): ordered dictionary is empty'") - - def riterkeys(self): - """To iterate on keys in reversed order. - """ - dict_impl = self._dict_impl() - curr_key = dict_impl.__getattribute__(self, 'lt') - while curr_key != _nil: - yield curr_key - curr_key = dict_impl.__getitem__(self, curr_key)[0] - - __reversed__ = riterkeys - - def rkeys(self): - """List of the keys in reversed order. - """ - return list(self.riterkeys()) - - def ritervalues(self): - """To iterate on values in reversed order. - """ - dict_impl = self._dict_impl() - curr_key = dict_impl.__getattribute__(self, 'lt') - while curr_key != _nil: - curr_key, val, _ = dict_impl.__getitem__(self, curr_key) - yield val - - def rvalues(self): - """List of the values in reversed order. - """ - return list(self.ritervalues()) - - def riteritems(self): - """To iterate on (key, value) in reversed order. - """ - dict_impl = self._dict_impl() - curr_key = dict_impl.__getattribute__(self, 'lt') - while curr_key != _nil: - pred_key, val, _ = dict_impl.__getitem__(self, curr_key) - yield curr_key, val - curr_key = pred_key - - def ritems(self): - """List of the (key, value) in reversed order. - """ - return list(self.riteritems()) - - def firstkey(self): - if self: - return self._dict_impl().__getattribute__(self, 'lh') - else: - raise KeyError("'firstkey(): ordered dictionary is empty'") - - def lastkey(self): - if self: - return self._dict_impl().__getattribute__(self, 'lt') - else: - raise KeyError("'lastkey(): ordered dictionary is empty'") - - def as_dict(self): - return self._dict_impl()(self.items()) - - def _repr(self): - """_repr(): low level repr of the whole data contained in the odict. - Useful for debugging. - """ - dict_impl = self._dict_impl() - form = "odict low level repr lh,lt,data: %r, %r, %s" - return form % (dict_impl.__getattribute__(self, 'lh'), - dict_impl.__getattribute__(self, 'lt'), - dict_impl.__repr__(self)) - -class OrderedDict(_odict, dict): - - def _dict_impl(self): - return dict diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/lib/oset.py --- a/rhodecode/lib/oset.py Fri Oct 07 21:49:28 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -KEY, PREV, NEXT = range(3) -import collections - -class OrderedSet(collections.MutableSet): - - def __init__(self, iterable=None): - self.end = end = [] - end += [None, end, end] # sentinel node for doubly linked list - self.map = {} # key --> [key, prev, next] - if iterable is not None: - self |= iterable - - def __len__(self): - return len(self.map) - - def __contains__(self, key): - return key in self.map - - def add(self, key): - if key not in self.map: - end = self.end - curr = end[PREV] - curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end] - - def discard(self, key): - if key in self.map: - key, prev, next = self.map.pop(key) - prev[NEXT] = next - next[PREV] = prev - - def __iter__(self): - end = self.end - curr = end[NEXT] - while curr is not end: - yield curr[KEY] - curr = curr[NEXT] - - def __reversed__(self): - end = self.end - curr = end[PREV] - while curr is not end: - yield curr[KEY] - curr = curr[PREV] - - def pop(self, last=True): - if not self: - raise KeyError('set is empty') - key = next(reversed(self)) if last else next(iter(self)) - self.discard(key) - return key - - def __repr__(self): - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, list(self)) - - def __eq__(self, other): - if isinstance(other, OrderedSet): - return len(self) == len(other) and list(self) == list(other) - return set(self) == set(other) - - def __del__(self): - self.clear() # remove circular references - diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/model/db.py --- a/rhodecode/model/db.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/model/db.py Fri Oct 07 21:57:24 2011 +0200 @@ -41,9 +41,10 @@ from vcs.exceptions import VCSError from vcs.utils.lazy import LazyProperty +from rhodecode.lib import str2bool, safe_str, get_changeset_safe,\ + generate_api_key from rhodecode.lib.exceptions import UsersGroupsAssignedException -from rhodecode.lib import str2bool, json, safe_str, get_changeset_safe, \ - generate_api_key +from rhodecode.lib.compat import json from rhodecode.model.meta import Base, Session from rhodecode.model.caching_query import FromCache diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/model/forms.py --- a/rhodecode/model/forms.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/model/forms.py Fri Oct 07 21:57:24 2011 +0200 @@ -283,6 +283,19 @@ def ValidForkName(): class _ValidForkName(formencode.validators.FancyValidator): def to_python(self, value, state): + + repo_name = value.get('fork_name') + + slug = repo_name_slug(repo_name) + if slug in ['_admin', '']: + e_dict = {'repo_name': _('This repository name is disallowed')} + raise formencode.Invalid('', value, state, error_dict=e_dict) + + if RepoModel().get_by_repo_name(repo_name): + e_dict = {'fork_name':_('This repository ' + 'already exists')} + raise formencode.Invalid('', value, state, + error_dict=e_dict) return value return _ValidForkName diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/model/repo.py --- a/rhodecode/model/repo.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/model/repo.py Fri Oct 07 21:57:24 2011 +0200 @@ -192,6 +192,9 @@ if k == 'repo_group': k = 'group_id' + if k == 'description': + v = v or repo_name + setattr(new_repo, k, v) if fork: @@ -302,7 +305,7 @@ :param clone_uri: """ from rhodecode.lib.utils import is_valid_repo - + if new_parent_id: paths = Group.get(new_parent_id).full_path.split(Group.url_sep()) new_parent_path = os.sep.join(paths) diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/model/user.py --- a/rhodecode/model/user.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/model/user.py Fri Oct 07 21:57:24 2011 +0200 @@ -28,6 +28,7 @@ from pylons.i18n.translation import _ +from rhodecode.lib import safe_unicode from rhodecode.model import BaseModel from rhodecode.model.caching_query import FromCache from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \ @@ -111,7 +112,7 @@ new_user.api_key = generate_api_key(username) new_user.email = attrs['email'] new_user.active = True - new_user.ldap_dn = user_dn + new_user.ldap_dn = safe_unicode(user_dn) new_user.name = attrs['name'] new_user.lastname = attrs['lastname'] diff -r 307ec693bdf2 -r 10d117545a7e rhodecode/tests/rhodecode_crawler.py --- a/rhodecode/tests/rhodecode_crawler.py Fri Oct 07 21:49:28 2011 +0200 +++ b/rhodecode/tests/rhodecode_crawler.py Fri Oct 07 21:57:24 2011 +0200 @@ -102,7 +102,7 @@ repo = vcs.get_repo(jn(PROJECT_PATH, PROJECT)) - from rhodecode.lib.oset import OrderedSet + from rhodecode.lib.compat import OrderedSet paths_ = OrderedSet(['']) try: diff -r 307ec693bdf2 -r 10d117545a7e setup.py --- a/setup.py Fri Oct 07 21:49:28 2011 +0200 +++ b/setup.py Fri Oct 07 21:57:24 2011 +0200 @@ -23,12 +23,12 @@ "python-dateutil>=1.5.0,<2.0.0", "dulwich>=0.8.0", "vcs>=0.2.1.dev", - "webob==1.0.8" + "webob==1.0.8" ] dependency_links = [ - "https://secure.rhodecode.org/vcs/archive/default.zip#egg=vcs-0.2.1.dev", - "https://bitbucket.org/marcinkuzminski/vcs/get/default.zip#egg=vcs-0.2.1.dev", + "https://secure.rhodecode.org/vcs/archive/default.zip#egg=vcs-0.2.2.dev", + "https://bitbucket.org/marcinkuzminski/vcs/get/default.zip#egg=vcs-0.2.2.dev", ] classifiers = ['Development Status :: 4 - Beta',