mercurial/context.py
changeset 3239 6d98149d70fe
parent 3238 d865390c1781
child 3240 8d4855fd9d7b
equal deleted inserted replaced
3238:d865390c1781 3239:6d98149d70fe
   224         getctx = util.cachefunc(getctx)
   224         getctx = util.cachefunc(getctx)
   225 
   225 
   226         def parents(f):
   226         def parents(f):
   227             # we want to reuse filectx objects as much as possible
   227             # we want to reuse filectx objects as much as possible
   228             p = f._path
   228             p = f._path
   229             pl = [ (p, f._filelog.rev(n)) for n in f._filelog.parents(f._filenode) ]
   229             if f._filerev is None: # working dir
       
   230                 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
       
   231             else:
       
   232                 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
   230 
   233 
   231             if follow:
   234             if follow:
   232                 r = f.renamed()
   235                 r = f.renamed()
   233                 if r:
   236                 if r:
   234                     pl[0] = (r[0], getlog(r[0]).rev(r[1]))
   237                     pl[0] = (r[0], getlog(r[0]).rev(r[1]))
   235 
   238 
   236             return [ getctx(p, n) for p, n in pl if n != -1 ]
   239             return [ getctx(p, n) for p, n in pl if n != -1 ]
   237                 
   240 
   238         # find all ancestors
   241         # find all ancestors
   239         needed = {self: 1}
   242         needed = {self: 1}
   240         visit = [self]
   243         visit = [self]
   241         files = [self._path]
   244         files = [self._path]
   242         while visit:
   245         while visit:
   277         """
   280         """
   278         find the common ancestor file context, if any, of self, and fc2
   281         find the common ancestor file context, if any, of self, and fc2
   279         """
   282         """
   280 
   283 
   281         acache = {}
   284         acache = {}
       
   285 
       
   286         # prime the ancestor cache for the working directory
       
   287         for c in (self, fc2):
       
   288             if c._filerev == None:
       
   289                 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
       
   290                 acache[(c._path, None)] = pl
       
   291 
   282         flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
   292         flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
   283         def parents(vertex):
   293         def parents(vertex):
   284             if vertex in acache:
   294             if vertex in acache:
   285                 return acache[vertex]
   295                 return acache[vertex]
   286             f, n = vertex
   296             f, n = vertex
   299         if v:
   309         if v:
   300             f,n = v
   310             f,n = v
   301             return filectx(self._repo, f, fileid=n, filelog=flcache[f])
   311             return filectx(self._repo, f, fileid=n, filelog=flcache[f])
   302 
   312 
   303         return None
   313         return None
       
   314 
       
   315 class workingctx(changectx):
       
   316     """A workingctx object makes access to data related to
       
   317     the current working directory convenient."""
       
   318     def __init__(self, repo):
       
   319         self._repo = repo
       
   320         self._rev = None
       
   321         self._node = None
       
   322 
       
   323     def __str__(self):
       
   324         return "."
       
   325 
       
   326     def __nonzero__(self):
       
   327         return True
       
   328 
       
   329     def __getattr__(self, name):
       
   330         if name == '_parents':
       
   331             self._parents = self._repo.parents()
       
   332             return self._parents
       
   333         if name == '_status':
       
   334             self._status = self._repo.status()
       
   335             return self._status
       
   336         if name == '_manifest':
       
   337             self._buildmanifest()
       
   338             return self._manifest
       
   339         else:
       
   340             raise AttributeError, name
       
   341 
       
   342     def _buildmanifest(self):
       
   343         """generate a manifest corresponding to the working directory"""
       
   344 
       
   345         man = self._parents[0].manifest().coy()
       
   346         copied = self._repo.dirstate.copies()
       
   347         modified, added, removed, deleted, unknown = self._status[:5]
       
   348         for i,l in (("a", added), ("m", modified), ("u", unknown)):
       
   349             for f in l:
       
   350                 man[f] = man.get(copied.get(f, f), nullid) + i
       
   351                 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
       
   352 
       
   353         for f in deleted + removed:
       
   354             del man[f]
       
   355 
       
   356         self._manifest = man
       
   357 
       
   358     def manifest(self): return self._manifest
       
   359 
       
   360     def user(self): return self._repo.ui.username()
       
   361     def date(self): return util.makedate()
       
   362     def description(self): return ""
       
   363     def files(self):
       
   364         f = self.modified() + self.added() + self.removed()
       
   365         f.sort()
       
   366         return f
       
   367 
       
   368     def modified(self): return self._status[0]
       
   369     def added(self): return self._status[1]
       
   370     def removed(self): return self._status[2]
       
   371     def deleted(self): return self._status[3]
       
   372     def unknown(self): return self._status[4]
       
   373     def clean(self): return self._status[5]
       
   374 
       
   375     def parents(self):
       
   376         """return contexts for each parent changeset"""
       
   377         return self._parents
       
   378 
       
   379     def children(self):
       
   380         return []
       
   381 
       
   382     def filectx(self, path):
       
   383         """get a file context from the working directory"""
       
   384         return workingfilectx(self._repo, path, workingctx=self)
       
   385 
       
   386     def ancestor(self, c2):
       
   387         """return the ancestor context of self and c2"""
       
   388         return self._parents[0].ancestor(c2) # punt on two parents for now
       
   389 
       
   390 class workingfilectx(filectx):
       
   391     """A workingfilectx object makes access to data related to a particular
       
   392        file in the working directory convenient."""
       
   393     def __init__(self, repo, path, filelog=None, workingctx=None):
       
   394         """changeid can be a changeset revision, node, or tag.
       
   395            fileid can be a file revision or node."""
       
   396         self._repo = repo
       
   397         self._path = path
       
   398         self._changeid = None
       
   399         self._filerev = self._filenode = None
       
   400 
       
   401         if filelog:
       
   402             self._filelog = filelog
       
   403         if workingctx:
       
   404             self._changectx = workingctx
       
   405 
       
   406     def __getattr__(self, name):
       
   407         if name == '_changectx':
       
   408             self._changectx = workingctx(repo)
       
   409             return self._changectx
       
   410         elif name == '_repopath':
       
   411             self._repopath = self._repo.dirstate.copied(p) or self._path
       
   412         elif name == '_filelog':
       
   413             self._filelog = self._repo.file(self._repopath)
       
   414             return self._filelog
       
   415         else:
       
   416             raise AttributeError, name
       
   417 
       
   418     def __nonzero__(self):
       
   419         return True
       
   420 
       
   421     def __str__(self):
       
   422         return "%s@." % self.path()
       
   423 
       
   424     def filectx(self, fileid):
       
   425         '''opens an arbitrary revision of the file without
       
   426         opening a new filelog'''
       
   427         return filectx(self._repo, self._repopath, fileid=fileid,
       
   428                        filelog=self._filelog)
       
   429 
       
   430     def rev(self):
       
   431         if hasattr(self, "_changectx"):
       
   432             return self._changectx.rev()
       
   433         return self._filelog.linkrev(self._filenode)
       
   434 
       
   435     def data(self): return self._repo.wread(self._path)
       
   436     def renamed(self):
       
   437         rp = self._repopath
       
   438         if rp == self._path:
       
   439             return None
       
   440         return rp, self._workingctx._parents._manifest.get(rp, nullid)
       
   441 
       
   442     def parents(self):
       
   443         '''return parent filectxs, following copies if necessary'''
       
   444         p = self._path
       
   445         rp = self._repopath
       
   446         pcl = self._workingctx._parents
       
   447         fl = self._filelog
       
   448         pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
       
   449         if len(pcl) > 1:
       
   450             if rp != p:
       
   451                 fl = None
       
   452             pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
       
   453 
       
   454         return [ filectx(self._repo, p, fileid=n, filelog=l)
       
   455                  for p,n,l in pl if n != nullid ]
       
   456 
       
   457     def children(self):
       
   458         return []
       
   459