Mercurial > kallithea
changeset 8678:16a359ce1801
vcs: move changeset diff from controller to vcs
Remove unfortunate model dependency on controller ... and put the VCS details
where they belong, with less VCS specific knowledge in the controllers.
author | Mads Kiilerich <mads@kiilerich.com> |
---|---|
date | Sun, 11 Oct 2020 11:52:22 +0200 |
parents | a765b2961eda |
children | 0be48652ca48 |
files | kallithea/controllers/compare.py kallithea/lib/vcs/backends/base.py kallithea/lib/vcs/backends/git/repository.py kallithea/lib/vcs/backends/hg/repository.py kallithea/model/pull_request.py |
diffstat | 5 files changed, 127 insertions(+), 111 deletions(-) [+] |
line wrap: on
line diff
--- a/kallithea/controllers/compare.py Sun Oct 11 00:19:46 2020 +0200 +++ b/kallithea/controllers/compare.py Sun Oct 11 11:52:22 2020 +0200 @@ -28,9 +28,7 @@ import logging -import re -import mercurial.unionrepo from tg import request from tg import tmpl_context as c from tg.i18n import ugettext as _ @@ -42,7 +40,6 @@ from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired from kallithea.lib.base import BaseRepoController, render from kallithea.lib.graphmod import graph_data -from kallithea.lib.utils2 import ascii_bytes, ascii_str, safe_bytes from kallithea.model.db import Repository @@ -74,104 +71,6 @@ h.flash(msg, category='error') raise HTTPFound(location=url('compare_home', repo_name=c.a_repo.repo_name)) - @staticmethod - def _get_changesets(alias, org_repo, org_rev, other_repo, other_rev): - """ - Returns lists of changesets that can be merged from org_repo@org_rev - to other_repo@other_rev - ... and the other way - ... and the ancestors that would be used for merge - - :param org_repo: repo object, that is most likely the original repo we forked from - :param org_rev: the revision we want our compare to be made - :param other_repo: repo object, most likely the fork of org_repo. It has - all changesets that we need to obtain - :param other_rev: revision we want out compare to be made on other_repo - """ - ancestors = None - if org_rev == other_rev: - org_changesets = [] - other_changesets = [] - - elif alias == 'hg': - # case two independent repos - if org_repo != other_repo: - hgrepo = mercurial.unionrepo.makeunionrepository(other_repo.baseui, - safe_bytes(other_repo.path), - safe_bytes(org_repo.path)) - # all ancestors of other_rev will be in other_repo and - # rev numbers from hgrepo can be used in other_repo - org_rev ancestors cannot - - # no remote compare do it on the same repository - else: - hgrepo = other_repo._repo - - ancestors = [ascii_str(hgrepo[ancestor].hex()) for ancestor in - hgrepo.revs(b"id(%s) & ::id(%s)", ascii_bytes(other_rev), ascii_bytes(org_rev))] - if ancestors: - log.debug("shortcut found: %s is already an ancestor of %s", other_rev, org_rev) - else: - log.debug("no shortcut found: %s is not an ancestor of %s", other_rev, org_rev) - ancestors = [ascii_str(hgrepo[ancestor].hex()) for ancestor in - hgrepo.revs(b"heads(::id(%s) & ::id(%s))", ascii_bytes(org_rev), ascii_bytes(other_rev))] # FIXME: expensive! - - other_changesets = [ - other_repo.get_changeset(rev) - for rev in hgrepo.revs( - b"ancestors(id(%s)) and not ancestors(id(%s)) and not id(%s)", - ascii_bytes(other_rev), ascii_bytes(org_rev), ascii_bytes(org_rev)) - ] - org_changesets = [ - org_repo.get_changeset(ascii_str(hgrepo[rev].hex())) - for rev in hgrepo.revs( - b"ancestors(id(%s)) and not ancestors(id(%s)) and not id(%s)", - ascii_bytes(org_rev), ascii_bytes(other_rev), ascii_bytes(other_rev)) - ] - - elif alias == 'git': - if org_repo != other_repo: - from dulwich.client import SubprocessGitClient - from dulwich.repo import Repo - - gitrepo = Repo(org_repo.path) - SubprocessGitClient(thin_packs=False).fetch(other_repo.path, gitrepo) - - gitrepo_remote = Repo(other_repo.path) - SubprocessGitClient(thin_packs=False).fetch(org_repo.path, gitrepo_remote) - - revs = [ - ascii_str(x.commit.id) - for x in gitrepo_remote.get_walker(include=[ascii_bytes(other_rev)], - exclude=[ascii_bytes(org_rev)]) - ] - other_changesets = [other_repo.get_changeset(rev) for rev in reversed(revs)] - if other_changesets: - ancestors = [other_changesets[0].parents[0].raw_id] - else: - # no changesets from other repo, ancestor is the other_rev - ancestors = [other_rev] - - gitrepo.close() - gitrepo_remote.close() - - else: - so = org_repo.run_git_command( - ['log', '--reverse', '--pretty=format:%H', - '-s', '%s..%s' % (org_rev, other_rev)] - ) - other_changesets = [org_repo.get_changeset(cs) - for cs in re.findall(r'[0-9a-fA-F]{40}', so)] - so = org_repo.run_git_command( - ['merge-base', org_rev, other_rev] - ) - ancestors = [re.findall(r'[0-9a-fA-F]{40}', so)[0]] - org_changesets = [] - - else: - raise Exception('Bad alias only git and hg is allowed') - - return other_changesets, org_changesets, ancestors - @LoginRequired(allow_default_user=True) @HasRepoPermissionLevelDecorator('read') def index(self, repo_name): @@ -220,9 +119,8 @@ c.cs_ref_name = other_ref_name c.cs_ref_type = other_ref_type - c.cs_ranges, c.cs_ranges_org, c.ancestors = self._get_changesets( - c.a_repo.scm_instance.alias, c.a_repo.scm_instance, c.a_rev, - c.cs_repo.scm_instance, c.cs_rev) + c.cs_ranges, c.cs_ranges_org, c.ancestors = c.a_repo.scm_instance.get_diff_changesets( + c.a_rev, c.cs_repo.scm_instance, c.cs_rev) raw_ids = [x.raw_id for x in c.cs_ranges] c.cs_comments = c.cs_repo.get_comments(raw_ids) c.cs_statuses = c.cs_repo.statuses(raw_ids)
--- a/kallithea/lib/vcs/backends/base.py Sun Oct 11 00:19:46 2020 +0200 +++ b/kallithea/lib/vcs/backends/base.py Sun Oct 11 11:52:22 2020 +0200 @@ -170,6 +170,20 @@ """ raise NotImplementedError + def get_diff_changesets(self, org_rev, other_repo, other_rev): + """ + Returns lists of changesets that can be merged from this repo @org_rev + to other_repo @other_rev + ... and the other way + ... and the ancestors that would be used for merge + + :param org_rev: the revision we want our compare to be made + :param other_repo: repo object, most likely the fork of org_repo. It has + all changesets that we need to obtain + :param other_rev: revision we want out compare to be made on other_repo + """ + raise NotImplementedError + def __getitem__(self, key): if isinstance(key, slice): return (self.get_changeset(rev) for rev in self.revisions[key])
--- a/kallithea/lib/vcs/backends/git/repository.py Sun Oct 11 00:19:46 2020 +0200 +++ b/kallithea/lib/vcs/backends/git/repository.py Sun Oct 11 11:52:22 2020 +0200 @@ -20,6 +20,7 @@ from collections import OrderedDict import mercurial.util # import url as hg_url +from dulwich.client import SubprocessGitClient from dulwich.config import ConfigFile from dulwich.objects import Tag from dulwich.repo import NotGitRepository, Repo @@ -30,7 +31,7 @@ from kallithea.lib.vcs.conf import settings from kallithea.lib.vcs.exceptions import (BranchDoesNotExistError, ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError, TagAlreadyExistError, TagDoesNotExistError) -from kallithea.lib.vcs.utils import ascii_str, date_fromtimestamp, makedate, safe_bytes, safe_str +from kallithea.lib.vcs.utils import ascii_bytes, ascii_str, date_fromtimestamp, makedate, safe_bytes, safe_str from kallithea.lib.vcs.utils.helpers import get_urllib_request_handlers from kallithea.lib.vcs.utils.lazy import LazyProperty from kallithea.lib.vcs.utils.paths import abspath, get_user_home @@ -544,6 +545,58 @@ return CollectionGenerator(self, revs) + def get_diff_changesets(self, org_rev, other_repo, other_rev): + """ + Returns lists of changesets that can be merged from this repo @org_rev + to other_repo @other_rev + ... and the other way + ... and the ancestors that would be used for merge + + :param org_rev: the revision we want our compare to be made + :param other_repo: repo object, most likely the fork of org_repo. It has + all changesets that we need to obtain + :param other_rev: revision we want out compare to be made on other_repo + """ + org_changesets = [] + ancestors = None + if org_rev == other_rev: + other_changesets = [] + elif self != other_repo: + gitrepo = Repo(self.path) + SubprocessGitClient(thin_packs=False).fetch(other_repo.path, gitrepo) + + gitrepo_remote = Repo(other_repo.path) + SubprocessGitClient(thin_packs=False).fetch(self.path, gitrepo_remote) + + revs = [ + ascii_str(x.commit.id) + for x in gitrepo_remote.get_walker(include=[ascii_bytes(other_rev)], + exclude=[ascii_bytes(org_rev)]) + ] + other_changesets = [other_repo.get_changeset(rev) for rev in reversed(revs)] + if other_changesets: + ancestors = [other_changesets[0].parents[0].raw_id] + else: + # no changesets from other repo, ancestor is the other_rev + ancestors = [other_rev] + + gitrepo.close() + gitrepo_remote.close() + + else: + so = self.run_git_command( + ['log', '--reverse', '--pretty=format:%H', + '-s', '%s..%s' % (org_rev, other_rev)] + ) + other_changesets = [self.get_changeset(cs) + for cs in re.findall(r'[0-9a-fA-F]{40}', so)] + so = self.run_git_command( + ['merge-base', org_rev, other_rev] + ) + ancestors = [re.findall(r'[0-9a-fA-F]{40}', so)[0]] + + return other_changesets, org_changesets, ancestors + def get_diff(self, rev1, rev2, path=None, ignore_whitespace=False, context=3): """
--- a/kallithea/lib/vcs/backends/hg/repository.py Sun Oct 11 00:19:46 2020 +0200 +++ b/kallithea/lib/vcs/backends/hg/repository.py Sun Oct 11 11:52:22 2020 +0200 @@ -33,12 +33,13 @@ import mercurial.sshpeer import mercurial.tags import mercurial.ui +import mercurial.unionrepo import mercurial.util from kallithea.lib.vcs.backends.base import BaseRepository, CollectionGenerator from kallithea.lib.vcs.exceptions import (BranchDoesNotExistError, ChangesetDoesNotExistError, EmptyRepositoryError, RepositoryError, TagAlreadyExistError, TagDoesNotExistError, VCSError) -from kallithea.lib.vcs.utils import ascii_str, author_email, author_name, date_fromtimestamp, makedate, safe_bytes, safe_str +from kallithea.lib.vcs.utils import ascii_bytes, ascii_str, author_email, author_name, date_fromtimestamp, makedate, safe_bytes, safe_str from kallithea.lib.vcs.utils.helpers import get_urllib_request_handlers from kallithea.lib.vcs.utils.lazy import LazyProperty from kallithea.lib.vcs.utils.paths import abspath @@ -545,6 +546,60 @@ return CollectionGenerator(self, revs) + def get_diff_changesets(self, org_rev, other_repo, other_rev): + """ + Returns lists of changesets that can be merged from this repo @org_rev + to other_repo @other_rev + ... and the other way + ... and the ancestors that would be used for merge + + :param org_rev: the revision we want our compare to be made + :param other_repo: repo object, most likely the fork of org_repo. It has + all changesets that we need to obtain + :param other_rev: revision we want out compare to be made on other_repo + """ + ancestors = None + if org_rev == other_rev: + org_changesets = [] + other_changesets = [] + + else: + # case two independent repos + if self != other_repo: + hgrepo = mercurial.unionrepo.makeunionrepository(other_repo.baseui, + safe_bytes(other_repo.path), + safe_bytes(self.path)) + # all ancestors of other_rev will be in other_repo and + # rev numbers from hgrepo can be used in other_repo - org_rev ancestors cannot + + # no remote compare do it on the same repository + else: + hgrepo = other_repo._repo + + ancestors = [ascii_str(hgrepo[ancestor].hex()) for ancestor in + hgrepo.revs(b"id(%s) & ::id(%s)", ascii_bytes(other_rev), ascii_bytes(org_rev))] + if ancestors: + log.debug("shortcut found: %s is already an ancestor of %s", other_rev, org_rev) + else: + log.debug("no shortcut found: %s is not an ancestor of %s", other_rev, org_rev) + ancestors = [ascii_str(hgrepo[ancestor].hex()) for ancestor in + hgrepo.revs(b"heads(::id(%s) & ::id(%s))", ascii_bytes(org_rev), ascii_bytes(other_rev))] # FIXME: expensive! + + other_changesets = [ + other_repo.get_changeset(rev) + for rev in hgrepo.revs( + b"ancestors(id(%s)) and not ancestors(id(%s)) and not id(%s)", + ascii_bytes(other_rev), ascii_bytes(org_rev), ascii_bytes(org_rev)) + ] + org_changesets = [ + self.get_changeset(ascii_str(hgrepo[rev].hex())) + for rev in hgrepo.revs( + b"ancestors(id(%s)) and not ancestors(id(%s)) and not id(%s)", + ascii_bytes(org_rev), ascii_bytes(other_rev), ascii_bytes(other_rev)) + ] + + return other_changesets, org_changesets, ancestors + def pull(self, url): """ Tries to pull changes from external location.
--- a/kallithea/model/pull_request.py Sun Oct 11 00:19:46 2020 +0200 +++ b/kallithea/model/pull_request.py Sun Oct 11 11:52:22 2020 +0200 @@ -192,7 +192,6 @@ return False def __init__(self, org_repo, other_repo, org_ref, other_ref, title, description, owner, reviewers): - from kallithea.controllers.compare import CompareController reviewers = set(reviewers) _assert_valid_reviewers(reviewers) @@ -214,10 +213,7 @@ other_display = h.short_ref(other_ref_type, other_ref_name) cs_ranges, _cs_ranges_not, ancestor_revs = \ - CompareController._get_changesets(org_repo.scm_instance.alias, - other_repo.scm_instance, other_rev, # org and other "swapped" - org_repo.scm_instance, org_rev, - ) + org_repo.scm_instance.get_diff_changesets(other_rev, org_repo.scm_instance, org_rev) # org and other "swapped" if not cs_ranges: raise self.Empty(_('Cannot create empty pull request'))