Changeset - 218ed589e44a
[Not reviewed]
default
0 4 0
Mads Kiilerich - 12 years ago 2013-06-04 13:26:41
madski@unity3d.com
Grafted from: 6d3b7006e98a
branch selectors: show closed branches too

It would be even better if they were fetched dynamically somehow and perhaps
placed in a sub sub menu ... but showing them in the list is often better than
not showing them at all.
4 files changed with 27 insertions and 1 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/changelog.py
Show inline comments
 
@@ -83,121 +83,125 @@ class ChangelogController(BaseRepoContro
 
        try:
 
            return c.rhodecode_repo.get_changeset(rev)
 
        except EmptyRepositoryError, e:
 
            if not redirect_after:
 
                return None
 
            h.flash(h.literal(_('There are no changesets yet')),
 
                    category='warning')
 
            redirect(url('changelog_home', repo_name=repo.repo_name))
 

	
 
        except RepositoryError, e:
 
            log.error(traceback.format_exc())
 
            h.flash(str(e), category='warning')
 
            if not partial:
 
                redirect(h.url('changelog_home', repo_name=repo.repo_name))
 
            raise HTTPBadRequest()
 

	
 
    def _graph(self, repo, revs_int, repo_size, size, p):
 
        """
 
        Generates a DAG graph for repo
 

	
 
        :param repo:
 
        :param revs_int:
 
        :param repo_size:
 
        :param size:
 
        :param p:
 
        """
 
        if not revs_int:
 
            c.jsdata = json.dumps([])
 
            return
 

	
 
        data = []
 
        revs = revs_int
 

	
 
        dag = _dagwalker(repo, revs, repo.alias)
 
        dag = _colored(dag)
 
        for (id, type, ctx, vtx, edges) in dag:
 
            data.append(['', vtx, edges])
 

	
 
        c.jsdata = json.dumps(data)
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def index(self, repo_name, revision=None, f_path=None):
 
        limit = 100
 
        default = 20
 
        if request.GET.get('size'):
 
            c.size = max(min(safe_int(request.GET.get('size')), limit), 1)
 
            session['changelog_size'] = c.size
 
            session.save()
 
        else:
 
            c.size = int(session.get('changelog_size', default))
 
        # min size must be 1
 
        c.size = max(c.size, 1)
 
        p = safe_int(request.GET.get('page', 1), 1)
 
        branch_name = request.GET.get('branch', None)
 
        c.changelog_for_path = f_path
 
        try:
 

	
 
            if f_path:
 
                log.debug('generating changelog for path %s' % f_path)
 
                # get the history for the file !
 
                tip_cs = c.rhodecode_repo.get_changeset()
 
                try:
 
                    collection = tip_cs.get_file_history(f_path)
 
                except (NodeDoesNotExistError, ChangesetError):
 
                    #this node is not present at tip !
 
                    try:
 
                        cs = self.__get_css_or_redirect(revision, repo_name)
 
                        collection = cs.get_file_history(f_path)
 
                    except RepositoryError, e:
 
                        h.flash(str(e), category='warning')
 
                        redirect(h.url('changelog_home', repo_name=repo_name))
 
                collection = list(reversed(collection))
 
            else:
 
                collection = c.rhodecode_repo.get_changesets(start=0,
 
                                                        branch_name=branch_name)
 
            c.total_cs = len(collection)
 

	
 
            c.pagination = RepoPage(collection, page=p, item_count=c.total_cs,
 
                                    items_per_page=c.size, branch=branch_name,)
 
            collection = list(c.pagination)
 
            page_revisions = [x.raw_id for x in c.pagination]
 
            c.comments = c.rhodecode_db_repo.get_comments(page_revisions)
 
            c.statuses = c.rhodecode_db_repo.statuses(page_revisions)
 
        except (EmptyRepositoryError), e:
 
            h.flash(str(e), category='warning')
 
            return redirect(url('summary_home', repo_name=c.repo_name))
 
        except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
 
            log.error(traceback.format_exc())
 
            h.flash(str(e), category='error')
 
            return redirect(url('changelog_home', repo_name=c.repo_name))
 

	
 
        c.branch_name = branch_name
 
        c.branch_filters = [('', _('All Branches'))] + \
 
            [(k, k) for k in c.rhodecode_repo.branches.keys()]
 
        if c.rhodecode_repo.closed_branches:
 
            prefix = _('(closed)') + ' '
 
            c.branch_filters += [('-', '-')] + \
 
                [(k, prefix + k) for k in c.rhodecode_repo.closed_branches.keys()]
 
        _revs = []
 
        if not f_path:
 
            _revs = [x.revision for x in c.pagination]
 
        self._graph(c.rhodecode_repo, _revs, c.total_cs, c.size, p)
 

	
 
        return render('changelog/changelog.html')
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def changelog_details(self, cs):
 
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            c.cs = c.rhodecode_repo.get_changeset(cs)
 
            return render('changelog/changelog_details.html')
 
        raise HTTPNotFound()
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def changelog_summary(self, repo_name):
 
        if request.environ.get('HTTP_X_PARTIAL_XHR'):
 
            _load_changelog_summary()
 

	
 
            return render('changelog/changelog_summary_data.html')
 
        raise HTTPNotFound()
rhodecode/lib/vcs/backends/git/repository.py
Show inline comments
 
@@ -278,192 +278,196 @@ class GitRepository(BaseRepository):
 
                    "for this repository" % (revision))
 

	
 
        elif is_bstr:
 
            # get by branch/tag name
 
            _ref_revision = self._parsed_refs.get(revision)
 
            if _ref_revision:  # and _ref_revision[1] in ['H', 'RH', 'T']:
 
                return _ref_revision[0]
 

	
 
            _tags_shas = self.tags.values()
 
            # maybe it's a tag ? we don't have them in self.revisions
 
            if revision in _tags_shas:
 
                return _tags_shas[_tags_shas.index(revision)]
 

	
 
            elif not SHA_PATTERN.match(revision) or revision not in self.revisions:
 
                raise ChangesetDoesNotExistError("Revision %s does not exist "
 
                    "for this repository" % (revision))
 

	
 
        # Ensure we return full id
 
        if not SHA_PATTERN.match(str(revision)):
 
            raise ChangesetDoesNotExistError("Given revision %s not recognized"
 
                % revision)
 
        return revision
 

	
 
    def _get_archives(self, archive_name='tip'):
 

	
 
        for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
 
                yield {"type": i[0], "extension": i[1], "node": archive_name}
 

	
 
    def _get_url(self, url):
 
        """
 
        Returns normalized url. If schema is not given, would fall to
 
        filesystem (``file:///``) schema.
 
        """
 
        url = str(url)
 
        if url != 'default' and not '://' in url:
 
            url = ':///'.join(('file', url))
 
        return url
 

	
 
    def get_hook_location(self):
 
        """
 
        returns absolute path to location where hooks are stored
 
        """
 
        loc = os.path.join(self.path, 'hooks')
 
        if not self.bare:
 
            loc = os.path.join(self.path, '.git', 'hooks')
 
        return loc
 

	
 
    @LazyProperty
 
    def name(self):
 
        return os.path.basename(self.path)
 

	
 
    @LazyProperty
 
    def last_change(self):
 
        """
 
        Returns last change made on this repository as datetime object
 
        """
 
        return date_fromtimestamp(self._get_mtime(), makedate()[1])
 

	
 
    def _get_mtime(self):
 
        try:
 
            return time.mktime(self.get_changeset().date.timetuple())
 
        except RepositoryError:
 
            idx_loc = '' if self.bare else '.git'
 
            # fallback to filesystem
 
            in_path = os.path.join(self.path, idx_loc, "index")
 
            he_path = os.path.join(self.path, idx_loc, "HEAD")
 
            if os.path.exists(in_path):
 
                return os.stat(in_path).st_mtime
 
            else:
 
                return os.stat(he_path).st_mtime
 

	
 
    @LazyProperty
 
    def description(self):
 
        idx_loc = '' if self.bare else '.git'
 
        undefined_description = u'unknown'
 
        description_path = os.path.join(self.path, idx_loc, 'description')
 
        if os.path.isfile(description_path):
 
            return safe_unicode(open(description_path).read())
 
        else:
 
            return undefined_description
 

	
 
    @LazyProperty
 
    def contact(self):
 
        undefined_contact = u'Unknown'
 
        return undefined_contact
 

	
 
    @property
 
    def branches(self):
 
        if not self.revisions:
 
            return {}
 
        sortkey = lambda ctx: ctx[0]
 
        _branches = [(x[0], x[1][0])
 
                     for x in self._parsed_refs.iteritems() if x[1][1] == 'H']
 
        return OrderedDict(sorted(_branches, key=sortkey, reverse=False))
 

	
 
    @LazyProperty
 
    def closed_branches(self):
 
        return {}
 

	
 
    @LazyProperty
 
    def tags(self):
 
        return self._get_tags()
 

	
 
    def _get_tags(self):
 
        if not self.revisions:
 
            return {}
 

	
 
        sortkey = lambda ctx: ctx[0]
 
        _tags = [(x[0], x[1][0])
 
                 for x in self._parsed_refs.iteritems() if x[1][1] == 'T']
 
        return OrderedDict(sorted(_tags, key=sortkey, reverse=True))
 

	
 
    def tag(self, name, user, revision=None, message=None, date=None,
 
            **kwargs):
 
        """
 
        Creates and returns a tag for the given ``revision``.
 

	
 
        :param name: name for new tag
 
        :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
 
        :param revision: changeset id for which new tag would be created
 
        :param message: message of the tag's commit
 
        :param date: date of tag's commit
 

	
 
        :raises TagAlreadyExistError: if tag with same name already exists
 
        """
 
        if name in self.tags:
 
            raise TagAlreadyExistError("Tag %s already exists" % name)
 
        changeset = self.get_changeset(revision)
 
        message = message or "Added tag %s for commit %s" % (name,
 
            changeset.raw_id)
 
        self._repo.refs["refs/tags/%s" % name] = changeset._commit.id
 

	
 
        self._parsed_refs = self._get_parsed_refs()
 
        self.tags = self._get_tags()
 
        return changeset
 

	
 
    def remove_tag(self, name, user, message=None, date=None):
 
        """
 
        Removes tag with the given ``name``.
 

	
 
        :param name: name of the tag to be removed
 
        :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
 
        :param message: message of the tag's removal commit
 
        :param date: date of tag's removal commit
 

	
 
        :raises TagDoesNotExistError: if tag with given name does not exists
 
        """
 
        if name not in self.tags:
 
            raise TagDoesNotExistError("Tag %s does not exist" % name)
 
        tagpath = posixpath.join(self._repo.refs.path, 'refs', 'tags', name)
 
        try:
 
            os.remove(tagpath)
 
            self._parsed_refs = self._get_parsed_refs()
 
            self.tags = self._get_tags()
 
        except OSError, e:
 
            raise RepositoryError(e.strerror)
 

	
 
    @LazyProperty
 
    def _parsed_refs(self):
 
        return self._get_parsed_refs()
 

	
 
    def _get_parsed_refs(self):
 
        # cache the property
 
        _repo = self._repo
 
        refs = _repo.get_refs()
 
        keys = [('refs/heads/', 'H'),
 
                ('refs/remotes/origin/', 'RH'),
 
                ('refs/tags/', 'T')]
 
        _refs = {}
 
        for ref, sha in refs.iteritems():
 
            for k, type_ in keys:
 
                if ref.startswith(k):
 
                    _key = ref[len(k):]
 
                    if type_ == 'T':
 
                        obj = _repo.get_object(sha)
 
                        if isinstance(obj, Tag):
 
                            sha = _repo.get_object(sha).object[1]
 
                    _refs[_key] = [sha, type_]
 
                    break
 
        return _refs
 

	
 
    def _heads(self, reverse=False):
 
        refs = self._repo.get_refs()
 
        heads = {}
 

	
 
        for key, val in refs.items():
 
            for ref_key in ['refs/heads/', 'refs/remotes/origin/']:
 
                if key.startswith(ref_key):
 
                    n = key[len(ref_key):]
 
                    if n not in ['HEAD']:
 
                        heads[n] = val
 

	
 
        return heads if reverse else dict((y, x) for x, y in heads.iteritems())
 

	
 
    def get_changeset(self, revision=None):
 
        """
rhodecode/lib/vcs/backends/hg/repository.py
Show inline comments
 
@@ -8,226 +8,233 @@
 
    :created_on: Apr 8, 2010
 
    :copyright: (c) 2010-2011 by Marcin Kuzminski, Lukasz Balcerzak.
 
"""
 

	
 
import os
 
import time
 
import urllib
 
import urllib2
 
import logging
 
import datetime
 

	
 

	
 
from rhodecode.lib.vcs.backends.base import BaseRepository, CollectionGenerator
 
from rhodecode.lib.vcs.conf import settings
 

	
 
from rhodecode.lib.vcs.exceptions import (
 
    BranchDoesNotExistError, ChangesetDoesNotExistError, EmptyRepositoryError,
 
    RepositoryError, VCSError, TagAlreadyExistError, TagDoesNotExistError
 
)
 
from rhodecode.lib.vcs.utils import (
 
    author_email, author_name, date_fromtimestamp, makedate, safe_unicode
 
)
 
from rhodecode.lib.vcs.utils.lazy import LazyProperty
 
from rhodecode.lib.vcs.utils.ordered_dict import OrderedDict
 
from rhodecode.lib.vcs.utils.paths import abspath
 
from rhodecode.lib.vcs.utils.hgcompat import (
 
    ui, nullid, match, patch, diffopts, clone, get_contact, pull,
 
    localrepository, RepoLookupError, Abort, RepoError, hex, scmutil, hg_url,
 
    httpbasicauthhandler, httpdigestauthhandler, peer
 
)
 

	
 
from .changeset import MercurialChangeset
 
from .inmemory import MercurialInMemoryChangeset
 
from .workdir import MercurialWorkdir
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class MercurialRepository(BaseRepository):
 
    """
 
    Mercurial repository backend
 
    """
 
    DEFAULT_BRANCH_NAME = 'default'
 
    scm = 'hg'
 

	
 
    def __init__(self, repo_path, create=False, baseui=None, src_url=None,
 
                 update_after_clone=False):
 
        """
 
        Raises RepositoryError if repository could not be find at the given
 
        ``repo_path``.
 

	
 
        :param repo_path: local path of the repository
 
        :param create=False: if set to True, would try to create repository if
 
           it does not exist rather than raising exception
 
        :param baseui=None: user data
 
        :param src_url=None: would try to clone repository from given location
 
        :param update_after_clone=False: sets update of working copy after
 
          making a clone
 
        """
 

	
 
        if not isinstance(repo_path, str):
 
            raise VCSError('Mercurial backend requires repository path to '
 
                           'be instance of <str> got %s instead' %
 
                           type(repo_path))
 

	
 
        self.path = abspath(repo_path)
 
        self.baseui = baseui or ui.ui()
 
        # We've set path and ui, now we can set _repo itself
 
        self._repo = self._get_repo(create, src_url, update_after_clone)
 

	
 
    @property
 
    def _empty(self):
 
        """
 
        Checks if repository is empty ie. without any changesets
 
        """
 
        # TODO: Following raises errors when using InMemoryChangeset...
 
        # return len(self._repo.changelog) == 0
 
        return len(self.revisions) == 0
 

	
 
    @LazyProperty
 
    def revisions(self):
 
        """
 
        Returns list of revisions' ids, in ascending order.  Being lazy
 
        attribute allows external tools to inject shas from cache.
 
        """
 
        return self._get_all_revisions()
 

	
 
    @LazyProperty
 
    def name(self):
 
        return os.path.basename(self.path)
 

	
 
    @LazyProperty
 
    def branches(self):
 
        return self._get_branches()
 

	
 
    @LazyProperty
 
    def closed_branches(self):
 
        return self._get_branches(normal=False, closed=True)
 

	
 
    @LazyProperty
 
    def allbranches(self):
 
        """
 
        List all branches, including closed branches.
 
        """
 
        return self._get_branches(closed=True)
 

	
 
    def _get_branches(self, closed=False):
 
    def _get_branches(self, normal=True, closed=False):
 
        """
 
        Get's branches for this repository
 
        Returns only not closed branches by default
 

	
 
        :param closed: return also closed branches for mercurial
 
        :param normal: return also normal branches
 
        """
 

	
 
        if self._empty:
 
            return {}
 

	
 
        def _branchtags(localrepo):
 
            """
 
            Patched version of mercurial branchtags to not return the closed
 
            branches
 

	
 
            :param localrepo: locarepository instance
 
            """
 

	
 
            bt = {}
 
            bt_closed = {}
 
            for bn, heads in localrepo.branchmap().iteritems():
 
                tip = heads[-1]
 
                if 'close' in localrepo.changelog.read(tip)[5]:
 
                    bt_closed[bn] = tip
 
                else:
 
                    bt[bn] = tip
 

	
 
            if not normal:
 
                return bt_closed
 
            if closed:
 
                bt.update(bt_closed)
 
            return bt
 

	
 
        sortkey = lambda ctx: ctx[0]  # sort by name
 
        _branches = [(safe_unicode(n), hex(h),) for n, h in
 
                     _branchtags(self._repo).items()]
 

	
 
        return OrderedDict(sorted(_branches, key=sortkey, reverse=False))
 

	
 
    @LazyProperty
 
    def tags(self):
 
        """
 
        Get's tags for this repository
 
        """
 
        return self._get_tags()
 

	
 
    def _get_tags(self):
 
        if self._empty:
 
            return {}
 

	
 
        sortkey = lambda ctx: ctx[0]  # sort by name
 
        _tags = [(safe_unicode(n), hex(h),) for n, h in
 
                 self._repo.tags().items()]
 

	
 
        return OrderedDict(sorted(_tags, key=sortkey, reverse=True))
 

	
 
    def tag(self, name, user, revision=None, message=None, date=None,
 
            **kwargs):
 
        """
 
        Creates and returns a tag for the given ``revision``.
 

	
 
        :param name: name for new tag
 
        :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
 
        :param revision: changeset id for which new tag would be created
 
        :param message: message of the tag's commit
 
        :param date: date of tag's commit
 

	
 
        :raises TagAlreadyExistError: if tag with same name already exists
 
        """
 
        if name in self.tags:
 
            raise TagAlreadyExistError("Tag %s already exists" % name)
 
        changeset = self.get_changeset(revision)
 
        local = kwargs.setdefault('local', False)
 

	
 
        if message is None:
 
            message = "Added tag %s for changeset %s" % (name,
 
                changeset.short_id)
 

	
 
        if date is None:
 
            date = datetime.datetime.now().ctime()
 

	
 
        try:
 
            self._repo.tag(name, changeset._ctx.node(), message, local, user,
 
                date)
 
        except Abort, e:
 
            raise RepositoryError(e.message)
 

	
 
        # Reinitialize tags
 
        self.tags = self._get_tags()
 
        tag_id = self.tags[name]
 

	
 
        return self.get_changeset(revision=tag_id)
 

	
 
    def remove_tag(self, name, user, message=None, date=None):
 
        """
 
        Removes tag with the given ``name``.
 

	
 
        :param name: name of the tag to be removed
 
        :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
 
        :param message: message of the tag's removal commit
 
        :param date: date of tag's removal commit
 

	
 
        :raises TagDoesNotExistError: if tag with given name does not exists
 
        """
 
        if name not in self.tags:
 
            raise TagDoesNotExistError("Tag %s does not exist" % name)
 
        if message is None:
 
            message = "Removed tag %s" % name
 
        if date is None:
 
            date = datetime.datetime.now().ctime()
 
        local = False
 

	
 
        try:
 
            self._repo.tag(name, nullid, message, local, user, date)
 
            self.tags = self._get_tags()
 
        except Abort, e:
 
            raise RepositoryError(e.message)
 

	
 
    @LazyProperty
 
    def bookmarks(self):
 
        """
 
        Get's bookmarks for this repository
 
        """
 
        return self._get_bookmarks()
 

	
rhodecode/templates/switch_to_list.html
Show inline comments
 
## -*- coding: utf-8 -*-
 
<li>
 
    ${h.link_to('%s (%s)' % (_('Branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
 
    <ul>
 
    %if c.rhodecode_repo.branches.values():
 
        %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
 
            <li><div><pre>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=(branch[0] if '/' not in branch[0] else branch[1]), at=branch[0]))}</pre></div></li>
 
        %endfor
 
    %else:
 
        <li>${h.link_to(_('There are no branches yet'),'#')}</li>
 
    %endif
 
    </ul>
 
</li>
 
%if c.rhodecode_repo.closed_branches.values():
 
<li>
 
    ${h.link_to('%s (%s)' % (_('Closed Branches'),len(c.rhodecode_repo.closed_branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
 
    <ul>
 
        <li><a>-</a></li>
 
        %for cnt,branch in enumerate(c.rhodecode_repo.closed_branches.items()):
 
            <li><div><pre>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=(branch[0] if '/' not in branch[0] else branch[1]), at=branch[0]))}</pre></div></li>
 
        %endfor
 
    </ul>
 
</li>
 
%endif
 
<li>
 
    ${h.link_to('%s (%s)' % (_('Tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
 
    <ul>
 
    %if c.rhodecode_repo.tags.values():
 
        %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
 
         <li><div><pre>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=(tag[0] if '/' not in tag[0] else tag[1]), at=tag[0]))}</pre></div></li>
 
        %endfor
 
    %else:
 
        <li>${h.link_to(_('There are no tags yet'),'#')}</li>
 
    %endif
 
    </ul>
 
</li>
 
%if c.rhodecode_repo.alias == 'hg':
 
<li>
 
    ${h.link_to('%s (%s)' % (_('Bookmarks'),len(c.rhodecode_repo.bookmarks.values()),),h.url('bookmarks_home',repo_name=c.repo_name),class_='bookmarks childs')}
 
    <ul>
 
    %if c.rhodecode_repo.bookmarks.values():
 
        %for cnt,book in enumerate(c.rhodecode_repo.bookmarks.items()):
 
         <li><div><pre>${h.link_to('%s - %s' % (book[0],h.short_id(book[1])),h.url('files_home',repo_name=c.repo_name,revision=(book[0] if '/' not in book[0] else book[1]), at=book[0]))}</pre></div></li>
 
        %endfor
 
    %else:
 
        <li>${h.link_to(_('There are no bookmarks yet'),'#')}</li>
 
    %endif
 
    </ul>
 
</li>
 
%endif
0 comments (0 inline, 0 general)