mercurial/context.py
changeset 19608 896193a9cab4
parent 19607 056a949799ac
child 19609 4e72ffec8c2d
equal deleted inserted replaced
19607:056a949799ac 19608:896193a9cab4
   557         p = self.parents()
   557         p = self.parents()
   558         if len(p) == 2:
   558         if len(p) == 2:
   559             return p[1]
   559             return p[1]
   560         return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
   560         return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog)
   561 
   561 
   562 class filectx(basefilectx):
       
   563     """A filecontext object makes access to data related to a particular
       
   564        filerevision convenient."""
       
   565     def __init__(self, repo, path, changeid=None, fileid=None,
       
   566                  filelog=None, changectx=None):
       
   567         """changeid can be a changeset revision, node, or tag.
       
   568            fileid can be a file revision or node."""
       
   569         self._repo = repo
       
   570         self._path = path
       
   571 
       
   572         assert (changeid is not None
       
   573                 or fileid is not None
       
   574                 or changectx is not None), \
       
   575                 ("bad args: changeid=%r, fileid=%r, changectx=%r"
       
   576                  % (changeid, fileid, changectx))
       
   577 
       
   578         if filelog is not None:
       
   579             self._filelog = filelog
       
   580 
       
   581         if changeid is not None:
       
   582             self._changeid = changeid
       
   583         if changectx is not None:
       
   584             self._changectx = changectx
       
   585         if fileid is not None:
       
   586             self._fileid = fileid
       
   587 
       
   588     @propertycache
       
   589     def _changectx(self):
       
   590         try:
       
   591             return changectx(self._repo, self._changeid)
       
   592         except error.RepoLookupError:
       
   593             # Linkrev may point to any revision in the repository.  When the
       
   594             # repository is filtered this may lead to `filectx` trying to build
       
   595             # `changectx` for filtered revision. In such case we fallback to
       
   596             # creating `changectx` on the unfiltered version of the reposition.
       
   597             # This fallback should not be an issue because `changectx` from
       
   598             # `filectx` are not used in complex operations that care about
       
   599             # filtering.
       
   600             #
       
   601             # This fallback is a cheap and dirty fix that prevent several
       
   602             # crashes. It does not ensure the behavior is correct. However the
       
   603             # behavior was not correct before filtering either and "incorrect
       
   604             # behavior" is seen as better as "crash"
       
   605             #
       
   606             # Linkrevs have several serious troubles with filtering that are
       
   607             # complicated to solve. Proper handling of the issue here should be
       
   608             # considered when solving linkrev issue are on the table.
       
   609             return changectx(self._repo.unfiltered(), self._changeid)
       
   610 
       
   611     def filectx(self, fileid):
       
   612         '''opens an arbitrary revision of the file without
       
   613         opening a new filelog'''
       
   614         return filectx(self._repo, self._path, fileid=fileid,
       
   615                        filelog=self._filelog)
       
   616 
       
   617     def data(self):
       
   618         return self._filelog.read(self._filenode)
       
   619     def size(self):
       
   620         return self._filelog.size(self._filerev)
       
   621 
       
   622     def renamed(self):
       
   623         """check if file was actually renamed in this changeset revision
       
   624 
       
   625         If rename logged in file revision, we report copy for changeset only
       
   626         if file revisions linkrev points back to the changeset in question
       
   627         or both changeset parents contain different file revisions.
       
   628         """
       
   629 
       
   630         renamed = self._filelog.renamed(self._filenode)
       
   631         if not renamed:
       
   632             return renamed
       
   633 
       
   634         if self.rev() == self.linkrev():
       
   635             return renamed
       
   636 
       
   637         name = self.path()
       
   638         fnode = self._filenode
       
   639         for p in self._changectx.parents():
       
   640             try:
       
   641                 if fnode == p.filenode(name):
       
   642                     return None
       
   643             except error.LookupError:
       
   644                 pass
       
   645         return renamed
       
   646 
       
   647     def children(self):
       
   648         # hard for renames
       
   649         c = self._filelog.children(self._filenode)
       
   650         return [filectx(self._repo, self._path, fileid=x,
       
   651                         filelog=self._filelog) for x in c]
       
   652 
       
   653     def annotate(self, follow=False, linenumber=None, diffopts=None):
   562     def annotate(self, follow=False, linenumber=None, diffopts=None):
   654         '''returns a list of tuples of (ctx, line) for each line
   563         '''returns a list of tuples of (ctx, line) for each line
   655         in the file, where ctx is the filectx of the node where
   564         in the file, where ctx is the filectx of the node where
   656         that line was last changed.
   565         that line was last changed.
   657         This returns tuples of ((ctx, linenumber), line) for each line,
   566         This returns tuples of ((ctx, linenumber), line) for each line,
   749 
   658 
   750                 hist[f] = curr
   659                 hist[f] = curr
   751                 pcache[f] = []
   660                 pcache[f] = []
   752 
   661 
   753         return zip(hist[base][0], hist[base][1].splitlines(True))
   662         return zip(hist[base][0], hist[base][1].splitlines(True))
       
   663 
       
   664 class filectx(basefilectx):
       
   665     """A filecontext object makes access to data related to a particular
       
   666        filerevision convenient."""
       
   667     def __init__(self, repo, path, changeid=None, fileid=None,
       
   668                  filelog=None, changectx=None):
       
   669         """changeid can be a changeset revision, node, or tag.
       
   670            fileid can be a file revision or node."""
       
   671         self._repo = repo
       
   672         self._path = path
       
   673 
       
   674         assert (changeid is not None
       
   675                 or fileid is not None
       
   676                 or changectx is not None), \
       
   677                 ("bad args: changeid=%r, fileid=%r, changectx=%r"
       
   678                  % (changeid, fileid, changectx))
       
   679 
       
   680         if filelog is not None:
       
   681             self._filelog = filelog
       
   682 
       
   683         if changeid is not None:
       
   684             self._changeid = changeid
       
   685         if changectx is not None:
       
   686             self._changectx = changectx
       
   687         if fileid is not None:
       
   688             self._fileid = fileid
       
   689 
       
   690     @propertycache
       
   691     def _changectx(self):
       
   692         try:
       
   693             return changectx(self._repo, self._changeid)
       
   694         except error.RepoLookupError:
       
   695             # Linkrev may point to any revision in the repository.  When the
       
   696             # repository is filtered this may lead to `filectx` trying to build
       
   697             # `changectx` for filtered revision. In such case we fallback to
       
   698             # creating `changectx` on the unfiltered version of the reposition.
       
   699             # This fallback should not be an issue because `changectx` from
       
   700             # `filectx` are not used in complex operations that care about
       
   701             # filtering.
       
   702             #
       
   703             # This fallback is a cheap and dirty fix that prevent several
       
   704             # crashes. It does not ensure the behavior is correct. However the
       
   705             # behavior was not correct before filtering either and "incorrect
       
   706             # behavior" is seen as better as "crash"
       
   707             #
       
   708             # Linkrevs have several serious troubles with filtering that are
       
   709             # complicated to solve. Proper handling of the issue here should be
       
   710             # considered when solving linkrev issue are on the table.
       
   711             return changectx(self._repo.unfiltered(), self._changeid)
       
   712 
       
   713     def filectx(self, fileid):
       
   714         '''opens an arbitrary revision of the file without
       
   715         opening a new filelog'''
       
   716         return filectx(self._repo, self._path, fileid=fileid,
       
   717                        filelog=self._filelog)
       
   718 
       
   719     def data(self):
       
   720         return self._filelog.read(self._filenode)
       
   721     def size(self):
       
   722         return self._filelog.size(self._filerev)
       
   723 
       
   724     def renamed(self):
       
   725         """check if file was actually renamed in this changeset revision
       
   726 
       
   727         If rename logged in file revision, we report copy for changeset only
       
   728         if file revisions linkrev points back to the changeset in question
       
   729         or both changeset parents contain different file revisions.
       
   730         """
       
   731 
       
   732         renamed = self._filelog.renamed(self._filenode)
       
   733         if not renamed:
       
   734             return renamed
       
   735 
       
   736         if self.rev() == self.linkrev():
       
   737             return renamed
       
   738 
       
   739         name = self.path()
       
   740         fnode = self._filenode
       
   741         for p in self._changectx.parents():
       
   742             try:
       
   743                 if fnode == p.filenode(name):
       
   744                     return None
       
   745             except error.LookupError:
       
   746                 pass
       
   747         return renamed
       
   748 
       
   749     def children(self):
       
   750         # hard for renames
       
   751         c = self._filelog.children(self._filenode)
       
   752         return [filectx(self._repo, self._path, fileid=x,
       
   753                         filelog=self._filelog) for x in c]
   754 
   754 
   755     def ancestor(self, fc2, actx):
   755     def ancestor(self, fc2, actx):
   756         """
   756         """
   757         find the common ancestor file context, if any, of self, and fc2
   757         find the common ancestor file context, if any, of self, and fc2
   758 
   758