##// END OF EJS Templates
run-tests: assign value to ESCAPEMAP - dict.update do not return self...
run-tests: assign value to ESCAPEMAP - dict.update do not return self a36cc85a5b7b did more than what the description said and introduced a bug.

File last commit:

r21482:869a28d0 default
r21539:0c407790 default
Show More
context.py
1624 lines | 54.1 KiB | text/x-python | PythonLexer
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 # context.py - changeset and file context objects for mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Matt Mackall
context: internalize lookup logic...
r16376 from node import nullid, nullrev, short, hex, bin
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Mads Kiilerich
context: remove unused filectx.ancestor
r20984 import mdiff, error, util, scmutil, subrepo, patch, encoding, phases
Matt Mackall
context: add a match builder method...
r14669 import match as matchmod
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 import os, errno, stat
Pierre-Yves David
obsolete: introduce caches for all meaningful sets...
r17469 import obsolete as obsmod
Pierre-Yves David
context: retrieve hidden from filteredrevs...
r18252 import repoview
Augie Fackler
context: add a getfileset() method so fewer things need fileset directly...
r20400 import fileset
Matt Mackall
filectx: add rename traversal for parents()
r3122
Matt Mackall
util: take propertycache from context.py
r8207 propertycache = util.propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368
Sean Farley
basectx: add an empty class that will be used as a parent of all contexts...
r19537 class basectx(object):
"""A basectx object represents the common logic for its children:
changectx: read-only context that is already present in the repo,
workingctx: a context that represents the working directory and can
be committed,
memctx: a context that represents changes in-memory and can also
be committed."""
def __new__(cls, repo, changeid='', *args, **kwargs):
Sean Farley
basectx: return a copied context if changeid is already a basectx...
r19538 if isinstance(changeid, basectx):
return changeid
o = super(basectx, cls).__new__(cls)
o._repo = repo
o._rev = nullrev
o._node = nullid
return o
Sean Farley
basectx: add an empty class that will be used as a parent of all contexts...
r19537
Sean Farley
basectx: move __str__ from changectx
r19540 def __str__(self):
return short(self.node())
Sean Farley
basectx: move __int__ from changectx
r19545 def __int__(self):
return self.rev()
Sean Farley
basectx: move __repr__ from changectx...
r19546 def __repr__(self):
return "<%s %s>" % (type(self).__name__, str(self))
Sean Farley
basectx: move __eq__ from changectx...
r19547 def __eq__(self, other):
try:
return type(self) == type(other) and self._rev == other._rev
except AttributeError:
return False
Sean Farley
basectx: move __ne__ from changectx
r19548 def __ne__(self, other):
return not (self == other)
Sean Farley
basectx: move __contains__ from changectx
r19550 def __contains__(self, key):
return key in self._manifest
Sean Farley
basectx: move __getitem__ from changectx
r19551 def __getitem__(self, key):
return self.filectx(key)
Sean Farley
basectx: move __iter__ from changectx
r19552 def __iter__(self):
for f in sorted(self._manifest):
yield f
Sean Farley
basectx: add _manifestmatches method...
r21466 def _manifestmatches(self, match, s):
"""generate a new manifest filtered by the match argument
This method is for internal use only and mainly exists to provide an
object oriented way for other contexts to customize the manifest
generation.
"""
mf = self.manifest().copy()
if match.always():
return mf
for fn in mf.keys():
if not match(fn):
del mf[fn]
return mf
Sean Farley
basectx: add _matchstatus method for factoring out last of parentworking logic...
r21481 def _matchstatus(self, other, s, match, listignored, listclean,
listunknown):
"""return match.always if match is none
This internal method provides a way for child objects to override the
match operator.
"""
return match or matchmod.always(self._repo.root, self._repo.getcwd())
Sean Farley
context: add a no-op _prestatus method...
r21473 def _prestatus(self, other, s, match, listignored, listclean, listunknown):
"""provide a hook to allow child objects to preprocess status results
For example, this allows other contexts, such as workingctx, to query
the dirstate before comparing the manifests.
"""
return s
Sean Farley
context: add a no-op _poststatus method...
r21476 def _poststatus(self, other, s, match, listignored, listclean, listunknown):
"""provide a hook to allow child objects to postprocess status results
For example, this allows other contexts, such as workingctx, to filter
suspect symlinks in the case of FAT32 and NTFS filesytems.
"""
return s
Sean Farley
context: add _buildstatus method...
r21471 def _buildstatus(self, other, s, match, listignored, listclean,
listunknown):
"""build a status with respect to another context"""
mf1 = other._manifestmatches(match, s)
mf2 = self._manifestmatches(match, s)
modified, added, clean = [], [], []
deleted, unknown, ignored = s[3], [], []
withflags = mf1.withflags() | mf2.withflags()
for fn, mf2node in mf2.iteritems():
if fn in mf1:
if (fn not in deleted and
((fn in withflags and mf1.flags(fn) != mf2.flags(fn)) or
(mf1[fn] != mf2node and
(mf2node or self[fn].cmp(other[fn]))))):
modified.append(fn)
elif listclean:
clean.append(fn)
del mf1[fn]
elif fn not in deleted:
added.append(fn)
removed = mf1.keys()
return [modified, added, removed, deleted, unknown, ignored, clean]
Sean Farley
basectx: move substate from changectx
r19549 @propertycache
def substate(self):
return subrepo.state(self, self._repo.ui)
Sean Farley
basectx: move rev from changectx
r19541 def rev(self):
return self._rev
Sean Farley
basectx: move node from changectx
r19542 def node(self):
return self._node
Sean Farley
basectx: move hex from changectx
r19543 def hex(self):
Sean Farley
basectx: change _node to node() in hex...
r19544 return hex(self.node())
Sean Farley
basectx: move manifest from changectx
r19553 def manifest(self):
return self._manifest
Sean Farley
basectx: move phasestr from changectx
r19554 def phasestr(self):
return phases.phasenames[self.phase()]
Sean Farley
basectx: move mutable from changectx
r19555 def mutable(self):
return self.phase() > phases.public
Sean Farley
basectx: move rev from changectx
r19541
Augie Fackler
context: add a getfileset() method so fewer things need fileset directly...
r20400 def getfileset(self, expr):
return fileset.getfileset(self, expr)
Sean Farley
context: move evolution functions from changectx to basectx...
r19734 def obsolete(self):
"""True if the changeset is obsolete"""
return self.rev() in obsmod.getrevs(self._repo, 'obsolete')
def extinct(self):
"""True if the changeset is extinct"""
return self.rev() in obsmod.getrevs(self._repo, 'extinct')
def unstable(self):
"""True if the changeset is not obsolete but it's ancestor are"""
return self.rev() in obsmod.getrevs(self._repo, 'unstable')
def bumped(self):
"""True if the changeset try to be a successor of a public changeset
Only non-public and non-obsolete changesets may be bumped.
"""
return self.rev() in obsmod.getrevs(self._repo, 'bumped')
def divergent(self):
"""Is a successors of a changeset with multiple possible successors set
Only non-public and non-obsolete changesets may be divergent.
"""
return self.rev() in obsmod.getrevs(self._repo, 'divergent')
def troubled(self):
"""True if the changeset is either unstable, bumped or divergent"""
return self.unstable() or self.bumped() or self.divergent()
def troubles(self):
"""return the list of troubles affecting this changesets.
Troubles are returned as strings. possible values are:
- unstable,
- bumped,
- divergent.
"""
troubles = []
if self.unstable():
troubles.append('unstable')
if self.bumped():
troubles.append('bumped')
if self.divergent():
troubles.append('divergent')
return troubles
Sean Farley
basectx: move parents from changectx
r19556 def parents(self):
"""return contexts for each parent changeset"""
return self._parents
Sean Farley
basectx: move p1 from changectx
r19557 def p1(self):
return self._parents[0]
Sean Farley
basectx: move p2 from changectx
r19558 def p2(self):
if len(self._parents) == 2:
return self._parents[1]
return changectx(self._repo, -1)
Sean Farley
basectx: move _fileinfo from changectx
r19559 def _fileinfo(self, path):
if '_manifest' in self.__dict__:
try:
return self._manifest[path], self._manifest.flags(path)
except KeyError:
raise error.ManifestLookupError(self._node, path,
_('not found in manifest'))
if '_manifestdelta' in self.__dict__ or path in self.files():
if path in self._manifestdelta:
return (self._manifestdelta[path],
self._manifestdelta.flags(path))
node, flag = self._repo.manifest.find(self._changeset[0], path)
if not node:
raise error.ManifestLookupError(self._node, path,
_('not found in manifest'))
return node, flag
Sean Farley
basectx: move filenode from changectx
r19560 def filenode(self, path):
return self._fileinfo(path)[0]
Sean Farley
basectx: move flags from changectx
r19561 def flags(self, path):
try:
return self._fileinfo(path)[1]
except error.LookupError:
return ''
Sean Farley
basectx: move sub from changectx
r19562 def sub(self, path):
return subrepo.subrepo(self, path)
Sean Farley
basectx: move match from changectx
r19563 def match(self, pats=[], include=None, exclude=None, default='glob'):
r = self._repo
return matchmod.match(r.root, r.getcwd(), pats,
include, exclude, default,
auditor=r.auditor, ctx=self)
Sean Farley
basectx: move diff from changectx
r19564 def diff(self, ctx2=None, match=None, **opts):
"""Returns a diff generator for the given contexts and matcher"""
if ctx2 is None:
ctx2 = self.p1()
Sean Farley
basectx: remove unnecessary check of instance...
r19568 if ctx2 is not None:
Sean Farley
basectx: move diff from changectx
r19564 ctx2 = self._repo[ctx2]
diffopts = patch.diffopts(self._repo.ui, opts)
return patch.diff(self._repo, ctx2.node(), self.node(),
match=match, opts=diffopts)
Sean Farley
basectx: move _dirs from changectx
r19565 @propertycache
def _dirs(self):
return scmutil.dirs(self._manifest)
Sean Farley
basectx: move dirs from changectx
r19566 def dirs(self):
return self._dirs
Sean Farley
basectx: move dirty from changectx
r19567 def dirty(self):
return False
Augie Fackler
makememctx: move from patch to context to break import cycle
r20035 def makememctx(repo, parents, text, user, date, branch, files, store,
editor=None):
def getfilectx(repo, memctx, path):
data, (islink, isexec), copied = store.getfile(path)
return memfilectx(path, data, islink=islink, isexec=isexec,
copied=copied)
extra = {}
if branch:
extra['branch'] = encoding.fromlocal(branch)
ctx = memctx(repo, parents, text, files, getfilectx, user,
FUJIWARA Katsunori
context: move editor invocation from "makememctx()" to "memctx.__init__()"...
r21238 date, extra, editor)
Augie Fackler
makememctx: move from patch to context to break import cycle
r20035 return ctx
Sean Farley
basectx: add an empty class that will be used as a parent of all contexts...
r19537 class changectx(basectx):
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 """A changecontext object makes access to data related to a particular
Mads Kiilerich
spelling: random spell checker fixes
r19951 changeset convenient. It represents a read-only context already present in
Sean Farley
basectx: add an empty class that will be used as a parent of all contexts...
r19537 the repo."""
Matt Mackall
context: simplify changeid logic
r6741 def __init__(self, repo, changeid=''):
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 """changeid is a revision number, node, or tag"""
Sean Farley
changectx: if passing a basectx then exit __init__ immediately
r19539
# since basectx.__new__ already took care of copying the object, we
# don't need to do anything in __init__, so we just exit here
if isinstance(changeid, basectx):
return
Matt Mackall
context: simplify changeid logic
r6741 if changeid == '':
changeid = '.'
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 self._repo = repo
Matt Mackall
context: internalize lookup logic...
r16376
if isinstance(changeid, int):
Pierre-Yves David
clfilter: ensure context raise RepoLookupError when the revision is filtered...
r18084 try:
self._node = repo.changelog.node(changeid)
except IndexError:
raise error.RepoLookupError(
_("unknown revision '%s'") % changeid)
Dirkjan Ochtman
context: special-case changectx setup for integer changeid
r7367 self._rev = changeid
Matt Mackall
context: internalize lookup logic...
r16376 return
Matt Mackall
context: grudging accept longs in constructor
r16760 if isinstance(changeid, long):
changeid = str(changeid)
Matt Mackall
context: internalize lookup logic...
r16376 if changeid == '.':
self._node = repo.dirstate.p1()
self._rev = repo.changelog.rev(self._node)
return
if changeid == 'null':
self._node = nullid
self._rev = nullrev
return
if changeid == 'tip':
Pierre-Yves David
changectx: fix the handling of `tip`...
r18464 self._node = repo.changelog.tip()
self._rev = repo.changelog.rev(self._node)
Matt Mackall
context: internalize lookup logic...
r16376 return
if len(changeid) == 20:
try:
self._node = changeid
self._rev = repo.changelog.rev(changeid)
return
except LookupError:
pass
try:
r = int(changeid)
if str(r) != changeid:
raise ValueError
l = len(repo.changelog)
if r < 0:
r += l
if r < 0 or r >= l:
raise ValueError
self._rev = r
self._node = repo.changelog.node(r)
return
Pierre-Yves David
clfilter: stronger detection of filtered changeset in changectx.__init__...
r18423 except (ValueError, OverflowError, IndexError):
Matt Mackall
context: internalize lookup logic...
r16376 pass
if len(changeid) == 40:
try:
self._node = bin(changeid)
self._rev = repo.changelog.rev(self._node)
return
except (TypeError, LookupError):
pass
if changeid in repo._bookmarks:
self._node = repo._bookmarks[changeid]
self._rev = repo.changelog.rev(self._node)
return
if changeid in repo._tagscache.tags:
self._node = repo._tagscache.tags[changeid]
self._rev = repo.changelog.rev(self._node)
return
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 try:
self._node = repo.branchtip(changeid)
Matt Mackall
context: internalize lookup logic...
r16376 self._rev = repo.changelog.rev(self._node)
return
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 except error.RepoLookupError:
pass
Matt Mackall
context: internalize lookup logic...
r16376
self._node = repo.changelog._partialmatch(changeid)
if self._node is not None:
self._rev = repo.changelog.rev(self._node)
return
# lookup failed
# check if it might have come from damaged dirstate
Pierre-Yves David
clfilter: prevent unwanted warning about filtered parents as unknown...
r18005 #
# XXX we could avoid the unfiltered if we had a recognizable exception
# for filtered changeset access
if changeid in repo.unfiltered().dirstate.parents():
Matt Mackall
context: internalize lookup logic...
r16376 raise error.Abort(_("working directory has unknown parent '%s'!")
% short(changeid))
try:
if len(changeid) == 20:
changeid = hex(changeid)
except TypeError:
pass
raise error.RepoLookupError(
_("unknown revision '%s'") % changeid)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Paul Moore
python 2.6 compatibility: add __hash__ to classes that have __eq__
r6469 def __hash__(self):
try:
return hash(self._rev)
except AttributeError:
return id(self)
Matt Mackall
context: add __nonzero__ methods
r3168 def __nonzero__(self):
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 return self._rev != nullrev
Matt Mackall
context: add __nonzero__ methods
r3168
Martin Geisler
context: use Python 2.4 decorator syntax
r8157 @propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 def _changeset(self):
Matt Mackall
context: use rev for changelog lookup...
r16377 return self._repo.changelog.read(self.rev())
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368
Martin Geisler
context: use Python 2.4 decorator syntax
r8157 @propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 def _manifest(self):
return self._repo.manifest.read(self._changeset[0])
Martin Geisler
context: use Python 2.4 decorator syntax
r8157 @propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 def _manifestdelta(self):
return self._repo.manifest.readdelta(self._changeset[0])
Martin Geisler
context: use Python 2.4 decorator syntax
r8157 @propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 def _parents(self):
p = self._repo.changelog.parentrevs(self._rev)
if p[1] == nullrev:
p = p[:-1]
return [changectx(self._repo, x) for x in p]
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215
Matt Mackall
many, many trivial check-code fixups
r10282 def changeset(self):
return self._changeset
def manifestnode(self):
return self._changeset[0]
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Matt Mackall
many, many trivial check-code fixups
r10282 def user(self):
return self._changeset[1]
def date(self):
return self._changeset[2]
def files(self):
return self._changeset[3]
def description(self):
return self._changeset[4]
def branch(self):
Matt Mackall
branch: operate on branch names in local string space where possible...
r13047 return encoding.tolocal(self._changeset[5].get("branch"))
Brodie Rao
context: add changectx.closesbranch() method...
r16720 def closesbranch(self):
return 'close' in self._changeset[5]
Matt Mackall
many, many trivial check-code fixups
r10282 def extra(self):
return self._changeset[5]
def tags(self):
return self._repo.nodetags(self._node)
David Soria Parra
context: add method to return all bookmarks pointing to a node
r13384 def bookmarks(self):
return self._repo.nodebookmarks(self._node)
Pierre-Yves David
phases: add a phase method to context
r15421 def phase(self):
Patrick Mezard
phases: introduce phasecache...
r16657 return self._repo._phasecache.phase(self._repo, self._rev)
Pierre-Yves David
hidden: Add ``hidden`` method for context
r14644 def hidden(self):
Kevin Bullock
filtering: rename filters to their antonyms...
r18382 return self._rev in repoview.filterrevs(self._repo, 'visible')
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
def children(self):
"""return contexts for each child changeset"""
Benoit Boissinot
context.py: self.repo is not defined, change to self._repo
r2627 c = self._repo.changelog.children(self._node)
Thomas Arendsen Hein
white space and line break cleanups
r3673 return [changectx(self._repo, x) for x in c]
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Matt Mackall
Merge with stable...
r6876 def ancestors(self):
Bryan O'Sullivan
revlog: ancestors(*revs) becomes ancestors(revs) (API)...
r16866 for a in self._repo.changelog.ancestors([self._rev]):
Matt Mackall
Merge with stable...
r6876 yield changectx(self._repo, a)
def descendants(self):
Bryan O'Sullivan
revlog: descendants(*revs) becomes descendants(revs) (API)...
r16867 for d in self._repo.changelog.descendants([self._rev]):
Matt Mackall
Merge with stable...
r6876 yield changectx(self._repo, d)
Benoit Boissinot
context: create a filectxt with filelog reuse
r3966 def filectx(self, path, fileid=None, filelog=None):
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 """get a file context from this changeset"""
Benoit Boissinot
context.py: filectxs was using a keyword arg, add it to filectx
r2628 if fileid is None:
fileid = self.filenode(path)
Benoit Boissinot
context: create a filectxt with filelog reuse
r3966 return filectx(self._repo, path, fileid=fileid,
changectx=self, filelog=filelog)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Matt Mackall
ancestor: silence multiple ancestor warning outside of merge (issue4234)...
r21203 def ancestor(self, c2, warn=False):
Matt Mackall
changectx: add ancestor function
r3125 """
Mads Kiilerich
context: introduce merge.preferancestor for controlling which ancestor to pick...
r21126 return the "best" ancestor context of self and c2
Matt Mackall
changectx: add ancestor function
r3125 """
Matt Mackall
merge: fix changectx.ancestor(workingctx) (issue1327)
r9843 # deal with workingctxs
n2 = c2._node
Martin Geisler
code style: prefer 'is' and 'is not' tests with singletons
r13031 if n2 is None:
Matt Mackall
merge: fix changectx.ancestor(workingctx) (issue1327)
r9843 n2 = c2._parents[0]._node
Mads Kiilerich
context: tell when .ancestor picks one of multiple common ancestors heads...
r21125 cahs = self._repo.changelog.commonancestorsheads(self._node, n2)
if not cahs:
anc = nullid
elif len(cahs) == 1:
anc = cahs[0]
else:
Mads Kiilerich
context: introduce merge.preferancestor for controlling which ancestor to pick...
r21126 for r in self._repo.ui.configlist('merge', 'preferancestor'):
ctx = changectx(self._repo, r)
anc = ctx.node()
if anc in cahs:
break
else:
anc = self._repo.changelog.ancestor(self._node, n2)
Matt Mackall
ancestor: silence multiple ancestor warning outside of merge (issue4234)...
r21203 if warn:
self._repo.ui.status(
(_("note: using %s as ancestor of %s and %s\n") %
(short(anc), short(self._node), short(n2))) +
''.join(_(" alternatively, use --config "
"merge.preferancestor=%s\n") %
short(n) for n in sorted(cahs) if n != anc))
Mads Kiilerich
context: tell when .ancestor picks one of multiple common ancestors heads...
r21125 return changectx(self._repo, anc)
Matt Mackall
changectx: add ancestor function
r3125
FUJIWARA Katsunori
context: add "descendant()" to changectx for efficient descendant examination...
r17626 def descendant(self, other):
"""True if other is descendant of this changeset"""
return self._repo.changelog.descendant(self._rev, other._rev)
Matt Mackall
context: add walk method
r6764 def walk(self, match):
Simon Heimberg
context: replace pseudo-set by real set
r8380 fset = set(match.files())
Matt Mackall
context: add walk method
r6764 # for dirstate.walk, files=['.'] means "walk the whole tree".
# follow that here, too
Simon Heimberg
context: replace pseudo-set by real set
r8380 fset.discard('.')
Durham Goode
changectx: increase perf of walk function...
r20292
# avoid the entire walk if we're only looking for specific files
if fset and not match.anypats():
if util.all([fn in self for fn in fset]):
for fn in sorted(fset):
if match(fn):
yield fn
raise StopIteration
Matt Mackall
context: add walk method
r6764 for fn in self:
FUJIWARA Katsunori
context: use 'changectx.dirs()' in 'walk()' for directory patterns...
r16145 if fn in fset:
# specified pattern is the exact name
fset.remove(fn)
Matt Mackall
context: add walk method
r6764 if match(fn):
yield fn
Simon Heimberg
context: replace pseudo-set by real set
r8380 for fn in sorted(fset):
FUJIWARA Katsunori
context: use 'changectx.dirs()' in 'walk()' for directory patterns...
r16145 if fn in self._dirs:
# specified pattern is a directory
continue
Mads Kiilerich
context: remove redundant handling of match.bad return value...
r21114 match.bad(fn, _('no such file in rev %s') % self)
Matt Mackall
context: add walk method
r6764
Sean Farley
basefilectx: add an empty class that will be used as a parent of file contexts...
r19572 class basefilectx(object):
"""A filecontext object represents the common logic for its children:
filectx: read-only access to a filerevision that is already present
in the repo,
workingfilectx: a filecontext that represents files from the working
directory,
memfilectx: a filecontext that represents files in-memory."""
def __new__(cls, repo, path, *args, **kwargs):
return super(basefilectx, cls).__new__(cls)
Sean Farley
basefilectx: move _filelog from filectx
r19573 @propertycache
def _filelog(self):
return self._repo.file(self._path)
Sean Farley
basefilectx: move _changeid from filectx
r19574 @propertycache
def _changeid(self):
if '_changeid' in self.__dict__:
return self._changeid
elif '_changectx' in self.__dict__:
return self._changectx.rev()
else:
return self._filelog.linkrev(self._filerev)
Sean Farley
basefilectx: move _filenode from filectx
r19575 @propertycache
def _filenode(self):
if '_fileid' in self.__dict__:
return self._filelog.lookup(self._fileid)
else:
return self._changectx.filenode(self._path)
Sean Farley
basefilectx: move _filerev from filectx
r19576 @propertycache
def _filerev(self):
return self._filelog.rev(self._filenode)
Sean Farley
basefilectx: move _repopath from filectx
r19577 @propertycache
def _repopath(self):
return self._path
Sean Farley
basefilectx: move __nonzero__ from filectx
r19578 def __nonzero__(self):
try:
self._filenode
return True
except error.LookupError:
# file is missing
return False
Sean Farley
basefilectx: move __str__ from filectx
r19579 def __str__(self):
Sean Farley
basefilectx: use basectx __str__ instead of duplicating logic...
r19660 return "%s@%s" % (self.path(), self._changectx)
Sean Farley
basefilectx: move __str__ from filectx
r19579
Sean Farley
basefilectx: move __repr__ from filectx...
r19580 def __repr__(self):
return "<%s %s>" % (type(self).__name__, str(self))
Sean Farley
basefilectx: move __hash__ from filectx
r19581 def __hash__(self):
try:
return hash((self._path, self._filenode))
except AttributeError:
return id(self)
Sean Farley
basefilectx: move __eq__ from filectx...
r19582 def __eq__(self, other):
try:
return (type(self) == type(other) and self._path == other._path
and self._filenode == other._filenode)
except AttributeError:
return False
Sean Farley
basefilectx: move __ne__ from filectx
r19583 def __ne__(self, other):
return not (self == other)
Sean Farley
basefilectx: move filerev from filectx
r19584 def filerev(self):
return self._filerev
Sean Farley
basefilectx: move filenode from filectx
r19585 def filenode(self):
return self._filenode
Sean Farley
basefilectx: move flags from filectx
r19586 def flags(self):
return self._changectx.flags(self._path)
Sean Farley
basefilectx: move filelog from filectx
r19587 def filelog(self):
return self._filelog
Sean Farley
basefilectx: move rev from filectx
r19588 def rev(self):
return self._changeid
Sean Farley
basefilectx: move linkrev from filectx
r19589 def linkrev(self):
return self._filelog.linkrev(self._filerev)
Sean Farley
basefilectx: move node from filectx
r19590 def node(self):
return self._changectx.node()
Sean Farley
basefilectx: move hex from filectx...
r19591 def hex(self):
return self._changectx.hex()
Sean Farley
basefilectx: move user from filectx
r19592 def user(self):
return self._changectx.user()
Sean Farley
basefilectx: move date from filectx
r19593 def date(self):
return self._changectx.date()
Sean Farley
basefilectx: move files from filectx
r19594 def files(self):
return self._changectx.files()
Sean Farley
basefilectx: move description from filectx
r19595 def description(self):
return self._changectx.description()
Sean Farley
basefilectx: move branch from filectx
r19596 def branch(self):
return self._changectx.branch()
Sean Farley
basefilectx: move extra from filectx
r19597 def extra(self):
return self._changectx.extra()
Sean Farley
basefilectx: move phase from filectx
r19598 def phase(self):
return self._changectx.phase()
Sean Farley
basefilectx: move phasestr from filectx
r19599 def phasestr(self):
return self._changectx.phasestr()
Sean Farley
basefilectx: move manifest from filectx
r19600 def manifest(self):
return self._changectx.manifest()
Sean Farley
basefilectx: move changectx from filectx
r19601 def changectx(self):
return self._changectx
Sean Farley
basefilectx: move filerev from filectx
r19584
Sean Farley
basefilectx: move path from filectx
r19602 def path(self):
return self._path
Sean Farley
basefilectx: move isbinary from filectx
r19603 def isbinary(self):
try:
return util.binary(self.data())
except IOError:
return False
Sean Farley
basefilectx: move cmp from filectx
r19604 def cmp(self, fctx):
"""compare with other file context
returns True if different than fctx.
"""
if (fctx._filerev is None
and (self._repo._encodefilterpats
# if file data starts with '\1\n', empty metadata block is
# prepended, which adds 4 bytes to filelog.size().
or self.size() - 4 == fctx.size())
or self.size() == fctx.size()):
return self._filelog.cmp(self._filenode, fctx.data())
return True
Sean Farley
basefilectx: move parents from filectx
r19605 def parents(self):
p = self._path
fl = self._filelog
pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
r = self._filelog.renamed(self._filenode)
if r:
pl[0] = (r[0], r[1], None)
return [filectx(self._repo, p, fileid=n, filelog=l)
for p, n, l in pl if n != nullid]
Sean Farley
basefilectx: move p1 from filectx
r19606 def p1(self):
return self.parents()[0]
Sean Farley
basefilectx: move p2 from filectx
r19607 def p2(self):
p = self.parents()
if len(p) == 2:
return p[1]
return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
Patrick Mezard
annotate: support diff whitespace filtering flags (issue3030)...
r15528 def annotate(self, follow=False, linenumber=None, diffopts=None):
Brendan Cully
Refactor annotate copy support.
r3172 '''returns a list of tuples of (ctx, line) for each line
in the file, where ctx is the filectx of the node where
FUJIWARA Katsunori
Allow filectx.annotate to return the line number of first appearance.
r4856 that line was last changed.
This returns tuples of ((ctx, linenumber), line) for each line,
if "linenumber" parameter is NOT "None".
In such tuples, linenumber means one at the first appearance
in the managed file.
To reduce annotation cost,
this returns fixed value(False is used) as linenumber,
if "linenumber" parameter is "False".'''
Brendan Cully
Refactor annotate copy support.
r3172
FUJIWARA Katsunori
Allow filectx.annotate to return the line number of first appearance.
r4856 def decorate_compat(text, rev):
Brendan Cully
Refactor annotate copy support.
r3172 return ([rev] * len(text.splitlines()), text)
FUJIWARA Katsunori
Allow filectx.annotate to return the line number of first appearance.
r4856 def without_linenumber(text, rev):
return ([(rev, False)] * len(text.splitlines()), text)
def with_linenumber(text, rev):
size = len(text.splitlines())
return ([(rev, i) for i in xrange(1, size + 1)], text)
decorate = (((linenumber is None) and decorate_compat) or
(linenumber and with_linenumber) or
without_linenumber)
Brendan Cully
Refactor annotate copy support.
r3172 def pair(parent, child):
Patrick Mezard
annotate: support diff whitespace filtering flags (issue3030)...
r15528 blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts,
refine=True)
for (a1, a2, b1, b2), t in blocks:
# Changed blocks ('!') or blocks made only of blank lines ('~')
# belong to the child.
if t == '=':
child[0][b1:b2] = parent[0][a1:a2]
Brendan Cully
Refactor annotate copy support.
r3172 return child
Matt Mackall
fix memory usage of revlog caches by limiting cache size [issue1639]
r9097 getlog = util.lrucachefunc(lambda x: self._repo.file(x))
Brendan Cully
Refactor annotate copy support.
r3172
def parents(f):
Durham Goode
annotate: simplify annotate parent function...
r19292 pl = f.parents()
# Don't return renamed parents if we aren't following.
if not follow:
pl = [p for p in pl if p.path() == f.path()]
Brendan Cully
Refactor annotate copy support.
r3172
Durham Goode
annotate: simplify annotate parent function...
r19292 # renamed filectx won't have a filelog yet, so set it
# from the cache to save time
for p in pl:
if not '_filelog' in p.__dict__:
p._filelog = getlog(p.path())
Brendan Cully
filectx.annotate: return filectx for each line instead of rev
r3146
Durham Goode
annotate: simplify annotate parent function...
r19292 return pl
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Brendan Cully
Fix annotate where linkrev != rev without exporting linkrev
r3404 # use linkrev to find the first changeset where self appeared
Maxim Dounin
Fix copies reporting in log and convert....
r5811 if self.rev() != self.linkrev():
Durham Goode
filectx: remove dependencies on filerev...
r19314 base = self.filectx(self.filenode())
Brendan Cully
Fix annotate where linkrev != rev without exporting linkrev
r3404 else:
base = self
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 # This algorithm would prefer to be recursive, but Python is a
# bit recursion-hostile. Instead we do an iterative
# depth-first search.
visit = [base]
hist = {}
pcache = {}
Brendan Cully
Fix annotate where linkrev != rev without exporting linkrev
r3404 needed = {base: 1}
Brendan Cully
Refactor annotate copy support.
r3172 while visit:
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 f = visit[-1]
FUJIWARA Katsunori
annotate: increase refcount of each revisions correctly (issue3841)...
r18993 pcached = f in pcache
if not pcached:
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 pcache[f] = parents(f)
Brendan Cully
Refactor annotate copy support.
r3172
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 ready = True
pl = pcache[f]
for p in pl:
if p not in hist:
ready = False
visit.append(p)
FUJIWARA Katsunori
annotate: increase refcount of each revisions correctly (issue3841)...
r18993 if not pcached:
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 needed[p] = needed.get(p, 0) + 1
if ready:
visit.pop()
FUJIWARA Katsunori
annotate: reuse already calculated annotation...
r18992 reusable = f in hist
if reusable:
curr = hist[f]
else:
curr = decorate(f.data(), f)
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 for p in pl:
FUJIWARA Katsunori
annotate: reuse already calculated annotation...
r18992 if not reusable:
curr = pair(hist[p], curr)
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 if needed[p] == 1:
del hist[p]
FUJIWARA Katsunori
annotate: discard refcount of discarded annotation for memory efficiency...
r19061 del needed[p]
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 else:
needed[p] -= 1
Matt Mackall
util: add sort helper
r6762
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 hist[f] = curr
pcache[f] = []
Brendan Cully
Refactor annotate copy support.
r3172
Matt Mackall
ancestor: rewrite to deal with crossed linkrevs (issue2682)...
r13552 return zip(hist[base][0], hist[base][1].splitlines(True))
Matt Mackall
filectx: allow passing filelog in init to avoid opening new filelogs
r3124
Sean Farley
basefilectx: move ancestors from filectx
r19610 def ancestors(self, followfirst=False):
visit = {}
c = self
cut = followfirst and 1 or None
while True:
for parent in c.parents()[:cut]:
visit[(parent.rev(), parent.node())] = parent
if not visit:
break
c = visit.pop(max(visit))
yield c
Sean Farley
basefilectx: move annotate from filectx
r19608 class filectx(basefilectx):
"""A filecontext object makes access to data related to a particular
filerevision convenient."""
def __init__(self, repo, path, changeid=None, fileid=None,
filelog=None, changectx=None):
"""changeid can be a changeset revision, node, or tag.
fileid can be a file revision or node."""
self._repo = repo
self._path = path
assert (changeid is not None
or fileid is not None
or changectx is not None), \
("bad args: changeid=%r, fileid=%r, changectx=%r"
% (changeid, fileid, changectx))
if filelog is not None:
self._filelog = filelog
if changeid is not None:
self._changeid = changeid
if changectx is not None:
self._changectx = changectx
if fileid is not None:
self._fileid = fileid
@propertycache
def _changectx(self):
try:
return changectx(self._repo, self._changeid)
except error.RepoLookupError:
# Linkrev may point to any revision in the repository. When the
# repository is filtered this may lead to `filectx` trying to build
# `changectx` for filtered revision. In such case we fallback to
# creating `changectx` on the unfiltered version of the reposition.
# This fallback should not be an issue because `changectx` from
# `filectx` are not used in complex operations that care about
# filtering.
#
# This fallback is a cheap and dirty fix that prevent several
# crashes. It does not ensure the behavior is correct. However the
# behavior was not correct before filtering either and "incorrect
# behavior" is seen as better as "crash"
#
# Linkrevs have several serious troubles with filtering that are
# complicated to solve. Proper handling of the issue here should be
# considered when solving linkrev issue are on the table.
return changectx(self._repo.unfiltered(), self._changeid)
def filectx(self, fileid):
'''opens an arbitrary revision of the file without
opening a new filelog'''
return filectx(self._repo, self._path, fileid=fileid,
filelog=self._filelog)
def data(self):
return self._filelog.read(self._filenode)
def size(self):
return self._filelog.size(self._filerev)
def renamed(self):
"""check if file was actually renamed in this changeset revision
If rename logged in file revision, we report copy for changeset only
if file revisions linkrev points back to the changeset in question
or both changeset parents contain different file revisions.
"""
renamed = self._filelog.renamed(self._filenode)
if not renamed:
return renamed
if self.rev() == self.linkrev():
return renamed
name = self.path()
fnode = self._filenode
for p in self._changectx.parents():
try:
if fnode == p.filenode(name):
return None
except error.LookupError:
pass
return renamed
def children(self):
# hard for renames
c = self._filelog.children(self._filenode)
return [filectx(self._repo, self._path, fileid=x,
filelog=self._filelog) for x in c]
Sean Farley
context: use correct spelling of committable
r19733 class committablectx(basectx):
"""A committablectx object provides common functionality for a context that
Sean Farley
commitablectx: add a class that will be used as a parent of mutable contexts...
r19664 wants the ability to commit, e.g. workingctx or memctx."""
def __init__(self, repo, text="", user=None, date=None, extra=None,
changes=None):
Matt Mackall
contexts: add working dir and working file contexts...
r3217 self._repo = repo
self._rev = None
self._node = None
Patrick Mezard
context: let workingctx.date(), .user() and description() be overriden
r6709 self._text = text
Christian Ebert
Fix commit date (issue1193)...
r6718 if date:
Patrick Mezard
context: let workingctx.date(), .user() and description() be overriden
r6709 self._date = util.parsedate(date)
Matt Mackall
minor status fixups
r6817 if user:
self._user = user
Patrick Mezard
localrepo: hide commit() file selection behind workingctx
r6707 if changes:
Matt Mackall
context: only scan unknowns when needed
r11101 self._status = list(changes[:4])
self._unknown = changes[4]
Steve Borho
workingctx: use member variables to store ignored and clean...
r11099 self._ignored = changes[5]
self._clean = changes[6]
else:
Matt Mackall
context: only scan unknowns when needed
r11101 self._unknown = None
Steve Borho
workingctx: use member variables to store ignored and clean...
r11099 self._ignored = None
self._clean = None
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Patrick Mezard
localrepo: let commit() get extra data from workingctx
r6708 self._extra = {}
if extra:
self._extra = extra.copy()
if 'branch' not in self._extra:
try:
Matt Mackall
branch: operate on branch names in local string space where possible...
r13047 branch = encoding.fromlocal(self._repo.dirstate.branch())
Patrick Mezard
localrepo: let commit() get extra data from workingctx
r6708 except UnicodeDecodeError:
raise util.Abort(_('branch name not in UTF-8!'))
self._extra['branch'] = branch
if self._extra['branch'] == '':
self._extra['branch'] = 'default'
Sean Farley
commitablectx: move __str__ from workingctx
r19666 def __str__(self):
return str(self._parents[0]) + "+"
Sean Farley
commitablectx: move __nonzero__ from workingctx
r19667 def __nonzero__(self):
return True
Sean Farley
commitablectx: move __contains__ from workingctx
r19668 def __contains__(self, key):
return self._repo.dirstate[key] not in "?r"
Matt Mackall
windows: recompute flags when committing a merge (issue1802)...
r15337 def _buildflagfunc(self):
# Create a fallback function for getting file flags when the
# filesystem doesn't support them
copiesget = self._repo.dirstate.copies().get
if len(self._parents) < 2:
# when we have one parent, it's easy: copy from parent
man = self._parents[0].manifest()
def func(f):
f = copiesget(f, f)
return man.flags(f)
else:
# merges are tricky: we try to reconstruct the unstored
# result from the merge (issue1802)
p1, p2 = self._parents
pa = p1.ancestor(p2)
m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
def func(f):
f = copiesget(f, f) # may be wrong for merges with copies
fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
if fl1 == fl2:
return fl1
if fl1 == fla:
return fl2
if fl2 == fla:
return fl1
return '' # punt for conflicts
return func
Sean Farley
commitablectx: move _flagfunc from workingctx
r19670 @propertycache
def _flagfunc(self):
return self._repo.dirstate.flagfunc(self._buildflagfunc)
Matt Mackall
windows: recompute flags when committing a merge (issue1802)...
r15337 @propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 def _manifest(self):
Matt Mackall
contexts: add working dir and working file contexts...
r3217 """generate a manifest corresponding to the working directory"""
Matt Mackall
merge: use new working context object in update
r3218 man = self._parents[0].manifest().copy()
Benoit Boissinot
workingctx: correctly compute the flag for noexec filesystems+merge...
r10921 if len(self._parents) > 1:
man2 = self.p2().manifest()
def getman(f):
if f in man:
return man
return man2
else:
getman = lambda f: man
Matt Mackall
windows: recompute flags when committing a merge (issue1802)...
r15337
copied = self._repo.dirstate.copies()
ff = self._flagfunc
Matt Mackall
context: only scan unknowns when needed
r11101 modified, added, removed, deleted = self._status
Matt Mackall
merge: don't use unknown()...
r16094 for i, l in (("a", added), ("m", modified)):
Matt Mackall
contexts: add working dir and working file contexts...
r3217 for f in l:
Benoit Boissinot
workingctx: correctly compute the flag for noexec filesystems+merge...
r10921 orig = copied.get(f, f)
man[f] = getman(orig).get(orig, nullid) + i
Matt Mackall
context: don't spuriously raise abort when a file goes missing.
r3823 try:
Matt Mackall
simplify flag handling...
r6743 man.set(f, ff(f))
Matt Mackall
context: don't spuriously raise abort when a file goes missing.
r3823 except OSError:
pass
Matt Mackall
contexts: add working dir and working file contexts...
r3217
for f in deleted + removed:
Giorgos Keramidas
Revert changeset c67920d78248....
r3325 if f in man:
del man[f]
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 return man
Sean Farley
commitablectx: move _status from workingctx
r19672 @propertycache
def _status(self):
return self._repo.status()[:4]
Sean Farley
commitablectx: move _user from workingctx
r19674 @propertycache
def _user(self):
return self._repo.ui.username()
Sean Farley
commitablectx: move _date from workingctx
r19676 @propertycache
def _date(self):
return util.makedate()
Sean Farley
commitablectx: move user from workingctx
r19675 def user(self):
return self._user or self._repo.ui.username()
Sean Farley
commitablectx: move date from workingctx
r19677 def date(self):
return self._date
Sean Farley
commitablectx: move description from workingctx
r19678 def description(self):
return self._text
Sean Farley
commitablectx: move files from workingctx
r19679 def files(self):
return sorted(self._status[0] + self._status[1] + self._status[2])
Sean Farley
commitablectx: move user from workingctx
r19675
Sean Farley
commitablectx: move modified from workingctx
r19680 def modified(self):
return self._status[0]
Sean Farley
commitablectx: move added from workingctx
r19681 def added(self):
return self._status[1]
Sean Farley
commitablectx: move removed from workingctx
r19682 def removed(self):
return self._status[2]
Sean Farley
commitablectx: move deleted from workingctx
r19683 def deleted(self):
return self._status[3]
Sean Farley
commitablectx: move unknown from workingctx
r19684 def unknown(self):
assert self._unknown is not None # must call status first
return self._unknown
Sean Farley
commitablectx: move ignored from workingctx
r19685 def ignored(self):
assert self._ignored is not None # must call status first
return self._ignored
Sean Farley
commitablectx: move clean from workingctx
r19686 def clean(self):
assert self._clean is not None # must call status first
return self._clean
Sean Farley
commitablectx: move branch from workingctx
r19687 def branch(self):
return encoding.tolocal(self._extra['branch'])
Sean Farley
commitablectx: move closesbranch from workingctx
r19688 def closesbranch(self):
return 'close' in self._extra
Sean Farley
commitablectx: move extra from workingctx
r19689 def extra(self):
return self._extra
Sean Farley
commitablectx: move modified from workingctx
r19680
Sean Farley
commitablectx: move tags from workingctx
r19690 def tags(self):
t = []
for p in self.parents():
t.extend(p.tags())
return t
Sean Farley
commitablectx: move bookmarks from workingctx
r19691 def bookmarks(self):
b = []
for p in self.parents():
b.extend(p.bookmarks())
return b
Sean Farley
commitablectx: move phase from workingctx
r19692 def phase(self):
phase = phases.draft # default phase to draft
for p in self.parents():
phase = max(phase, p.phase())
return phase
Sean Farley
commitablectx: move hidden from workingctx
r19693 def hidden(self):
return False
Sean Farley
commitablectx: move children from workingctx
r19694 def children(self):
return []
Sean Farley
commitablectx: move flags from workingctx
r19695 def flags(self, path):
if '_manifest' in self.__dict__:
try:
return self._manifest.flags(path)
except KeyError:
return ''
try:
return self._flagfunc(path)
except OSError:
return ''
Sean Farley
commitablectx: move ancestor from workingctx
r19696 def ancestor(self, c2):
"""return the ancestor context of self and c2"""
return self._parents[0].ancestor(c2) # punt on two parents for now
Sean Farley
commitablectx: move walk from workingctx
r19697 def walk(self, match):
return sorted(self._repo.dirstate.walk(match, sorted(self.substate),
True, False))
Sean Farley
commitablectx: move ancestors from workingctx
r19698 def ancestors(self):
for a in self._repo.changelog.ancestors(
[p.rev() for p in self._parents]):
yield changectx(self._repo, a)
Sean Farley
commitablectx: move markcommitted from workingctx
r19699 def markcommitted(self, node):
"""Perform post-commit cleanup necessary after committing this ctx
Specifically, this updates backing stores this working context
wraps to reflect the fact that the changes reflected by this
workingctx have been committed. For example, it marks
modified and added files as normal in the dirstate.
"""
for f in self.modified() + self.added():
self._repo.dirstate.normal(f)
for f in self.removed():
self._repo.dirstate.drop(f)
self._repo.dirstate.setparents(node)
Sean Farley
commitablectx: move dirs from workingctx
r19700 def dirs(self):
return self._repo.dirstate.dirs()
Sean Farley
context: use correct spelling of committable
r19733 class workingctx(committablectx):
Sean Farley
commitablectx: move _manifest from workingctx
r19671 """A workingctx object makes access to data related to
the current working directory convenient.
date - any valid date string or (unixtime, offset), or None.
user - username string, or None.
extra - a dictionary of extra values, or None.
changes - a list of file lists as returned by localrepo.status()
or None to use the repository status.
"""
def __init__(self, repo, text="", user=None, date=None, extra=None,
changes=None):
super(workingctx, self).__init__(repo, text, user, date, extra, changes)
Matt Mackall
context: provide an efficient iterator for workingctx...
r14129 def __iter__(self):
d = self._repo.dirstate
for f in d:
if d[f] != 'r':
yield f
Martin Geisler
context: use Python 2.4 decorator syntax
r8157 @propertycache
Dirkjan Ochtman
context: use descriptors to speed up lazy attributes
r7368 def _parents(self):
p = self._repo.dirstate.parents()
if p[1] == nullid:
p = p[:-1]
Patrick Mezard
context: simplify workingctx._parents
r17330 return [changectx(self._repo, x) for x in p]
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Benoit Boissinot
context: create a filectxt with filelog reuse
r3966 def filectx(self, path, filelog=None):
Matt Mackall
contexts: add working dir and working file contexts...
r3217 """get a file context from the working directory"""
Benoit Boissinot
context: create a filectxt with filelog reuse
r3966 return workingfilectx(self._repo, path, workingctx=self,
filelog=filelog)
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Patrick Mezard
update: make --check abort with dirty subrepos...
r16491 def dirty(self, missing=False, merge=True, branch=True):
Matt Mackall
context: add a dirty method to detect modified contexts
r8717 "check whether a working directory is modified"
Edouard Gomez
subrepo: dirtiness checks should iterate over subrepos
r11110 # check subrepos first
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 for s in sorted(self.substate):
Edouard Gomez
subrepo: dirtiness checks should iterate over subrepos
r11110 if self.sub(s).dirty():
return True
# check current working dir
Patrick Mezard
update: make --check abort with dirty subrepos...
r16491 return ((merge and self.p2()) or
(branch and self.branch() != self.p1().branch()) or
Matt Mackall
context: add a dirty method to detect modified contexts
r8717 self.modified() or self.added() or self.removed() or
(missing and self.deleted()))
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 def add(self, list, prefix=""):
join = lambda f: os.path.join(prefix, f)
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 wlock = self._repo.wlock()
ui, ds = self._repo.ui, self._repo.dirstate
try:
rejected = []
FUJIWARA Katsunori
context: use "vfs.lstat()" instead of "os.lstat()"...
r19900 lstat = self._repo.wvfs.lstat
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 for f in list:
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 scmutil.checkportable(ui, join(f))
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 try:
FUJIWARA Katsunori
context: use "vfs.lstat()" instead of "os.lstat()"...
r19900 st = lstat(f)
Idan Kamara
eliminate various naked except clauses
r14004 except OSError:
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 ui.warn(_("%s does not exist!\n") % join(f))
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 rejected.append(f)
continue
if st.st_size > 10000000:
ui.warn(_("%s: up to %d MB of RAM may be required "
"to manage this file\n"
"(use 'hg revert %s' to cancel the "
"pending addition)\n")
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 % (f, 3 * st.st_size // 1000000, join(f)))
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
ui.warn(_("%s not added: only files and symlinks "
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 "supported currently\n") % join(f))
FUJIWARA Katsunori
context: use "vfs.lstat()" instead of "os.lstat()"...
r19900 rejected.append(f)
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 elif ds[f] in 'amn':
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 ui.warn(_("%s already tracked!\n") % join(f))
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 elif ds[f] == 'r':
ds.normallookup(f)
else:
ds.add(f)
return rejected
finally:
wlock.release()
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 def forget(self, files, prefix=""):
join = lambda f: os.path.join(prefix, f)
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 wlock = self._repo.wlock()
try:
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 rejected = []
Matt Mackall
context: make forget work like commands.forget...
r14435 for f in files:
Patrick Mezard
context: make workingctx.forget() really warn about untracked files
r16111 if f not in self._repo.dirstate:
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 self._repo.ui.warn(_("%s not tracked!\n") % join(f))
rejected.append(f)
Patrick Mezard
context: make workingctx.forget() really warn about untracked files
r16111 elif self._repo.dirstate[f] != 'a':
self._repo.dirstate.remove(f)
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 else:
Matt Mackall
dirstate: rename forget to drop...
r14434 self._repo.dirstate.drop(f)
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 return rejected
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 finally:
wlock.release()
def undelete(self, list):
pctxs = self.parents()
wlock = self._repo.wlock()
try:
for f in list:
if self._repo.dirstate[f] != 'r':
self._repo.ui.warn(_("%s not removed!\n") % f)
else:
Patrick Mezard
context: fix filectx.undelete() (issue2388)
r12360 fctx = f in pctxs[0] and pctxs[0][f] or pctxs[1][f]
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 t = fctx.data()
self._repo.wwrite(f, t, fctx.flags())
self._repo.dirstate.normal(f)
finally:
wlock.release()
def copy(self, source, dest):
FUJIWARA Katsunori
context: use "vfs.lstat()" to examine target path instead of "os.path.*"...
r19902 try:
st = self._repo.wvfs.lstat(dest)
except OSError, err:
if err.errno != errno.ENOENT:
raise
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 self._repo.ui.warn(_("%s does not exist!\n") % dest)
FUJIWARA Katsunori
context: use "vfs.lstat()" to examine target path instead of "os.path.*"...
r19902 return
if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 self._repo.ui.warn(_("copy failed: %s is not a file or a "
"symbolic link\n") % dest)
else:
wlock = self._repo.wlock()
try:
if self._repo.dirstate[dest] in '?r':
self._repo.dirstate.add(dest)
self._repo.dirstate.copy(source, dest)
finally:
wlock.release()
Sean Farley
localrepo: move symlink logic to workingctx
r21393 def _filtersuspectsymlink(self, files):
if not files or self._repo.dirstate._checklink:
return files
# Symlink placeholders may get non-symlink-like contents
# via user error or dereferencing by NFS or Samba servers,
# so we filter out any placeholders that don't look like a
# symlink
sane = []
for f in files:
if self.flags(f) == 'l':
d = self[f].data()
if d == '' or len(d) >= 1024 or '\n' in d or util.binary(d):
self._repo.ui.debug('ignoring suspect symlink placeholder'
' "%s"\n' % f)
continue
sane.append(f)
return sane
Sean Farley
localrepo: factor out parentworking logic for comparing files...
r21395 def _checklookup(self, files):
# check for any possibly clean files
if not files:
return [], []
modified = []
fixup = []
pctx = self._parents[0]
# do a full compare of any files that might have changed
for f in sorted(files):
if (f not in pctx or self.flags(f) != pctx.flags(f)
or pctx[f].cmp(self[f])):
modified.append(f)
else:
fixup.append(f)
# update dirstate for files that are actually clean
if fixup:
try:
# updating the dirstate is optional
# so we don't wait on the lock
normal = self._repo.dirstate.normal
wlock = self._repo.wlock(False)
try:
for f in fixup:
normal(f)
finally:
wlock.release()
except error.LockError:
pass
return modified, fixup
Sean Farley
localrepo: factor out _manifestmatch logic for workingctx
r21468 def _manifestmatches(self, match, s):
"""Slow path for workingctx
The fast path is when we compare the working directory to its parent
which means this function is comparing with a non-parent; therefore we
need to build a manifest and return what matches.
"""
mf = self._repo['.']._manifestmatches(match, s)
modified, added, removed = s[0:3]
for f in modified + added:
mf[f] = None
mf.set(f, self.flags(f))
for f in removed:
if f in mf:
del mf[f]
return mf
Sean Farley
workingctx: add _prestatus method to call _dirstatestatus...
r21474 def _prestatus(self, other, s, match, listignored, listclean, listunknown):
"""override the parent hook with a dirstate query
We use this prestatus hook to populate the status with information from
the dirstate.
"""
return self._dirstatestatus(match, listignored, listclean, listunknown)
Sean Farley
workingctx: add _poststatus method to call _filtersuspectsymlink...
r21477 def _poststatus(self, other, s, match, listignored, listclean, listunknown):
"""override the parent hook with a filter for suspect symlinks
We use this poststatus hook to filter out symlinks that might have
accidentally ended up with the entire contents of the file they are
susposed to be linking to.
"""
s[0] = self._filtersuspectsymlink(s[0])
return s
Sean Farley
context: add private _dirstatestatus method...
r21397 def _dirstatestatus(self, match=None, ignored=False, clean=False,
unknown=False):
'''Gets the status from the dirstate -- internal use only.'''
listignored, listclean, listunknown = ignored, clean, unknown
match = match or matchmod.always(self._repo.root, self._repo.getcwd())
subrepos = []
if '.hgsub' in self:
subrepos = sorted(self.substate)
s = self._repo.dirstate.status(match, subrepos, listignored,
listclean, listunknown)
cmp, modified, added, removed, deleted, unknown, ignored, clean = s
# check for any possibly clean files
if cmp:
modified2, fixup = self._checklookup(cmp)
modified += modified2
# update dirstate for files that are actually clean
if fixup and listclean:
clean += fixup
return [modified, added, removed, deleted, unknown, ignored, clean]
Sean Farley
workingctx: use inheritance for _buildstatus while keeping the fastpath...
r21480 def _buildstatus(self, other, s, match, listignored, listclean,
listunknown):
"""build a status with respect to another context
This includes logic for maintaining the fast path of status when
comparing the working directory against its parent, which is to skip
building a new manifest if self (working directory) is not comparing
against its parent (repo['.']).
"""
if other != self._repo['.']:
s = super(workingctx, self)._buildstatus(other, s, match,
listignored, listclean,
listunknown)
return s
Sean Farley
workingctx: override _matchstatus for parentworking case...
r21482 def _matchstatus(self, other, s, match, listignored, listclean,
listunknown):
"""override the match method with a filter for directory patterns
We use inheritance to customize the match.bad method only in cases of
workingctx since it belongs only to the working directory when
comparing against the parent changeset.
If we aren't comparing against the working directory's parent, then we
just use the default match object sent to us.
"""
superself = super(workingctx, self)
match = superself._matchstatus(other, s, match, listignored, listclean,
listunknown)
if other != self._repo['.']:
def bad(f, msg):
# 'f' may be a directory pattern from 'match.files()',
# so 'f not in ctx1' is not enough
if f not in other and f not in other.dirs():
self._repo.ui.warn('%s: %s\n' %
(self._repo.dirstate.pathto(f), msg))
match.bad = bad
return match
Sean Farley
workingctx: call _dirstatestatus in status...
r21398 def status(self, ignored=False, clean=False, unknown=False, match=None):
Sean Farley
committablectx: move status to workingctx...
r21396 """Explicit status query
Unless this method is used to query the working copy status, the
_status property will implicitly read the status using its default
arguments."""
Sean Farley
workingctx: call _dirstatestatus in status...
r21398 listignored, listclean, listunknown = ignored, clean, unknown
s = self._dirstatestatus(match=match, ignored=listignored,
clean=listclean, unknown=listunknown)
modified, added, removed, deleted, unknown, ignored, clean = s
modified = self._filtersuspectsymlink(modified)
Sean Farley
committablectx: move status to workingctx...
r21396 self._unknown = self._ignored = self._clean = None
Sean Farley
workingctx: call _dirstatestatus in status...
r21398 if listunknown:
self._unknown = unknown
if listignored:
self._ignored = ignored
if listclean:
self._clean = clean
self._status = modified, added, removed, deleted
return modified, added, removed, deleted, unknown, ignored, clean
Sean Farley
committablectx: move status to workingctx...
r21396
Sean Farley
localrepo: factor out parentworking logic for comparing files...
r21395
Sean Farley
context: use correct spelling of committable
r19733 class committablefilectx(basefilectx):
"""A committablefilectx provides common functionality for a file context
that wants the ability to commit, e.g. workingfilectx or memfilectx."""
Sean Farley
commitablefilectx: add a class that will be used for mutable file contexts...
r19701 def __init__(self, repo, path, filelog=None, ctx=None):
Matt Mackall
contexts: add working dir and working file contexts...
r3217 self._repo = repo
self._path = path
self._changeid = None
self._filerev = self._filenode = None
Durham Goode
filecontext: use 'is not None' to check for filelog existence...
r19149 if filelog is not None:
Matt Mackall
contexts: add working dir and working file contexts...
r3217 self._filelog = filelog
Sean Farley
commitablefilectx: move __init__ from workingfilectx
r19702 if ctx:
self._changectx = ctx
Sean Farley
commitablefilectx: move __nonzero__ from workingfilectx
r19703 def __nonzero__(self):
return True
Matt Mackall
contexts: add working dir and working file contexts...
r3217 def parents(self):
'''return parent filectxs, following copies if necessary'''
Benoit Boissinot
workingfilectx: always use the same filelog, even for renames...
r8528 def filenode(ctx, path):
return ctx._manifest.get(path, nullid)
path = self._path
Matt Mackall
contexts: add working dir and working file contexts...
r3217 fl = self._filelog
Benoit Boissinot
workingfilectx: always use the same filelog, even for renames...
r8528 pcl = self._changectx._parents
renamed = self.renamed()
if renamed:
pl = [renamed + (None,)]
else:
pl = [(path, filenode(pcl[0], path), fl)]
for pc in pcl[1:]:
pl.append((path, filenode(pc, path), fl))
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Thomas Arendsen Hein
white space and line break cleanups
r3673 return [filectx(self._repo, p, fileid=n, filelog=l)
Matt Mackall
many, many trivial check-code fixups
r10282 for p, n, l in pl if n != nullid]
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Sean Farley
commitablefilectx: move children from workingfilectx
r19705 def children(self):
return []
Sean Farley
context: use correct spelling of committable
r19733 class workingfilectx(committablefilectx):
Sean Farley
commitablefilectx: move parents from workingfilectx
r19704 """A workingfilectx object makes access to data related to a particular
file in the working directory convenient."""
def __init__(self, repo, path, filelog=None, workingctx=None):
super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
@propertycache
def _changectx(self):
return workingctx(self._repo)
def data(self):
return self._repo.wread(self._path)
def renamed(self):
rp = self._repo.dirstate.copied(self._path)
if not rp:
return None
return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
Matt Mackall
many, many trivial check-code fixups
r10282 def size(self):
FUJIWARA Katsunori
context: use "vfs.lstat()" instead of "os.lstat()"
r19901 return self._repo.wvfs.lstat(self._path).st_size
Benoit Boissinot
add date attribute to workingfilectx
r3962 def date(self):
t, tz = self._changectx.date()
try:
FUJIWARA Katsunori
context: use "vfs.lstat()" instead of "os.lstat()"
r19901 return (int(self._repo.wvfs.lstat(self._path).st_mtime), tz)
Benoit Boissinot
add date attribute to workingfilectx
r3962 except OSError, err:
Matt Mackall
many, many trivial check-code fixups
r10282 if err.errno != errno.ENOENT:
raise
Benoit Boissinot
add date attribute to workingfilectx
r3962 return (t, tz)
Matt Mackall
context: add cmp for filectxs
r3310
Nicolas Dumazet
filectx: use cmp(self, fctx) instead of cmp(self, text)...
r11702 def cmp(self, fctx):
"""compare with other file context
Nicolas Dumazet
cmp: document the fact that we return True if content is different...
r11539
Nicolas Dumazet
filectx: use cmp(self, fctx) instead of cmp(self, text)...
r11702 returns True if different than fctx.
Nicolas Dumazet
cmp: document the fact that we return True if content is different...
r11539 """
Mads Kiilerich
fix wording and not-completely-trivial spelling errors and bad docstrings
r17425 # fctx should be a filectx (not a workingfilectx)
Nicolas Dumazet
context: reuse filecontext.cmp in workingfilecontext.cmp...
r11703 # invert comparison to reuse the same code path
return fctx.cmp(self)
Patrick Mezard
context: add memctx for memory commits
r6715
class memctx(object):
Patrick Mezard
context: improve memctx documentation
r7077 """Use memctx to perform in-memory commits via localrepo.commitctx().
Patrick Mezard
context: add memctx for memory commits
r6715
Patrick Mezard
context: improve memctx documentation
r7077 Revision information is supplied at initialization time while
related files data and is made available through a callback
mechanism. 'repo' is the current localrepo, 'parents' is a
sequence of two parent revisions identifiers (pass None for every
missing parent), 'text' is the commit message and 'files' lists
names of files touched by the revision (normalized and relative to
repository root).
Patrick Mezard
context: add memctx for memory commits
r6715
Patrick Mezard
context: improve memctx documentation
r7077 filectxfn(repo, memctx, path) is a callable receiving the
repository, the current memctx object and the normalized path of
requested file, relative to repository root. It is fired by the
commit function for every file in 'files', but calls order is
undefined. If the file is available in the revision being
committed (updated or added), filectxfn returns a memfilectx
object. If the file was removed, filectxfn raises an
IOError. Moved files are represented by marking the source file
removed and the new file added with copy information (see
memfilectx).
user receives the committer name and defaults to current
repository username, date is the commit date in any format
supported by util.parsedate() and defaults to current date, extra
is a dictionary of metadata or is left empty.
Patrick Mezard
context: add memctx for memory commits
r6715 """
Dirkjan Ochtman
kill some trailing spaces
r6721 def __init__(self, repo, parents, text, files, filectxfn, user=None,
FUJIWARA Katsunori
context: move editor invocation from "makememctx()" to "memctx.__init__()"...
r21238 date=None, extra=None, editor=False):
Patrick Mezard
context: add memctx for memory commits
r6715 self._repo = repo
self._rev = None
self._node = None
self._text = text
self._date = date and util.parsedate(date) or util.makedate()
Patrick Mezard
context: trigger missing username warning only when necessary
r6809 self._user = user
Patrick Mezard
context: add memctx for memory commits
r6715 parents = [(p or nullid) for p in parents]
p1, p2 = parents
Matt Mackall
use repo[changeid] to get a changectx
r6747 self._parents = [changectx(self._repo, p) for p in (p1, p2)]
Matt Mackall
replace util.sort with sorted built-in...
r8209 files = sorted(set(files))
Patrick Mezard
context: add memctx for memory commits
r6715 self._status = [files, [], [], [], []]
self._filectxfn = filectxfn
self._extra = extra and extra.copy() or {}
Patrick Mezard
memctx: simplify constructor
r14528 if self._extra.get('branch', '') == '':
Patrick Mezard
context: add memctx for memory commits
r6715 self._extra['branch'] = 'default'
FUJIWARA Katsunori
context: move editor invocation from "makememctx()" to "memctx.__init__()"...
r21238 if editor:
self._text = editor(self._repo, self, [])
self._repo.savecommitmessage(self._text)
Patrick Mezard
context: add memctx for memory commits
r6715 def __str__(self):
return str(self._parents[0]) + "+"
Matt Mackall
context: add __int__ and hex methods
r6763 def __int__(self):
return self._rev
Patrick Mezard
context: add memctx for memory commits
r6715 def __nonzero__(self):
return True
Matt Mackall
filecommit: swallow some bits from _commitctx, add _
r8401 def __getitem__(self, key):
return self.filectx(key)
Matt Mackall
many, many trivial check-code fixups
r10282 def p1(self):
return self._parents[0]
def p2(self):
return self._parents[1]
Matt Mackall
context: add p1 and p2 methods
r8406
Matt Mackall
many, many trivial check-code fixups
r10282 def user(self):
return self._user or self._repo.ui.username()
def date(self):
return self._date
def description(self):
return self._text
def files(self):
return self.modified()
def modified(self):
return self._status[0]
def added(self):
return self._status[1]
def removed(self):
return self._status[2]
def deleted(self):
return self._status[3]
def unknown(self):
return self._status[4]
Steve Borho
workingctx: add explicit status method, add ignored and fix clean...
r11098 def ignored(self):
return self._status[5]
Matt Mackall
many, many trivial check-code fixups
r10282 def clean(self):
Steve Borho
workingctx: add explicit status method, add ignored and fix clean...
r11098 return self._status[6]
Matt Mackall
many, many trivial check-code fixups
r10282 def branch(self):
Matt Mackall
branch: operate on branch names in local string space where possible...
r13047 return encoding.tolocal(self._extra['branch'])
Matt Mackall
many, many trivial check-code fixups
r10282 def extra(self):
return self._extra
def flags(self, f):
return self[f].flags()
Patrick Mezard
context: add memctx for memory commits
r6715
def parents(self):
"""return contexts for each parent changeset"""
return self._parents
def filectx(self, path, filelog=None):
"""get a file context from the working directory"""
return self._filectxfn(self._repo, self, path)
Alexander Solovyov
slightly improve memctx api
r11151 def commit(self):
"""commit context to the repo"""
return self._repo.commitctx(self)
Patrick Mezard
context: add memctx for memory commits
r6715 class memfilectx(object):
Patrick Mezard
context: improve memctx documentation
r7077 """memfilectx represents an in-memory file to commit.
See memctx for more details.
Patrick Mezard
context: add memctx for memory commits
r6715 """
Alexander Solovyov
slightly improve memctx api
r11151 def __init__(self, path, data, islink=False, isexec=False, copied=None):
Patrick Mezard
context: improve memctx documentation
r7077 """
path is the normalized file path relative to repository root.
data is the file content as a string.
islink is True if the file is a symbolic link.
isexec is True if the file is executable.
copied is the source file path if current file was copied in the
revision being committed, or None."""
Patrick Mezard
context: add memctx for memory commits
r6715 self._path = path
self._data = data
self._flags = (islink and 'l' or '') + (isexec and 'x' or '')
self._copied = None
if copied:
self._copied = (copied, nullid)
Matt Mackall
many, many trivial check-code fixups
r10282 def __nonzero__(self):
return True
def __str__(self):
return "%s@%s" % (self.path(), self._changectx)
def path(self):
return self._path
def data(self):
return self._data
def flags(self):
return self._flags
def isexec(self):
return 'x' in self._flags
def islink(self):
return 'l' in self._flags
def renamed(self):
return self._copied