Changeset - b956e6f415a2
[Not reviewed]
beta
0 5 0
Marcin Kuzminski - 15 years ago 2010-12-21 01:11:38
marcin@python-works.com
implemented #91,
updated docs, and changelog
bumped to newest libs possible for setup.py requirements
5 files changed with 44 insertions and 23 deletions:
0 comments (0 inline, 0 general)
docs/changelog.rst
Show inline comments
 
.. _changelog:
 

	
 
Changelog
 
=========
 

	
 
1.1.0 (**2010-XX-XX**)
 
1.2.0 (**2010-12-18**)
 
----------------------
 

	
 
:status: in-progress
 
:branch: beta
 

	
 
news
 
++++
 

	
 
- implemented #91 added nicer looking archive urls
 

	
 
fixes
 
++++
 

	
 

	
 
1.1.0 (**2010-12-18**)
 
----------------------
 

	
 
news
 
++++
 

	
 
- rewrite of internals for vcs >=0.1.10
 
- uses mercurial 1.7 with dotencode disabled for maintaining compatibility 
 
  with older clients
 
- anonymous access, authentication via ldap
 
- performance upgrade for cached repos list - each repository has it's own 
 
  cache that's invalidated when needed.
 
- performance upgrades on repositories with large amount of commits (20K+)
 
- main page quick filter for filtering repositories
 
- user dashboards with ability to follow chosen repositories actions
 
- sends email to admin on new user registration
 
- added cache/statistics reset options into repository settings
 
- more detailed action logger (based on hooks) with pushed changesets lists
 
  and options to disable those hooks from admin panel
 
- introduced new enhanced changelog for merges that shows more accurate results
 
- new improved and faster code stats (based on pygments lexers mapping tables, 
 
  showing up to 10 trending sources for each repository. Additionally stats
 
  can be disabled in repository settings.
 
- gui optimizations, fixed application width to 1024px
 
- added cut off (for large files/changesets) limit into config files
 
- whoosh, celeryd, upgrade moved to paster command
 
- other than sqlite database backends can be used
 

	
 
fixes
 
+++++
 

	
 
- fixes #61 forked repo was showing only after cache expired
 
- fixes #76 no confirmation on user deletes
 
- fixes #66 Name field misspelled
 
- fixes #72 block user removal when he owns repositories
 
- fixes #69 added password confirmation fields
 
- fixes #87 RhodeCode crashes occasionally on updating repository owner
 
- fixes #82 broken annotations on files with more than 1 blank line at the end
 
- a lot of fixes and tweaks for file browser
 
- fixed detached session issues
 
- fixed when user had no repos he would see all repos listed in my account
 
- fixed ui() instance bug when global hgrc settings was loaded for server 
 
  instance and all hgrc options were merged with our db ui() object
 
- numerous small bugfixes
 
 
 
(special thanks for TkSoh for detailed feedback)
 

	
 

	
 
1.0.2 (**2010-11-12**)
 
----------------------
 

	
 
news
 
++++
 

	
 
- tested under python2.7
 
- bumped sqlalchemy and celery versions
 

	
 
fixes
 
+++++
 

	
 
- fixed #59 missing graph.js
 
- fixed repo_size crash when repository had broken symlinks
 
- fixed python2.5 crashes.
 

	
 

	
 
1.0.1 (**2010-11-10**)
 
----------------------
 

	
 
news
 
++++
 

	
 
- small css updated
 

	
 
fixes
 
+++++
 

	
 
- fixed #53 python2.5 incompatible enumerate calls
 
- fixed #52 disable mercurial extension for web
 
- fixed #51 deleting repositories don't delete it's dependent objects
 

	
 

	
 
1.0.0 (**2010-11-02**)
 
----------------------
 

	
 
- security bugfix simplehg wasn't checking for permissions on commands
 
  other than pull or push.
 
- fixed doubled messages after push or pull in admin journal
 
- templating and css corrections, fixed repo switcher on chrome, updated titles
 
- admin menu accessible from options menu on repository view
 
- permissions cached queries
 

	
 
1.0.0rc4  (**2010-10-12**)
 
--------------------------
 

	
 
- fixed python2.5 missing simplejson imports (thanks to Jens Bäckman)
 
- removed cache_manager settings from sqlalchemy meta
 
- added sqlalchemy cache settings to ini files
 
- validated password length and added second try of failure on paster setup-app
 
- fixed setup database destroy prompt even when there was no db
 

	
 

	
 
1.0.0rc3 (**2010-10-11**)
 
-------------------------
 

	
 
- fixed i18n during installation.
 

	
 
1.0.0rc2 (**2010-10-11**)
 
-------------------------
 

	
 
- Disabled dirsize in file browser, it's causing nasty bug when dir renames 
 
  occure. After vcs is fixed it'll be put back again.
 
- templating/css rewrites, optimized css.
 

	
 
- templating/css rewrites, optimized css.
 
\ No newline at end of file
rhodecode/config/routing.py
Show inline comments
 
"""
 
Routes configuration
 

	
 
The more specific and detailed routes should be defined first so they
 
may take precedent over the more generic routes. For more information
 
refer to the routes manual at http://routes.groovie.org/docs/
 
"""
 
from __future__ import with_statement
 
from routes import Mapper
 
from rhodecode.lib.utils import check_repo_fast as cr
 

	
 
def make_map(config):
 
    """Create, configure and return the routes Mapper"""
 
    map = Mapper(directory=config['pylons.paths']['controllers'],
 
                 always_scan=config['debug'])
 
    map.minimization = False
 
    map.explicit = False
 

	
 
    def check_repo(environ, match_dict):
 
        """
 
        check for valid repository for proper 404 handling
 
        :param environ:
 
        :param match_dict:
 
        """
 
        repo_name = match_dict.get('repo_name')
 
        return not cr(repo_name, config['base_path'])
 

	
 
    # The ErrorController route (handles 404/500 error pages); it should
 
    # likely stay at the top, ensuring it can always be resolved
 
    map.connect('/error/{action}', controller='error')
 
    map.connect('/error/{action}/{id}', controller='error')
 

	
 
    #==========================================================================
 
    # CUSTOM ROUTES HERE
 
    #==========================================================================
 

	
 
    #MAIN PAGE
 
    map.connect('home', '/', controller='home', action='index')
 
    map.connect('bugtracker', "http://bitbucket.org/marcinkuzminski/rhodecode/issues", _static=True)
 
    map.connect('gpl_license', "http://www.gnu.org/licenses/gpl.html", _static=True)
 
    #ADMIN REPOSITORY REST ROUTES
 
    with map.submapper(path_prefix='/_admin', controller='admin/repos') as m:
 
        m.connect("repos", "/repos",
 
             action="create", conditions=dict(method=["POST"]))
 
        m.connect("repos", "/repos",
 
             action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_repos", "/repos.{format}",
 
             action="index",
 
            conditions=dict(method=["GET"]))
 
        m.connect("new_repo", "/repos/new",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_new_repo", "/repos/new.{format}",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("/repos/{repo_name:.*}",
 
             action="update", conditions=dict(method=["PUT"],
 
                                              function=check_repo))
 
        m.connect("/repos/{repo_name:.*}",
 
             action="delete", conditions=dict(method=["DELETE"],
 
                                              function=check_repo))
 
        m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
 
             action="edit", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
 
             action="edit", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("repo", "/repos/{repo_name:.*}",
 
             action="show", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
 
             action="show", conditions=dict(method=["GET"],
 
                                            function=check_repo))
 
        #ajax delete repo perm user
 
        m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
 
             action="delete_perm_user", conditions=dict(method=["DELETE"],
 
                                                        function=check_repo))
 
        #settings actions
 
        m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
 
             action="repo_stats", conditions=dict(method=["DELETE"],
 
                                                        function=check_repo))
 
        m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
 
             action="repo_cache", conditions=dict(method=["DELETE"],
 
                                                        function=check_repo))
 
    #ADMIN USER REST ROUTES
 
    map.resource('user', 'users', controller='admin/users', path_prefix='/_admin')
 

	
 
    #ADMIN PERMISSIONS REST ROUTES
 
    map.resource('permission', 'permissions', controller='admin/permissions', path_prefix='/_admin')
 

	
 

	
 
    ##ADMIN LDAP SETTINGS
 
    map.connect('ldap_settings', '/_admin/ldap', controller='admin/ldap_settings',
 
                action='ldap_settings', conditions=dict(method=["POST"]))
 
    map.connect('ldap_home', '/_admin/ldap', controller='admin/ldap_settings',)
 

	
 

	
 

	
 
    #ADMIN SETTINGS REST ROUTES
 
    with map.submapper(path_prefix='/_admin', controller='admin/settings') as m:
 
        m.connect("admin_settings", "/settings",
 
             action="create", conditions=dict(method=["POST"]))
 
        m.connect("admin_settings", "/settings",
 
             action="index", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_settings", "/settings.{format}",
 
             action="index", conditions=dict(method=["GET"]))
 
        m.connect("admin_new_setting", "/settings/new",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_new_setting", "/settings/new.{format}",
 
             action="new", conditions=dict(method=["GET"]))
 
        m.connect("/settings/{setting_id}",
 
             action="update", conditions=dict(method=["PUT"]))
 
        m.connect("/settings/{setting_id}",
 
             action="delete", conditions=dict(method=["DELETE"]))
 
        m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
 
             action="edit", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_edit_setting", "/settings/{setting_id}.{format}/edit",
 
             action="edit", conditions=dict(method=["GET"]))
 
        m.connect("admin_setting", "/settings/{setting_id}",
 
             action="show", conditions=dict(method=["GET"]))
 
        m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
 
             action="show", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_account", "/my_account",
 
             action="my_account", conditions=dict(method=["GET"]))
 
        m.connect("admin_settings_my_account_update", "/my_account_update",
 
             action="my_account_update", conditions=dict(method=["PUT"]))
 
        m.connect("admin_settings_create_repository", "/create_repository",
 
             action="create_repository", conditions=dict(method=["GET"]))
 

	
 
    #ADMIN MAIN PAGES
 
    with map.submapper(path_prefix='/_admin', controller='admin/admin') as m:
 
        m.connect('admin_home', '', action='index')#main page
 
        m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
 
                  action='add_repo')
 

	
 

	
 
    #USER JOURNAL
 
    map.connect('journal', '/_admin/journal', controller='journal',)
 
    map.connect('toggle_following', '/_admin/toggle_following', controller='journal',
 
                action='toggle_following', conditions=dict(method=["POST"]))
 

	
 

	
 
    #SEARCH
 
    map.connect('search', '/_admin/search', controller='search',)
 
    map.connect('search_repo', '/_admin/search/{search_repo:.*}', controller='search')
 

	
 
    #LOGIN/LOGOUT/REGISTER/SIGN IN
 
    map.connect('login_home', '/_admin/login', controller='login')
 
    map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
 
    map.connect('register', '/_admin/register', controller='login', action='register')
 
    map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
 

	
 
    #FEEDS
 
    map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
 
                controller='feed', action='rss',
 
                conditions=dict(function=check_repo))
 
    map.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
 
                controller='feed', action='atom',
 
                conditions=dict(function=check_repo))
 

	
 

	
 
    #REPOSITORY ROUTES
 
    map.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
 
                controller='changeset', revision='tip',
 
                conditions=dict(function=check_repo))
 
    map.connect('raw_changeset_home', '/{repo_name:.*}/raw-changeset/{revision}',
 
                controller='changeset', action='raw_changeset', revision='tip',
 
                conditions=dict(function=check_repo))
 
    map.connect('summary_home', '/{repo_name:.*}/summary',
 
                controller='summary', conditions=dict(function=check_repo))
 
    map.connect('shortlog_home', '/{repo_name:.*}/shortlog',
 
                controller='shortlog', conditions=dict(function=check_repo))
 
    map.connect('branches_home', '/{repo_name:.*}/branches',
 
                controller='branches', conditions=dict(function=check_repo))
 
    map.connect('tags_home', '/{repo_name:.*}/tags',
 
                controller='tags', conditions=dict(function=check_repo))
 
    map.connect('changelog_home', '/{repo_name:.*}/changelog',
 
                controller='changelog', conditions=dict(function=check_repo))
 
    map.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
 
                controller='files', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 
    map.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
 
                controller='files', action='diff', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 
    map.connect('files_rawfile_home', '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
 
                controller='files', action='rawfile', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 
    map.connect('files_raw_home', '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
 
                controller='files', action='raw', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 
    map.connect('files_annotate_home', '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
 
                controller='files', action='annotate', revision='tip', f_path='',
 
                conditions=dict(function=check_repo))
 
    map.connect('files_archive_home', '/{repo_name:.*}/archive/{revision}/{fileformat}',
 
                controller='files', action='archivefile', revision='tip',
 
    map.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
 
                controller='files', action='archivefile',
 
                conditions=dict(function=check_repo))
 
    map.connect('repo_settings_delete', '/{repo_name:.*}/settings',
 
                controller='settings', action="delete",
 
                conditions=dict(method=["DELETE"], function=check_repo))
 
    map.connect('repo_settings_update', '/{repo_name:.*}/settings',
 
                controller='settings', action="update",
 
                conditions=dict(method=["PUT"], function=check_repo))
 
    map.connect('repo_settings_home', '/{repo_name:.*}/settings',
 
                controller='settings', action='index',
 
                conditions=dict(function=check_repo))
 

	
 
    map.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
 
                controller='settings', action='fork_create',
 
                conditions=dict(function=check_repo, method=["POST"]))
 
    map.connect('repo_fork_home', '/{repo_name:.*}/fork',
 
                controller='settings', action='fork',
 
                conditions=dict(function=check_repo))
 

	
 
    return map
rhodecode/controllers/files.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
"""
 
    rhodecode.controllers.files
 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
    Files controller for RhodeCode
 
    
 
    :created_on: Apr 21, 2010
 
    :author: marcink
 
    :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>    
 
    :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; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# 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, write to the Free Software
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
# MA  02110-1301, USA.
 
import tempfile
 
import logging
 
import rhodecode.lib.helpers as h
 

	
 
from mercurial import archival
 

	
 
from pylons import request, response, session, tmpl_context as c, url
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import redirect
 

	
 
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.lib.utils import EmptyChangeset
 
from rhodecode.model.scm import ScmModel
 

	
 
from vcs.exceptions import RepositoryError, ChangesetError
 
from vcs.exceptions import RepositoryError, ChangesetError, ChangesetDoesNotExistError
 
from vcs.nodes import FileNode
 
from vcs.utils import diffs as differ
 

	
 
log = logging.getLogger(__name__)
 

	
 
class FilesController(BaseController):
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def __before__(self):
 
        super(FilesController, self).__before__()
 
        c.cut_off_limit = self.cut_off_limit
 

	
 
    def index(self, repo_name, revision, f_path):
 
        hg_model = ScmModel()
 
        c.repo = hg_model.get_repo(c.repo_name)
 
        revision = request.POST.get('at_rev', None) or revision
 

	
 
        def get_next_rev(cur):
 
            max_rev = len(c.repo.revisions) - 1
 
            r = cur + 1
 
            if r > max_rev:
 
                r = max_rev
 
            return r
 

	
 
        def get_prev_rev(cur):
 
            r = cur - 1
 
            return r
 

	
 
        c.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 RepositoryError, e:
 
            h.flash(str(e), category='warning')
 
            redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
 

	
 

	
 

	
 
        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)
 
        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)
 
        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)
 

	
 
        try:
 
            c.cs = c.repo.get_changeset(revision)
 
            c.file = c.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))
 

	
 
        c.file_history = self._get_history(c.repo, c.file, f_path)
 

	
 
        c.f_path = f_path
 

	
 
        return render('files/files_annotate.html')
 

	
 
    def archivefile(self, repo_name, revision, fileformat):
 
    def archivefile(self, repo_name, fname):
 
        info = fname.split('.')
 
        revision, fileformat = info[0], '.' + '.'.join(info[1:])
 
        archive_specs = {
 
          '.tar.bz2': ('application/x-tar', 'tbz2'),
 
          '.tar.gz': ('application/x-tar', 'tgz'),
 
          '.zip': ('application/zip', 'zip'),
 
        }
 
        if not archive_specs.has_key(fileformat):
 
            return 'Unknown archive type %s' % fileformat
 
            return _('Unknown archive type %s') % fileformat
 

	
 
        repo = ScmModel().get_repo(repo_name)
 

	
 
        try:
 
            repo.get_changeset(revision)
 
        except ChangesetDoesNotExistError:
 
            return _('Unknown revision %s') % revision
 

	
 
        archive = tempfile.TemporaryFile()
 
        localrepo = repo.repo
 
        fname = '%s-%s%s' % (repo_name, revision, fileformat)
 
        archival.archive(localrepo, archive, revision, archive_specs[fileformat][1],
 
                         prefix='%s-%s' % (repo_name, revision))
 
        response.content_type = archive_specs[fileformat][0]
 
        response.content_disposition = 'attachment; filename=%s' % fname
 
        archive.seek(0)
 

	
 
        def read_in_chunks(file_object, chunk_size=1024 * 40):
 
            """Lazy function (generator) to read a file piece by piece.
 
            Default chunk size: 40k."""
 
            while True:
 
                data = file_object.read(chunk_size)
 
                if not data:
 
                    break
 
                yield data
 

	
 
        archive = tempfile.TemporaryFile()
 
        repo = ScmModel().get_repo(repo_name).repo
 
        fname = '%s-%s%s' % (repo_name, revision, fileformat)
 
        archival.archive(repo, archive, revision, archive_specs[fileformat][1],
 
                         prefix='%s-%s' % (repo_name, revision))
 
        response.content_type = archive_specs[fileformat][0]
 
        response.content_disposition = 'attachment; filename=%s' % fname
 
        archive.seek(0)
 
        return read_in_chunks(archive)
 

	
 
    def diff(self, repo_name, f_path):
 
        hg_model = ScmModel()
 
        diff1 = request.GET.get('diff1')
 
        diff2 = request.GET.get('diff2')
 
        c.action = request.GET.get('diff')
 
        c.no_changes = diff1 == diff2
 
        c.f_path = f_path
 
        c.repo = hg_model.get_repo(c.repo_name)
 

	
 
        try:
 
            if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
 
                c.changeset_1 = c.repo.get_changeset(diff1)
 
                node1 = c.changeset_1.get_node(f_path)
 
            else:
 
                c.changeset_1 = EmptyChangeset()
 
                node1 = FileNode('.', '', changeset=c.changeset_1)
 

	
 
            if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
 
                c.changeset_2 = c.repo.get_changeset(diff2)
 
                node2 = c.changeset_2.get_node(f_path)
 
            else:
 
                c.changeset_2 = EmptyChangeset()
 
                node2 = FileNode('.', '', changeset=c.changeset_2)
 
        except RepositoryError:
 
            return redirect(url('files_home',
 
                                repo_name=c.repo_name, f_path=f_path))
 

	
 
        f_udiff = differ.get_udiff(node1, node2)
 
        diff = differ.DiffProcessor(f_udiff)
 

	
 
        if c.action == 'download':
 
            diff_name = '%s_vs_%s.diff' % (diff1, diff2)
 
            response.content_type = 'text/plain'
 
            response.content_disposition = 'attachment; filename=%s' \
 
                                                    % diff_name
 
            return diff.raw_diff()
 

	
 
        elif c.action == 'raw':
 
            response.content_type = 'text/plain'
 
            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')
 
            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')
 
            else:
 
                c.cur_diff = diff.as_html()
 

	
 
        if not c.cur_diff: c.no_changes = True
 
        return render('files/file_diff.html')
 

	
 
    def _get_history(self, repo, node, f_path):
 
        from vcs.nodes import NodeKind
 
        if not node.kind is NodeKind.FILE:
 
            return []
 
        changesets = node.history
 
        hist_l = []
 

	
 
        changesets_group = ([], _("Changesets"))
 
        branches_group = ([], _("Branches"))
 
        tags_group = ([], _("Tags"))
 

	
 
        for chs in changesets:
 
            n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
 
            changesets_group[0].append((chs.raw_id, n_desc,))
 

	
 
        hist_l.append(changesets_group)
 

	
 
        for name, chs in c.repository_branches.items():
 
            #chs = chs.split(':')[-1]
 
            branches_group[0].append((chs, name),)
 
        hist_l.append(branches_group)
 

	
 
        for name, chs in c.repository_tags.items():
 
            #chs = chs.split(':')[-1]
 
            tags_group[0].append((chs, name),)
 
        hist_l.append(tags_group)
 

	
 
        return hist_l
 

	
 
#                [
 
#                 ([("u1", "User1"), ("u2", "User2")], "Users"),
 
#                 ([("g1", "Group1"), ("g2", "Group2")], "Groups")
 
#                 ]
 

	
rhodecode/templates/summary/summary.html
Show inline comments
 
<%inherit file="/base/base.html"/>
 

	
 
<%def name="title()">
 
    ${c.repo_name} ${_('Summary')} - ${c.rhodecode_name}
 
</%def>
 

	
 
<%def name="breadcrumbs_links()">
 
    ${h.link_to(u'Home',h.url('/'))}
 
    &raquo; 
 
    ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('summary')}
 
</%def>
 

	
 
<%def name="page_nav()">
 
	${self.menu('summary')}    
 
</%def>
 

	
 
<%def name="main()">
 
<div class="box box-left">
 
    <!-- box / title -->
 
    <div class="title">
 
        ${self.breadcrumbs()}
 
    </div>
 
    <!-- end box / title -->
 
	<div class="form">
 
	  <div class="fields">
 
		 
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Name')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
		         %if c.repo_info.dbrepo.repo_type =='hg':
 
		           <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
 
		         %endif
 
		         %if c.repo_info.dbrepo.repo_type =='git':
 
		           <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
 
		         %endif 
 
                                 			  
 
	             %if c.repo_info.dbrepo.private:
 
	                <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
 
	             %else:
 
	                <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
 
	             %endif
 
			      <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
 
			      %if c.rhodecode_user.username != 'default':
 
				      %if c.following:
 
	                  <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
 
	                        onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
 
	                  </span>			      
 
				      %else:
 
				      <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
 
				            onclick="javascript:toggleFollowingRepo(${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
 
				      </span>
 
				      %endif
 
				  %endif:
 
			      <br/>
 
		            %if c.repo_info.dbrepo.fork:
 
		            	<span style="margin-top:5px">
 
		            	<a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
 
		            	<img class="icon" alt="${_('public')}"
 
		            	title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}" 
 
		            	src="/images/icons/arrow_divide.png"/>
 
		            	${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
 
		            	</a>
 
		            	</span>
 
		            %endif			      
 
			  </div>
 
			 </div>
 
			
 
			
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Description')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
			      ${c.repo_info.dbrepo.description}
 
			  </div>
 
			 </div>
 
			
 
			
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Contact')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
			  	<div class="gravatar">
 
			  		<img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
 
			  	</div>
 
			  		${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
 
			  		${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
 
			  		${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
 
			  </div>
 
			 </div>
 
			
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Last change')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
			      ${h.age(c.repo_info.last_change)} - ${c.repo_info.last_change} 
 
			      ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author} 
 
			      
 
			  </div>
 
			 </div>
 
			
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Clone url')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
			      <input type="text" id="clone_url" readonly="readonly" value="hg clone ${c.clone_repo_url}" size="70"/>
 
			  </div>
 
			 </div>
 
			 
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Trending source files')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
			    <div id="lang_stats">
 
			    
 
			    </div> 			  
 
			  	<script type="text/javascript">
 
				  	YUE.onDOMReady(function(e){
 
				  	    id = 'clone_url';
 
				  	    YUE.on(id,'click',function(e){
 
				  	        YUD.get('clone_url').select();
 
				  	    })
 
				  	})
 
			  		var data = ${c.trending_languages|n};
 
			  		var total = 0;
 
			  		var no_data = true;
 
			  		for (k in data){
 
			  		    total += data[k];
 
			  		    no_data = false;
 
			  		} 
 
					var tbl = document.createElement('table');
 
					tbl.setAttribute('class','trending_language_tbl');
 
					var cnt =0;
 
			  		for (k in data){
 
			  			cnt+=1;
 
			  			var hide = cnt>2;
 
				  		var tr = document.createElement('tr');
 
				  		if (hide){
 
				  			tr.setAttribute('style','display:none');
 
				  			tr.setAttribute('class','stats_hidden');
 
				  		}
 
				  		var percentage = Math.round((data[k]/total*100),2);
 
						var value = data[k];
 
				  		var td1 = document.createElement('td');
 
				  		td1.width=150;
 
				  		var trending_language_label = document.createElement('div');
 
				  		trending_language_label.innerHTML = k;
 
				  		td1.appendChild(trending_language_label);
 

	
 
				  		var td2 = document.createElement('td');
 
				  		td2.setAttribute('style','padding-right:14px !important');
 
			  		    var trending_language = document.createElement('div');
 
			  		    var nr_files = value+" ${_('files')}";
 
			  		    
 
			  		    trending_language.title = k+" "+nr_files;
 
			  		    
 
			  		    if (percentage>20){
 
			  		    	trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>";	
 
			  		    }
 
			  		    else{
 
			  		    	trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>";
 
			  		    }
 
			  		    
 
			  		    trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner');
 
			  		    trending_language.style.width=percentage+"%";
 
						td2.appendChild(trending_language);
 
						
 
						tr.appendChild(td1);
 
						tr.appendChild(td2);
 
			  		    tbl.appendChild(tr);
 
			  		    if(cnt == 2){
 
			  		    	var show_more = document.createElement('tr');
 
			  		    	var td=document.createElement('td');
 
			  		    	lnk = document.createElement('a');
 
			  		    	lnk.href='#';
 
			  		    	lnk.innerHTML = "${_("show more")}";
 
			  		    	lnk.id='code_stats_show_more';
 
			  		        td.appendChild(lnk);
 
			  		    	show_more.appendChild(td);
 
			  		    	show_more.appendChild(document.createElement('td'));
 
			  		    	tbl.appendChild(show_more);
 
			  		    }
 
			  		    
 
			  		}
 
			  		if(no_data){
 
			  			var tr = document.createElement('tr');
 
			  			var td1 = document.createElement('td');
 
			  			td1.innerHTML = "${c.no_data_msg}";
 
			  			tr.appendChild(td1);
 
			  			tbl.appendChild(tr);
 
					}
 
			  		YUD.get('lang_stats').appendChild(tbl);
 
			  		YUE.on('code_stats_show_more','click',function(){
 
			  			l = YUD.getElementsByClassName('stats_hidden')
 
			  			for (e in l){
 
			  			    YUD.setStyle(l[e],'display','');
 
			  			};
 
			  			YUD.setStyle(YUD.get('code_stats_show_more'),
 
			  					'display','none');
 
			  		})
 
			  		
 
			  	</script>
 
 
 
			  </div>
 
			 </div>
 
			 			
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Download')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
		        %for cnt,archive in enumerate(c.repo_info._get_archives()):
 
		             %if cnt >=1:
 
		             |
 
		             %endif
 
		             ${h.link_to(c.repo_info.name+'.'+archive['type'],
 
		                h.url('files_archive_home',repo_name=c.repo_info.name,
 
		                revision='tip',fileformat=archive['extension']),class_="archive_icon")}
 
		                fname='tip'+archive['extension']),class_="archive_icon")}
 
		        %endfor
 
			  </div>
 
			 </div>
 
			 
 
			 <div class="field">
 
			  <div class="label">
 
			      <label>${_('Feeds')}:</label>
 
			  </div>
 
			  <div class="input-short">
 
	            ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
 
	            ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
 
			  </div>
 
			 </div>				 			 			 
 
	  </div>		 
 
	</div>				
 
</div>
 
        
 
<div class="box box-right"  style="min-height:455px">
 
    <!-- box / title -->
 
    <div class="title">
 
        <h5>${_('Commit activity by day / author')}</h5>
 
    </div>
 
    
 
    <div class="table">
 
        
 
         %if c.no_data:
 
           <div style="padding:0 10px 10px 15px;font-size: 1.2em;">${c.no_data_msg}</div>
 
        %endif:  
 
        <div id="commit_history" style="width:460px;height:300px;float:left"></div>
 
        <div style="clear: both;height: 10px"></div>
 
        <div id="overview" style="width:460px;height:100px;float:left"></div>
 
        
 
    	<div id="legend_data" style="clear:both;margin-top:10px;">
 
	    	<div id="legend_container"></div>
 
	    	<div id="legend_choices">
 
				<table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table>
 
	    	</div>
 
    	</div>
 
		<script type="text/javascript">
 
		/**
 
		 * Plots summary graph
 
		 *
 
		 * @class SummaryPlot
 
		 * @param {from} initial from for detailed graph
 
		 * @param {to} initial to for detailed graph
 
		 * @param {dataset}
 
		 * @param {overview_dataset}
 
		 */
 
		function SummaryPlot(from,to,dataset,overview_dataset) {
 
			var initial_ranges = {
 
			    "xaxis":{
 
				    "from":from,
 
				   	"to":to,
 
				},
 
			};
 
		    var dataset = dataset;
 
		    var overview_dataset = [overview_dataset];
 
		    var choiceContainer = YUD.get("legend_choices");
 
		    var choiceContainerTable = YUD.get("legend_choices_tables");
 
		    var plotContainer = YUD.get('commit_history');
 
		    var overviewContainer = YUD.get('overview');
 
		    
 
		    var plot_options = {
 
				bars: {show:true,align:'center',lineWidth:4},
 
				legend: {show:true, container:"legend_container"},
 
				points: {show:true,radius:0,fill:false},
 
				yaxis: {tickDecimals:0,},
 
				xaxis: {
 
					mode: "time", 
 
					timeformat: "%d/%m",
 
				    min:from,
 
				    max:to,	
 
				}, 
 
				grid: {
 
					hoverable: true, 
 
				    clickable: true,
 
				    autoHighlight:true,
 
				    color: "#999"
 
				},
 
				//selection: {mode: "x"}
 
		    };
 
		    var overview_options = {
 
				legend:{show:false},
 
			    bars: {show:true,barWidth: 2,},
 
			    shadowSize: 0,
 
			    xaxis: {mode: "time", timeformat: "%d/%m/%y",},
 
			    yaxis: {ticks: 3, min: 0,tickDecimals:0,},
 
			    grid: {color: "#999",},
 
			    selection: {mode: "x"}
 
			};
 

	
 
			/**
 
			*get dummy data needed in few places
 
			*/
 
		    function getDummyData(label){
 
		    	return {"label":label,
 
               	 "data":[{"time":0,
 
               		 "commits":0,
 
	                     "added":0,
 
	                     "changed":0,
 
	                     "removed":0,
 
                    }],
 
                    "schema":["commits"],
 
                    "color":'#ffffff',
 
           		}
 
			}
 
			
 
		    /**
 
		     * generate checkboxes accordindly to data
 
		     * @param keys
 
		     * @returns
 
		     */
 
		    function generateCheckboxes(data) {
 
			    //append checkboxes
 
			    var i = 0;
 
			    choiceContainerTable.innerHTML = '';
 
			    for(var pos in data) {
 
			    	
 
			    	data[pos].color = i;
 
			        i++;
 
			        if(data[pos].label != ''){
 
				        choiceContainerTable.innerHTML += '<tr><td>'+
 
				        '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />'
 
				        +data[pos].label+
 
				        '</td></tr>';
 
			        }
 
			    }	
 
		    }
 
		    
 
		    /**
 
		     * ToolTip show
 
		     */
 
		    function showTooltip(x, y, contents) {
 
		        var div=document.getElementById('tooltip');
 
		        if(!div) {
 
		            div = document.createElement('div');
 
		            div.id="tooltip";
 
		            div.style.position="absolute";
 
		            div.style.border='1px solid #fdd';
 
		            div.style.padding='2px';
 
		            div.style.backgroundColor='#fee';
 
		            document.body.appendChild(div);
 
		        }
 
		        YUD.setStyle(div, 'opacity', 0);
 
		        div.innerHTML = contents;
 
		        div.style.top=(y + 5) + "px";
 
		        div.style.left=(x + 5) + "px";
 

	
 
		        var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2);
 
		        anim.animate();
 
		    }
 
		    
 
			/**
 
			 * This function will detect if selected period has some changesets 
 
			   for this user if it does this data is then pushed for displaying
 
			   Additionally it will only display users that are selected by the checkbox
 
			*/
 
		    function getDataAccordingToRanges(ranges) {
 
		    	
 
		        var data = [];
 
		        var keys = [];
 
				for(var key in dataset){
 
					var push = false;
 
					
 
					//method1 slow !!
 
		            //*
 
		            for(var ds in dataset[key].data){
 
			            commit_data = dataset[key].data[ds];
 
			            if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){
 
			            	push = true;
 
			            	break;
 
					    }
 
				    }
 
					//*/
 
				    
 
				    /*//method2 sorted commit data !!!
 
				    
 
				    var first_commit = dataset[key].data[0].time;
 
				    var last_commit = dataset[key].data[dataset[key].data.length-1].time;
 
				    
 
				    if (first_commit >= ranges.xaxis.from && last_commit <= ranges.xaxis.to){
 
						push = true;
 
					}
 
				    //*/
 
				    
 
				    if(push){			
 
				    	data.push(dataset[key]);
 
				    }
 
				}
 
				if(data.length >= 1){
 
					return data;
 
				} 
 
				else{
 
					//just return dummy data for graph to plot itself
 
					return [getDummyData('')];	
 
				}
 
				
 
		    }
 
		    
 
			/**
 
			* redraw using new checkbox data
 
			*/
 
		    function plotchoiced(e,args){
 
			    var cur_data = args[0];
 
			    var cur_ranges = args[1];
 
		    	
 
				var new_data = [];
 
		    	var inputs = choiceContainer.getElementsByTagName("input");
 

	
 
		    	//show only checked labels
 
		        for(var i=0; i<inputs.length; i++) {
 
		            var checkbox_key = inputs[i].name;
 
		            
 
	                if(inputs[i].checked){
 
						for(var d in cur_data){
 
							if(cur_data[d].label == checkbox_key){
 
								new_data.push(cur_data[d]);
 
							}
 
						}			                
 
	    	        }
 
	                else{
 
		                //push dummy data to not hide the label
 
						new_data.push(getDummyData(checkbox_key));
 
			        }
 
		        }
 
					        
 
		    	var new_options = YAHOO.lang.merge(plot_options, {
 
		            xaxis: { 
 
		  	      		min: cur_ranges.xaxis.from, 
 
		  	      		max: cur_ranges.xaxis.to,
 
		  	      		mode:"time",
 
		  	      		timeformat: "%d/%m",
 
		        	},
 
		    	});
 
		    	if (!new_data){
 
					new_data = [[0,1]];
 
				}
 
		    	// do the zooming
 
		       plot = YAHOO.widget.Flot(plotContainer, new_data, new_options);
 
		       
 
		       plot.subscribe("plotselected", plotselected);
 
	
 
		       //resubscribe plothover
 
		       plot.subscribe("plothover", plothover);
 
		        
 
		       // don't fire event on the overview to prevent eternal loop
 
		       overview.setSelection(cur_ranges, true);
 
	
 
		    }
 
		    
 
			/**
 
		     * plot only selected items from overview
 
		     * @param ranges
 
		     * @returns
 
		     */
 
		    function plotselected(ranges,cur_data) {
 
			    //updates the data for new plot
 
	    		data = getDataAccordingToRanges(ranges);
 
	    		generateCheckboxes(data);
 
	    		
 
		    	var new_options = YAHOO.lang.merge(plot_options, {
 
		            xaxis: { 
 
		  	      		min: ranges.xaxis.from, 
 
		  	      		max: ranges.xaxis.to,
 
		  	      		mode:"time",
 
		  	      		timeformat: "%d/%m",
 
		        	},
 
		        	yaxis: { 
 
                        min: ranges.yaxis.from, 
 
                        max: ranges.yaxis.to,
 
                    },
 
                    		        	
 
		    	});
 
		    	// do the zooming
 
		        plot = YAHOO.widget.Flot(plotContainer, data, new_options);
 

	
 
		        plot.subscribe("plotselected", plotselected);
 

	
 
		        //resubscribe plothover
 
		        plot.subscribe("plothover", plothover);
 
		        
 
		        // don't fire event on the overview to prevent eternal loop
 
		        overview.setSelection(ranges, true);
 

	
 
		        //resubscribe choiced
 
		        YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]);
 
		    }
 
		    
 
		    var previousPoint = null;
 

	
 
			function plothover(o) {
 
		        var pos = o.pos;
 
		        var item = o.item;
 
		        
 
		        //YUD.get("x").innerHTML = pos.x.toFixed(2);
 
		        //YUD.get("y").innerHTML = pos.y.toFixed(2);
 
		        if (item) {
 
		            if (previousPoint != item.datapoint) {
 
		                previousPoint = item.datapoint;
 
		                
 
		                var tooltip = YUD.get("tooltip");
 
		                if(tooltip) {
 
		                	  tooltip.parentNode.removeChild(tooltip);
 
		                }
 
		                var x = item.datapoint.x.toFixed(2);
 
		                var y = item.datapoint.y.toFixed(2);
 
						
 
		                if (!item.series.label){
 
		                    item.series.label = 'commits';
 
		                }
 
		                var d = new Date(x*1000);
 
		                var fd = d.toDateString()
 
		                var nr_commits = parseInt(y);
 
		                
 
		                var cur_data = dataset[item.series.label].data[item.dataIndex];
 
		                var added = cur_data.added;
 
		                var changed = cur_data.changed;
 
		                var removed = cur_data.removed;
 
		                
 
		                var nr_commits_suffix = " ${_('commits')} ";
 
		                var added_suffix = " ${_('files added')} ";
 
		                var changed_suffix = " ${_('files changed')} ";
 
		                var removed_suffix = " ${_('files removed')} ";
 

	
 
		                
 
		                if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";}
 
						if(added==1){added_suffix=" ${_('file added')} ";}
 
						if(changed==1){changed_suffix=" ${_('file changed')} ";}
 
						if(removed==1){removed_suffix=" ${_('file removed')} ";}
 
										                
 
		                showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd
 
								 +'<br/>'+
 
		                         nr_commits + nr_commits_suffix+'<br/>'+
 
		                         added + added_suffix +'<br/>'+
 
		                         changed + changed_suffix + '<br/>'+
 
		                         removed + removed_suffix + '<br/>');
 
		            }
 
		        }
 
		        else {
 
		        	  var tooltip = YUD.get("tooltip");
 
		        	  
 
			          if(tooltip) {
 
			                tooltip.parentNode.removeChild(tooltip);
 
			          }
 
		            previousPoint = null;
 
		        }
 
		    }
 
			
 
		    /**
 
		     * MAIN EXECUTION
 
		     */
 
			
 
			var data = getDataAccordingToRanges(initial_ranges);
 
			generateCheckboxes(data);
 
			
 
		    //main plot
 
		    var plot = YAHOO.widget.Flot(plotContainer,data,plot_options);
 
		    
 
			//overview
 
			var overview = YAHOO.widget.Flot(overviewContainer, overview_dataset, overview_options);
 
			
 
			//show initial selection on overview
 
			overview.setSelection(initial_ranges);    
 
			
 
		    plot.subscribe("plotselected", plotselected);
 
		    
 
		    overview.subscribe("plotselected", function (ranges) {
 
		        plot.setSelection(ranges);
 
		    });		
 
				
 
		    plot.subscribe("plothover", plothover);
 

	
 
		    YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]);
 
		}
 
			SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n});		
 
		</script>
 

	
 
    </div>
 
</div>    
 

	
 
<div class="box">    
 
    <div class="title">
 
        <div class="breadcrumbs">${h.link_to(_('Shortlog'),h.url('shortlog_home',repo_name=c.repo_name))}</div>
 
    </div>    
setup.py
Show inline comments
 
import sys
 
py_version = sys.version_info
 

	
 
from rhodecode import get_version
 

	
 
requirements = [
 
        "Pylons==1.0.0",
 
        "SQLAlchemy==0.6.5",
 
        "SQLAlchemy>=0.6.5",
 
        "Mako==0.3.6",
 
        "vcs==0.1.10",
 
        "pygments==1.3.1",
 
        "mercurial==1.7.2",
 
        "whoosh==1.3.4",
 
        "celery==2.1.4",
 
        "vcs=>0.1.10",
 
        "pygments>=1.3.1",
 
        "mercurial>=1.7.2",
 
        "whoosh>=1.3.4",
 
        "celery>=2.1.4",
 
        "py-bcrypt",
 
        "babel",
 
    ]
 

	
 
classifiers = ['Development Status :: 4 - Beta',
 
               'Environment :: Web Environment',
 
               'Framework :: Pylons',
 
               'Intended Audience :: Developers',
 
               'License :: OSI Approved :: BSD License',
 
               'Operating System :: OS Independent',
 
               'Programming Language :: Python', ]
 

	
 
if sys.version_info < (2, 6):
 
    requirements.append("simplejson")
 
    requirements.append("pysqlite")
 

	
 
#additional files from project that goes somewhere in the filesystem
 
#relative to sys.prefix
 
data_files = []
 

	
 
#additional files that goes into package itself
 
package_data = {'rhodecode': ['i18n/*/LC_MESSAGES/*.mo', ], }
 

	
 
description = ('Mercurial repository browser/management with '
 
               'build in push/pull server and full text search')
 
#long description
 
try:
 
    readme_file = 'README.rst'
 
    changelog_file = 'docs/changelog.rst'
 
    long_description = open(readme_file).read() + '\n\n' + \
 
        open(changelog_file).read()
 

	
 
except IOError, err:
 
    sys.stderr.write("[WARNING] Cannot find file specified as "
 
        "long_description (%s)\n or changelog (%s) skipping that file" \
 
            % (readme_file, changelog_file))
 
    long_description = description
 

	
 

	
 
try:
 
    from setuptools import setup, find_packages
 
except ImportError:
 
    from ez_setup import use_setuptools
 
    use_setuptools()
 
    from setuptools import setup, find_packages
 
#packages
 
packages = find_packages(exclude=['ez_setup'])
 

	
 
setup(
 
    name='RhodeCode',
 
    version=get_version(),
 
    description=description,
 
    long_description=long_description,
 
    keywords='rhodiumcode mercurial web hgwebdir gitweb git replacement serving hgweb rhodecode',
 
    license='BSD',
 
    author='Marcin Kuzminski',
 
    author_email='marcin@python-works.com',
 
    url='http://hg.python-works.com',
 
    install_requires=requirements,
 
    classifiers=classifiers,
 
    setup_requires=["PasteScript>=1.6.3"],
 
    data_files=data_files,
 
    packages=packages,
 
    include_package_data=True,
 
    test_suite='nose.collector',
 
    package_data=package_data,
 
    message_extractors={'rhodecode': [
 
            ('**.py', 'python', None),
 
            ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
 
            ('public/**', 'ignore', None)]},
 
    zip_safe=False,
 
    paster_plugins=['PasteScript', 'Pylons'],
 
    entry_points="""
 
    [paste.app_factory]
 
    main = rhodecode.config.middleware:make_app
 

	
 
    [paste.app_install]
 
    main = pylons.util:PylonsInstaller
 

	
 
    [paste.global_paster_command]
 
    make-index = rhodecode.lib.indexers:MakeIndex
 
    upgrade-db = rhodecode.lib.dbmigrate:UpgradeDb
 
    celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
 
    celerybeat=rhodecode.lib.celerypylons.commands:CeleryBeatCommand
 
    camqadm=rhodecode.lib.celerypylons.commands:CAMQPAdminCommand
 
    celeryev=rhodecode.lib.celerypylons.commands:CeleryEventCommand
 
              
 
    """,
 
)
0 comments (0 inline, 0 general)