Mercurial > kallithea
changeset 1136:93b980ebee55
changes for release 1.1.5
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Thu, 17 Mar 2011 01:13:48 +0100 |
parents | 3cdacd152b24 |
children | 49032f99b4ab |
files | README.rst docs/changelog.rst docs/contributing.rst docs/index.rst docs/installation.rst docs/setup.rst docs/upgrade.rst rhodecode/__init__.py rhodecode/config/deployment.ini_tmpl rhodecode/controllers/admin/settings.py rhodecode/controllers/files.py rhodecode/controllers/home.py rhodecode/controllers/journal.py rhodecode/lib/__init__.py rhodecode/lib/auth.py rhodecode/lib/auth_ldap.py rhodecode/lib/db_manage.py rhodecode/lib/helpers.py rhodecode/model/db.py rhodecode/model/meta.py rhodecode/model/scm.py setup.py |
diffstat | 22 files changed, 371 insertions(+), 235 deletions(-) [+] |
line wrap: on
line diff
--- a/README.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/README.rst Thu Mar 17 01:13:48 2011 +0100 @@ -8,19 +8,19 @@ It works on http/https and has a built in permission/authentication system with the ability to authenticate via LDAP. -RhodeCode is similar in some respects to github or bitbucket, -however RhodeCode can be run as standalone hosted application on your own server. It is open source -and donation ware and focuses more on providing a customized, self administered -interface for Mercurial(and soon GIT) repositories. RhodeCode is powered by a vcs_ -library that Lukasz Balcerzak and I created to handle multiple different version -control systems. +RhodeCode is similar in some respects to github or bitbucket_, +however RhodeCode can be run as standalone hosted application on your own server. +It is open source and donation ware and focuses more on providing a customized, +self administered interface for Mercurial(and soon GIT) repositories. +RhodeCode is powered by a vcs_ library that Lukasz Balcerzak and I created to +handle multiple different version control systems. RhodeCode uses `Semantic Versioning <http://semver.org/>`_ RhodeCode demo -------------- -http://hg.python-works.com +http://demo.rhodecode.org The default access is anonymous but you can login to an administrative account using the following credentials: @@ -31,8 +31,8 @@ Source code ----------- -The latest source for RhodeCode can be obtained from my own RhodeCode instance -https://rhodecode.org +The latest source for RhodeCode can be obtained from official RhodeCode instance +https://hg.rhodecode.org Rarely updated source code and issue tracker is available at bitbcuket http://bitbucket.org/marcinkuzminski/rhodecode @@ -123,6 +123,7 @@ .. _python: http://www.python.org/ .. _django: http://www.djangoproject.com/ .. _mercurial: http://mercurial.selenic.com/ +.. _bitbucket: http://bitbucket.org/ .. _subversion: http://subversion.tigris.org/ .. _git: http://git-scm.com/ .. _celery: http://celeryproject.org/
--- a/docs/changelog.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/docs/changelog.rst Thu Mar 17 01:13:48 2011 +0100 @@ -3,6 +3,28 @@ Changelog ========= + +1.1.5 (**2011-03-1X**) +====================== + +news +---- + +- basic windows support, by exchanging pybcrypt into sha256 for windows only + highly inspired by idea of mantis406 + +fixes +----- + +- fixed sorting by author in main page +- fixed crashes with diffs on binary files +- fixed #131 problem with boolean values for LDAP +- fixed #122 mysql problems thanks to striker69 +- fixed problem with errors on calling raw/raw_files/annotate functions + with unknown revisions +- fixed returned rawfiles attachment names with international character +- cleaned out docs, big thanks to Jason Harris + 1.1.4 (**2011-02-19**) ======================
--- a/docs/contributing.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/docs/contributing.rst Thu Mar 17 01:13:48 2011 +0100 @@ -7,13 +7,19 @@ greatly appreciated! Could I request that you make your source contributions by first forking the -RhodeCode repository on bitbucket +RhodeCode repository on bitbucket_ https://bitbucket.org/marcinkuzminski/rhodecode and then make your changes to -your forked repository. Finally, when you are finished making a change, please -send me a pull request. +your forked repository. Please post all fixes into **BETA** branch since your +fix might be already fixed there and i try to merge all fixes from beta into +stable, and not the other way. Finally, when you are finished making a change, +please send me a pull request. To run RhodeCode in a development version you always need to install the tip version of RhodeCode and the VCS library. | Thank you for any contributions! -| Marcin \ No newline at end of file +| Marcin + + + +.. _bitbucket: http://bitbucket.org/
--- a/docs/index.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/docs/index.rst Thu Mar 17 01:13:48 2011 +0100 @@ -48,6 +48,7 @@ .. _python: http://www.python.org/ .. _django: http://www.djangoproject.com/ .. _mercurial: http://mercurial.selenic.com/ +.. _bitbucket: http://bitbucket.org/ .. _subversion: http://subversion.tigris.org/ .. _git: http://git-scm.com/ .. _celery: http://celeryproject.org/
--- a/docs/installation.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/docs/installation.rst Thu Mar 17 01:13:48 2011 +0100 @@ -9,12 +9,13 @@ recommended one is rabbitmq_ to make the async tasks work. Of course RhodeCode works in sync mode also and then you do not have to install -any third party applications. However, using Celery_ will give you a large speed improvement when using -many big repositories. If you plan to use RhodeCode for say 7 to 10 small repositories, RhodeCode -will perform perfectly well without celery running. +any third party applications. However, using Celery_ will give you a large +speed improvement when using many big repositories. If you plan to use +RhodeCode for say 7 to 10 small repositories, RhodeCode will perform perfectly +well without celery running. -If you make the decision to run RhodeCode with celery make sure you run celeryd using paster -and message broker together with the application. +If you make the decision to run RhodeCode with celery make sure you run +celeryd using paster and message broker together with the application. Installing RhodeCode from Cheese Shop -------------------------------------
--- a/docs/setup.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/docs/setup.rst Thu Mar 17 01:13:48 2011 +0100 @@ -348,19 +348,19 @@ double check the root path for your http setup. It should point to for example: /home/my-virtual-python/lib/python2.6/site-packages/rhodecode/public - -| + +| :Q: **Can't install celery/rabbitmq** :A: Don't worry RhodeCode works without them too. No extra setup is required. | - + :Q: **Long lasting push timeouts?** :A: Make sure you set a longer timeouts in your proxy/fcgi settings, timeouts are caused by https server and not RhodeCode. - -| + +| :Q: **Large pushes timeouts?** :A: Make sure you set a proper max_body_size for the http server.
--- a/docs/upgrade.rst Sun Feb 27 00:35:11 2011 +0100 +++ b/docs/upgrade.rst Thu Mar 17 01:13:48 2011 +0100 @@ -7,7 +7,8 @@ -------------------------- .. note:: - Firstly, it is recommended that you **always** perform a database backup before doing an upgrade. + Firstly, it is recommended that you **always** perform a database backup + before doing an upgrade. The easiest way to upgrade ``rhodecode`` is to run:: @@ -24,15 +25,16 @@ This will display any changes made by the new version of RhodeCode to your current configuration. It will try to perform an automerge. It's always better -to make a backup of your configuration file before hand and recheck the content after the automerge. +to make a backup of your configuration file before hand and recheck the +content after the automerge. .. note:: The next steps only apply to upgrading from non bugfix releases eg. from any minor or major releases. Bugfix releases (eg. 1.1.2->1.1.3) will not have any database schema changes or whoosh library updates. -It is also recommended that you rebuild the whoosh index after upgrading since the new whoosh -version could introduce some incompatible index changes. +It is also recommended that you rebuild the whoosh index after upgrading since +the new whoosh version could introduce some incompatible index changes. The final step is to upgrade the database. To do this simply run:: @@ -40,8 +42,8 @@ paster upgrade-db production.ini This will upgrade the schema and update some of the defaults in the database, -and will always recheck the settings of the application, if there are no new options -that need to be set. +and will always recheck the settings of the application, if there are no new +options that need to be set. .. _virtualenv: http://pypi.python.org/pypi/virtualenv
--- a/rhodecode/__init__.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/__init__.py Thu Mar 17 01:13:48 2011 +0100 @@ -25,11 +25,12 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. - +import platform -VERSION = (1, 1, 4) +VERSION = (1, 1, 5) __version__ = '.'.join((str(each) for each in VERSION[:4])) __dbversion__ = 2 #defines current db version for migrations +__platform__ = platform.system() try: from rhodecode.lib.utils import get_current_revision
--- a/rhodecode/config/deployment.ini_tmpl Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/config/deployment.ini_tmpl Thu Mar 17 01:13:48 2011 +0100 @@ -71,7 +71,7 @@ celeryd.concurrency = 2 #celeryd.log.file = celeryd.log celeryd.log.level = debug -celeryd.max.tasks.per.child = 3 +celeryd.max.tasks.per.child = 1 #tasks will never be sent to the queue, but executed locally instead. celery.always.eager = false
--- a/rhodecode/controllers/admin/settings.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/controllers/admin/settings.py Thu Mar 17 01:13:48 2011 +0100 @@ -140,8 +140,8 @@ except: log.error(traceback.format_exc()) - h.flash(_('error occurred during updating application settings'), - category='error') + h.flash(_('error occurred during updating' + ' application settings'), category='error') self.sa.rollback()
--- a/rhodecode/controllers/files.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/controllers/files.py Thu Mar 17 01:13:48 2011 +0100 @@ -7,7 +7,7 @@ :created_on: Apr 21, 2010 :author: marcink - :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> + :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> :license: GPLv3, see COPYING for more details. """ # This program is free software; you can redistribute it and/or @@ -55,9 +55,30 @@ super(FilesController, self).__before__() c.cut_off_limit = self.cut_off_limit + def __get_cs_or_redirect(self, rev, repo_name): + """ + Safe way to get changeset if error occur it redirects to tip with + proper message + + :param rev: revision to fetch + :param repo_name: repo name to redirect after + """ + + _repo = ScmModel().get_repo(c.repo_name) + try: + return _repo.get_changeset(rev) + except EmptyRepositoryError, e: + h.flash(_('There are no files yet'), category='warning') + redirect(h.url('summary_home', repo_name=repo_name)) + + except RepositoryError, e: + h.flash(str(e), category='warning') + redirect(h.url('files_home', repo_name=repo_name, revision='tip')) + def index(self, repo_name, revision, f_path): - hg_model = ScmModel() - c.repo = hg_model.get_repo(c.repo_name) + cs = self.__get_cs_or_redirect(revision, repo_name) + c.repo = ScmModel().get_repo(c.repo_name) + revision = request.POST.get('at_rev', None) or revision def get_next_rev(cur): @@ -72,68 +93,64 @@ return r c.f_path = f_path + c.changeset = cs + cur_rev = c.changeset.revision + prev_rev = c.repo.get_changeset(get_prev_rev(cur_rev)).raw_id + next_rev = c.repo.get_changeset(get_next_rev(cur_rev)).raw_id + c.url_prev = url('files_home', repo_name=c.repo_name, + revision=prev_rev, f_path=f_path) + c.url_next = url('files_home', repo_name=c.repo_name, + revision=next_rev, f_path=f_path) try: - c.changeset = c.repo.get_changeset(revision) - cur_rev = c.changeset.revision - prev_rev = c.repo.get_changeset(get_prev_rev(cur_rev)).raw_id - next_rev = c.repo.get_changeset(get_next_rev(cur_rev)).raw_id - - c.url_prev = url('files_home', repo_name=c.repo_name, - revision=prev_rev, f_path=f_path) - c.url_next = url('files_home', repo_name=c.repo_name, - revision=next_rev, f_path=f_path) - - try: - c.files_list = c.changeset.get_node(f_path) - c.file_history = self._get_history(c.repo, c.files_list, f_path) - except RepositoryError, e: - h.flash(str(e), category='warning') - redirect(h.url('files_home', repo_name=repo_name, revision=revision)) - - except EmptyRepositoryError, e: - h.flash(_('There are no files yet'), category='warning') - redirect(h.url('summary_home', repo_name=repo_name)) - + c.files_list = c.changeset.get_node(f_path) + c.file_history = self._get_history(c.repo, c.files_list, f_path) except RepositoryError, e: h.flash(str(e), category='warning') - redirect(h.url('files_home', repo_name=repo_name, revision='tip')) - + redirect(h.url('files_home', repo_name=repo_name, + revision=revision)) return render('files/files.html') def rawfile(self, repo_name, revision, f_path): - hg_model = ScmModel() - c.repo = hg_model.get_repo(c.repo_name) - file_node = c.repo.get_changeset(revision).get_node(f_path) + cs = self.__get_cs_or_redirect(revision, repo_name) + try: + file_node = cs.get_node(f_path) + except RepositoryError, e: + h.flash(str(e), category='warning') + redirect(h.url('files_home', repo_name=repo_name, + revision=cs.raw_id)) + + fname = f_path.split('/')[-1].encode('utf8', 'replace') + + response.content_disposition = 'attachment; filename=%s' % fname response.content_type = file_node.mimetype - response.content_disposition = 'attachment; filename=%s' \ - % f_path.split('/')[-1] return file_node.content def raw(self, repo_name, revision, f_path): - hg_model = ScmModel() - c.repo = hg_model.get_repo(c.repo_name) - file_node = c.repo.get_changeset(revision).get_node(f_path) + cs = self.__get_cs_or_redirect(revision, repo_name) + try: + file_node = cs.get_node(f_path) + except RepositoryError, e: + h.flash(str(e), category='warning') + redirect(h.url('files_home', repo_name=repo_name, + revision=cs.raw_id)) + response.content_type = 'text/plain' - return file_node.content def annotate(self, repo_name, revision, f_path): - hg_model = ScmModel() - c.repo = hg_model.get_repo(c.repo_name) - + cs = self.__get_cs_or_redirect(revision, repo_name) try: - c.cs = c.repo.get_changeset(revision) - c.file = c.cs.get_node(f_path) + c.file = cs.get_node(f_path) except RepositoryError, e: h.flash(str(e), category='warning') - redirect(h.url('files_home', repo_name=repo_name, revision=revision)) + redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id)) - c.file_history = self._get_history(c.repo, c.file, f_path) - + c.file_history = self._get_history(ScmModel().get_repo(c.repo_name), c.file, f_path) + c.cs = cs c.f_path = f_path return render('files/files_annotate.html') @@ -201,25 +218,34 @@ response.content_type = 'text/plain' response.content_disposition = 'attachment; filename=%s' \ % diff_name + if node1.is_binary or node2.is_binary: + return _('binary file changed') return diff.raw_diff() elif c.action == 'raw': response.content_type = 'text/plain' + if node1.is_binary or node2.is_binary: + return _('binary file changed') return diff.raw_diff() elif c.action == 'diff': if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit: c.cur_diff = _('Diff is to big to display') + elif node1.is_binary or node2.is_binary: + c.cur_diff = _('Binary file') else: c.cur_diff = diff.as_html() else: #default option if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit: c.cur_diff = _('Diff is to big to display') + elif node1.is_binary or node2.is_binary: + c.cur_diff = _('Binary file') else: c.cur_diff = diff.as_html() - if not c.cur_diff: c.no_changes = True + if not c.cur_diff: + c.no_changes = True return render('files/file_diff.html') def _get_history(self, repo, node, f_path): @@ -250,9 +276,3 @@ hist_l.append(tags_group) return hist_l - -# [ -# ([("u1", "User1"), ("u2", "User2")], "Users"), -# ([("g1", "Group1"), ("g2", "Group2")], "Groups") -# ] -
--- a/rhodecode/controllers/home.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/controllers/home.py Thu Mar 17 01:13:48 2011 +0100 @@ -43,7 +43,7 @@ super(HomeController, self).__before__() def index(self): - sortables = ['name', 'description', 'last_change', 'tip', 'contact'] + sortables = ['name', 'description', 'last_change', 'tip', 'owner'] current_sort = request.GET.get('sort', 'name') current_sort_slug = current_sort.replace('-', '')
--- a/rhodecode/controllers/journal.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/controllers/journal.py Thu Mar 17 01:13:48 2011 +0100 @@ -26,9 +26,12 @@ # MA 02110-1301, USA. import logging -from sqlalchemy import or_ +import traceback from pylons import request, response, session, tmpl_context as c, url +from paste.httpexceptions import HTTPInternalServerError, HTTPBadRequest + +from sqlalchemy import or_ from rhodecode.lib.auth import LoginRequired, NotAnonymous from rhodecode.lib.base import BaseController, render @@ -36,8 +39,6 @@ from rhodecode.model.db import UserLog, UserFollowing from rhodecode.model.scm import ScmModel -from paste.httpexceptions import HTTPInternalServerError - log = logging.getLogger(__name__) class JournalController(BaseController): @@ -81,6 +82,7 @@ c.rhodecode_user.user_id) return 'ok' except: + log.error(traceback.format_exc()) raise HTTPInternalServerError() repo_id = request.POST.get('follows_repo_id') @@ -90,8 +92,9 @@ c.rhodecode_user.user_id) return 'ok' except: + log.error(traceback.format_exc()) raise HTTPInternalServerError() - raise HTTPInternalServerError() + raise HTTPBadRequest()
--- a/rhodecode/lib/__init__.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/lib/__init__.py Thu Mar 17 01:13:48 2011 +0100 @@ -26,4 +26,21 @@ # MA 02110-1301, USA. def str2bool(v): - return v.lower() in ["yes", "true", "t", "1"] if v else None + if isinstance(v, (str, unicode)): + obj = v.strip().lower() + if obj in ['true', 'yes', 'on', 'y', 't', '1']: + return True + elif obj in ['false', 'no', 'off', 'n', 'f', '0']: + return False + else: + raise ValueError("String is not true/false: %r" % obj) + return bool(obj) + +def generate_api_key(username, salt=None): + from tempfile import _RandomNameSequence + import hashlib + + if salt is None: + salt = _RandomNameSequence().next() + + return hashlib.sha1(username + salt).hexdigest()
--- a/rhodecode/lib/auth.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/lib/auth.py Thu Mar 17 01:13:48 2011 +0100 @@ -1,8 +1,14 @@ -#!/usr/bin/env python -# encoding: utf-8 -# authentication and permission libraries -# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> -# +# -*- coding: utf-8 -*- +""" + rhodecode.lib.auth + ~~~~~~~~~~~~~~~~~~ + + authentication and permission libraries + + :created_on: Apr 4, 2010 + :copyright: (c) 2010 by marcink. + :license: LICENSE_NAME, see LICENSE_FILE 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; version 2 @@ -17,26 +23,34 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. -""" -Created on April 4, 2010 -@author: marcink -""" +import random +import logging +import traceback + +from decorator import decorator + from pylons import config, session, url, request from pylons.controllers.util import abort, redirect -from rhodecode.lib.exceptions import * +from pylons.i18n.translation import _ + +from rhodecode import __platform__ + +if __platform__ == 'Windows': + from hashlib import sha256 +if __platform__ in ('Linux', 'Darwin'): + import bcrypt + +from rhodecode.lib import str2bool +from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError from rhodecode.lib.utils import get_repo_slug from rhodecode.lib.auth_ldap import AuthLdap + from rhodecode.model import meta from rhodecode.model.user import UserModel -from rhodecode.model.caching_query import FromCache -from rhodecode.model.db import User, RepoToPerm, Repository, Permission, \ - UserToPerm -import bcrypt -from decorator import decorator -import logging -import random -import traceback +from rhodecode.model.db import Permission, RepoToPerm, Repository, \ + User, UserToPerm + log = logging.getLogger(__name__) @@ -65,15 +79,46 @@ self.passwd = ''.join([random.choice(type) for _ in xrange(len)]) return self.passwd +class RhodeCodeCrypto(object): + + @classmethod + def hash_string(cls, str_): + """ + Cryptographic function used for password hashing based on pybcrypt + or pycrypto in windows + + :param password: password to hash + """ + if __platform__ == 'Windows': + return sha256(str_).hexdigest() + elif __platform__ in ('Linux', 'Darwin'): + return bcrypt.hashpw(str_, bcrypt.gensalt(10)) + else: + raise Exception('Unknown or unsupported platform %s' % __platform__) + + @classmethod + def hash_check(cls, password, hashed): + """ + Checks matching password with it's hashed value, runs different + implementation based on platform it runs on + + :param password: password + :param hashed: password in hashed form + """ + + if __platform__ == 'Windows': + return sha256(password).hexdigest() == hashed + elif __platform__ in ('Linux', 'Darwin'): + return bcrypt.hashpw(password, hashed) == hashed + else: + raise Exception('Unknown or unsupported platform %s' % __platform__) + def get_crypt_password(password): - """Cryptographic function used for password hashing based on sha1 - :param password: password to hash - """ - return bcrypt.hashpw(password, bcrypt.gensalt(10)) + return RhodeCodeCrypto.hash_string(password) def check_password(password, hashed): - return bcrypt.hashpw(password, hashed) == hashed + return RhodeCodeCrypto.hash_check(password, hashed) def authfunc(environ, username, password): """ @@ -126,7 +171,7 @@ #====================================================================== # FALLBACK TO LDAP AUTH IN ENABLE #====================================================================== - if ldap_settings.get('ldap_active', False): + if str2bool(ldap_settings.get('ldap_active')): log.debug("Authenticating user using ldap") kwargs = { 'server':ldap_settings.get('ldap_host', ''), @@ -134,7 +179,7 @@ 'port':ldap_settings.get('ldap_port'), 'bind_dn':ldap_settings.get('ldap_dn_user'), 'bind_pass':ldap_settings.get('ldap_dn_pass'), - 'use_ldaps':ldap_settings.get('ldap_ldaps'), + 'use_ldaps':str2bool(ldap_settings.get('ldap_ldaps')), 'ldap_version':3, } log.debug('Checking for ldap authentication')
--- a/rhodecode/lib/auth_ldap.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/lib/auth_ldap.py Thu Mar 17 01:13:48 2011 +0100 @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 # ldap authentication lib -# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> +# Copyright (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License
--- a/rhodecode/lib/db_manage.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/lib/db_manage.py Thu Mar 17 01:13:48 2011 +0100 @@ -60,39 +60,19 @@ init_model(engine) self.sa = meta.Session() - def check_for_db(self, override): - db_path = jn(self.root, self.dbname) - if self.dburi.startswith('sqlite'): - log.info('checking for existing db in %s', db_path) - if os.path.isfile(db_path): - - self.db_exists = True - if not override: - raise Exception('database already exists') - return 'sqlite' - if self.dburi.startswith('postgresql'): - self.db_exists = True - return 'postgresql' - - def create_tables(self, override=False): """Create a auth database """ - db_type = self.check_for_db(override) - if self.db_exists: - log.info("database exist and it's going to be destroyed") - if self.tests: - destroy = True - else: - destroy = ask_ok('Are you sure to destroy old database ? [y/n]') - if not destroy: - sys.exit() - if self.db_exists and destroy: - if db_type == 'sqlite': - os.remove(jn(self.root, self.dbname)) - if db_type == 'postgresql': - meta.Base.metadata.drop_all() + log.info("Any existing database is going to be destroyed") + if self.tests: + destroy = True + else: + destroy = ask_ok('Are you sure to destroy old database ? [y/n]') + if not destroy: + sys.exit() + if destroy: + meta.Base.metadata.drop_all() checkfirst = not override meta.Base.metadata.create_all(checkfirst=checkfirst) @@ -322,10 +302,14 @@ """Creates ldap settings""" try: - for k in ['ldap_active', 'ldap_host', 'ldap_port', 'ldap_ldaps', - 'ldap_dn_user', 'ldap_dn_pass', 'ldap_base_dn']: + for k, v in [('ldap_active', 'false'), + ('ldap_host', ''), + ('ldap_port', '389'), + ('ldap_ldaps', 'false'), + ('ldap_dn_user', ''), ('ldap_dn_pass', ''), + ('ldap_base_dn', '')]: - setting = RhodeCodeSettings(k, '') + setting = RhodeCodeSettings(k, v) self.sa.add(setting) self.sa.commit() except:
--- a/rhodecode/lib/helpers.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/lib/helpers.py Thu Mar 17 01:13:48 2011 +0100 @@ -230,6 +230,8 @@ class _FilesBreadCrumbs(object): def __call__(self, repo_name, rev, paths): + if isinstance(paths, str): + paths = paths.decode('utf-8', 'replace') url_l = [link_to(repo_name, url('files_home', repo_name=repo_name, revision=rev, f_path=''))] @@ -483,7 +485,7 @@ if len(x) > 1: action, action_params = x - tmpl = """<img src="%s/%s" alt="%s"/>""" + tmpl = """<img src="%s%s" alt="%s"/>""" map = {'user_deleted_repo':'database_delete.png', 'user_created_repo':'database_add.png', 'user_forked_repo':'arrow_divide.png', @@ -550,6 +552,6 @@ suf = '' if len(nodes) > 30: suf = '<br/>' + _(' and %s more') % (len(nodes) - 30) - return literal(pref + '<br/> '.join([x.path for x in nodes[:30]]) + suf) + return literal(pref + '<br/> '.join([x.path.decode('utf-8', 'replace') for x in nodes[:30]]) + suf) else: return ': ' + _('No Files')
--- a/rhodecode/model/db.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/model/db.py Thu Mar 17 01:13:48 2011 +0100 @@ -30,51 +30,20 @@ from sqlalchemy import * from sqlalchemy.exc import DatabaseError -from sqlalchemy.orm import relationship, backref, class_mapper -from sqlalchemy.orm.session import Session +from sqlalchemy.orm import relationship, backref +from sqlalchemy.orm.interfaces import MapperExtension -from rhodecode.model.meta import Base +from rhodecode.model.meta import Base, Session log = logging.getLogger(__name__) -class BaseModel(object): - @classmethod - def _get_keys(cls): - """return column names for this model """ - return class_mapper(cls).c.keys() - - def get_dict(self): - """return dict with keys and values corresponding - to this model data """ - - d = {} - for k in self._get_keys(): - d[k] = getattr(self, k) - return d - - def get_appstruct(self): - """return list with keys and values tupples corresponding - to this model data """ - - l = [] - for k in self._get_keys(): - l.append((k, getattr(self, k),)) - return l - - def populate_obj(self, populate_dict): - """populate model with data from given populate_dict""" - - for k in self._get_keys(): - if k in populate_dict: - setattr(self, k, populate_dict[k]) - -class RhodeCodeSettings(Base, BaseModel): +class RhodeCodeSettings(Base): __tablename__ = 'rhodecode_settings' __table_args__ = (UniqueConstraint('app_settings_name'), {'useexisting':True}) app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - app_settings_name = Column("app_settings_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - app_settings_value = Column("app_settings_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) def __init__(self, k='', v=''): self.app_settings_name = k @@ -84,27 +53,27 @@ return "<%s('%s:%s')>" % (self.__class__.__name__, self.app_settings_name, self.app_settings_value) -class RhodeCodeUi(Base, BaseModel): +class RhodeCodeUi(Base): __tablename__ = 'rhodecode_ui' __table_args__ = {'useexisting':True} ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - ui_section = Column("ui_section", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - ui_key = Column("ui_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - ui_value = Column("ui_value", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True) -class User(Base, BaseModel): +class User(Base): __tablename__ = 'users' __table_args__ = (UniqueConstraint('username'), UniqueConstraint('email'), {'useexisting':True}) user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - username = Column("username", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - password = Column("password", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) active = Column("active", Boolean(), nullable=True, unique=None, default=None) admin = Column("admin", Boolean(), nullable=True, unique=None, default=False) - name = Column("name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - lastname = Column("lastname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - email = Column("email", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None) is_ldap = Column("is_ldap", Boolean(), nullable=False, unique=None, default=False) @@ -118,6 +87,10 @@ def full_contact(self): return '%s %s <%s>' % (self.name, self.lastname, self.email) + @property + def short_contact(self): + return '%s %s' % (self.name, self.lastname) + @property def is_admin(self): @@ -127,6 +100,11 @@ return "<%s('id:%s:%s')>" % (self.__class__.__name__, self.user_id, self.username) + @classmethod + def by_username(cls, username): + return Session.query(cls).filter(cls.username == username).one() + + def update_lastlogin(self): """Update user lastlogin""" @@ -140,15 +118,15 @@ session.rollback() -class UserLog(Base, BaseModel): +class UserLog(Base): __tablename__ = 'user_logs' __table_args__ = {'useexisting':True} user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) repository_id = Column("repository_id", Integer(length=None, convert_unicode=False, assert_unicode=None), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None) - repository_name = Column("repository_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - user_ip = Column("user_ip", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - action = Column("action", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None) @property @@ -158,16 +136,16 @@ user = relationship('User') repository = relationship('Repository') -class Repository(Base, BaseModel): +class Repository(Base): __tablename__ = 'repositories' __table_args__ = (UniqueConstraint('repo_name'), {'useexisting':True},) repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - repo_name = Column("repo_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) - repo_type = Column("repo_type", String(length=None, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg') + repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None) + repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg') user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None) private = Column("private", Boolean(), nullable=True, unique=None, default=None) enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True) - description = Column("description", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None) user = relationship('User') @@ -178,23 +156,23 @@ repo_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all') logs = relationship('UserLog', cascade='all') - + def __repr__(self): return "<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id, self.repo_name) -class Permission(Base, BaseModel): +class Permission(Base): __tablename__ = 'permissions' __table_args__ = {'useexisting':True} permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - permission_name = Column("permission_name", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - permission_longname = Column("permission_longname", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) def __repr__(self): return "<%s('%s:%s')>" % (self.__class__.__name__, self.permission_id, self.permission_name) -class RepoToPerm(Base, BaseModel): +class RepoToPerm(Base): __tablename__ = 'repo_to_perm' __table_args__ = (UniqueConstraint('user_id', 'repository_id'), {'useexisting':True}) repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) @@ -206,7 +184,7 @@ permission = relationship('Permission') repository = relationship('Repository') -class UserToPerm(Base, BaseModel): +class UserToPerm(Base): __tablename__ = 'user_to_perm' __table_args__ = (UniqueConstraint('user_id', 'permission_id'), {'useexisting':True}) user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) @@ -216,19 +194,19 @@ user = relationship('User') permission = relationship('Permission') -class Statistics(Base, BaseModel): +class Statistics(Base): __tablename__ = 'statistics' __table_args__ = (UniqueConstraint('repository_id'), {'useexisting':True}) stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - repository_id = Column("repository_id", Integer(), ForeignKey(u'repositories.repo_id'), nullable=False, unique=True, default=None) + repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None) stat_on_revision = Column("stat_on_revision", Integer(), nullable=False) - commit_activity = Column("commit_activity", LargeBinary(), nullable=False)#JSON data + commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data - languages = Column("languages", LargeBinary(), nullable=False)#JSON data + languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data repository = relationship('Repository', single_parent=True) -class UserFollowing(Base, BaseModel): +class UserFollowing(Base): __tablename__ = 'user_followings' __table_args__ = (UniqueConstraint('user_id', 'follows_repository_id'), UniqueConstraint('user_id', 'follows_user_id') @@ -244,12 +222,12 @@ follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') follows_repository = relationship('Repository', order_by='Repository.repo_name') -class CacheInvalidation(Base, BaseModel): +class CacheInvalidation(Base): __tablename__ = 'cache_invalidation' __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True}) cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True) - cache_key = Column("cache_key", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) - cache_args = Column("cache_args", String(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) + cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None) cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False) @@ -262,10 +240,10 @@ return "<%s('%s:%s')>" % (self.__class__.__name__, self.cache_id, self.cache_key) -class DbMigrateVersion(Base, BaseModel): +class DbMigrateVersion(Base): __tablename__ = 'db_migrate_version' __table_args__ = {'useexisting':True} - repository_id = Column('repository_id', String(250), primary_key=True) + repository_id = Column('repository_id', String(255), primary_key=True) repository_path = Column('repository_path', Text) version = Column('version', Integer)
--- a/rhodecode/model/meta.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/model/meta.py Thu Mar 17 01:13:48 2011 +0100 @@ -1,8 +1,10 @@ """SQLAlchemy Metadata and Session object""" from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import scoped_session, sessionmaker, class_mapper +from beaker import cache + from rhodecode.model import caching_query -from beaker import cache + # Beaker CacheManager. A home base for cache configurations. cache_manager = cache.CacheManager() @@ -17,10 +19,52 @@ ) ) +class BaseModel(object): + """Base Model for all classess + + """ + + @classmethod + def _get_keys(cls): + """return column names for this model """ + return class_mapper(cls).c.keys() + + def get_dict(self): + """return dict with keys and values corresponding + to this model data """ + + d = {} + for k in self._get_keys(): + d[k] = getattr(self, k) + return d + + def get_appstruct(self): + """return list with keys and values tupples corresponding + to this model data """ + + l = [] + for k in self._get_keys(): + l.append((k, getattr(self, k),)) + return l + + def populate_obj(self, populate_dict): + """populate model with data from given populate_dict""" + + for k in self._get_keys(): + if k in populate_dict: + setattr(self, k, populate_dict[k]) + + @classmethod + def query(cls): + return Session.query(cls) + + @classmethod + def get(cls, id_): + return Session.query(cls).get(id_) + + # The declarative Base -Base = declarative_base() -#For another db... -#Base2 = declarative_base() +Base = declarative_base(cls=BaseModel) #to use cache use this in query #.options(FromCache("sqlalchemy_cache_type", "cachekey"))
--- a/rhodecode/model/scm.py Sun Feb 27 00:35:11 2011 +0100 +++ b/rhodecode/model/scm.py Thu Mar 17 01:13:48 2011 +0100 @@ -146,6 +146,7 @@ tmp_d['rev'] = tip.revision tmp_d['contact'] = repo.dbrepo.user.full_contact tmp_d['contact_sort'] = tmp_d['contact'] + tmp_d['owner_sort'] = tmp_d['contact'] tmp_d['repo_archives'] = list(repo._get_archives()) tmp_d['last_msg'] = tip.message tmp_d['repo'] = repo
--- a/setup.py Sun Feb 27 00:35:11 2011 +0100 +++ b/setup.py Thu Mar 17 01:13:48 2011 +0100 @@ -1,19 +1,19 @@ import sys +from rhodecode import get_version +from rhodecode import __platform__ + py_version = sys.version_info -from rhodecode import get_version - requirements = [ "Pylons==1.0.0", "WebHelpers==1.2", "SQLAlchemy==0.6.6", - "Mako==0.3.6", - "vcs==0.1.10", - "pygments==1.3.1", + "Mako==0.4.0", + "vcs==0.1.11", + "pygments==1.4.0", "mercurial==1.7.5", "whoosh==1.3.4", - "celery==2.1.4", - "py-bcrypt", + "celery==2.2.4", "babel", ] @@ -25,10 +25,14 @@ 'Operating System :: OS Independent', 'Programming Language :: Python', ] -if sys.version_info < (2, 6): +if py_version < (2, 6): requirements.append("simplejson") requirements.append("pysqlite") +if __platform__ in ('Linux', 'Darwin'): + requirements.append("py-bcrypt") + + #additional files from project that goes somewhere in the filesystem #relative to sys.prefix data_files = [] @@ -38,6 +42,10 @@ description = ('Mercurial repository browser/management with ' 'build in push/pull server and full text search') +keywords = ' '.join (['rhodecode', 'rhodiumcode', 'mercurial', 'git', + 'repository management', 'hgweb replacement' + 'hgwebdir', 'gitweb replacement', 'serving hgweb', + ]) #long description try: readme_file = 'README.rst' @@ -66,7 +74,7 @@ version=get_version(), description=description, long_description=long_description, - keywords='rhodiumcode mercurial web hgwebdir gitweb git replacement serving hgweb rhodecode', + keywords=keywords, license='BSD', author='Marcin Kuzminski', author_email='marcin@python-works.com',