Mercurial > public > mercurial-scm > hg-stable
diff mercurial/context.py @ 3241:a184cd0c2db9
Merge with upstream
author | Brendan Cully <brendan@kublai.com> |
---|---|
date | Tue, 03 Oct 2006 12:14:33 -0700 |
parents | f7a8228fde17 8d4855fd9d7b |
children | 1539f788e913 |
line wrap: on
line diff
--- a/mercurial/context.py Tue Oct 03 11:54:11 2006 +0200 +++ b/mercurial/context.py Tue Oct 03 12:14:33 2006 -0700 @@ -33,7 +33,7 @@ return short(self.node()) def __repr__(self): - return "<changectx %s>" % short(self.node()) + return "<changectx %s>" % str(self) def __eq__(self, other): return self._rev == other._rev @@ -41,26 +41,25 @@ def __nonzero__(self): return self._rev != -1 - def changeset(self): - try: - return self._changeset - except AttributeError: + def __getattr__(self, name): + if name == '_changeset': self._changeset = self._repo.changelog.read(self.node()) return self._changeset - - def manifest(self): - try: + elif name == '_manifest': + self._manifest = self._repo.manifest.read(self._changeset[0]) return self._manifest - except AttributeError: - self._manifest = self._repo.manifest.read(self.changeset()[0]) - return self._manifest + else: + raise AttributeError, name + + def changeset(self): return self._changeset + def manifest(self): return self._manifest def rev(self): return self._rev def node(self): return self._node - 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 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 parents(self): """return contexts for each parent changeset""" @@ -73,17 +72,16 @@ return [ changectx(self._repo, x) for x in c ] def filenode(self, path): - node, flag = self._repo.manifest.find(self.changeset()[0], path) + if hasattr(self, "_manifest"): + return self._manifest[path] + node, flag = self._repo.manifest.find(self._changeset[0], path) return node def filectx(self, path, fileid=None): """get a file context from this changeset""" if fileid is None: fileid = self.filenode(path) - if not fileid: - raise repo.LookupError(_("'%s' does not exist in changeset %s") % - (path, hex(self.node()))) - return filectx(self._repo, path, fileid=fileid) + return filectx(self._repo, path, fileid=fileid, changectx=self) def filectxs(self): """generate a file context for each file in this changeset's @@ -104,34 +102,44 @@ class filectx(object): """A filecontext object makes access to data related to a particular filerevision convenient.""" - def __init__(self, repo_, path, changeid=None, fileid=None, filelog=None): + 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._repo = repo self._path = path assert changeid is not None or fileid is not None if filelog: self._filelog = filelog - else: - self._filelog = self._repo.file(self._path) + if changectx: + self._changectx = changectx + self._changeid = changectx.node() if fileid is None: self._changeid = changeid else: - try: - self._filenode = self._filelog.lookup(fileid) - except revlog.RevlogError, inst: - raise repo.LookupError(str(inst)) - self._changeid = self._filelog.linkrev(self._filenode) + self._fileid = fileid def __getattr__(self, name): if name == '_changectx': self._changectx = changectx(self._repo, self._changeid) return self._changectx + elif name == '_filelog': + self._filelog = self._repo.file(self._path) + return self._filelog + elif name == '_changeid': + self._changeid = self._filelog.linkrev(self._filenode) + return self._changeid elif name == '_filenode': - self._filenode = self._changectx.filenode(self._path) + try: + if hasattr(self, "_fileid"): + self._filenode = self._filelog.lookup(self._fileid) + else: + self._filenode = self._changectx.filenode(self._path) + except revlog.RevlogError, inst: + raise repo.LookupError(str(inst)) return self._filenode elif name == '_filerev': self._filerev = self._filelog.rev(self._filenode) @@ -146,7 +154,7 @@ return "%s@%s" % (self.path(), short(self.node())) def __repr__(self): - return "<filectx %s@%s>" % (self.path(), short(self.node())) + return "<filectx %s>" % str(self) def __eq__(self, other): return self._path == other._path and self._changeid == other._changeid @@ -218,7 +226,10 @@ def parents(f): # we want to reuse filectx objects as much as possible p = f._path - pl = [ (p, r) for r in f._filelog.parentrevs(f._filerev) ] + if f._filerev is None: # working dir + pl = [ (n.path(), n.filerev()) for n in f.parents() ] + else: + pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ] if follow: r = f.renamed() @@ -271,6 +282,13 @@ """ acache = {} + + # prime the ancestor cache for the working directory + for c in (self, fc2): + if c._filerev == None: + pl = [ (n.path(), n.filenode()) for n in c.parents() ] + acache[(c._path, None)] = pl + flcache = {self._path:self._filelog, fc2._path:fc2._filelog} def parents(vertex): if vertex in acache: @@ -293,3 +311,149 @@ return filectx(self._repo, f, fileid=n, filelog=flcache[f]) return None + +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): + return "." + + 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""" + + man = self._parents[0].manifest().copy() + copied = self._repo.dirstate.copies() + modified, added, removed, deleted, unknown = self._status[:5] + for i,l in (("a", added), ("m", modified), ("u", unknown)): + for f in l: + man[f] = man.get(copied.get(f, f), nullid) + i + man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f))) + + for f in deleted + removed: + del man[f] + + 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] + + def parents(self): + """return contexts for each parent changeset""" + return self._parents + + def children(self): + return [] + + def filectx(self, path): + """get a file context from the working directory""" + return workingfilectx(self._repo, path, workingctx=self) + + 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': + self._changectx = workingctx(repo) + return self._changectx + elif name == '_repopath': + self._repopath = self._repo.dirstate.copied(p) or self._path + 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): + return "%s@." % self.path() + + 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): + if hasattr(self, "_changectx"): + 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 + return rp, self._workingctx._parents._manifest.get(rp, nullid) + + def parents(self): + '''return parent filectxs, following copies if necessary''' + p = self._path + rp = self._repopath + pcl = self._workingctx._parents + fl = self._filelog + pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ] + if len(pcl) > 1: + if rp != p: + fl = None + pl.append((p, pcl[1]._manifest.get(p, nullid), fl)) + + return [ filectx(self._repo, p, fileid=n, filelog=l) + for p,n,l in pl if n != nullid ] + + def children(self): + return [] +