mercurial/context.py
changeset 43076 2372284d9457
parent 43023 8af909893188
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    47     stringutil,
    47     stringutil,
    48 )
    48 )
    49 
    49 
    50 propertycache = util.propertycache
    50 propertycache = util.propertycache
    51 
    51 
       
    52 
    52 class basectx(object):
    53 class basectx(object):
    53     """A basectx object represents the common logic for its children:
    54     """A basectx object represents the common logic for its children:
    54     changectx: read-only context that is already present in the repo,
    55     changectx: read-only context that is already present in the repo,
    55     workingctx: a context that represents the working directory and can
    56     workingctx: a context that represents the working directory and can
    56                 be committed,
    57                 be committed,
    96         """This internal method provides a way for child objects to override the
    97         """This internal method provides a way for child objects to override the
    97         match operator.
    98         match operator.
    98         """
    99         """
    99         return match
   100         return match
   100 
   101 
   101     def _buildstatus(self, other, s, match, listignored, listclean,
   102     def _buildstatus(
   102                      listunknown):
   103         self, other, s, match, listignored, listclean, listunknown
       
   104     ):
   103         """build a status with respect to another context"""
   105         """build a status with respect to another context"""
   104         # Load earliest manifest first for caching reasons. More specifically,
   106         # Load earliest manifest first for caching reasons. More specifically,
   105         # if you have revisions 1000 and 1001, 1001 is probably stored as a
   107         # if you have revisions 1000 and 1001, 1001 is probably stored as a
   106         # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
   108         # delta against 1000. Thus, if you read 1000 first, we'll reconstruct
   107         # 1000 and cache it so that when you read 1001, we just need to apply a
   109         # 1000 and cache it so that when you read 1001, we just need to apply a
   144             else:
   146             else:
   145                 clean.append(fn)
   147                 clean.append(fn)
   146 
   148 
   147         if removed:
   149         if removed:
   148             # need to filter files if they are already reported as removed
   150             # need to filter files if they are already reported as removed
   149             unknown = [fn for fn in unknown if fn not in mf1 and
   151             unknown = [
   150                                                (not match or match(fn))]
   152                 fn
   151             ignored = [fn for fn in ignored if fn not in mf1 and
   153                 for fn in unknown
   152                                                (not match or match(fn))]
   154                 if fn not in mf1 and (not match or match(fn))
       
   155             ]
       
   156             ignored = [
       
   157                 fn
       
   158                 for fn in ignored
       
   159                 if fn not in mf1 and (not match or match(fn))
       
   160             ]
   153             # if they're deleted, don't report them as removed
   161             # if they're deleted, don't report them as removed
   154             removed = [fn for fn in removed if fn not in deletedset]
   162             removed = [fn for fn in removed if fn not in deletedset]
   155 
   163 
   156         return scmutil.status(modified, added, removed, deleted, unknown,
   164         return scmutil.status(
   157                               ignored, clean)
   165             modified, added, removed, deleted, unknown, ignored, clean
       
   166         )
   158 
   167 
   159     @propertycache
   168     @propertycache
   160     def substate(self):
   169     def substate(self):
   161         return subrepoutil.state(self, self._repo.ui)
   170         return subrepoutil.state(self, self._repo.ui)
   162 
   171 
   163     def subrev(self, subpath):
   172     def subrev(self, subpath):
   164         return self.substate[subpath][1]
   173         return self.substate[subpath][1]
   165 
   174 
   166     def rev(self):
   175     def rev(self):
   167         return self._rev
   176         return self._rev
       
   177 
   168     def node(self):
   178     def node(self):
   169         return self._node
   179         return self._node
       
   180 
   170     def hex(self):
   181     def hex(self):
   171         return hex(self.node())
   182         return hex(self.node())
       
   183 
   172     def manifest(self):
   184     def manifest(self):
   173         return self._manifest
   185         return self._manifest
       
   186 
   174     def manifestctx(self):
   187     def manifestctx(self):
   175         return self._manifestctx
   188         return self._manifestctx
       
   189 
   176     def repo(self):
   190     def repo(self):
   177         return self._repo
   191         return self._repo
       
   192 
   178     def phasestr(self):
   193     def phasestr(self):
   179         return phases.phasenames[self.phase()]
   194         return phases.phasenames[self.phase()]
       
   195 
   180     def mutable(self):
   196     def mutable(self):
   181         return self.phase() > phases.public
   197         return self.phase() > phases.public
   182 
   198 
   183     def matchfileset(self, expr, badfn=None):
   199     def matchfileset(self, expr, badfn=None):
   184         return fileset.match(self, expr, badfn=badfn)
   200         return fileset.match(self, expr, badfn=badfn)
   247     def _fileinfo(self, path):
   263     def _fileinfo(self, path):
   248         if r'_manifest' in self.__dict__:
   264         if r'_manifest' in self.__dict__:
   249             try:
   265             try:
   250                 return self._manifest[path], self._manifest.flags(path)
   266                 return self._manifest[path], self._manifest.flags(path)
   251             except KeyError:
   267             except KeyError:
   252                 raise error.ManifestLookupError(self._node, path,
   268                 raise error.ManifestLookupError(
   253                                                 _('not found in manifest'))
   269                     self._node, path, _('not found in manifest')
       
   270                 )
   254         if r'_manifestdelta' in self.__dict__ or path in self.files():
   271         if r'_manifestdelta' in self.__dict__ or path in self.files():
   255             if path in self._manifestdelta:
   272             if path in self._manifestdelta:
   256                 return (self._manifestdelta[path],
   273                 return (
   257                         self._manifestdelta.flags(path))
   274                     self._manifestdelta[path],
       
   275                     self._manifestdelta.flags(path),
       
   276                 )
   258         mfl = self._repo.manifestlog
   277         mfl = self._repo.manifestlog
   259         try:
   278         try:
   260             node, flag = mfl[self._changeset.manifest].find(path)
   279             node, flag = mfl[self._changeset.manifest].find(path)
   261         except KeyError:
   280         except KeyError:
   262             raise error.ManifestLookupError(self._node, path,
   281             raise error.ManifestLookupError(
   263                                             _('not found in manifest'))
   282                 self._node, path, _('not found in manifest')
       
   283             )
   264 
   284 
   265         return node, flag
   285         return node, flag
   266 
   286 
   267     def filenode(self, path):
   287     def filenode(self, path):
   268         return self._fileinfo(path)[0]
   288         return self._fileinfo(path)[0]
   274             return ''
   294             return ''
   275 
   295 
   276     @propertycache
   296     @propertycache
   277     def _copies(self):
   297     def _copies(self):
   278         return copies.computechangesetcopies(self)
   298         return copies.computechangesetcopies(self)
       
   299 
   279     def p1copies(self):
   300     def p1copies(self):
   280         return self._copies[0]
   301         return self._copies[0]
       
   302 
   281     def p2copies(self):
   303     def p2copies(self):
   282         return self._copies[1]
   304         return self._copies[1]
   283 
   305 
   284     def sub(self, path, allowcreate=True):
   306     def sub(self, path, allowcreate=True):
   285         '''return a subrepo for the stored revision of path, never wdir()'''
   307         '''return a subrepo for the stored revision of path, never wdir()'''
   292         '''return a subrepo for the stored revision, or wdir if this is a wdir
   314         '''return a subrepo for the stored revision, or wdir if this is a wdir
   293         context.
   315         context.
   294         '''
   316         '''
   295         return subrepo.subrepo(self, path, allowwdir=True)
   317         return subrepo.subrepo(self, path, allowwdir=True)
   296 
   318 
   297     def match(self, pats=None, include=None, exclude=None, default='glob',
   319     def match(
   298               listsubrepos=False, badfn=None):
   320         self,
       
   321         pats=None,
       
   322         include=None,
       
   323         exclude=None,
       
   324         default='glob',
       
   325         listsubrepos=False,
       
   326         badfn=None,
       
   327     ):
   299         r = self._repo
   328         r = self._repo
   300         return matchmod.match(r.root, r.getcwd(), pats,
   329         return matchmod.match(
   301                               include, exclude, default,
   330             r.root,
   302                               auditor=r.nofsauditor, ctx=self,
   331             r.getcwd(),
   303                               listsubrepos=listsubrepos, badfn=badfn)
   332             pats,
   304 
   333             include,
   305     def diff(self, ctx2=None, match=None, changes=None, opts=None,
   334             exclude,
   306              losedatafn=None, pathfn=None, copy=None,
   335             default,
   307              copysourcematch=None, hunksfilterfn=None):
   336             auditor=r.nofsauditor,
       
   337             ctx=self,
       
   338             listsubrepos=listsubrepos,
       
   339             badfn=badfn,
       
   340         )
       
   341 
       
   342     def diff(
       
   343         self,
       
   344         ctx2=None,
       
   345         match=None,
       
   346         changes=None,
       
   347         opts=None,
       
   348         losedatafn=None,
       
   349         pathfn=None,
       
   350         copy=None,
       
   351         copysourcematch=None,
       
   352         hunksfilterfn=None,
       
   353     ):
   308         """Returns a diff generator for the given contexts and matcher"""
   354         """Returns a diff generator for the given contexts and matcher"""
   309         if ctx2 is None:
   355         if ctx2 is None:
   310             ctx2 = self.p1()
   356             ctx2 = self.p1()
   311         if ctx2 is not None:
   357         if ctx2 is not None:
   312             ctx2 = self._repo[ctx2]
   358             ctx2 = self._repo[ctx2]
   313         return patch.diff(self._repo, ctx2, self, match=match, changes=changes,
   359         return patch.diff(
   314                           opts=opts, losedatafn=losedatafn, pathfn=pathfn,
   360             self._repo,
   315                           copy=copy, copysourcematch=copysourcematch,
   361             ctx2,
   316                           hunksfilterfn=hunksfilterfn)
   362             self,
       
   363             match=match,
       
   364             changes=changes,
       
   365             opts=opts,
       
   366             losedatafn=losedatafn,
       
   367             pathfn=pathfn,
       
   368             copy=copy,
       
   369             copysourcematch=copysourcematch,
       
   370             hunksfilterfn=hunksfilterfn,
       
   371         )
   317 
   372 
   318     def dirs(self):
   373     def dirs(self):
   319         return self._manifest.dirs()
   374         return self._manifest.dirs()
   320 
   375 
   321     def hasdir(self, dir):
   376     def hasdir(self, dir):
   322         return self._manifest.hasdir(dir)
   377         return self._manifest.hasdir(dir)
   323 
   378 
   324     def status(self, other=None, match=None, listignored=False,
   379     def status(
   325                listclean=False, listunknown=False, listsubrepos=False):
   380         self,
       
   381         other=None,
       
   382         match=None,
       
   383         listignored=False,
       
   384         listclean=False,
       
   385         listunknown=False,
       
   386         listsubrepos=False,
       
   387     ):
   326         """return status of files between two nodes or node and working
   388         """return status of files between two nodes or node and working
   327         directory.
   389         directory.
   328 
   390 
   329         If other is None, compare this node with working directory.
   391         If other is None, compare this node with working directory.
   330 
   392 
   345         #
   407         #
   346         # If we always built the manifest for each context and compared those,
   408         # If we always built the manifest for each context and compared those,
   347         # then we'd be done. But the special case of the above call means we
   409         # then we'd be done. But the special case of the above call means we
   348         # just copy the manifest of the parent.
   410         # just copy the manifest of the parent.
   349         reversed = False
   411         reversed = False
   350         if (not isinstance(ctx1, changectx)
   412         if not isinstance(ctx1, changectx) and isinstance(ctx2, changectx):
   351             and isinstance(ctx2, changectx)):
       
   352             reversed = True
   413             reversed = True
   353             ctx1, ctx2 = ctx2, ctx1
   414             ctx1, ctx2 = ctx2, ctx1
   354 
   415 
   355         match = self._repo.narrowmatch(match)
   416         match = self._repo.narrowmatch(match)
   356         match = ctx2._matchstatus(ctx1, match)
   417         match = ctx2._matchstatus(ctx1, match)
   357         r = scmutil.status([], [], [], [], [], [], [])
   418         r = scmutil.status([], [], [], [], [], [], [])
   358         r = ctx2._buildstatus(ctx1, r, match, listignored, listclean,
   419         r = ctx2._buildstatus(
   359                               listunknown)
   420             ctx1, r, match, listignored, listclean, listunknown
       
   421         )
   360 
   422 
   361         if reversed:
   423         if reversed:
   362             # Reverse added and removed. Clear deleted, unknown and ignored as
   424             # Reverse added and removed. Clear deleted, unknown and ignored as
   363             # these make no sense to reverse.
   425             # these make no sense to reverse.
   364             r = scmutil.status(r.modified, r.removed, r.added, [], [], [],
   426             r = scmutil.status(
   365                                r.clean)
   427                 r.modified, r.removed, r.added, [], [], [], r.clean
       
   428             )
   366 
   429 
   367         if listsubrepos:
   430         if listsubrepos:
   368             for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
   431             for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
   369                 try:
   432                 try:
   370                     rev2 = ctx2.subrev(subpath)
   433                     rev2 = ctx2.subrev(subpath)
   372                     # A subrepo that existed in node1 was deleted between
   435                     # A subrepo that existed in node1 was deleted between
   373                     # node1 and node2 (inclusive). Thus, ctx2's substate
   436                     # node1 and node2 (inclusive). Thus, ctx2's substate
   374                     # won't contain that subpath. The best we can do ignore it.
   437                     # won't contain that subpath. The best we can do ignore it.
   375                     rev2 = None
   438                     rev2 = None
   376                 submatch = matchmod.subdirmatcher(subpath, match)
   439                 submatch = matchmod.subdirmatcher(subpath, match)
   377                 s = sub.status(rev2, match=submatch, ignored=listignored,
   440                 s = sub.status(
   378                                clean=listclean, unknown=listunknown,
   441                     rev2,
   379                                listsubrepos=True)
   442                     match=submatch,
       
   443                     ignored=listignored,
       
   444                     clean=listclean,
       
   445                     unknown=listunknown,
       
   446                     listsubrepos=True,
       
   447                 )
   380                 for rfiles, sfiles in zip(r, s):
   448                 for rfiles, sfiles in zip(r, s):
   381                     rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
   449                     rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
   382 
   450 
   383         for l in r:
   451         for l in r:
   384             l.sort()
   452             l.sort()
   385 
   453 
   386         return r
   454         return r
       
   455 
   387 
   456 
   388 class changectx(basectx):
   457 class changectx(basectx):
   389     """A changecontext object makes access to data related to a particular
   458     """A changecontext object makes access to data related to a particular
   390     changeset convenient. It represents a read-only context already present in
   459     changeset convenient. It represents a read-only context already present in
   391     the repo."""
   460     the repo."""
       
   461 
   392     def __init__(self, repo, rev, node):
   462     def __init__(self, repo, rev, node):
   393         super(changectx, self).__init__(repo)
   463         super(changectx, self).__init__(repo)
   394         self._rev = rev
   464         self._rev = rev
   395         self._node = node
   465         self._node = node
   396 
   466 
   437             c.date,
   507             c.date,
   438             c.files,
   508             c.files,
   439             c.description,
   509             c.description,
   440             c.extra,
   510             c.extra,
   441         )
   511         )
       
   512 
   442     def manifestnode(self):
   513     def manifestnode(self):
   443         return self._changeset.manifest
   514         return self._changeset.manifest
   444 
   515 
   445     def user(self):
   516     def user(self):
   446         return self._changeset.user
   517         return self._changeset.user
       
   518 
   447     def date(self):
   519     def date(self):
   448         return self._changeset.date
   520         return self._changeset.date
       
   521 
   449     def files(self):
   522     def files(self):
   450         return self._changeset.files
   523         return self._changeset.files
       
   524 
   451     def filesmodified(self):
   525     def filesmodified(self):
   452         modified = set(self.files())
   526         modified = set(self.files())
   453         modified.difference_update(self.filesadded())
   527         modified.difference_update(self.filesadded())
   454         modified.difference_update(self.filesremoved())
   528         modified.difference_update(self.filesremoved())
   455         return sorted(modified)
   529         return sorted(modified)
   506             p1copies, p2copies = super(changectx, self)._copies
   580             p1copies, p2copies = super(changectx, self)._copies
   507         return p1copies, p2copies
   581         return p1copies, p2copies
   508 
   582 
   509     def description(self):
   583     def description(self):
   510         return self._changeset.description
   584         return self._changeset.description
       
   585 
   511     def branch(self):
   586     def branch(self):
   512         return encoding.tolocal(self._changeset.extra.get("branch"))
   587         return encoding.tolocal(self._changeset.extra.get("branch"))
       
   588 
   513     def closesbranch(self):
   589     def closesbranch(self):
   514         return 'close' in self._changeset.extra
   590         return 'close' in self._changeset.extra
       
   591 
   515     def extra(self):
   592     def extra(self):
   516         """Return a dict of extra information."""
   593         """Return a dict of extra information."""
   517         return self._changeset.extra
   594         return self._changeset.extra
       
   595 
   518     def tags(self):
   596     def tags(self):
   519         """Return a list of byte tag names"""
   597         """Return a list of byte tag names"""
   520         return self._repo.nodetags(self._node)
   598         return self._repo.nodetags(self._node)
       
   599 
   521     def bookmarks(self):
   600     def bookmarks(self):
   522         """Return a list of byte bookmark names."""
   601         """Return a list of byte bookmark names."""
   523         return self._repo.nodebookmarks(self._node)
   602         return self._repo.nodebookmarks(self._node)
       
   603 
   524     def phase(self):
   604     def phase(self):
   525         return self._repo._phasecache.phase(self._repo, self._rev)
   605         return self._repo._phasecache.phase(self._repo, self._rev)
       
   606 
   526     def hidden(self):
   607     def hidden(self):
   527         return self._rev in repoview.filterrevs(self._repo, 'visible')
   608         return self._rev in repoview.filterrevs(self._repo, 'visible')
   528 
   609 
   529     def isinmemory(self):
   610     def isinmemory(self):
   530         return False
   611         return False
   552 
   633 
   553     def filectx(self, path, fileid=None, filelog=None):
   634     def filectx(self, path, fileid=None, filelog=None):
   554         """get a file context from this changeset"""
   635         """get a file context from this changeset"""
   555         if fileid is None:
   636         if fileid is None:
   556             fileid = self.filenode(path)
   637             fileid = self.filenode(path)
   557         return filectx(self._repo, path, fileid=fileid,
   638         return filectx(
   558                        changectx=self, filelog=filelog)
   639             self._repo, path, fileid=fileid, changectx=self, filelog=filelog
       
   640         )
   559 
   641 
   560     def ancestor(self, c2, warn=False):
   642     def ancestor(self, c2, warn=False):
   561         """return the "best" ancestor context of self and c2
   643         """return the "best" ancestor context of self and c2
   562 
   644 
   563         If there are multiple candidates, it will show a message and check
   645         If there are multiple candidates, it will show a message and check
   584                     break
   666                     break
   585             else:
   667             else:
   586                 anc = self._repo.changelog.ancestor(self._node, n2)
   668                 anc = self._repo.changelog.ancestor(self._node, n2)
   587             if warn:
   669             if warn:
   588                 self._repo.ui.status(
   670                 self._repo.ui.status(
   589                     (_("note: using %s as ancestor of %s and %s\n") %
   671                     (
   590                      (short(anc), short(self._node), short(n2))) +
   672                         _("note: using %s as ancestor of %s and %s\n")
   591                     ''.join(_("      alternatively, use --config "
   673                         % (short(anc), short(self._node), short(n2))
   592                               "merge.preferancestor=%s\n") %
   674                     )
   593                             short(n) for n in sorted(cahs) if n != anc))
   675                     + ''.join(
       
   676                         _(
       
   677                             "      alternatively, use --config "
       
   678                             "merge.preferancestor=%s\n"
       
   679                         )
       
   680                         % short(n)
       
   681                         for n in sorted(cahs)
       
   682                         if n != anc
       
   683                     )
       
   684                 )
   594         return self._repo[anc]
   685         return self._repo[anc]
   595 
   686 
   596     def isancestorof(self, other):
   687     def isancestorof(self, other):
   597         """True if this changeset is an ancestor of other"""
   688         """True if this changeset is an ancestor of other"""
   598         return self._repo.changelog.isancestorrev(self._rev, other._rev)
   689         return self._repo.changelog.isancestorrev(self._rev, other._rev)
   602 
   693 
   603         # Wrap match.bad method to have message with nodeid
   694         # Wrap match.bad method to have message with nodeid
   604         def bad(fn, msg):
   695         def bad(fn, msg):
   605             # The manifest doesn't know about subrepos, so don't complain about
   696             # The manifest doesn't know about subrepos, so don't complain about
   606             # paths into valid subrepos.
   697             # paths into valid subrepos.
   607             if any(fn == s or fn.startswith(s + '/')
   698             if any(fn == s or fn.startswith(s + '/') for s in self.substate):
   608                    for s in self.substate):
       
   609                 return
   699                 return
   610             match.bad(fn, _('no such file in rev %s') % self)
   700             match.bad(fn, _('no such file in rev %s') % self)
   611 
   701 
   612         m = matchmod.badmatch(self._repo.narrowmatch(match), bad)
   702         m = matchmod.badmatch(self._repo.narrowmatch(match), bad)
   613         return self._manifest.walk(m)
   703         return self._manifest.walk(m)
   614 
   704 
   615     def matches(self, match):
   705     def matches(self, match):
   616         return self.walk(match)
   706         return self.walk(match)
       
   707 
   617 
   708 
   618 class basefilectx(object):
   709 class basefilectx(object):
   619     """A filecontext object represents the common logic for its children:
   710     """A filecontext object represents the common logic for its children:
   620     filectx: read-only access to a filerevision that is already present
   711     filectx: read-only access to a filerevision that is already present
   621              in the repo,
   712              in the repo,
   622     workingfilectx: a filecontext that represents files from the working
   713     workingfilectx: a filecontext that represents files from the working
   623                     directory,
   714                     directory,
   624     memfilectx: a filecontext that represents files in-memory,
   715     memfilectx: a filecontext that represents files in-memory,
   625     """
   716     """
       
   717 
   626     @propertycache
   718     @propertycache
   627     def _filelog(self):
   719     def _filelog(self):
   628         return self._repo.file(self._path)
   720         return self._repo.file(self._path)
   629 
   721 
   630     @propertycache
   722     @propertycache
   680         except AttributeError:
   772         except AttributeError:
   681             return id(self)
   773             return id(self)
   682 
   774 
   683     def __eq__(self, other):
   775     def __eq__(self, other):
   684         try:
   776         try:
   685             return (type(self) == type(other) and self._path == other._path
   777             return (
   686                     and self._filenode == other._filenode)
   778                 type(self) == type(other)
       
   779                 and self._path == other._path
       
   780                 and self._filenode == other._filenode
       
   781             )
   687         except AttributeError:
   782         except AttributeError:
   688             return False
   783             return False
   689 
   784 
   690     def __ne__(self, other):
   785     def __ne__(self, other):
   691         return not (self == other)
   786         return not (self == other)
   692 
   787 
   693     def filerev(self):
   788     def filerev(self):
   694         return self._filerev
   789         return self._filerev
       
   790 
   695     def filenode(self):
   791     def filenode(self):
   696         return self._filenode
   792         return self._filenode
       
   793 
   697     @propertycache
   794     @propertycache
   698     def _flags(self):
   795     def _flags(self):
   699         return self._changectx.flags(self._path)
   796         return self._changectx.flags(self._path)
       
   797 
   700     def flags(self):
   798     def flags(self):
   701         return self._flags
   799         return self._flags
       
   800 
   702     def filelog(self):
   801     def filelog(self):
   703         return self._filelog
   802         return self._filelog
       
   803 
   704     def rev(self):
   804     def rev(self):
   705         return self._changeid
   805         return self._changeid
       
   806 
   706     def linkrev(self):
   807     def linkrev(self):
   707         return self._filelog.linkrev(self._filerev)
   808         return self._filelog.linkrev(self._filerev)
       
   809 
   708     def node(self):
   810     def node(self):
   709         return self._changectx.node()
   811         return self._changectx.node()
       
   812 
   710     def hex(self):
   813     def hex(self):
   711         return self._changectx.hex()
   814         return self._changectx.hex()
       
   815 
   712     def user(self):
   816     def user(self):
   713         return self._changectx.user()
   817         return self._changectx.user()
       
   818 
   714     def date(self):
   819     def date(self):
   715         return self._changectx.date()
   820         return self._changectx.date()
       
   821 
   716     def files(self):
   822     def files(self):
   717         return self._changectx.files()
   823         return self._changectx.files()
       
   824 
   718     def description(self):
   825     def description(self):
   719         return self._changectx.description()
   826         return self._changectx.description()
       
   827 
   720     def branch(self):
   828     def branch(self):
   721         return self._changectx.branch()
   829         return self._changectx.branch()
       
   830 
   722     def extra(self):
   831     def extra(self):
   723         return self._changectx.extra()
   832         return self._changectx.extra()
       
   833 
   724     def phase(self):
   834     def phase(self):
   725         return self._changectx.phase()
   835         return self._changectx.phase()
       
   836 
   726     def phasestr(self):
   837     def phasestr(self):
   727         return self._changectx.phasestr()
   838         return self._changectx.phasestr()
       
   839 
   728     def obsolete(self):
   840     def obsolete(self):
   729         return self._changectx.obsolete()
   841         return self._changectx.obsolete()
       
   842 
   730     def instabilities(self):
   843     def instabilities(self):
   731         return self._changectx.instabilities()
   844         return self._changectx.instabilities()
       
   845 
   732     def manifest(self):
   846     def manifest(self):
   733         return self._changectx.manifest()
   847         return self._changectx.manifest()
       
   848 
   734     def changectx(self):
   849     def changectx(self):
   735         return self._changectx
   850         return self._changectx
       
   851 
   736     def renamed(self):
   852     def renamed(self):
   737         return self._copied
   853         return self._copied
       
   854 
   738     def copysource(self):
   855     def copysource(self):
   739         return self._copied and self._copied[0]
   856         return self._copied and self._copied[0]
       
   857 
   740     def repo(self):
   858     def repo(self):
   741         return self._repo
   859         return self._repo
       
   860 
   742     def size(self):
   861     def size(self):
   743         return len(self.data())
   862         return len(self.data())
   744 
   863 
   745     def path(self):
   864     def path(self):
   746         return self._path
   865         return self._path
   748     def isbinary(self):
   867     def isbinary(self):
   749         try:
   868         try:
   750             return stringutil.binary(self.data())
   869             return stringutil.binary(self.data())
   751         except IOError:
   870         except IOError:
   752             return False
   871             return False
       
   872 
   753     def isexec(self):
   873     def isexec(self):
   754         return 'x' in self.flags()
   874         return 'x' in self.flags()
       
   875 
   755     def islink(self):
   876     def islink(self):
   756         return 'l' in self.flags()
   877         return 'l' in self.flags()
   757 
   878 
   758     def isabsent(self):
   879     def isabsent(self):
   759         """whether this filectx represents a file not in self._changectx
   880         """whether this filectx represents a file not in self._changectx
   761         This is mainly for merge code to detect change/delete conflicts. This is
   882         This is mainly for merge code to detect change/delete conflicts. This is
   762         expected to be True for all subclasses of basectx."""
   883         expected to be True for all subclasses of basectx."""
   763         return False
   884         return False
   764 
   885 
   765     _customcmp = False
   886     _customcmp = False
       
   887 
   766     def cmp(self, fctx):
   888     def cmp(self, fctx):
   767         """compare with other file context
   889         """compare with other file context
   768 
   890 
   769         returns True if different than fctx.
   891         returns True if different than fctx.
   770         """
   892         """
   771         if fctx._customcmp:
   893         if fctx._customcmp:
   772             return fctx.cmp(self)
   894             return fctx.cmp(self)
   773 
   895 
   774         if self._filenode is None:
   896         if self._filenode is None:
   775             raise error.ProgrammingError(
   897             raise error.ProgrammingError(
   776                 'filectx.cmp() must be reimplemented if not backed by revlog')
   898                 'filectx.cmp() must be reimplemented if not backed by revlog'
       
   899             )
   777 
   900 
   778         if fctx._filenode is None:
   901         if fctx._filenode is None:
   779             if self._repo._encodefilterpats:
   902             if self._repo._encodefilterpats:
   780                 # can't rely on size() because wdir content may be decoded
   903                 # can't rely on size() because wdir content may be decoded
   781                 return self._filelog.cmp(self._filenode, fctx.data())
   904                 return self._filelog.cmp(self._filenode, fctx.data())
   816         memberanc = getattr(self, '_ancestrycontext', None)
   939         memberanc = getattr(self, '_ancestrycontext', None)
   817         iteranc = None
   940         iteranc = None
   818         if srcrev is None:
   941         if srcrev is None:
   819             # wctx case, used by workingfilectx during mergecopy
   942             # wctx case, used by workingfilectx during mergecopy
   820             revs = [p.rev() for p in self._repo[None].parents()]
   943             revs = [p.rev() for p in self._repo[None].parents()]
   821             inclusive = True # we skipped the real (revless) source
   944             inclusive = True  # we skipped the real (revless) source
   822         else:
   945         else:
   823             revs = [srcrev]
   946             revs = [srcrev]
   824         if memberanc is None:
   947         if memberanc is None:
   825             memberanc = iteranc = cl.ancestors(revs, lkr,
   948             memberanc = iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
   826                                                inclusive=inclusive)
       
   827         # check if this linkrev is an ancestor of srcrev
   949         # check if this linkrev is an ancestor of srcrev
   828         if lkr not in memberanc:
   950         if lkr not in memberanc:
   829             if iteranc is None:
   951             if iteranc is None:
   830                 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
   952                 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive)
   831             fnode = self._filenode
   953             fnode = self._filenode
   832             path = self._path
   954             path = self._path
   833             for a in iteranc:
   955             for a in iteranc:
   834                 if stoprev is not None and a < stoprev:
   956                 if stoprev is not None and a < stoprev:
   835                     return None
   957                     return None
   836                 ac = cl.read(a) # get changeset data (we avoid object creation)
   958                 ac = cl.read(a)  # get changeset data (we avoid object creation)
   837                 if path in ac[3]: # checking the 'files' field.
   959                 if path in ac[3]:  # checking the 'files' field.
   838                     # The file has been touched, check if the content is
   960                     # The file has been touched, check if the content is
   839                     # similar to the one we search for.
   961                     # similar to the one we search for.
   840                     if fnode == mfl[ac[0]].readfast().get(path):
   962                     if fnode == mfl[ac[0]].readfast().get(path):
   841                         return a
   963                         return a
   842             # In theory, we should never get out of that loop without a result.
   964             # In theory, we should never get out of that loop without a result.
   983         if getattr(base, '_ancestrycontext', None) is None:
  1105         if getattr(base, '_ancestrycontext', None) is None:
   984             cl = self._repo.changelog
  1106             cl = self._repo.changelog
   985             if base.rev() is None:
  1107             if base.rev() is None:
   986                 # wctx is not inclusive, but works because _ancestrycontext
  1108                 # wctx is not inclusive, but works because _ancestrycontext
   987                 # is used to test filelog revisions
  1109                 # is used to test filelog revisions
   988                 ac = cl.ancestors([p.rev() for p in base.parents()],
  1110                 ac = cl.ancestors(
   989                                   inclusive=True)
  1111                     [p.rev() for p in base.parents()], inclusive=True
       
  1112                 )
   990             else:
  1113             else:
   991                 ac = cl.ancestors([base.rev()], inclusive=True)
  1114                 ac = cl.ancestors([base.rev()], inclusive=True)
   992             base._ancestrycontext = ac
  1115             base._ancestrycontext = ac
   993 
  1116 
   994         return dagop.annotate(base, parents, skiprevs=skiprevs,
  1117         return dagop.annotate(
   995                               diffopts=diffopts)
  1118             base, parents, skiprevs=skiprevs, diffopts=diffopts
       
  1119         )
   996 
  1120 
   997     def ancestors(self, followfirst=False):
  1121     def ancestors(self, followfirst=False):
   998         visit = {}
  1122         visit = {}
   999         c = self
  1123         c = self
  1000         if followfirst:
  1124         if followfirst:
  1015 
  1139 
  1016         This is often equivalent to how the data would be expressed on disk.
  1140         This is often equivalent to how the data would be expressed on disk.
  1017         """
  1141         """
  1018         return self._repo.wwritedata(self.path(), self.data())
  1142         return self._repo.wwritedata(self.path(), self.data())
  1019 
  1143 
       
  1144 
  1020 class filectx(basefilectx):
  1145 class filectx(basefilectx):
  1021     """A filecontext object makes access to data related to a particular
  1146     """A filecontext object makes access to data related to a particular
  1022        filerevision convenient."""
  1147        filerevision convenient."""
  1023     def __init__(self, repo, path, changeid=None, fileid=None,
  1148 
  1024                  filelog=None, changectx=None):
  1149     def __init__(
       
  1150         self,
       
  1151         repo,
       
  1152         path,
       
  1153         changeid=None,
       
  1154         fileid=None,
       
  1155         filelog=None,
       
  1156         changectx=None,
       
  1157     ):
  1025         """changeid must be a revision number, if specified.
  1158         """changeid must be a revision number, if specified.
  1026            fileid can be a file revision or node."""
  1159            fileid can be a file revision or node."""
  1027         self._repo = repo
  1160         self._repo = repo
  1028         self._path = path
  1161         self._path = path
  1029 
  1162 
  1030         assert (changeid is not None
  1163         assert (
  1031                 or fileid is not None
  1164             changeid is not None or fileid is not None or changectx is not None
  1032                 or changectx is not None), (
  1165         ), "bad args: changeid=%r, fileid=%r, changectx=%r" % (
  1033                     "bad args: changeid=%r, fileid=%r, changectx=%r"
  1166             changeid,
  1034                     % (changeid, fileid, changectx))
  1167             fileid,
       
  1168             changectx,
       
  1169         )
  1035 
  1170 
  1036         if filelog is not None:
  1171         if filelog is not None:
  1037             self._filelog = filelog
  1172             self._filelog = filelog
  1038 
  1173 
  1039         if changeid is not None:
  1174         if changeid is not None:
  1067             return self._repo.unfiltered()[self._changeid]
  1202             return self._repo.unfiltered()[self._changeid]
  1068 
  1203 
  1069     def filectx(self, fileid, changeid=None):
  1204     def filectx(self, fileid, changeid=None):
  1070         '''opens an arbitrary revision of the file without
  1205         '''opens an arbitrary revision of the file without
  1071         opening a new filelog'''
  1206         opening a new filelog'''
  1072         return filectx(self._repo, self._path, fileid=fileid,
  1207         return filectx(
  1073                        filelog=self._filelog, changeid=changeid)
  1208             self._repo,
       
  1209             self._path,
       
  1210             fileid=fileid,
       
  1211             filelog=self._filelog,
       
  1212             changeid=changeid,
       
  1213         )
  1074 
  1214 
  1075     def rawdata(self):
  1215     def rawdata(self):
  1076         return self._filelog.rawdata(self._filenode)
  1216         return self._filelog.rawdata(self._filenode)
  1077 
  1217 
  1078     def rawflags(self):
  1218     def rawflags(self):
  1083         try:
  1223         try:
  1084             return self._filelog.read(self._filenode)
  1224             return self._filelog.read(self._filenode)
  1085         except error.CensoredNodeError:
  1225         except error.CensoredNodeError:
  1086             if self._repo.ui.config("censor", "policy") == "ignore":
  1226             if self._repo.ui.config("censor", "policy") == "ignore":
  1087                 return ""
  1227                 return ""
  1088             raise error.Abort(_("censored node: %s") % short(self._filenode),
  1228             raise error.Abort(
  1089                              hint=_("set censor.policy to ignore errors"))
  1229                 _("censored node: %s") % short(self._filenode),
       
  1230                 hint=_("set censor.policy to ignore errors"),
       
  1231             )
  1090 
  1232 
  1091     def size(self):
  1233     def size(self):
  1092         return self._filelog.size(self._filerev)
  1234         return self._filelog.size(self._filerev)
  1093 
  1235 
  1094     @propertycache
  1236     @propertycache
  1118         return renamed
  1260         return renamed
  1119 
  1261 
  1120     def children(self):
  1262     def children(self):
  1121         # hard for renames
  1263         # hard for renames
  1122         c = self._filelog.children(self._filenode)
  1264         c = self._filelog.children(self._filenode)
  1123         return [filectx(self._repo, self._path, fileid=x,
  1265         return [
  1124                         filelog=self._filelog) for x in c]
  1266             filectx(self._repo, self._path, fileid=x, filelog=self._filelog)
       
  1267             for x in c
       
  1268         ]
       
  1269 
  1125 
  1270 
  1126 class committablectx(basectx):
  1271 class committablectx(basectx):
  1127     """A committablectx object provides common functionality for a context that
  1272     """A committablectx object provides common functionality for a context that
  1128     wants the ability to commit, e.g. workingctx or memctx."""
  1273     wants the ability to commit, e.g. workingctx or memctx."""
  1129     def __init__(self, repo, text="", user=None, date=None, extra=None,
  1274 
  1130                  changes=None, branch=None):
  1275     def __init__(
       
  1276         self,
       
  1277         repo,
       
  1278         text="",
       
  1279         user=None,
       
  1280         date=None,
       
  1281         extra=None,
       
  1282         changes=None,
       
  1283         branch=None,
       
  1284     ):
  1131         super(committablectx, self).__init__(repo)
  1285         super(committablectx, self).__init__(repo)
  1132         self._rev = None
  1286         self._rev = None
  1133         self._node = None
  1287         self._node = None
  1134         self._text = text
  1288         self._text = text
  1135         if date:
  1289         if date:
  1176     def subrev(self, subpath):
  1330     def subrev(self, subpath):
  1177         return None
  1331         return None
  1178 
  1332 
  1179     def manifestnode(self):
  1333     def manifestnode(self):
  1180         return None
  1334         return None
       
  1335 
  1181     def user(self):
  1336     def user(self):
  1182         return self._user or self._repo.ui.username()
  1337         return self._user or self._repo.ui.username()
       
  1338 
  1183     def date(self):
  1339     def date(self):
  1184         return self._date
  1340         return self._date
       
  1341 
  1185     def description(self):
  1342     def description(self):
  1186         return self._text
  1343         return self._text
       
  1344 
  1187     def files(self):
  1345     def files(self):
  1188         return sorted(self._status.modified + self._status.added +
  1346         return sorted(
  1189                       self._status.removed)
  1347             self._status.modified + self._status.added + self._status.removed
       
  1348         )
       
  1349 
  1190     def modified(self):
  1350     def modified(self):
  1191         return self._status.modified
  1351         return self._status.modified
       
  1352 
  1192     def added(self):
  1353     def added(self):
  1193         return self._status.added
  1354         return self._status.added
       
  1355 
  1194     def removed(self):
  1356     def removed(self):
  1195         return self._status.removed
  1357         return self._status.removed
       
  1358 
  1196     def deleted(self):
  1359     def deleted(self):
  1197         return self._status.deleted
  1360         return self._status.deleted
       
  1361 
  1198     filesmodified = modified
  1362     filesmodified = modified
  1199     filesadded = added
  1363     filesadded = added
  1200     filesremoved = removed
  1364     filesremoved = removed
  1201 
  1365 
  1202     def branch(self):
  1366     def branch(self):
  1203         return encoding.tolocal(self._extra['branch'])
  1367         return encoding.tolocal(self._extra['branch'])
       
  1368 
  1204     def closesbranch(self):
  1369     def closesbranch(self):
  1205         return 'close' in self._extra
  1370         return 'close' in self._extra
       
  1371 
  1206     def extra(self):
  1372     def extra(self):
  1207         return self._extra
  1373         return self._extra
  1208 
  1374 
  1209     def isinmemory(self):
  1375     def isinmemory(self):
  1210         return False
  1376         return False
  1217         for p in self.parents():
  1383         for p in self.parents():
  1218             b.extend(p.bookmarks())
  1384             b.extend(p.bookmarks())
  1219         return b
  1385         return b
  1220 
  1386 
  1221     def phase(self):
  1387     def phase(self):
  1222         phase = phases.draft # default phase to draft
  1388         phase = phases.draft  # default phase to draft
  1223         for p in self.parents():
  1389         for p in self.parents():
  1224             phase = max(phase, p.phase())
  1390             phase = max(phase, p.phase())
  1225         return phase
  1391         return phase
  1226 
  1392 
  1227     def hidden(self):
  1393     def hidden(self):
  1230     def children(self):
  1396     def children(self):
  1231         return []
  1397         return []
  1232 
  1398 
  1233     def ancestor(self, c2):
  1399     def ancestor(self, c2):
  1234         """return the "best" ancestor context of self and c2"""
  1400         """return the "best" ancestor context of self and c2"""
  1235         return self._parents[0].ancestor(c2) # punt on two parents for now
  1401         return self._parents[0].ancestor(c2)  # punt on two parents for now
  1236 
  1402 
  1237     def ancestors(self):
  1403     def ancestors(self):
  1238         for p in self._parents:
  1404         for p in self._parents:
  1239             yield p
  1405             yield p
  1240         for a in self._repo.changelog.ancestors(
  1406         for a in self._repo.changelog.ancestors(
  1241             [p.rev() for p in self._parents]):
  1407             [p.rev() for p in self._parents]
       
  1408         ):
  1242             yield self._repo[a]
  1409             yield self._repo[a]
  1243 
  1410 
  1244     def markcommitted(self, node):
  1411     def markcommitted(self, node):
  1245         """Perform post-commit cleanup necessary after committing this ctx
  1412         """Perform post-commit cleanup necessary after committing this ctx
  1246 
  1413 
  1251 
  1418 
  1252         """
  1419         """
  1253 
  1420 
  1254     def dirty(self, missing=False, merge=True, branch=True):
  1421     def dirty(self, missing=False, merge=True, branch=True):
  1255         return False
  1422         return False
       
  1423 
  1256 
  1424 
  1257 class workingctx(committablectx):
  1425 class workingctx(committablectx):
  1258     """A workingctx object makes access to data related to
  1426     """A workingctx object makes access to data related to
  1259     the current working directory convenient.
  1427     the current working directory convenient.
  1260     date - any valid date string or (unixtime, offset), or None.
  1428     date - any valid date string or (unixtime, offset), or None.
  1261     user - username string, or None.
  1429     user - username string, or None.
  1262     extra - a dictionary of extra values, or None.
  1430     extra - a dictionary of extra values, or None.
  1263     changes - a list of file lists as returned by localrepo.status()
  1431     changes - a list of file lists as returned by localrepo.status()
  1264                or None to use the repository status.
  1432                or None to use the repository status.
  1265     """
  1433     """
  1266     def __init__(self, repo, text="", user=None, date=None, extra=None,
  1434 
  1267                  changes=None):
  1435     def __init__(
       
  1436         self, repo, text="", user=None, date=None, extra=None, changes=None
       
  1437     ):
  1268         branch = None
  1438         branch = None
  1269         if not extra or 'branch' not in extra:
  1439         if not extra or 'branch' not in extra:
  1270             try:
  1440             try:
  1271                 branch = repo.dirstate.branch()
  1441                 branch = repo.dirstate.branch()
  1272             except UnicodeDecodeError:
  1442             except UnicodeDecodeError:
  1273                 raise error.Abort(_('branch name not in UTF-8!'))
  1443                 raise error.Abort(_('branch name not in UTF-8!'))
  1274         super(workingctx, self).__init__(repo, text, user, date, extra, changes,
  1444         super(workingctx, self).__init__(
  1275                                          branch=branch)
  1445             repo, text, user, date, extra, changes, branch=branch
       
  1446         )
  1276 
  1447 
  1277     def __iter__(self):
  1448     def __iter__(self):
  1278         d = self._repo.dirstate
  1449         d = self._repo.dirstate
  1279         for f in d:
  1450         for f in d:
  1280             if d[f] != 'r':
  1451             if d[f] != 'r':
  1307         copiesget = self._repo.dirstate.copies().get
  1478         copiesget = self._repo.dirstate.copies().get
  1308         parents = self.parents()
  1479         parents = self.parents()
  1309         if len(parents) < 2:
  1480         if len(parents) < 2:
  1310             # when we have one parent, it's easy: copy from parent
  1481             # when we have one parent, it's easy: copy from parent
  1311             man = parents[0].manifest()
  1482             man = parents[0].manifest()
       
  1483 
  1312             def func(f):
  1484             def func(f):
  1313                 f = copiesget(f, f)
  1485                 f = copiesget(f, f)
  1314                 return man.flags(f)
  1486                 return man.flags(f)
       
  1487 
  1315         else:
  1488         else:
  1316             # merges are tricky: we try to reconstruct the unstored
  1489             # merges are tricky: we try to reconstruct the unstored
  1317             # result from the merge (issue1802)
  1490             # result from the merge (issue1802)
  1318             p1, p2 = parents
  1491             p1, p2 = parents
  1319             pa = p1.ancestor(p2)
  1492             pa = p1.ancestor(p2)
  1320             m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
  1493             m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
  1321 
  1494 
  1322             def func(f):
  1495             def func(f):
  1323                 f = copiesget(f, f) # may be wrong for merges with copies
  1496                 f = copiesget(f, f)  # may be wrong for merges with copies
  1324                 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
  1497                 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f)
  1325                 if fl1 == fl2:
  1498                 if fl1 == fl2:
  1326                     return fl1
  1499                     return fl1
  1327                 if fl1 == fla:
  1500                 if fl1 == fla:
  1328                     return fl2
  1501                     return fl2
  1329                 if fl2 == fla:
  1502                 if fl2 == fla:
  1330                     return fl1
  1503                     return fl1
  1331                 return '' # punt for conflicts
  1504                 return ''  # punt for conflicts
  1332 
  1505 
  1333         return func
  1506         return func
  1334 
  1507 
  1335     @propertycache
  1508     @propertycache
  1336     def _flagfunc(self):
  1509     def _flagfunc(self):
  1348         except OSError:
  1521         except OSError:
  1349             return ''
  1522             return ''
  1350 
  1523 
  1351     def filectx(self, path, filelog=None):
  1524     def filectx(self, path, filelog=None):
  1352         """get a file context from the working directory"""
  1525         """get a file context from the working directory"""
  1353         return workingfilectx(self._repo, path, workingctx=self,
  1526         return workingfilectx(
  1354                               filelog=filelog)
  1527             self._repo, path, workingctx=self, filelog=filelog
       
  1528         )
  1355 
  1529 
  1356     def dirty(self, missing=False, merge=True, branch=True):
  1530     def dirty(self, missing=False, merge=True, branch=True):
  1357         "check whether a working directory is modified"
  1531         "check whether a working directory is modified"
  1358         # check subrepos first
  1532         # check subrepos first
  1359         for s in sorted(self.substate):
  1533         for s in sorted(self.substate):
  1360             if self.sub(s).dirty(missing=missing):
  1534             if self.sub(s).dirty(missing=missing):
  1361                 return True
  1535                 return True
  1362         # check current working dir
  1536         # check current working dir
  1363         return ((merge and self.p2()) or
  1537         return (
  1364                 (branch and self.branch() != self.p1().branch()) or
  1538             (merge and self.p2())
  1365                 self.modified() or self.added() or self.removed() or
  1539             or (branch and self.branch() != self.p1().branch())
  1366                 (missing and self.deleted()))
  1540             or self.modified()
       
  1541             or self.added()
       
  1542             or self.removed()
       
  1543             or (missing and self.deleted())
       
  1544         )
  1367 
  1545 
  1368     def add(self, list, prefix=""):
  1546     def add(self, list, prefix=""):
  1369         with self._repo.wlock():
  1547         with self._repo.wlock():
  1370             ui, ds = self._repo.ui, self._repo.dirstate
  1548             ui, ds = self._repo.ui, self._repo.dirstate
  1371             uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
  1549             uipath = lambda f: ds.pathto(pathutil.join(prefix, f))
  1382                     ui.warn(_("%s does not exist!\n") % uipath(f))
  1560                     ui.warn(_("%s does not exist!\n") % uipath(f))
  1383                     rejected.append(f)
  1561                     rejected.append(f)
  1384                     continue
  1562                     continue
  1385                 limit = ui.configbytes('ui', 'large-file-limit')
  1563                 limit = ui.configbytes('ui', 'large-file-limit')
  1386                 if limit != 0 and st.st_size > limit:
  1564                 if limit != 0 and st.st_size > limit:
  1387                     ui.warn(_("%s: up to %d MB of RAM may be required "
  1565                     ui.warn(
  1388                               "to manage this file\n"
  1566                         _(
  1389                               "(use 'hg revert %s' to cancel the "
  1567                             "%s: up to %d MB of RAM may be required "
  1390                               "pending addition)\n")
  1568                             "to manage this file\n"
  1391                             % (f, 3 * st.st_size // 1000000, uipath(f)))
  1569                             "(use 'hg revert %s' to cancel the "
       
  1570                             "pending addition)\n"
       
  1571                         )
       
  1572                         % (f, 3 * st.st_size // 1000000, uipath(f))
       
  1573                     )
  1392                 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
  1574                 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
  1393                     ui.warn(_("%s not added: only files and symlinks "
  1575                     ui.warn(
  1394                               "supported currently\n") % uipath(f))
  1576                         _(
       
  1577                             "%s not added: only files and symlinks "
       
  1578                             "supported currently\n"
       
  1579                         )
       
  1580                         % uipath(f)
       
  1581                     )
  1395                     rejected.append(f)
  1582                     rejected.append(f)
  1396                 elif ds[f] in 'amn':
  1583                 elif ds[f] in 'amn':
  1397                     ui.warn(_("%s already tracked!\n") % uipath(f))
  1584                     ui.warn(_("%s already tracked!\n") % uipath(f))
  1398                 elif ds[f] == 'r':
  1585                 elif ds[f] == 'r':
  1399                     ds.normallookup(f)
  1586                     ds.normallookup(f)
  1420         try:
  1607         try:
  1421             st = self._repo.wvfs.lstat(dest)
  1608             st = self._repo.wvfs.lstat(dest)
  1422         except OSError as err:
  1609         except OSError as err:
  1423             if err.errno != errno.ENOENT:
  1610             if err.errno != errno.ENOENT:
  1424                 raise
  1611                 raise
  1425             self._repo.ui.warn(_("%s does not exist!\n")
  1612             self._repo.ui.warn(
  1426                                % self._repo.dirstate.pathto(dest))
  1613                 _("%s does not exist!\n") % self._repo.dirstate.pathto(dest)
       
  1614             )
  1427             return
  1615             return
  1428         if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
  1616         if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
  1429             self._repo.ui.warn(_("copy failed: %s is not a file or a "
  1617             self._repo.ui.warn(
  1430                                  "symbolic link\n")
  1618                 _("copy failed: %s is not a file or a " "symbolic link\n")
  1431                                % self._repo.dirstate.pathto(dest))
  1619                 % self._repo.dirstate.pathto(dest)
       
  1620             )
  1432         else:
  1621         else:
  1433             with self._repo.wlock():
  1622             with self._repo.wlock():
  1434                 ds = self._repo.dirstate
  1623                 ds = self._repo.dirstate
  1435                 if ds[dest] in '?':
  1624                 if ds[dest] in '?':
  1436                     ds.add(dest)
  1625                     ds.add(dest)
  1437                 elif ds[dest] in 'r':
  1626                 elif ds[dest] in 'r':
  1438                     ds.normallookup(dest)
  1627                     ds.normallookup(dest)
  1439                 ds.copy(source, dest)
  1628                 ds.copy(source, dest)
  1440 
  1629 
  1441     def match(self, pats=None, include=None, exclude=None, default='glob',
  1630     def match(
  1442               listsubrepos=False, badfn=None):
  1631         self,
       
  1632         pats=None,
       
  1633         include=None,
       
  1634         exclude=None,
       
  1635         default='glob',
       
  1636         listsubrepos=False,
       
  1637         badfn=None,
       
  1638     ):
  1443         r = self._repo
  1639         r = self._repo
  1444 
  1640 
  1445         # Only a case insensitive filesystem needs magic to translate user input
  1641         # Only a case insensitive filesystem needs magic to translate user input
  1446         # to actual case in the filesystem.
  1642         # to actual case in the filesystem.
  1447         icasefs = not util.fscasesensitive(r.root)
  1643         icasefs = not util.fscasesensitive(r.root)
  1448         return matchmod.match(r.root, r.getcwd(), pats, include, exclude,
  1644         return matchmod.match(
  1449                               default, auditor=r.auditor, ctx=self,
  1645             r.root,
  1450                               listsubrepos=listsubrepos, badfn=badfn,
  1646             r.getcwd(),
  1451                               icasefs=icasefs)
  1647             pats,
       
  1648             include,
       
  1649             exclude,
       
  1650             default,
       
  1651             auditor=r.auditor,
       
  1652             ctx=self,
       
  1653             listsubrepos=listsubrepos,
       
  1654             badfn=badfn,
       
  1655             icasefs=icasefs,
       
  1656         )
  1452 
  1657 
  1453     def _filtersuspectsymlink(self, files):
  1658     def _filtersuspectsymlink(self, files):
  1454         if not files or self._repo.dirstate._checklink:
  1659         if not files or self._repo.dirstate._checklink:
  1455             return files
  1660             return files
  1456 
  1661 
  1460         # symlink
  1665         # symlink
  1461         sane = []
  1666         sane = []
  1462         for f in files:
  1667         for f in files:
  1463             if self.flags(f) == 'l':
  1668             if self.flags(f) == 'l':
  1464                 d = self[f].data()
  1669                 d = self[f].data()
  1465                 if (d == '' or len(d) >= 1024 or '\n' in d
  1670                 if (
  1466                     or stringutil.binary(d)):
  1671                     d == ''
  1467                     self._repo.ui.debug('ignoring suspect symlink placeholder'
  1672                     or len(d) >= 1024
  1468                                         ' "%s"\n' % f)
  1673                     or '\n' in d
       
  1674                     or stringutil.binary(d)
       
  1675                 ):
       
  1676                     self._repo.ui.debug(
       
  1677                         'ignoring suspect symlink placeholder' ' "%s"\n' % f
       
  1678                     )
  1469                     continue
  1679                     continue
  1470             sane.append(f)
  1680             sane.append(f)
  1471         return sane
  1681         return sane
  1472 
  1682 
  1473     def _checklookup(self, files):
  1683     def _checklookup(self, files):
  1482         # do a full compare of any files that might have changed
  1692         # do a full compare of any files that might have changed
  1483         for f in sorted(files):
  1693         for f in sorted(files):
  1484             try:
  1694             try:
  1485                 # This will return True for a file that got replaced by a
  1695                 # This will return True for a file that got replaced by a
  1486                 # directory in the interim, but fixing that is pretty hard.
  1696                 # directory in the interim, but fixing that is pretty hard.
  1487                 if (f not in pctx or self.flags(f) != pctx.flags(f)
  1697                 if (
  1488                     or pctx[f].cmp(self[f])):
  1698                     f not in pctx
       
  1699                     or self.flags(f) != pctx.flags(f)
       
  1700                     or pctx[f].cmp(self[f])
       
  1701                 ):
  1489                     modified.append(f)
  1702                     modified.append(f)
  1490                 else:
  1703                 else:
  1491                     fixup.append(f)
  1704                     fixup.append(f)
  1492             except (IOError, OSError):
  1705             except (IOError, OSError):
  1493                 # A file become inaccessible in between? Mark it as deleted,
  1706                 # A file become inaccessible in between? Mark it as deleted,
  1530                     else:
  1743                     else:
  1531                         # in this case, writing changes out breaks
  1744                         # in this case, writing changes out breaks
  1532                         # consistency, because .hg/dirstate was
  1745                         # consistency, because .hg/dirstate was
  1533                         # already changed simultaneously after last
  1746                         # already changed simultaneously after last
  1534                         # caching (see also issue5584 for detail)
  1747                         # caching (see also issue5584 for detail)
  1535                         self._repo.ui.debug('skip updating dirstate: '
  1748                         self._repo.ui.debug(
  1536                                             'identity mismatch\n')
  1749                             'skip updating dirstate: ' 'identity mismatch\n'
       
  1750                         )
  1537             except error.LockError:
  1751             except error.LockError:
  1538                 pass
  1752                 pass
  1539             finally:
  1753             finally:
  1540                 # Even if the wlock couldn't be grabbed, clear out the list.
  1754                 # Even if the wlock couldn't be grabbed, clear out the list.
  1541                 self._repo.clearpostdsstatus()
  1755                 self._repo.clearpostdsstatus()
  1543     def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
  1757     def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
  1544         '''Gets the status from the dirstate -- internal use only.'''
  1758         '''Gets the status from the dirstate -- internal use only.'''
  1545         subrepos = []
  1759         subrepos = []
  1546         if '.hgsub' in self:
  1760         if '.hgsub' in self:
  1547             subrepos = sorted(self.substate)
  1761             subrepos = sorted(self.substate)
  1548         cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored,
  1762         cmp, s = self._repo.dirstate.status(
  1549                                             clean=clean, unknown=unknown)
  1763             match, subrepos, ignored=ignored, clean=clean, unknown=unknown
       
  1764         )
  1550 
  1765 
  1551         # check for any possibly clean files
  1766         # check for any possibly clean files
  1552         fixup = []
  1767         fixup = []
  1553         if cmp:
  1768         if cmp:
  1554             modified2, deleted2, fixup = self._checklookup(cmp)
  1769             modified2, deleted2, fixup = self._checklookup(cmp)
  1562 
  1777 
  1563         if match.always():
  1778         if match.always():
  1564             # cache for performance
  1779             # cache for performance
  1565             if s.unknown or s.ignored or s.clean:
  1780             if s.unknown or s.ignored or s.clean:
  1566                 # "_status" is cached with list*=False in the normal route
  1781                 # "_status" is cached with list*=False in the normal route
  1567                 self._status = scmutil.status(s.modified, s.added, s.removed,
  1782                 self._status = scmutil.status(
  1568                                               s.deleted, [], [], [])
  1783                     s.modified, s.added, s.removed, s.deleted, [], [], []
       
  1784                 )
  1569             else:
  1785             else:
  1570                 self._status = s
  1786                 self._status = s
  1571 
  1787 
  1572         return s
  1788         return s
  1573 
  1789 
  1605         parents = self.parents()
  1821         parents = self.parents()
  1606 
  1822 
  1607         man = parents[0].manifest().copy()
  1823         man = parents[0].manifest().copy()
  1608 
  1824 
  1609         ff = self._flagfunc
  1825         ff = self._flagfunc
  1610         for i, l in ((addednodeid, status.added),
  1826         for i, l in (
  1611                      (modifiednodeid, status.modified)):
  1827             (addednodeid, status.added),
       
  1828             (modifiednodeid, status.modified),
       
  1829         ):
  1612             for f in l:
  1830             for f in l:
  1613                 man[f] = i
  1831                 man[f] = i
  1614                 try:
  1832                 try:
  1615                     man.setflag(f, ff(f))
  1833                     man.setflag(f, ff(f))
  1616                 except OSError:
  1834                 except OSError:
  1620             if f in man:
  1838             if f in man:
  1621                 del man[f]
  1839                 del man[f]
  1622 
  1840 
  1623         return man
  1841         return man
  1624 
  1842 
  1625     def _buildstatus(self, other, s, match, listignored, listclean,
  1843     def _buildstatus(
  1626                      listunknown):
  1844         self, other, s, match, listignored, listclean, listunknown
       
  1845     ):
  1627         """build a status with respect to another context
  1846         """build a status with respect to another context
  1628 
  1847 
  1629         This includes logic for maintaining the fast path of status when
  1848         This includes logic for maintaining the fast path of status when
  1630         comparing the working directory against its parent, which is to skip
  1849         comparing the working directory against its parent, which is to skip
  1631         building a new manifest if self (working directory) is not comparing
  1850         building a new manifest if self (working directory) is not comparing
  1635         # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
  1854         # Filter out symlinks that, in the case of FAT32 and NTFS filesystems,
  1636         # might have accidentally ended up with the entire contents of the file
  1855         # might have accidentally ended up with the entire contents of the file
  1637         # they are supposed to be linking to.
  1856         # they are supposed to be linking to.
  1638         s.modified[:] = self._filtersuspectsymlink(s.modified)
  1857         s.modified[:] = self._filtersuspectsymlink(s.modified)
  1639         if other != self._repo['.']:
  1858         if other != self._repo['.']:
  1640             s = super(workingctx, self)._buildstatus(other, s, match,
  1859             s = super(workingctx, self)._buildstatus(
  1641                                                      listignored, listclean,
  1860                 other, s, match, listignored, listclean, listunknown
  1642                                                      listunknown)
  1861             )
  1643         return s
  1862         return s
  1644 
  1863 
  1645     def _matchstatus(self, other, match):
  1864     def _matchstatus(self, other, match):
  1646         """override the match method with a filter for directory patterns
  1865         """override the match method with a filter for directory patterns
  1647 
  1866 
  1651 
  1870 
  1652         If we aren't comparing against the working directory's parent, then we
  1871         If we aren't comparing against the working directory's parent, then we
  1653         just use the default match object sent to us.
  1872         just use the default match object sent to us.
  1654         """
  1873         """
  1655         if other != self._repo['.']:
  1874         if other != self._repo['.']:
       
  1875 
  1656             def bad(f, msg):
  1876             def bad(f, msg):
  1657                 # 'f' may be a directory pattern from 'match.files()',
  1877                 # 'f' may be a directory pattern from 'match.files()',
  1658                 # so 'f not in ctx1' is not enough
  1878                 # so 'f not in ctx1' is not enough
  1659                 if f not in other and not other.hasdir(f):
  1879                 if f not in other and not other.hasdir(f):
  1660                     self._repo.ui.warn('%s: %s\n' %
  1880                     self._repo.ui.warn(
  1661                                        (self._repo.dirstate.pathto(f), msg))
  1881                         '%s: %s\n' % (self._repo.dirstate.pathto(f), msg)
       
  1882                     )
       
  1883 
  1662             match.bad = bad
  1884             match.bad = bad
  1663         return match
  1885         return match
  1664 
  1886 
  1665     def walk(self, match):
  1887     def walk(self, match):
  1666         '''Generates matching file names.'''
  1888         '''Generates matching file names.'''
  1667         return sorted(self._repo.dirstate.walk(self._repo.narrowmatch(match),
  1889         return sorted(
  1668                                                subrepos=sorted(self.substate),
  1890             self._repo.dirstate.walk(
  1669                                                unknown=True, ignored=False))
  1891                 self._repo.narrowmatch(match),
       
  1892                 subrepos=sorted(self.substate),
       
  1893                 unknown=True,
       
  1894                 ignored=False,
       
  1895             )
       
  1896         )
  1670 
  1897 
  1671     def matches(self, match):
  1898     def matches(self, match):
  1672         match = self._repo.narrowmatch(match)
  1899         match = self._repo.narrowmatch(match)
  1673         ds = self._repo.dirstate
  1900         ds = self._repo.dirstate
  1674         return sorted(f for f in ds.matches(match) if ds[f] != 'r')
  1901         return sorted(f for f in ds.matches(match) if ds[f] != 'r')
  1686         # from immediately doing so for subsequent changing files
  1913         # from immediately doing so for subsequent changing files
  1687         self._repo.dirstate.write(self._repo.currenttransaction())
  1914         self._repo.dirstate.write(self._repo.currenttransaction())
  1688 
  1915 
  1689         sparse.aftercommit(self._repo, node)
  1916         sparse.aftercommit(self._repo, node)
  1690 
  1917 
       
  1918 
  1691 class committablefilectx(basefilectx):
  1919 class committablefilectx(basefilectx):
  1692     """A committablefilectx provides common functionality for a file context
  1920     """A committablefilectx provides common functionality for a file context
  1693     that wants the ability to commit, e.g. workingfilectx or memfilectx."""
  1921     that wants the ability to commit, e.g. workingfilectx or memfilectx."""
       
  1922 
  1694     def __init__(self, repo, path, filelog=None, ctx=None):
  1923     def __init__(self, repo, path, filelog=None, ctx=None):
  1695         self._repo = repo
  1924         self._repo = repo
  1696         self._path = path
  1925         self._path = path
  1697         self._changeid = None
  1926         self._changeid = None
  1698         self._filerev = self._filenode = None
  1927         self._filerev = self._filenode = None
  1717             return None
  1946             return None
  1718         return path, self._changectx._parents[0]._manifest.get(path, nullid)
  1947         return path, self._changectx._parents[0]._manifest.get(path, nullid)
  1719 
  1948 
  1720     def parents(self):
  1949     def parents(self):
  1721         '''return parent filectxs, following copies if necessary'''
  1950         '''return parent filectxs, following copies if necessary'''
       
  1951 
  1722         def filenode(ctx, path):
  1952         def filenode(ctx, path):
  1723             return ctx._manifest.get(path, nullid)
  1953             return ctx._manifest.get(path, nullid)
  1724 
  1954 
  1725         path = self._path
  1955         path = self._path
  1726         fl = self._filelog
  1956         fl = self._filelog
  1733             pl = [(path, filenode(pcl[0], path), fl)]
  1963             pl = [(path, filenode(pcl[0], path), fl)]
  1734 
  1964 
  1735         for pc in pcl[1:]:
  1965         for pc in pcl[1:]:
  1736             pl.append((path, filenode(pc, path), fl))
  1966             pl.append((path, filenode(pc, path), fl))
  1737 
  1967 
  1738         return [self._parentfilectx(p, fileid=n, filelog=l)
  1968         return [
  1739                 for p, n, l in pl if n != nullid]
  1969             self._parentfilectx(p, fileid=n, filelog=l)
       
  1970             for p, n, l in pl
       
  1971             if n != nullid
       
  1972         ]
  1740 
  1973 
  1741     def children(self):
  1974     def children(self):
  1742         return []
  1975         return []
       
  1976 
  1743 
  1977 
  1744 class workingfilectx(committablefilectx):
  1978 class workingfilectx(committablefilectx):
  1745     """A workingfilectx object makes access to data related to a particular
  1979     """A workingfilectx object makes access to data related to a particular
  1746        file in the working directory convenient."""
  1980        file in the working directory convenient."""
       
  1981 
  1747     def __init__(self, repo, path, filelog=None, workingctx=None):
  1982     def __init__(self, repo, path, filelog=None, workingctx=None):
  1748         super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
  1983         super(workingfilectx, self).__init__(repo, path, filelog, workingctx)
  1749 
  1984 
  1750     @propertycache
  1985     @propertycache
  1751     def _changectx(self):
  1986     def _changectx(self):
  1752         return workingctx(self._repo)
  1987         return workingctx(self._repo)
  1753 
  1988 
  1754     def data(self):
  1989     def data(self):
  1755         return self._repo.wread(self._path)
  1990         return self._repo.wread(self._path)
       
  1991 
  1756     def copysource(self):
  1992     def copysource(self):
  1757         return self._repo.dirstate.copied(self._path)
  1993         return self._repo.dirstate.copied(self._path)
  1758 
  1994 
  1759     def size(self):
  1995     def size(self):
  1760         return self._repo.wvfs.lstat(self._path).st_size
  1996         return self._repo.wvfs.lstat(self._path).st_size
       
  1997 
  1761     def lstat(self):
  1998     def lstat(self):
  1762         return self._repo.wvfs.lstat(self._path)
  1999         return self._repo.wvfs.lstat(self._path)
       
  2000 
  1763     def date(self):
  2001     def date(self):
  1764         t, tz = self._changectx.date()
  2002         t, tz = self._changectx.date()
  1765         try:
  2003         try:
  1766             return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
  2004             return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
  1767         except OSError as err:
  2005         except OSError as err:
  1788         return fctx.cmp(self)
  2026         return fctx.cmp(self)
  1789 
  2027 
  1790     def remove(self, ignoremissing=False):
  2028     def remove(self, ignoremissing=False):
  1791         """wraps unlink for a repo's working directory"""
  2029         """wraps unlink for a repo's working directory"""
  1792         rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs')
  2030         rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs')
  1793         self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing,
  2031         self._repo.wvfs.unlinkpath(
  1794                                    rmdir=rmdir)
  2032             self._path, ignoremissing=ignoremissing, rmdir=rmdir
       
  2033         )
  1795 
  2034 
  1796     def write(self, data, flags, backgroundclose=False, **kwargs):
  2035     def write(self, data, flags, backgroundclose=False, **kwargs):
  1797         """wraps repo.wwrite"""
  2036         """wraps repo.wwrite"""
  1798         return self._repo.wwrite(self._path, data, flags,
  2037         return self._repo.wwrite(
  1799                                  backgroundclose=backgroundclose,
  2038             self._path, data, flags, backgroundclose=backgroundclose, **kwargs
  1800                                  **kwargs)
  2039         )
  1801 
  2040 
  1802     def markcopied(self, src):
  2041     def markcopied(self, src):
  1803         """marks this file a copy of `src`"""
  2042         """marks this file a copy of `src`"""
  1804         self._repo.dirstate.copy(src, self._path)
  2043         self._repo.dirstate.copy(src, self._path)
  1805 
  2044 
  1825                 wvfs.removedirs(f)
  2064                 wvfs.removedirs(f)
  1826 
  2065 
  1827     def setflags(self, l, x):
  2066     def setflags(self, l, x):
  1828         self._repo.wvfs.setflags(self._path, l, x)
  2067         self._repo.wvfs.setflags(self._path, l, x)
  1829 
  2068 
       
  2069 
  1830 class overlayworkingctx(committablectx):
  2070 class overlayworkingctx(committablectx):
  1831     """Wraps another mutable context with a write-back cache that can be
  2071     """Wraps another mutable context with a write-back cache that can be
  1832     converted into a commit context.
  2072     converted into a commit context.
  1833 
  2073 
  1834     self._cache[path] maps to a dict with keys: {
  2074     self._cache[path] maps to a dict with keys: {
  1861                     return self._cache[path]['data']
  2101                     return self._cache[path]['data']
  1862                 else:
  2102                 else:
  1863                     # Must fallback here, too, because we only set flags.
  2103                     # Must fallback here, too, because we only set flags.
  1864                     return self._wrappedctx[path].data()
  2104                     return self._wrappedctx[path].data()
  1865             else:
  2105             else:
  1866                 raise error.ProgrammingError("No such file or directory: %s" %
  2106                 raise error.ProgrammingError(
  1867                                              path)
  2107                     "No such file or directory: %s" % path
       
  2108                 )
  1868         else:
  2109         else:
  1869             return self._wrappedctx[path].data()
  2110             return self._wrappedctx[path].data()
  1870 
  2111 
  1871     @propertycache
  2112     @propertycache
  1872     def _manifest(self):
  2113     def _manifest(self):
  1886 
  2127 
  1887     @propertycache
  2128     @propertycache
  1888     def _flagfunc(self):
  2129     def _flagfunc(self):
  1889         def f(path):
  2130         def f(path):
  1890             return self._cache[path]['flags']
  2131             return self._cache[path]['flags']
       
  2132 
  1891         return f
  2133         return f
  1892 
  2134 
  1893     def files(self):
  2135     def files(self):
  1894         return sorted(self.added() + self.modified() + self.removed())
  2136         return sorted(self.added() + self.modified() + self.removed())
  1895 
  2137 
  1896     def modified(self):
  2138     def modified(self):
  1897         return [f for f in self._cache.keys() if self._cache[f]['exists'] and
  2139         return [
  1898                 self._existsinparent(f)]
  2140             f
       
  2141             for f in self._cache.keys()
       
  2142             if self._cache[f]['exists'] and self._existsinparent(f)
       
  2143         ]
  1899 
  2144 
  1900     def added(self):
  2145     def added(self):
  1901         return [f for f in self._cache.keys() if self._cache[f]['exists'] and
  2146         return [
  1902                 not self._existsinparent(f)]
  2147             f
       
  2148             for f in self._cache.keys()
       
  2149             if self._cache[f]['exists'] and not self._existsinparent(f)
       
  2150         ]
  1903 
  2151 
  1904     def removed(self):
  2152     def removed(self):
  1905         return [f for f in self._cache.keys() if
  2153         return [
  1906                 not self._cache[f]['exists'] and self._existsinparent(f)]
  2154             f
       
  2155             for f in self._cache.keys()
       
  2156             if not self._cache[f]['exists'] and self._existsinparent(f)
       
  2157         ]
  1907 
  2158 
  1908     def p1copies(self):
  2159     def p1copies(self):
  1909         copies = self._repo._wrappedctx.p1copies().copy()
  2160         copies = self._repo._wrappedctx.p1copies().copy()
  1910         narrowmatch = self._repo.narrowmatch()
  2161         narrowmatch = self._repo.narrowmatch()
  1911         for f in self._cache.keys():
  2162         for f in self._cache.keys():
  1912             if not narrowmatch(f):
  2163             if not narrowmatch(f):
  1913                 continue
  2164                 continue
  1914             copies.pop(f, None) # delete if it exists
  2165             copies.pop(f, None)  # delete if it exists
  1915             source = self._cache[f]['copied']
  2166             source = self._cache[f]['copied']
  1916             if source:
  2167             if source:
  1917                 copies[f] = source
  2168                 copies[f] = source
  1918         return copies
  2169         return copies
  1919 
  2170 
  1921         copies = self._repo._wrappedctx.p2copies().copy()
  2172         copies = self._repo._wrappedctx.p2copies().copy()
  1922         narrowmatch = self._repo.narrowmatch()
  2173         narrowmatch = self._repo.narrowmatch()
  1923         for f in self._cache.keys():
  2174         for f in self._cache.keys():
  1924             if not narrowmatch(f):
  2175             if not narrowmatch(f):
  1925                 continue
  2176                 continue
  1926             copies.pop(f, None) # delete if it exists
  2177             copies.pop(f, None)  # delete if it exists
  1927             source = self._cache[f]['copied']
  2178             source = self._cache[f]['copied']
  1928             if source:
  2179             if source:
  1929                 copies[f] = source
  2180                 copies[f] = source
  1930         return copies
  2181         return copies
  1931 
  2182 
  1937             return self._cache[path]['date']
  2188             return self._cache[path]['date']
  1938         else:
  2189         else:
  1939             return self._wrappedctx[path].date()
  2190             return self._wrappedctx[path].date()
  1940 
  2191 
  1941     def markcopied(self, path, origin):
  2192     def markcopied(self, path, origin):
  1942         self._markdirty(path, exists=True, date=self.filedate(path),
  2193         self._markdirty(
  1943                         flags=self.flags(path), copied=origin)
  2194             path,
       
  2195             exists=True,
       
  2196             date=self.filedate(path),
       
  2197             flags=self.flags(path),
       
  2198             copied=origin,
       
  2199         )
  1944 
  2200 
  1945     def copydata(self, path):
  2201     def copydata(self, path):
  1946         if self.isdirty(path):
  2202         if self.isdirty(path):
  1947             return self._cache[path]['copied']
  2203             return self._cache[path]['copied']
  1948         else:
  2204         else:
  1951     def flags(self, path):
  2207     def flags(self, path):
  1952         if self.isdirty(path):
  2208         if self.isdirty(path):
  1953             if self._cache[path]['exists']:
  2209             if self._cache[path]['exists']:
  1954                 return self._cache[path]['flags']
  2210                 return self._cache[path]['flags']
  1955             else:
  2211             else:
  1956                 raise error.ProgrammingError("No such file or directory: %s" %
  2212                 raise error.ProgrammingError(
  1957                                              self._path)
  2213                     "No such file or directory: %s" % self._path
       
  2214                 )
  1958         else:
  2215         else:
  1959             return self._wrappedctx[path].flags()
  2216             return self._wrappedctx[path].flags()
  1960 
  2217 
  1961     def __contains__(self, key):
  2218     def __contains__(self, key):
  1962         if key in self._cache:
  2219         if key in self._cache:
  1978 
  2235 
  1979         Since we never write to the filesystem and never call `applyupdates` in
  2236         Since we never write to the filesystem and never call `applyupdates` in
  1980         IMM, we'll never check that a path is actually writable -- e.g., because
  2237         IMM, we'll never check that a path is actually writable -- e.g., because
  1981         it adds `a/foo`, but `a` is actually a file in the other commit.
  2238         it adds `a/foo`, but `a` is actually a file in the other commit.
  1982         """
  2239         """
       
  2240 
  1983         def fail(path, component):
  2241         def fail(path, component):
  1984             # p1() is the base and we're receiving "writes" for p2()'s
  2242             # p1() is the base and we're receiving "writes" for p2()'s
  1985             # files.
  2243             # files.
  1986             if 'l' in self.p1()[component].flags():
  2244             if 'l' in self.p1()[component].flags():
  1987                 raise error.Abort("error: %s conflicts with symlink %s "
  2245                 raise error.Abort(
  1988                                   "in %d." % (path, component,
  2246                     "error: %s conflicts with symlink %s "
  1989                                               self.p1().rev()))
  2247                     "in %d." % (path, component, self.p1().rev())
       
  2248                 )
  1990             else:
  2249             else:
  1991                 raise error.Abort("error: '%s' conflicts with file '%s' in "
  2250                 raise error.Abort(
  1992                                   "%d." % (path, component,
  2251                     "error: '%s' conflicts with file '%s' in "
  1993                                            self.p1().rev()))
  2252                     "%d." % (path, component, self.p1().rev())
       
  2253                 )
  1994 
  2254 
  1995         # Test that each new directory to be created to write this path from p2
  2255         # Test that each new directory to be created to write this path from p2
  1996         # is not a file in p1.
  2256         # is not a file in p1.
  1997         components = path.split('/')
  2257         components = path.split('/')
  1998         for i in pycompat.xrange(len(components)):
  2258         for i in pycompat.xrange(len(components)):
  2010                 return
  2270                 return
  2011             # omit the files which are deleted in current IMM wctx
  2271             # omit the files which are deleted in current IMM wctx
  2012             mfiles = [m for m in mfiles if m in self]
  2272             mfiles = [m for m in mfiles if m in self]
  2013             if not mfiles:
  2273             if not mfiles:
  2014                 return
  2274                 return
  2015             raise error.Abort("error: file '%s' cannot be written because "
  2275             raise error.Abort(
  2016                               " '%s/' is a directory in %s (containing %d "
  2276                 "error: file '%s' cannot be written because "
  2017                               "entries: %s)"
  2277                 " '%s/' is a directory in %s (containing %d "
  2018                               % (path, path, self.p1(), len(mfiles),
  2278                 "entries: %s)"
  2019                                  ', '.join(mfiles)))
  2279                 % (path, path, self.p1(), len(mfiles), ', '.join(mfiles))
       
  2280             )
  2020 
  2281 
  2021     def write(self, path, data, flags='', **kwargs):
  2282     def write(self, path, data, flags='', **kwargs):
  2022         if data is None:
  2283         if data is None:
  2023             raise error.ProgrammingError("data must be non-None")
  2284             raise error.ProgrammingError("data must be non-None")
  2024         self._auditconflicts(path)
  2285         self._auditconflicts(path)
  2025         self._markdirty(path, exists=True, data=data, date=dateutil.makedate(),
  2286         self._markdirty(
  2026                         flags=flags)
  2287             path, exists=True, data=data, date=dateutil.makedate(), flags=flags
       
  2288         )
  2027 
  2289 
  2028     def setflags(self, path, l, x):
  2290     def setflags(self, path, l, x):
  2029         flag = ''
  2291         flag = ''
  2030         if l:
  2292         if l:
  2031             flag = 'l'
  2293             flag = 'l'
  2032         elif x:
  2294         elif x:
  2033             flag = 'x'
  2295             flag = 'x'
  2034         self._markdirty(path, exists=True, date=dateutil.makedate(),
  2296         self._markdirty(path, exists=True, date=dateutil.makedate(), flags=flag)
  2035                         flags=flag)
       
  2036 
  2297 
  2037     def remove(self, path):
  2298     def remove(self, path):
  2038         self._markdirty(path, exists=False)
  2299         self._markdirty(path, exists=False)
  2039 
  2300 
  2040     def exists(self, path):
  2301     def exists(self, path):
  2042         return False if they are broken.
  2303         return False if they are broken.
  2043         """
  2304         """
  2044         if self.isdirty(path):
  2305         if self.isdirty(path):
  2045             # If this path exists and is a symlink, "follow" it by calling
  2306             # If this path exists and is a symlink, "follow" it by calling
  2046             # exists on the destination path.
  2307             # exists on the destination path.
  2047             if (self._cache[path]['exists'] and
  2308             if (
  2048                         'l' in self._cache[path]['flags']):
  2309                 self._cache[path]['exists']
       
  2310                 and 'l' in self._cache[path]['flags']
       
  2311             ):
  2049                 return self.exists(self._cache[path]['data'].strip())
  2312                 return self.exists(self._cache[path]['data'].strip())
  2050             else:
  2313             else:
  2051                 return self._cache[path]['exists']
  2314                 return self._cache[path]['exists']
  2052 
  2315 
  2053         return self._existsinparent(path)
  2316         return self._existsinparent(path)
  2062     def size(self, path):
  2325     def size(self, path):
  2063         if self.isdirty(path):
  2326         if self.isdirty(path):
  2064             if self._cache[path]['exists']:
  2327             if self._cache[path]['exists']:
  2065                 return len(self._cache[path]['data'])
  2328                 return len(self._cache[path]['data'])
  2066             else:
  2329             else:
  2067                 raise error.ProgrammingError("No such file or directory: %s" %
  2330                 raise error.ProgrammingError(
  2068                                              self._path)
  2331                     "No such file or directory: %s" % self._path
       
  2332                 )
  2069         return self._wrappedctx[path].size()
  2333         return self._wrappedctx[path].size()
  2070 
  2334 
  2071     def tomemctx(self, text, branch=None, extra=None, date=None, parents=None,
  2335     def tomemctx(
  2072                  user=None, editor=None):
  2336         self,
       
  2337         text,
       
  2338         branch=None,
       
  2339         extra=None,
       
  2340         date=None,
       
  2341         parents=None,
       
  2342         user=None,
       
  2343         editor=None,
       
  2344     ):
  2073         """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
  2345         """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be
  2074         committed.
  2346         committed.
  2075 
  2347 
  2076         ``text`` is the commit message.
  2348         ``text`` is the commit message.
  2077         ``parents`` (optional) are rev numbers.
  2349         ``parents`` (optional) are rev numbers.
  2087             parents = (self._repo[parents[0]], None)
  2359             parents = (self._repo[parents[0]], None)
  2088         else:
  2360         else:
  2089             parents = (self._repo[parents[0]], self._repo[parents[1]])
  2361             parents = (self._repo[parents[0]], self._repo[parents[1]])
  2090 
  2362 
  2091         files = self.files()
  2363         files = self.files()
       
  2364 
  2092         def getfile(repo, memctx, path):
  2365         def getfile(repo, memctx, path):
  2093             if self._cache[path]['exists']:
  2366             if self._cache[path]['exists']:
  2094                 return memfilectx(repo, memctx, path,
  2367                 return memfilectx(
  2095                                   self._cache[path]['data'],
  2368                     repo,
  2096                                   'l' in self._cache[path]['flags'],
  2369                     memctx,
  2097                                   'x' in self._cache[path]['flags'],
  2370                     path,
  2098                                   self._cache[path]['copied'])
  2371                     self._cache[path]['data'],
       
  2372                     'l' in self._cache[path]['flags'],
       
  2373                     'x' in self._cache[path]['flags'],
       
  2374                     self._cache[path]['copied'],
       
  2375                 )
  2099             else:
  2376             else:
  2100                 # Returning None, but including the path in `files`, is
  2377                 # Returning None, but including the path in `files`, is
  2101                 # necessary for memctx to register a deletion.
  2378                 # necessary for memctx to register a deletion.
  2102                 return None
  2379                 return None
  2103         return memctx(self._repo, parents, text, files, getfile, date=date,
  2380 
  2104                       extra=extra, user=user, branch=branch, editor=editor)
  2381         return memctx(
       
  2382             self._repo,
       
  2383             parents,
       
  2384             text,
       
  2385             files,
       
  2386             getfile,
       
  2387             date=date,
       
  2388             extra=extra,
       
  2389             user=user,
       
  2390             branch=branch,
       
  2391             editor=editor,
       
  2392         )
  2105 
  2393 
  2106     def isdirty(self, path):
  2394     def isdirty(self, path):
  2107         return path in self._cache
  2395         return path in self._cache
  2108 
  2396 
  2109     def isempty(self):
  2397     def isempty(self):
  2124         """
  2412         """
  2125         keys = []
  2413         keys = []
  2126         # This won't be perfect, but can help performance significantly when
  2414         # This won't be perfect, but can help performance significantly when
  2127         # using things like remotefilelog.
  2415         # using things like remotefilelog.
  2128         scmutil.prefetchfiles(
  2416         scmutil.prefetchfiles(
  2129             self.repo(), [self.p1().rev()],
  2417             self.repo(),
  2130             scmutil.matchfiles(self.repo(), self._cache.keys()))
  2418             [self.p1().rev()],
       
  2419             scmutil.matchfiles(self.repo(), self._cache.keys()),
       
  2420         )
  2131 
  2421 
  2132         for path in self._cache.keys():
  2422         for path in self._cache.keys():
  2133             cache = self._cache[path]
  2423             cache = self._cache[path]
  2134             try:
  2424             try:
  2135                 underlying = self._wrappedctx[path]
  2425                 underlying = self._wrappedctx[path]
  2136                 if (underlying.data() == cache['data'] and
  2426                 if (
  2137                             underlying.flags() == cache['flags']):
  2427                     underlying.data() == cache['data']
       
  2428                     and underlying.flags() == cache['flags']
       
  2429                 ):
  2138                     keys.append(path)
  2430                     keys.append(path)
  2139             except error.ManifestLookupError:
  2431             except error.ManifestLookupError:
  2140                 # Path not in the underlying manifest (created).
  2432                 # Path not in the underlying manifest (created).
  2141                 continue
  2433                 continue
  2142 
  2434 
  2143         for path in keys:
  2435         for path in keys:
  2144             del self._cache[path]
  2436             del self._cache[path]
  2145         return keys
  2437         return keys
  2146 
  2438 
  2147     def _markdirty(self, path, exists, data=None, date=None, flags='',
  2439     def _markdirty(
  2148         copied=None):
  2440         self, path, exists, data=None, date=None, flags='', copied=None
       
  2441     ):
  2149         # data not provided, let's see if we already have some; if not, let's
  2442         # data not provided, let's see if we already have some; if not, let's
  2150         # grab it from our underlying context, so that we always have data if
  2443         # grab it from our underlying context, so that we always have data if
  2151         # the file is marked as existing.
  2444         # the file is marked as existing.
  2152         if exists and data is None:
  2445         if exists and data is None:
  2153             oldentry = self._cache.get(path) or {}
  2446             oldentry = self._cache.get(path) or {}
  2162             'flags': flags,
  2455             'flags': flags,
  2163             'copied': copied,
  2456             'copied': copied,
  2164         }
  2457         }
  2165 
  2458 
  2166     def filectx(self, path, filelog=None):
  2459     def filectx(self, path, filelog=None):
  2167         return overlayworkingfilectx(self._repo, path, parent=self,
  2460         return overlayworkingfilectx(
  2168                                      filelog=filelog)
  2461             self._repo, path, parent=self, filelog=filelog
       
  2462         )
       
  2463 
  2169 
  2464 
  2170 class overlayworkingfilectx(committablefilectx):
  2465 class overlayworkingfilectx(committablefilectx):
  2171     """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
  2466     """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory
  2172     cache, which can be flushed through later by calling ``flush()``."""
  2467     cache, which can be flushed through later by calling ``flush()``."""
  2173 
  2468 
  2174     def __init__(self, repo, path, filelog=None, parent=None):
  2469     def __init__(self, repo, path, filelog=None, parent=None):
  2175         super(overlayworkingfilectx, self).__init__(repo, path, filelog,
  2470         super(overlayworkingfilectx, self).__init__(repo, path, filelog, parent)
  2176                                                     parent)
       
  2177         self._repo = repo
  2471         self._repo = repo
  2178         self._parent = parent
  2472         self._parent = parent
  2179         self._path = path
  2473         self._path = path
  2180 
  2474 
  2181     def cmp(self, fctx):
  2475     def cmp(self, fctx):
  2221         return self._parent.remove(self._path)
  2515         return self._parent.remove(self._path)
  2222 
  2516 
  2223     def clearunknown(self):
  2517     def clearunknown(self):
  2224         pass
  2518         pass
  2225 
  2519 
       
  2520 
  2226 class workingcommitctx(workingctx):
  2521 class workingcommitctx(workingctx):
  2227     """A workingcommitctx object makes access to data related to
  2522     """A workingcommitctx object makes access to data related to
  2228     the revision being committed convenient.
  2523     the revision being committed convenient.
  2229 
  2524 
  2230     This hides changes in the working directory, if they aren't
  2525     This hides changes in the working directory, if they aren't
  2231     committed in this context.
  2526     committed in this context.
  2232     """
  2527     """
  2233     def __init__(self, repo, changes,
  2528 
  2234                  text="", user=None, date=None, extra=None):
  2529     def __init__(
  2235         super(workingcommitctx, self).__init__(repo, text, user, date, extra,
  2530         self, repo, changes, text="", user=None, date=None, extra=None
  2236                                                changes)
  2531     ):
       
  2532         super(workingcommitctx, self).__init__(
       
  2533             repo, text, user, date, extra, changes
       
  2534         )
  2237 
  2535 
  2238     def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
  2536     def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False):
  2239         """Return matched files only in ``self._status``
  2537         """Return matched files only in ``self._status``
  2240 
  2538 
  2241         Uncommitted files appear "clean" via this context, even if
  2539         Uncommitted files appear "clean" via this context, even if
  2243         """
  2541         """
  2244         if clean:
  2542         if clean:
  2245             clean = [f for f in self._manifest if f not in self._changedset]
  2543             clean = [f for f in self._manifest if f not in self._changedset]
  2246         else:
  2544         else:
  2247             clean = []
  2545             clean = []
  2248         return scmutil.status([f for f in self._status.modified if match(f)],
  2546         return scmutil.status(
  2249                               [f for f in self._status.added if match(f)],
  2547             [f for f in self._status.modified if match(f)],
  2250                               [f for f in self._status.removed if match(f)],
  2548             [f for f in self._status.added if match(f)],
  2251                               [], [], [], clean)
  2549             [f for f in self._status.removed if match(f)],
       
  2550             [],
       
  2551             [],
       
  2552             [],
       
  2553             clean,
       
  2554         )
  2252 
  2555 
  2253     @propertycache
  2556     @propertycache
  2254     def _changedset(self):
  2557     def _changedset(self):
  2255         """Return the set of files changed in this context
  2558         """Return the set of files changed in this context
  2256         """
  2559         """
  2257         changed = set(self._status.modified)
  2560         changed = set(self._status.modified)
  2258         changed.update(self._status.added)
  2561         changed.update(self._status.added)
  2259         changed.update(self._status.removed)
  2562         changed.update(self._status.removed)
  2260         return changed
  2563         return changed
       
  2564 
  2261 
  2565 
  2262 def makecachingfilectxfn(func):
  2566 def makecachingfilectxfn(func):
  2263     """Create a filectxfn that caches based on the path.
  2567     """Create a filectxfn that caches based on the path.
  2264 
  2568 
  2265     We can't use util.cachefunc because it uses all arguments as the cache
  2569     We can't use util.cachefunc because it uses all arguments as the cache
  2273             cache[path] = func(repo, memctx, path)
  2577             cache[path] = func(repo, memctx, path)
  2274         return cache[path]
  2578         return cache[path]
  2275 
  2579 
  2276     return getfilectx
  2580     return getfilectx
  2277 
  2581 
       
  2582 
  2278 def memfilefromctx(ctx):
  2583 def memfilefromctx(ctx):
  2279     """Given a context return a memfilectx for ctx[path]
  2584     """Given a context return a memfilectx for ctx[path]
  2280 
  2585 
  2281     This is a convenience method for building a memctx based on another
  2586     This is a convenience method for building a memctx based on another
  2282     context.
  2587     context.
  2283     """
  2588     """
       
  2589 
  2284     def getfilectx(repo, memctx, path):
  2590     def getfilectx(repo, memctx, path):
  2285         fctx = ctx[path]
  2591         fctx = ctx[path]
  2286         copysource = fctx.copysource()
  2592         copysource = fctx.copysource()
  2287         return memfilectx(repo, memctx, path, fctx.data(),
  2593         return memfilectx(
  2288                           islink=fctx.islink(), isexec=fctx.isexec(),
  2594             repo,
  2289                           copysource=copysource)
  2595             memctx,
       
  2596             path,
       
  2597             fctx.data(),
       
  2598             islink=fctx.islink(),
       
  2599             isexec=fctx.isexec(),
       
  2600             copysource=copysource,
       
  2601         )
  2290 
  2602 
  2291     return getfilectx
  2603     return getfilectx
       
  2604 
  2292 
  2605 
  2293 def memfilefrompatch(patchstore):
  2606 def memfilefrompatch(patchstore):
  2294     """Given a patch (e.g. patchstore object) return a memfilectx
  2607     """Given a patch (e.g. patchstore object) return a memfilectx
  2295 
  2608 
  2296     This is a convenience method for building a memctx based on a patchstore.
  2609     This is a convenience method for building a memctx based on a patchstore.
  2297     """
  2610     """
       
  2611 
  2298     def getfilectx(repo, memctx, path):
  2612     def getfilectx(repo, memctx, path):
  2299         data, mode, copysource = patchstore.getfile(path)
  2613         data, mode, copysource = patchstore.getfile(path)
  2300         if data is None:
  2614         if data is None:
  2301             return None
  2615             return None
  2302         islink, isexec = mode
  2616         islink, isexec = mode
  2303         return memfilectx(repo, memctx, path, data, islink=islink,
  2617         return memfilectx(
  2304                           isexec=isexec, copysource=copysource)
  2618             repo,
       
  2619             memctx,
       
  2620             path,
       
  2621             data,
       
  2622             islink=islink,
       
  2623             isexec=isexec,
       
  2624             copysource=copysource,
       
  2625         )
  2305 
  2626 
  2306     return getfilectx
  2627     return getfilectx
       
  2628 
  2307 
  2629 
  2308 class memctx(committablectx):
  2630 class memctx(committablectx):
  2309     """Use memctx to perform in-memory commits via localrepo.commitctx().
  2631     """Use memctx to perform in-memory commits via localrepo.commitctx().
  2310 
  2632 
  2311     Revision information is supplied at initialization time while
  2633     Revision information is supplied at initialization time while
  2336     # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
  2658     # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files.
  2337     # Extensions that need to retain compatibility across Mercurial 3.1 can use
  2659     # Extensions that need to retain compatibility across Mercurial 3.1 can use
  2338     # this field to determine what to do in filectxfn.
  2660     # this field to determine what to do in filectxfn.
  2339     _returnnoneformissingfiles = True
  2661     _returnnoneformissingfiles = True
  2340 
  2662 
  2341     def __init__(self, repo, parents, text, files, filectxfn, user=None,
  2663     def __init__(
  2342                  date=None, extra=None, branch=None, editor=False):
  2664         self,
  2343         super(memctx, self).__init__(repo, text, user, date, extra,
  2665         repo,
  2344                                      branch=branch)
  2666         parents,
       
  2667         text,
       
  2668         files,
       
  2669         filectxfn,
       
  2670         user=None,
       
  2671         date=None,
       
  2672         extra=None,
       
  2673         branch=None,
       
  2674         editor=False,
       
  2675     ):
       
  2676         super(memctx, self).__init__(
       
  2677             repo, text, user, date, extra, branch=branch
       
  2678         )
  2345         self._rev = None
  2679         self._rev = None
  2346         self._node = None
  2680         self._node = None
  2347         parents = [(p or nullid) for p in parents]
  2681         parents = [(p or nullid) for p in parents]
  2348         p1, p2 = parents
  2682         p1, p2 = parents
  2349         self._parents = [self._repo[p] for p in (p1, p2)]
  2683         self._parents = [self._repo[p] for p in (p1, p2)]
  2418             else:
  2752             else:
  2419                 removed.append(f)
  2753                 removed.append(f)
  2420 
  2754 
  2421         return scmutil.status(modified, added, removed, [], [], [], [])
  2755         return scmutil.status(modified, added, removed, [], [], [], [])
  2422 
  2756 
       
  2757 
  2423 class memfilectx(committablefilectx):
  2758 class memfilectx(committablefilectx):
  2424     """memfilectx represents an in-memory file to commit.
  2759     """memfilectx represents an in-memory file to commit.
  2425 
  2760 
  2426     See memctx and committablefilectx for more details.
  2761     See memctx and committablefilectx for more details.
  2427     """
  2762     """
  2428     def __init__(self, repo, changectx, path, data, islink=False,
  2763 
  2429                  isexec=False, copysource=None):
  2764     def __init__(
       
  2765         self,
       
  2766         repo,
       
  2767         changectx,
       
  2768         path,
       
  2769         data,
       
  2770         islink=False,
       
  2771         isexec=False,
       
  2772         copysource=None,
       
  2773     ):
  2430         """
  2774         """
  2431         path is the normalized file path relative to repository root.
  2775         path is the normalized file path relative to repository root.
  2432         data is the file content as a string.
  2776         data is the file content as a string.
  2433         islink is True if the file is a symbolic link.
  2777         islink is True if the file is a symbolic link.
  2434         isexec is True if the file is executable.
  2778         isexec is True if the file is executable.
  2476     user receives the committer name and defaults to current repository
  2820     user receives the committer name and defaults to current repository
  2477     username, date is the commit date in any format supported by
  2821     username, date is the commit date in any format supported by
  2478     dateutil.parsedate() and defaults to current date, extra is a dictionary of
  2822     dateutil.parsedate() and defaults to current date, extra is a dictionary of
  2479     metadata or is left empty.
  2823     metadata or is left empty.
  2480     """
  2824     """
  2481     def __init__(self, repo, originalctx, parents=None, text=None, user=None,
  2825 
  2482                  date=None, extra=None, editor=False):
  2826     def __init__(
       
  2827         self,
       
  2828         repo,
       
  2829         originalctx,
       
  2830         parents=None,
       
  2831         text=None,
       
  2832         user=None,
       
  2833         date=None,
       
  2834         extra=None,
       
  2835         editor=False,
       
  2836     ):
  2483         if text is None:
  2837         if text is None:
  2484             text = originalctx.description()
  2838             text = originalctx.description()
  2485         super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
  2839         super(metadataonlyctx, self).__init__(repo, text, user, date, extra)
  2486         self._rev = None
  2840         self._rev = None
  2487         self._node = None
  2841         self._node = None
  2498 
  2852 
  2499         # sanity check to ensure that the reused manifest parents are
  2853         # sanity check to ensure that the reused manifest parents are
  2500         # manifests of our commit parents
  2854         # manifests of our commit parents
  2501         mp1, mp2 = self.manifestctx().parents
  2855         mp1, mp2 = self.manifestctx().parents
  2502         if p1 != nullid and p1.manifestnode() != mp1:
  2856         if p1 != nullid and p1.manifestnode() != mp1:
  2503             raise RuntimeError(r"can't reuse the manifest: its p1 "
  2857             raise RuntimeError(
  2504                                r"doesn't match the new ctx p1")
  2858                 r"can't reuse the manifest: its p1 "
       
  2859                 r"doesn't match the new ctx p1"
       
  2860             )
  2505         if p2 != nullid and p2.manifestnode() != mp2:
  2861         if p2 != nullid and p2.manifestnode() != mp2:
  2506             raise RuntimeError(r"can't reuse the manifest: "
  2862             raise RuntimeError(
  2507                                r"its p2 doesn't match the new ctx p2")
  2863                 r"can't reuse the manifest: "
       
  2864                 r"its p2 doesn't match the new ctx p2"
       
  2865             )
  2508 
  2866 
  2509         self._files = originalctx.files()
  2867         self._files = originalctx.files()
  2510         self.substate = {}
  2868         self.substate = {}
  2511 
  2869 
  2512         if editor:
  2870         if editor:
  2556             else:
  2914             else:
  2557                 removed.append(f)
  2915                 removed.append(f)
  2558 
  2916 
  2559         return scmutil.status(modified, added, removed, [], [], [], [])
  2917         return scmutil.status(modified, added, removed, [], [], [], [])
  2560 
  2918 
       
  2919 
  2561 class arbitraryfilectx(object):
  2920 class arbitraryfilectx(object):
  2562     """Allows you to use filectx-like functions on a file in an arbitrary
  2921     """Allows you to use filectx-like functions on a file in an arbitrary
  2563     location on disk, possibly not in the working directory.
  2922     location on disk, possibly not in the working directory.
  2564     """
  2923     """
       
  2924 
  2565     def __init__(self, path, repo=None):
  2925     def __init__(self, path, repo=None):
  2566         # Repo is optional because contrib/simplemerge uses this class.
  2926         # Repo is optional because contrib/simplemerge uses this class.
  2567         self._repo = repo
  2927         self._repo = repo
  2568         self._path = path
  2928         self._path = path
  2569 
  2929 
  2570     def cmp(self, fctx):
  2930     def cmp(self, fctx):
  2571         # filecmp follows symlinks whereas `cmp` should not, so skip the fast
  2931         # filecmp follows symlinks whereas `cmp` should not, so skip the fast
  2572         # path if either side is a symlink.
  2932         # path if either side is a symlink.
  2573         symlinks = ('l' in self.flags() or 'l' in fctx.flags())
  2933         symlinks = 'l' in self.flags() or 'l' in fctx.flags()
  2574         if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
  2934         if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
  2575             # Add a fast-path for merge if both sides are disk-backed.
  2935             # Add a fast-path for merge if both sides are disk-backed.
  2576             # Note that filecmp uses the opposite return values (True if same)
  2936             # Note that filecmp uses the opposite return values (True if same)
  2577             # from our cmp functions (True if different).
  2937             # from our cmp functions (True if different).
  2578             return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
  2938             return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))