##// END OF EJS Templates
py3: add b'' annotations in some places where they will be needed later...
py3: add b'' annotations in some places where they will be needed later Mostly entirely trivial adding of b prefix that is a ignored for py2 ... and also a bit of related trivial reformatting/refactorings.

File last commit:

r7958:45bfab30 default
r7958:45bfab30 default
Show More
changeset.py
410 lines | 13.0 KiB | text/x-python | PythonLexer
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 import os
import posixpath
from kallithea.lib.vcs.backends.base import BaseChangeset
Mads Kiilerich
scripts: initial run of import cleanup using isort
r7718 from kallithea.lib.vcs.conf import settings
from kallithea.lib.vcs.exceptions import ChangesetDoesNotExistError, ChangesetError, ImproperArchiveTypeError, NodeDoesNotExistError, VCSError
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 from kallithea.lib.vcs.nodes import (
Mads Kiilerich
scripts: initial run of import cleanup using isort
r7718 AddedFileNodesGenerator, ChangedFileNodesGenerator, DirNode, FileNode, NodeKind, RemovedFileNodesGenerator, RootNode, SubModuleNode)
from kallithea.lib.vcs.utils import date_fromtimestamp, safe_str, safe_unicode
from kallithea.lib.vcs.utils.hgcompat import archival, hex, obsutil
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 from kallithea.lib.vcs.utils.lazy import LazyProperty
from kallithea.lib.vcs.utils.paths import get_dirs_for_path
Lars Kruse
codingstyle: trivial whitespace fixes...
r6789
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 class MercurialChangeset(BaseChangeset):
"""
Mads Kiilerich
vcs: improved alignment between hg and git changeset.py
r7903 Represents state of the repository at a revision.
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 """
def __init__(self, repository, revision):
self.repository = repository
Mads Kiilerich
compare: handle revset revision errors more gracefully
r4364 assert isinstance(revision, basestring), repr(revision)
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 self.raw_id = revision
self._ctx = repository._repo[revision]
self.revision = self._ctx._rev
self.nodes = {}
@LazyProperty
def tags(self):
Mads Kiilerich
py3: cleanup map usage and avoid py3 ambiguity...
r7892 return [safe_unicode(tag) for tag in self._ctx.tags()]
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
@LazyProperty
def branch(self):
Lars Kruse
codingstyle: trivial whitespace fixes...
r6789 return safe_unicode(self._ctx.branch())
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
@LazyProperty
Mads Kiilerich
vcs: introduce 'branches' attribute on changesets, making it possible for Git to show multiple branches for a changeset...
r7067 def branches(self):
return [safe_unicode(self._ctx.branch())]
@LazyProperty
Mads Kiilerich
graph: show branch close markers
r4348 def closesbranch(self):
domruf
changelog: add evolve information to the graph and the mark unstable changesets in red based on that information
r6074 return self._ctx.closesbranch()
Mads Kiilerich
graph: show branch close markers
r4348
@LazyProperty
Sean Farley
graph: show obsolete changesets with an 'X'
r5347 def obsolete(self):
domruf
changelog: add evolve information to the graph and the mark unstable changesets in red based on that information
r6074 return self._ctx.obsolete()
@LazyProperty
def bumped(self):
Mads Kiilerich
hg: bump minimum version to 5.1...
r7913 return self._ctx.phasedivergent()
domruf
changelog: add evolve information to the graph and the mark unstable changesets in red based on that information
r6074
@LazyProperty
def divergent(self):
Mads Kiilerich
hg: bump minimum version to 5.1...
r7913 return self._ctx.contentdivergent()
domruf
changelog: add evolve information to the graph and the mark unstable changesets in red based on that information
r6074
@LazyProperty
def extinct(self):
return self._ctx.extinct()
@LazyProperty
def unstable(self):
Mads Kiilerich
hg: bump minimum version to 5.1...
r7913 return self._ctx.orphan()
domruf
changelog: add evolve information to the graph and the mark unstable changesets in red based on that information
r6074
@LazyProperty
def phase(self):
if(self._ctx.phase() == 1):
return 'Draft'
elif(self._ctx.phase() == 2):
return 'Secret'
else:
return ''
Sean Farley
graph: show obsolete changesets with an 'X'
r5347
@LazyProperty
Sean Farley
changeset: add successors method for hg backend
r5349 def successors(self):
Mads Kiilerich
setup: bump Mercurial minimum version to 4.5 - that allow us to drop some hacks, and it was released more than one year ago
r7615 successors = obsutil.successorssets(self._ctx._repo, self._ctx.node(), closest=True)
Sean Farley
changeset: add successors method for hg backend
r5349 if successors:
# flatten the list here handles both divergent (len > 1)
# and the usual case (len = 1)
successors = [hex(n)[:12] for sub in successors for n in sub if n != self._ctx.node()]
return successors
@LazyProperty
Manuel Jacob
hg: rename `precursors` property of MercurialChangeset to `predecessors`...
r7445 def predecessors(self):
Mads Kiilerich
setup: bump Mercurial minimum version to 4.5 - that allow us to drop some hacks, and it was released more than one year ago
r7615 return [hex(n)[:12] for n in obsutil.closestpredecessors(self._ctx._repo, self._ctx.node())]
Sean Farley
changeset: add precursors method for hg backend
r5351
@LazyProperty
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 def bookmarks(self):
Mads Kiilerich
py3: cleanup map usage and avoid py3 ambiguity...
r7892 return [safe_unicode(bookmark) for bookmark in self._ctx.bookmarks()]
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
@LazyProperty
def message(self):
return safe_unicode(self._ctx.description())
@LazyProperty
def committer(self):
return safe_unicode(self.author)
@LazyProperty
def author(self):
return safe_unicode(self._ctx.user())
@LazyProperty
def date(self):
return date_fromtimestamp(*self._ctx.date())
@LazyProperty
def _timestamp(self):
return self._ctx.date()[0]
@LazyProperty
def status(self):
"""
Returns modified, added, removed, deleted files for current changeset
"""
return self.repository._repo.status(self._ctx.p1().node(),
self._ctx.node())
@LazyProperty
def _file_paths(self):
return list(self._ctx)
@LazyProperty
def _dir_paths(self):
p = list(set(get_dirs_for_path(*self._file_paths)))
p.insert(0, '')
return p
@LazyProperty
def _paths(self):
return self._dir_paths + self._file_paths
@LazyProperty
def id(self):
if self.last:
return u'tip'
return self.short_id
@LazyProperty
def short_id(self):
return self.raw_id[:12]
@LazyProperty
def parents(self):
"""
Returns list of parents changesets.
"""
return [self.repository.get_changeset(parent.rev())
for parent in self._ctx.parents() if parent.rev() >= 0]
@LazyProperty
def children(self):
"""
Returns list of children changesets.
"""
return [self.repository.get_changeset(child.rev())
for child in self._ctx.children() if child.rev() >= 0]
def next(self, branch=None):
if branch and self.branch != branch:
raise VCSError('Branch option used on changeset not belonging '
'to that branch')
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 cs = self
while True:
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 try:
domruf
hg: fix next() and prev() for obsolete changesets...
r6702 next_ = cs.repository.revisions.index(cs.raw_id) + 1
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 next_rev = cs.repository.revisions[next_]
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 except IndexError:
raise ChangesetDoesNotExistError
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 cs = cs.repository.get_changeset(next_rev)
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 if not branch or branch == cs.branch:
return cs
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
def prev(self, branch=None):
if branch and self.branch != branch:
raise VCSError('Branch option used on changeset not belonging '
'to that branch')
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 cs = self
while True:
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 try:
domruf
hg: fix next() and prev() for obsolete changesets...
r6702 prev_ = cs.repository.revisions.index(cs.raw_id) - 1
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 if prev_ < 0:
raise IndexError
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 prev_rev = cs.repository.revisions[prev_]
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 except IndexError:
raise ChangesetDoesNotExistError
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 cs = cs.repository.get_changeset(prev_rev)
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
Mads Kiilerich
vcs: replace recursive implementation of prev&next with iterative...
r4400 if not branch or branch == cs.branch:
return cs
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
Mads Kiilerich
hg: don't use custom diff arguments when generating diffstats for rss feed...
r7266 def diff(self):
Mads Kiilerich
vcs: improved alignment between hg and git changeset.py
r7903 # Only used to feed diffstat
Mads Kiilerich
py3: add b'' annotations in some places where they will be needed later...
r7958 return b''.join(self._ctx.diff())
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
def _fix_path(self, path):
"""
Paths are stored without trailing slash so we need to get rid off it if
needed. Also mercurial keeps filenodes as str so we need to decode
from unicode to str
"""
if path.endswith('/'):
path = path.rstrip('/')
return safe_str(path)
def _get_kind(self, path):
path = self._fix_path(path)
if path in self._file_paths:
return NodeKind.FILE
elif path in self._dir_paths:
return NodeKind.DIR
else:
raise ChangesetError("Node does not exist at the given path '%s'"
% (path))
def _get_filectx(self, path):
path = self._fix_path(path)
if self._get_kind(path) != NodeKind.FILE:
raise ChangesetError("File does not exist for revision %s at "
" '%s'" % (self.raw_id, path))
return self._ctx.filectx(path)
def _extract_submodules(self):
"""
returns a dictionary with submodule information from substate file
of hg repository
"""
return self._ctx.substate
def get_file_mode(self, path):
"""
Returns stat mode of the file at the given ``path``.
"""
fctx = self._get_filectx(path)
Mads Kiilerich
py3: add b'' annotations in some places where they will be needed later...
r7958 if b'x' in fctx.flags():
Mads Kiilerich
py3: use explicit octal literals...
r7890 return 0o100755
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 else:
Mads Kiilerich
py3: use explicit octal literals...
r7890 return 0o100644
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
def get_file_content(self, path):
"""
Returns content of the file at given ``path``.
"""
fctx = self._get_filectx(path)
return fctx.data()
def get_file_size(self, path):
"""
Returns size of the file at given ``path``.
"""
fctx = self._get_filectx(path)
return fctx.size()
def get_file_changeset(self, path):
"""
Returns last commit of the file at the given ``path``.
"""
return self.get_file_history(path, limit=1)[0]
def get_file_history(self, path, limit=None):
"""
Returns history of file as reversed list of ``Changeset`` objects for
which file at given ``path`` has been modified.
"""
fctx = self._get_filectx(path)
hist = []
cnt = 0
for cs in reversed([x for x in fctx.filelog()]):
cnt += 1
hist.append(hex(fctx.filectx(cs).node()))
Mads Kiilerich
cleanup: fixes of checking for None...
r5564 if limit is not None and cnt == limit:
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 break
return [self.repository.get_changeset(node) for node in hist]
def get_file_annotate(self, path):
"""
Returns a generator of four element tuples with
lineno, sha, changeset lazy loader and line
"""
Mads Kiilerich
hg: don't provide annotate linenumber parameter - it has always defaulted to False and was removed in 4.6
r7198 annotations = self._get_filectx(path).annotate()
Mads Kiilerich
hg: bump minimum version to 5.1...
r7913 annotation_lines = [(annotateline.fctx, annotateline.text) for annotateline in annotations]
Mads Kiilerich
hg: refactor annotation to generate a list of normalized annotation lines before iterating...
r7197 for i, (fctx, l) in enumerate(annotation_lines):
Mads Kiilerich
hg: trivial refactorings of annotate functionality...
r7196 sha = fctx.hex()
yield (i + 1, sha, lambda sha=sha, l=l: self.repository.get_changeset(sha), l)
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
def fill_archive(self, stream=None, kind='tgz', prefix=None,
subrepos=False):
"""
Fills up given stream.
:param stream: file like object.
:param kind: one of following: ``zip``, ``tgz`` or ``tbz2``.
Default: ``tgz``.
:param prefix: name of root directory in archive.
Default is repository name and changeset's raw_id joined with dash
(``repo-tip.<KIND>``).
:param subrepos: include subrepos in this archive.
:raise ImproperArchiveTypeError: If given kind is wrong.
:raise VcsError: If given stream is None
"""
Mads Kiilerich
cleanup: minor refactorings and simplification of dict usage...
r7906 allowed_kinds = settings.ARCHIVE_SPECS
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 if kind not in allowed_kinds:
raise ImproperArchiveTypeError('Archive kind not supported use one'
Mads Kiilerich
cleanup: minor refactorings and simplification of dict usage...
r7906 'of %s' % ' '.join(allowed_kinds))
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
if stream is None:
raise VCSError('You need to pass in a valid stream for filling'
' with archival data')
if prefix is None:
prefix = '%s-%s' % (self.repository.name, self.short_id)
elif prefix.startswith('/'):
raise VCSError("Prefix cannot start with leading slash")
elif prefix.strip() == '':
raise VCSError("Prefix cannot be empty")
archival.archive(self.repository._repo, stream, self.raw_id,
kind, prefix=prefix, subrepos=subrepos)
def get_nodes(self, path):
"""
Returns combined ``DirNode`` and ``FileNode`` objects list representing
state of changeset at the given ``path``. If node at the given ``path``
is not instance of ``DirNode``, ChangesetError would be raised.
"""
if self._get_kind(path) != NodeKind.DIR:
raise ChangesetError("Directory does not exist for revision %s at "
" '%s'" % (self.revision, path))
path = self._fix_path(path)
filenodes = [FileNode(f, changeset=self) for f in self._file_paths
if os.path.dirname(f) == path]
dirs = path == '' and '' or [d for d in self._dir_paths
if d and posixpath.dirname(d) == path]
dirnodes = [DirNode(d, changeset=self) for d in dirs
if os.path.dirname(d) == path]
als = self.repository.alias
for k, vals in self._extract_submodules().iteritems():
#vals = url,rev,type
loc = vals[0]
cs = vals[1]
dirnodes.append(SubModuleNode(k, url=loc, changeset=cs,
alias=als))
nodes = dirnodes + filenodes
for node in nodes:
self.nodes[node.path] = node
nodes.sort()
return nodes
def get_node(self, path):
"""
Returns ``Node`` object from the given ``path``. If there is no node at
the given ``path``, ``ChangesetError`` would be raised.
"""
path = self._fix_path(path)
Lars Kruse
codingstyle: replace "not ... in ..." with "... not in ..."...
r6791 if path not in self.nodes:
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187 if path in self._file_paths:
node = FileNode(path, changeset=self)
elif path in self._dir_paths or path in self._dir_paths:
if path == '':
node = RootNode(changeset=self)
else:
node = DirNode(path, changeset=self)
else:
raise NodeDoesNotExistError("There is no file nor directory "
"at the given path: '%s' at revision %s"
% (path, self.short_id))
# cache node
self.nodes[path] = node
return self.nodes[path]
@LazyProperty
def affected_files(self):
"""
Gets a fast accessible file changes for given changeset
"""
return self._ctx.files()
@property
def added(self):
"""
Returns list of added ``FileNode`` objects.
"""
return AddedFileNodesGenerator([n for n in self.status[1]], self)
@property
def changed(self):
"""
Returns list of modified ``FileNode`` objects.
"""
Lars Kruse
codingstyle: trivial whitespace fixes...
r6789 return ChangedFileNodesGenerator([n for n in self.status[0]], self)
Bradley M. Kuhn
Second step in two-part process to rename directories....
r4187
@property
def removed(self):
"""
Returns list of removed ``FileNode`` objects.
"""
return RemovedFileNodesGenerator([n for n in self.status[2]], self)
Mads Kiilerich
changeset: show and link to graft or transplant source
r4375
@LazyProperty
def extra(self):
return self._ctx.extra()