##// END OF EJS Templates
hgweb: return iterable, add deprecation note
hgweb: return iterable, add deprecation note

File last commit:

r5813:3ef27907 default
r5887:41a3fce1 default
Show More
context.py
620 lines | 20.7 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 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Brendan Cully
Refactor annotate copy support.
r3172 from node import *
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Benoit Boissinot
add date attribute to workingfilectx
r3962 import ancestor, bdiff, repo, revlog, util, os, errno
Matt Mackall
filectx: add rename traversal for parents()
r3122
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 class changectx(object):
"""A changecontext object makes access to data related to a particular
changeset convenient."""
Brendan Cully
Move defaultrev into changectx...
r3132 def __init__(self, repo, changeid=None):
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 """changeid is a revision number, node, or tag"""
self._repo = repo
Brendan Cully
context: handle fileid or changeid == 0
r3143 if not changeid and changeid != 0:
Brendan Cully
Move defaultrev into changectx...
r3132 p1, p2 = self._repo.dirstate.parents()
self._rev = self._repo.changelog.rev(p1)
if self._rev == -1:
changeid = 'tip'
else:
self._node = p1
return
Benoit Boissinot
fix filectxt to really work...
r2643 self._node = self._repo.lookup(changeid)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 self._rev = self._repo.changelog.rev(self._node)
Matt Mackall
Add str methods to contexts
r3166 def __str__(self):
return short(self.node())
Matt Mackall
context: add __repr__ methods
r3151 def __repr__(self):
Matt Mackall
context: simplify repr methods
r3216 return "<changectx %s>" % str(self)
Matt Mackall
context: add __repr__ methods
r3151
Matt Mackall
Add equality operators to changectx and filectx
r3165 def __eq__(self, other):
Brendan Cully
Make context __eq__ handle arbitrary RHS values
r3715 try:
return self._rev == other._rev
except AttributeError:
return False
Matt Mackall
Add equality operators to changectx and filectx
r3165
Matt Mackall
merge: make test for fast-forward merge stricter (issue619)...
r4748 def __ne__(self, other):
return not (self == other)
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
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215 def __getattr__(self, name):
if name == '_changeset':
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 self._changeset = self._repo.changelog.read(self.node())
return self._changeset
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215 elif name == '_manifest':
self._manifest = self._repo.manifest.read(self._changeset[0])
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 return self._manifest
Brendan Cully
changectx: search manifest delta for filenode
r3337 elif name == '_manifestdelta':
md = self._repo.manifest.readdelta(self._changeset[0])
self._manifestdelta = md
return self._manifestdelta
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215 else:
raise AttributeError, name
Matt Mackall
context: add __contains__, __getitem__, and __iter__
r4909 def __contains__(self, key):
return key in self._manifest
def __getitem__(self, key):
return self.filectx(key)
def __iter__(self):
a = self._manifest.keys()
a.sort()
for f in a:
Bryan O'Sullivan
Fix context iterator.
r5485 yield f
Matt Mackall
context: add __contains__, __getitem__, and __iter__
r4909
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215 def changeset(self): return self._changeset
def manifest(self): return self._manifest
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
def rev(self): return self._rev
def node(self): return self._node
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215 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]
Matt Mackall
Minor default branch cleanups
r4178 def branch(self): return self._changeset[5].get("branch")
Bryan O'Sullivan
convert: make contents of "extra" dict available from sources, for sinks....
r5439 def extra(self): return self._changeset[5]
Matt Mackall
context: add tags() method
r4663 def tags(self): return self._repo.nodetags(self._node)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
def parents(self):
"""return contexts for each parent changeset"""
Benoit Boissinot
context.py: self.repo is not defined, change to self._repo
r2627 p = self._repo.changelog.parents(self._node)
Thomas Arendsen Hein
white space and line break cleanups
r3673 return [changectx(self._repo, x) for x in p]
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
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 def _fileinfo(self, path):
Brendan Cully
context: check self.__dict__ instead of using hasattr...
r3336 if '_manifest' in self.__dict__:
Brendan Cully
Make changectx.filenode raise repo.LookupError on failure
r3242 try:
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 return self._manifest[path], self._manifest.flags(path)
Brendan Cully
Make changectx.filenode raise repo.LookupError on failure
r3242 except KeyError:
Bryan O'Sullivan
make LookupError more detailed
r5558 raise revlog.LookupError(path, _("'%s' not found in manifest") % path)
Brendan Cully
changectx: search manifest delta for filenode
r3337 if '_manifestdelta' in self.__dict__ or path in self.files():
if path in self._manifestdelta:
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 return self._manifestdelta[path], self._manifestdelta.flags(path)
Matt Mackall
contexts: use __getattr__ rather than try/except in changectx
r3215 node, flag = self._repo.manifest.find(self._changeset[0], path)
Brendan Cully
Make changectx.filenode raise repo.LookupError on failure
r3242 if not node:
Bryan O'Sullivan
make LookupError more detailed
r5558 raise revlog.LookupError(path, _("'%s' not found in manifest") % path)
Brendan Cully
Make changectx.filenode raise repo.LookupError on failure
r3242
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 return node, flag
def filenode(self, path):
return self._fileinfo(path)[0]
def fileflags(self, path):
try:
return self._fileinfo(path)[1]
except revlog.LookupError:
return ''
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
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
def filectxs(self):
"""generate a file context for each file in this changeset's
manifest"""
mf = self.manifest()
m = mf.keys()
m.sort()
for f in m:
yield self.filectx(f, fileid=mf[f])
Matt Mackall
changectx: add ancestor function
r3125 def ancestor(self, c2):
"""
return the ancestor context of self and c2
"""
n = self._repo.changelog.ancestor(self._node, c2._node)
return changectx(self._repo, n)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 class filectx(object):
"""A filecontext object makes access to data related to a particular
filerevision convenient."""
Matt Mackall
context: make filectx remember changectx in changectx.filectx
r3214 def __init__(self, repo, path, changeid=None, fileid=None,
filelog=None, changectx=None):
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 """changeid can be a changeset revision, node, or tag.
fileid can be a file revision or node."""
self._repo = repo
self._path = path
Benoit Boissinot
make it possible to use changectx to create a filectx
r3964 assert (changeid is not None
or fileid is not None
or changectx is not None)
Benoit Boissinot
fix filectxt to really work...
r2643
Matt Mackall
filectx: allow passing filelog in init to avoid opening new filelogs
r3124 if filelog:
self._filelog = filelog
Maxim Dounin
context: preserve changeset in filectx if we have one...
r5810 if changeid is not None:
self._changeid = changeid
if changectx is not None:
self._changectx = changectx
if fileid is not None:
Matt Mackall
Make filectx lazier...
r3213 self._fileid = fileid
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Brendan Cully
Make filectx lazier - some users never use filenode
r3144 def __getattr__(self, name):
if name == '_changectx':
Benoit Boissinot
fix filectxt to really work...
r2643 self._changectx = changectx(self._repo, self._changeid)
return self._changectx
Matt Mackall
Make filectx lazier...
r3213 elif name == '_filelog':
self._filelog = self._repo.file(self._path)
return self._filelog
elif name == '_changeid':
Maxim Dounin
context: preserve changeset in filectx if we have one...
r5810 if '_changectx' in self.__dict__:
self._changeid = self._changectx.rev()
else:
self._changeid = self._filelog.linkrev(self._filenode)
Matt Mackall
Make filectx lazier...
r3213 return self._changeid
Brendan Cully
Make filectx lazier - some users never use filenode
r3144 elif name == '_filenode':
Benoit Boissinot
fix tab vs space
r3961 if '_fileid' in self.__dict__:
self._filenode = self._filelog.lookup(self._fileid)
else:
self._filenode = self._changectx.filenode(self._path)
Brendan Cully
Make filectx lazier - some users never use filenode
r3144 return self._filenode
elif name == '_filerev':
self._filerev = self._filelog.rev(self._filenode)
return self._filerev
else:
raise AttributeError, name
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Matt Mackall
context: add __nonzero__ methods
r3168 def __nonzero__(self):
Benoit Boissinot
context: None is not a valid filenode (revert from 23ede9e7ad4d)
r3712 try:
n = self._filenode
return True
Brendan Cully
Add revlog.LookupError exception, and use it instead of RevlogError....
r3930 except revlog.LookupError:
Benoit Boissinot
context: None is not a valid filenode (revert from 23ede9e7ad4d)
r3712 # file is missing
return False
Matt Mackall
context: add __nonzero__ methods
r3168
Matt Mackall
Add str methods to contexts
r3166 def __str__(self):
return "%s@%s" % (self.path(), short(self.node()))
Matt Mackall
context: add __repr__ methods
r3151 def __repr__(self):
Matt Mackall
context: simplify repr methods
r3216 return "<filectx %s>" % str(self)
Matt Mackall
context: add __repr__ methods
r3151
Matt Mackall
Add equality operators to changectx and filectx
r3165 def __eq__(self, other):
Brendan Cully
Make context __eq__ handle arbitrary RHS values
r3715 try:
return (self._path == other._path
Matt Mackall
contexts: improve filectx eq test
r4889 and self._fileid == other._fileid)
Brendan Cully
Make context __eq__ handle arbitrary RHS values
r3715 except AttributeError:
return False
Matt Mackall
Add equality operators to changectx and filectx
r3165
Matt Mackall
merge: make test for fast-forward merge stricter (issue619)...
r4748 def __ne__(self, other):
return not (self == other)
Brendan Cully
Add lookup method to filectx
r3207 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)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 def filerev(self): return self._filerev
def filenode(self): return self._filenode
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 def fileflags(self): return self._changectx.fileflags(self._path)
def isexec(self): return 'x' in self.fileflags()
def islink(self): return 'l' in self.fileflags()
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 def filelog(self): return self._filelog
Matt Mackall
filectx: lazy linkrev usage
r3150 def rev(self):
Brendan Cully
context: check self.__dict__ instead of using hasattr...
r3336 if '_changectx' in self.__dict__:
Matt Mackall
filectx: lazy linkrev usage
r3150 return self._changectx.rev()
Maxim Dounin
context: preserve changeset in filectx if we have one...
r5810 if '_changeid' in self.__dict__:
return self._changectx.rev()
Brendan Cully
Back out d8eba1c3ce9b and a004164dbeef
r3403 return self._filelog.linkrev(self._filenode)
Matt Mackall
filectx: lazy linkrev usage
r3150
Maxim Dounin
Fix copies reporting in log and convert....
r5811 def linkrev(self): return self._filelog.linkrev(self._filenode)
Brendan Cully
Make filectx lazier - some users never use filenode
r3144 def node(self): return self._changectx.node()
def user(self): return self._changectx.user()
def date(self): return self._changectx.date()
def files(self): return self._changectx.files()
def description(self): return self._changectx.description()
Matt Mackall
Add branch method to contexts
r3413 def branch(self): return self._changectx.branch()
Brendan Cully
Make filectx lazier - some users never use filenode
r3144 def manifest(self): return self._changectx.manifest()
Matt Mackall
restore filectx.changectx() method
r3149 def changectx(self): return self._changectx
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
def data(self): return self._filelog.read(self._filenode)
Matt Mackall
filectx: add rename traversal for parents()
r3122 def path(self): return self._path
Matt Mackall
filectx: add size method
r3302 def size(self): return self._filelog.size(self._filerev)
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
Matt Mackall
context: add cmp for filectxs
r3310 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
Maxim Dounin
Fix copies reporting in log and convert....
r5811 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 revlog.LookupError:
pass
return renamed
Matt Mackall
Add context.py: changeset and file revision contexts
r2563 def parents(self):
Matt Mackall
filectx: allow passing filelog in init to avoid opening new filelogs
r3124 p = self._path
fl = self._filelog
Thomas Arendsen Hein
white space and line break cleanups
r3673 pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)]
Matt Mackall
filelog: make metadata method private
r3123
Patrick Mezard
context: fix filectx.parents() bug introduced when editing 180a3eee4b75
r5813 r = self._filelog.renamed(self._filenode)
Matt Mackall
filectx: add rename traversal for parents()
r3122 if r:
Matt Mackall
filectx: allow passing filelog in init to avoid opening new filelogs
r3124 pl[0] = (r[0], r[1], None)
Thomas Arendsen Hein
white space and line break cleanups
r3673 return [filectx(self._repo, p, fileid=n, filelog=l)
for p,n,l in pl if n != nullid]
Matt Mackall
Add context.py: changeset and file revision contexts
r2563
def children(self):
# hard for renames
c = self._filelog.children(self._filenode)
Thomas Arendsen Hein
white space and line break cleanups
r3673 return [filectx(self._repo, self._path, fileid=x,
filelog=self._filelog) for x in c]
Matt Mackall
Convert hg annotate to context api
r2566
FUJIWARA Katsunori
Allow filectx.annotate to return the line number of first appearance.
r4856 def annotate(self, follow=False, linenumber=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):
for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
child[0][b1:b2] = parent[0][a1:a2]
return child
getlog = util.cachefunc(lambda x: self._repo.file(x))
def getctx(path, fileid):
log = path == self._path and self._filelog or getlog(path)
return filectx(self._repo, path, fileid=fileid, filelog=log)
getctx = util.cachefunc(getctx)
def parents(f):
# we want to reuse filectx objects as much as possible
p = f._path
Matt Mackall
contexts: add working dir and working file contexts...
r3217 if f._filerev is None: # working dir
Thomas Arendsen Hein
white space and line break cleanups
r3673 pl = [(n.path(), n.filerev()) for n in f.parents()]
Matt Mackall
contexts: add working dir and working file contexts...
r3217 else:
Thomas Arendsen Hein
white space and line break cleanups
r3673 pl = [(p, n) for n in f._filelog.parentrevs(f._filerev)]
Brendan Cully
Refactor annotate copy support.
r3172
if follow:
r = f.renamed()
if r:
pl[0] = (r[0], getlog(r[0]).rev(r[1]))
Brendan Cully
filectx.annotate: return filectx for each line instead of rev
r3146
Thomas Arendsen Hein
Define and use nullrev (revision of nullid) instead of -1.
r3578 return [getctx(p, n) for p, n in pl if n != nullrev]
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():
Brendan Cully
Fix annotate where linkrev != rev without exporting linkrev
r3404 base = self.filectx(self.filerev())
else:
base = self
Brendan Cully
Refactor annotate copy support.
r3172 # find all ancestors
Brendan Cully
Fix annotate where linkrev != rev without exporting linkrev
r3404 needed = {base: 1}
visit = [base]
files = [base._path]
Brendan Cully
Refactor annotate copy support.
r3172 while visit:
f = visit.pop(0)
for p in parents(f):
if p not in needed:
needed[p] = 1
visit.append(p)
if p._path not in files:
files.append(p._path)
else:
# count how many times we'll use this
needed[p] += 1
# sort by revision (per file) which is a topological order
visit = []
for f in files:
Patrick Mezard
Fix issue 589: "undelete" sequence leads to crash.
r4638 fn = [(n.rev(), n) for n in needed.keys() if n._path == f]
Brendan Cully
Refactor annotate copy support.
r3172 visit.extend(fn)
Patrick Mezard
Fix issue 589: "undelete" sequence leads to crash.
r4638 visit.sort()
Brendan Cully
Refactor annotate copy support.
r3172 hist = {}
for r, f in visit:
curr = decorate(f.data(), f)
for p in parents(f):
if p != nullid:
curr = pair(hist[p], curr)
# trim the history of unneeded revs
needed[p] -= 1
if not needed[p]:
del hist[p]
hist[f] = curr
return zip(hist[f][0], hist[f][1].splitlines(1))
Matt Mackall
filectx: allow passing filelog in init to avoid opening new filelogs
r3124
Matt Mackall
filectx: add rename-aware ancestor algorithm...
r3126 def ancestor(self, fc2):
"""
find the common ancestor file context, if any, of self, and fc2
"""
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 acache = {}
Matt Mackall
contexts: add working dir and working file contexts...
r3217
# prime the ancestor cache for the working directory
for c in (self, fc2):
if c._filerev == None:
Thomas Arendsen Hein
white space and line break cleanups
r3673 pl = [(n.path(), n.filenode()) for n in c.parents()]
Matt Mackall
contexts: add working dir and working file contexts...
r3217 acache[(c._path, None)] = pl
Matt Mackall
filectx: add rename-aware ancestor algorithm...
r3126 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 def parents(vertex):
if vertex in acache:
return acache[vertex]
f, n = vertex
if f not in flcache:
Matt Mackall
filectx: add rename-aware ancestor algorithm...
r3126 flcache[f] = self._repo.file(f)
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 fl = flcache[f]
Thomas Arendsen Hein
white space and line break cleanups
r3673 pl = [(f, p) for p in fl.parents(n) if p != nullid]
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 re = fl.renamed(n)
if re:
pl.append(re)
Thomas Arendsen Hein
white space and line break cleanups
r3673 acache[vertex] = pl
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 return pl
Matt Mackall
filectx: add rename-aware ancestor algorithm...
r3126
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
v = ancestor.ancestor(a, b, parents)
if v:
Thomas Arendsen Hein
white space and line break cleanups
r3673 f, n = v
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
Matt Mackall
filectx: add rename-aware ancestor algorithm...
r3126
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 return None
Matt Mackall
contexts: add working dir and working file contexts...
r3217
class workingctx(changectx):
"""A workingctx object makes access to data related to
the current working directory convenient."""
def __init__(self, repo):
self._repo = repo
self._rev = None
self._node = None
def __str__(self):
Matt Mackall
context: change workingctx str() from . to <node>+
r3313 return str(self._parents[0]) + "+"
Matt Mackall
contexts: add working dir and working file contexts...
r3217
def __nonzero__(self):
return True
def __getattr__(self, name):
if name == '_parents':
self._parents = self._repo.parents()
return self._parents
if name == '_status':
self._status = self._repo.status()
return self._status
if name == '_manifest':
self._buildmanifest()
return self._manifest
else:
raise AttributeError, name
def _buildmanifest(self):
"""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()
Matt Mackall
contexts: add working dir and working file contexts...
r3217 copied = self._repo.dirstate.copies()
Patrick Mezard
Fix workingctx exec/link bit of copies on non-supporting systems
r5407 is_exec = util.execfunc(self._repo.root,
lambda p: man.execf(copied.get(p,p)))
is_link = util.linkfunc(self._repo.root,
lambda p: man.linkf(copied.get(p,p)))
Matt Mackall
contexts: add working dir and working file contexts...
r3217 modified, added, removed, deleted, unknown = self._status[:5]
Thomas Arendsen Hein
white space and line break cleanups
r3673 for i, l in (("a", added), ("m", modified), ("u", unknown)):
Matt Mackall
contexts: add working dir and working file contexts...
r3217 for f in l:
man[f] = man.get(copied.get(f, f), nullid) + i
Matt Mackall
context: don't spuriously raise abort when a file goes missing.
r3823 try:
Matt Mackall
symlinks: use is_link wherever is_exec is used
r4002 man.set(f, is_exec(f), is_link(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
self._manifest = man
def manifest(self): return self._manifest
def user(self): return self._repo.ui.username()
def date(self): return util.makedate()
def description(self): return ""
def files(self):
f = self.modified() + self.added() + self.removed()
f.sort()
return f
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]
def clean(self): return self._status[5]
Matt Mackall
Move branch read/write to dirstate where it belongs
r4179 def branch(self): return self._repo.dirstate.branch()
Matt Mackall
contexts: add working dir and working file contexts...
r3217
Matt Mackall
context: add tags() method
r4663 def tags(self):
t = []
[t.extend(p.tags()) for p in self.parents()]
return t
Matt Mackall
contexts: add working dir and working file contexts...
r3217 def parents(self):
"""return contexts for each parent changeset"""
return self._parents
def children(self):
return []
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 def fileflags(self, path):
if '_manifest' in self.__dict__:
try:
return self._manifest.flags(path)
except KeyError:
return ''
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 pnode = self._parents[0].changeset()[0]
Patrick Mezard
Fix workingctx exec/link bit of copies on non-supporting systems
r5407 orig = self._repo.dirstate.copies().get(path, path)
node, flag = self._repo.manifest.find(pnode, orig)
Patrick Mezard
Fix bad lambda prototype in workingctx.fileflags()
r5399 is_link = util.linkfunc(self._repo.root, lambda p: 'l' in flag)
is_exec = util.execfunc(self._repo.root, lambda p: 'x' in flag)
Patrick Mezard
context: add fileflags() to avoid rebuilding manifests
r5389 try:
return (is_link(path) and 'l' or '') + (is_exec(path) and 'e' or '')
except OSError:
pass
if not node or path in self.deleted() or path in self.removed():
return ''
return flag
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
def ancestor(self, c2):
"""return the ancestor context of self and c2"""
return self._parents[0].ancestor(c2) # punt on two parents for now
class workingfilectx(filectx):
"""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):
"""changeid can be a changeset revision, node, or tag.
fileid can be a file revision or node."""
self._repo = repo
self._path = path
self._changeid = None
self._filerev = self._filenode = None
if filelog:
self._filelog = filelog
if workingctx:
self._changectx = workingctx
def __getattr__(self, name):
if name == '_changectx':
Matt Mackall
context: fix workingfilectx._changectx
r4414 self._changectx = workingctx(self._repo)
Matt Mackall
contexts: add working dir and working file contexts...
r3217 return self._changectx
elif name == '_repopath':
Matt Mackall
fix workingfilectx parents and ancestor functions
r3298 self._repopath = (self._repo.dirstate.copied(self._path)
or self._path)
return self._repopath
Matt Mackall
contexts: add working dir and working file contexts...
r3217 elif name == '_filelog':
self._filelog = self._repo.file(self._repopath)
return self._filelog
else:
raise AttributeError, name
def __nonzero__(self):
return True
def __str__(self):
Matt Mackall
context: change workingctx str() from . to <node>+
r3313 return "%s@%s" % (self.path(), self._changectx)
Matt Mackall
contexts: add working dir and working file contexts...
r3217
def filectx(self, fileid):
'''opens an arbitrary revision of the file without
opening a new filelog'''
return filectx(self._repo, self._repopath, fileid=fileid,
filelog=self._filelog)
def rev(self):
Brendan Cully
context: check self.__dict__ instead of using hasattr...
r3336 if '_changectx' in self.__dict__:
Matt Mackall
contexts: add working dir and working file contexts...
r3217 return self._changectx.rev()
return self._filelog.linkrev(self._filenode)
def data(self): return self._repo.wread(self._path)
def renamed(self):
rp = self._repopath
if rp == self._path:
return None
Benoit Boissinot
context: fix a bug in workingfilectx.renamed
r3965 return rp, self._changectx._parents[0]._manifest.get(rp, nullid)
Matt Mackall
contexts: add working dir and working file contexts...
r3217
def parents(self):
'''return parent filectxs, following copies if necessary'''
p = self._path
rp = self._repopath
Matt Mackall
fix workingfilectx parents and ancestor functions
r3298 pcl = self._changectx._parents
Matt Mackall
contexts: add working dir and working file contexts...
r3217 fl = self._filelog
Thomas Arendsen Hein
white space and line break cleanups
r3673 pl = [(rp, pcl[0]._manifest.get(rp, nullid), fl)]
Matt Mackall
contexts: add working dir and working file contexts...
r3217 if len(pcl) > 1:
if rp != p:
fl = None
pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
Thomas Arendsen Hein
white space and line break cleanups
r3673 return [filectx(self._repo, p, fileid=n, filelog=l)
for p,n,l in pl if n != nullid]
Matt Mackall
contexts: add working dir and working file contexts...
r3217
def children(self):
return []
Matt Mackall
filectx: add size method
r3302 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
Benoit Boissinot
add date attribute to workingfilectx
r3962 def date(self):
t, tz = self._changectx.date()
try:
Thomas Arendsen Hein
Use only integer part of mtime in workingfilectx.date(), fixes test-context.py...
r4117 return (int(os.lstat(self._repo.wjoin(self._path)).st_mtime), tz)
Benoit Boissinot
add date attribute to workingfilectx
r3962 except OSError, err:
if err.errno != errno.ENOENT: raise
return (t, tz)
Matt Mackall
context: add cmp for filectxs
r3310
def cmp(self, text): return self._repo.wread(self._path) == text