mercurial/scmutil.py
changeset 45942 89a2afe31e82
parent 45919 aba4f2c97e74
child 46039 b9ebe0bfed4e
equal deleted inserted replaced
45941:346af7687c6f 45942:89a2afe31e82
    64 termsize = scmplatform.termsize
    64 termsize = scmplatform.termsize
    65 
    65 
    66 
    66 
    67 @attr.s(slots=True, repr=False)
    67 @attr.s(slots=True, repr=False)
    68 class status(object):
    68 class status(object):
    69     '''Struct with a list of files per status.
    69     """Struct with a list of files per status.
    70 
    70 
    71     The 'deleted', 'unknown' and 'ignored' properties are only
    71     The 'deleted', 'unknown' and 'ignored' properties are only
    72     relevant to the working copy.
    72     relevant to the working copy.
    73     '''
    73     """
    74 
    74 
    75     modified = attr.ib(default=attr.Factory(list))
    75     modified = attr.ib(default=attr.Factory(list))
    76     added = attr.ib(default=attr.Factory(list))
    76     added = attr.ib(default=attr.Factory(list))
    77     removed = attr.ib(default=attr.Factory(list))
    77     removed = attr.ib(default=attr.Factory(list))
    78     deleted = attr.ib(default=attr.Factory(list))
    78     deleted = attr.ib(default=attr.Factory(list))
   121     for subpath in missing:
   121     for subpath in missing:
   122         yield subpath, ctx2.nullsub(subpath, ctx1)
   122         yield subpath, ctx2.nullsub(subpath, ctx1)
   123 
   123 
   124 
   124 
   125 def nochangesfound(ui, repo, excluded=None):
   125 def nochangesfound(ui, repo, excluded=None):
   126     '''Report no changes for push/pull, excluded is None or a list of
   126     """Report no changes for push/pull, excluded is None or a list of
   127     nodes excluded from the push/pull.
   127     nodes excluded from the push/pull.
   128     '''
   128     """
   129     secretlist = []
   129     secretlist = []
   130     if excluded:
   130     if excluded:
   131         for n in excluded:
   131         for n in excluded:
   132             ctx = repo[n]
   132             ctx = repo[n]
   133             if ctx.phase() >= phases.secret and not ctx.extinct():
   133             if ctx.phase() >= phases.secret and not ctx.extinct():
   333                 raise error.InputError(msg)
   333                 raise error.InputError(msg)
   334             ui.warn(_(b"warning: %s\n") % msg)
   334             ui.warn(_(b"warning: %s\n") % msg)
   335 
   335 
   336 
   336 
   337 def checkportabilityalert(ui):
   337 def checkportabilityalert(ui):
   338     '''check if the user's config requests nothing, a warning, or abort for
   338     """check if the user's config requests nothing, a warning, or abort for
   339     non-portable filenames'''
   339     non-portable filenames"""
   340     val = ui.config(b'ui', b'portablefilenames')
   340     val = ui.config(b'ui', b'portablefilenames')
   341     lval = val.lower()
   341     lval = val.lower()
   342     bval = stringutil.parsebool(val)
   342     bval = stringutil.parsebool(val)
   343     abort = pycompat.iswindows or lval == b'abort'
   343     abort = pycompat.iswindows or lval == b'abort'
   344     warn = bval or lval == b'warn'
   344     warn = bval or lval == b'warn'
   400             cl._filteredrevs_hashcache[maxrev] = key
   400             cl._filteredrevs_hashcache[maxrev] = key
   401     return key
   401     return key
   402 
   402 
   403 
   403 
   404 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
   404 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
   405     '''yield every hg repository under path, always recursively.
   405     """yield every hg repository under path, always recursively.
   406     The recurse flag will only control recursion into repo working dirs'''
   406     The recurse flag will only control recursion into repo working dirs"""
   407 
   407 
   408     def errhandler(err):
   408     def errhandler(err):
   409         if err.filename == path:
   409         if err.filename == path:
   410             raise err
   410             raise err
   411 
   411 
   791         if windowsize < sizelimit:
   791         if windowsize < sizelimit:
   792             windowsize *= 2
   792             windowsize *= 2
   793 
   793 
   794 
   794 
   795 def walkchangerevs(repo, revs, makefilematcher, prepare):
   795 def walkchangerevs(repo, revs, makefilematcher, prepare):
   796     '''Iterate over files and the revs in a "windowed" way.
   796     """Iterate over files and the revs in a "windowed" way.
   797 
   797 
   798     Callers most commonly need to iterate backwards over the history
   798     Callers most commonly need to iterate backwards over the history
   799     in which they are interested. Doing so has awful (quadratic-looking)
   799     in which they are interested. Doing so has awful (quadratic-looking)
   800     performance, so we use iterators in a "windowed" way.
   800     performance, so we use iterators in a "windowed" way.
   801 
   801 
   803     window, we first walk forwards to gather data, then in the desired
   803     window, we first walk forwards to gather data, then in the desired
   804     order (usually backwards) to display it.
   804     order (usually backwards) to display it.
   805 
   805 
   806     This function returns an iterator yielding contexts. Before
   806     This function returns an iterator yielding contexts. Before
   807     yielding each context, the iterator will first call the prepare
   807     yielding each context, the iterator will first call the prepare
   808     function on each context in the window in forward order.'''
   808     function on each context in the window in forward order."""
   809 
   809 
   810     if not revs:
   810     if not revs:
   811         return []
   811         return []
   812     change = repo.__getitem__
   812     change = repo.__getitem__
   813 
   813 
   895     '''Create a new uipathfn that treats the file as relative to subpath.'''
   895     '''Create a new uipathfn that treats the file as relative to subpath.'''
   896     return lambda f: uipathfn(posixpath.join(subpath, f))
   896     return lambda f: uipathfn(posixpath.join(subpath, f))
   897 
   897 
   898 
   898 
   899 def anypats(pats, opts):
   899 def anypats(pats, opts):
   900     '''Checks if any patterns, including --include and --exclude were given.
   900     """Checks if any patterns, including --include and --exclude were given.
   901 
   901 
   902     Some commands (e.g. addremove) use this condition for deciding whether to
   902     Some commands (e.g. addremove) use this condition for deciding whether to
   903     print absolute or relative paths.
   903     print absolute or relative paths.
   904     '''
   904     """
   905     return bool(pats or opts.get(b'include') or opts.get(b'exclude'))
   905     return bool(pats or opts.get(b'include') or opts.get(b'exclude'))
   906 
   906 
   907 
   907 
   908 def expandpats(pats):
   908 def expandpats(pats):
   909     '''Expand bare globs when running on windows.
   909     """Expand bare globs when running on windows.
   910     On posix we assume it already has already been done by sh.'''
   910     On posix we assume it already has already been done by sh."""
   911     if not util.expandglobs:
   911     if not util.expandglobs:
   912         return list(pats)
   912         return list(pats)
   913     ret = []
   913     ret = []
   914     for kindpat in pats:
   914     for kindpat in pats:
   915         kind, pat = matchmod._patsplit(kindpat, None)
   915         kind, pat = matchmod._patsplit(kindpat, None)
   926 
   926 
   927 
   927 
   928 def matchandpats(
   928 def matchandpats(
   929     ctx, pats=(), opts=None, globbed=False, default=b'relpath', badfn=None
   929     ctx, pats=(), opts=None, globbed=False, default=b'relpath', badfn=None
   930 ):
   930 ):
   931     '''Return a matcher and the patterns that were used.
   931     """Return a matcher and the patterns that were used.
   932     The matcher will warn about bad matches, unless an alternate badfn callback
   932     The matcher will warn about bad matches, unless an alternate badfn callback
   933     is provided.'''
   933     is provided."""
   934     if opts is None:
   934     if opts is None:
   935         opts = {}
   935         opts = {}
   936     if not globbed and default == b'relpath':
   936     if not globbed and default == b'relpath':
   937         pats = expandpats(pats or [])
   937         pats = expandpats(pats or [])
   938 
   938 
   999         return None
   999         return None
  1000     return vfs.vfs(repo.wvfs.join(origbackuppath))
  1000     return vfs.vfs(repo.wvfs.join(origbackuppath))
  1001 
  1001 
  1002 
  1002 
  1003 def backuppath(ui, repo, filepath):
  1003 def backuppath(ui, repo, filepath):
  1004     '''customize where working copy backup files (.orig files) are created
  1004     """customize where working copy backup files (.orig files) are created
  1005 
  1005 
  1006     Fetch user defined path from config file: [ui] origbackuppath = <path>
  1006     Fetch user defined path from config file: [ui] origbackuppath = <path>
  1007     Fall back to default (filepath with .orig suffix) if not specified
  1007     Fall back to default (filepath with .orig suffix) if not specified
  1008 
  1008 
  1009     filepath is repo-relative
  1009     filepath is repo-relative
  1010 
  1010 
  1011     Returns an absolute path
  1011     Returns an absolute path
  1012     '''
  1012     """
  1013     origvfs = getorigvfs(ui, repo)
  1013     origvfs = getorigvfs(ui, repo)
  1014     if origvfs is None:
  1014     if origvfs is None:
  1015         return repo.wjoin(filepath + b".orig")
  1015         return repo.wjoin(filepath + b".orig")
  1016 
  1016 
  1017     origbackupdir = origvfs.dirname(filepath)
  1017     origbackupdir = origvfs.dirname(filepath)
  1298             return 1
  1298             return 1
  1299     return ret
  1299     return ret
  1300 
  1300 
  1301 
  1301 
  1302 def marktouched(repo, files, similarity=0.0):
  1302 def marktouched(repo, files, similarity=0.0):
  1303     '''Assert that files have somehow been operated upon. files are relative to
  1303     """Assert that files have somehow been operated upon. files are relative to
  1304     the repo root.'''
  1304     the repo root."""
  1305     m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
  1305     m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
  1306     rejected = []
  1306     rejected = []
  1307 
  1307 
  1308     added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
  1308     added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
  1309 
  1309 
  1333             return 1
  1333             return 1
  1334     return 0
  1334     return 0
  1335 
  1335 
  1336 
  1336 
  1337 def _interestingfiles(repo, matcher):
  1337 def _interestingfiles(repo, matcher):
  1338     '''Walk dirstate with matcher, looking for files that addremove would care
  1338     """Walk dirstate with matcher, looking for files that addremove would care
  1339     about.
  1339     about.
  1340 
  1340 
  1341     This is different from dirstate.status because it doesn't care about
  1341     This is different from dirstate.status because it doesn't care about
  1342     whether files are modified or clean.'''
  1342     whether files are modified or clean."""
  1343     added, unknown, deleted, removed, forgotten = [], [], [], [], []
  1343     added, unknown, deleted, removed, forgotten = [], [], [], [], []
  1344     audit_path = pathutil.pathauditor(repo.root, cached=True)
  1344     audit_path = pathutil.pathauditor(repo.root, cached=True)
  1345 
  1345 
  1346     ctx = repo[None]
  1346     ctx = repo[None]
  1347     dirstate = repo.dirstate
  1347     dirstate = repo.dirstate
  1392             renames[new] = old
  1392             renames[new] = old
  1393     return renames
  1393     return renames
  1394 
  1394 
  1395 
  1395 
  1396 def _markchanges(repo, unknown, deleted, renames):
  1396 def _markchanges(repo, unknown, deleted, renames):
  1397     '''Marks the files in unknown as added, the files in deleted as removed,
  1397     """Marks the files in unknown as added, the files in deleted as removed,
  1398     and the files in renames as copied.'''
  1398     and the files in renames as copied."""
  1399     wctx = repo[None]
  1399     wctx = repo[None]
  1400     with repo.wlock():
  1400     with repo.wlock():
  1401         wctx.forget(deleted)
  1401         wctx.forget(deleted)
  1402         wctx.add(unknown)
  1402         wctx.add(unknown)
  1403         for new, old in pycompat.iteritems(renames):
  1403         for new, old in pycompat.iteritems(renames):
  1422     rcache = {}
  1422     rcache = {}
  1423     if endrev is None:
  1423     if endrev is None:
  1424         endrev = len(repo)
  1424         endrev = len(repo)
  1425 
  1425 
  1426     def getrenamed(fn, rev):
  1426     def getrenamed(fn, rev):
  1427         '''looks up all renames for a file (up to endrev) the first
  1427         """looks up all renames for a file (up to endrev) the first
  1428         time the file is given. It indexes on the changerev and only
  1428         time the file is given. It indexes on the changerev and only
  1429         parses the manifest if linkrev != changerev.
  1429         parses the manifest if linkrev != changerev.
  1430         Returns rename info for fn at changerev rev.'''
  1430         Returns rename info for fn at changerev rev."""
  1431         if fn not in rcache:
  1431         if fn not in rcache:
  1432             rcache[fn] = {}
  1432             rcache[fn] = {}
  1433             fl = repo.file(fn)
  1433             fl = repo.file(fn)
  1434             for i in fl:
  1434             for i in fl:
  1435                 lr = fl.linkrev(i)
  1435                 lr = fl.linkrev(i)
  1546         ds.copy(src, dst)
  1546         ds.copy(src, dst)
  1547     repo._quick_access_changeid_invalidate()
  1547     repo._quick_access_changeid_invalidate()
  1548 
  1548 
  1549 
  1549 
  1550 def filterrequirements(requirements):
  1550 def filterrequirements(requirements):
  1551     """ filters the requirements into two sets:
  1551     """filters the requirements into two sets:
  1552 
  1552 
  1553     wcreq: requirements which should be written in .hg/requires
  1553     wcreq: requirements which should be written in .hg/requires
  1554     storereq: which should be written in .hg/store/requires
  1554     storereq: which should be written in .hg/store/requires
  1555 
  1555 
  1556     Returns (wcreq, storereq)
  1556     Returns (wcreq, storereq)
  1869         else:
  1869         else:
  1870             self.ui.debug(b'%s:%s %d%s\n' % (self.topic, item, self.pos, unit))
  1870             self.ui.debug(b'%s:%s %d%s\n' % (self.topic, item, self.pos, unit))
  1871 
  1871 
  1872 
  1872 
  1873 def gdinitconfig(ui):
  1873 def gdinitconfig(ui):
  1874     """helper function to know if a repo should be created as general delta
  1874     """helper function to know if a repo should be created as general delta"""
  1875     """
       
  1876     # experimental config: format.generaldelta
  1875     # experimental config: format.generaldelta
  1877     return ui.configbool(b'format', b'generaldelta') or ui.configbool(
  1876     return ui.configbool(b'format', b'generaldelta') or ui.configbool(
  1878         b'format', b'usegeneraldelta'
  1877         b'format', b'usegeneraldelta'
  1879     )
  1878     )
  1880 
  1879 
  1881 
  1880 
  1882 def gddeltaconfig(ui):
  1881 def gddeltaconfig(ui):
  1883     """helper function to know if incoming delta should be optimised
  1882     """helper function to know if incoming delta should be optimised"""
  1884     """
       
  1885     # experimental config: format.generaldelta
  1883     # experimental config: format.generaldelta
  1886     return ui.configbool(b'format', b'generaldelta')
  1884     return ui.configbool(b'format', b'generaldelta')
  1887 
  1885 
  1888 
  1886 
  1889 class simplekeyvaluefile(object):
  1887 class simplekeyvaluefile(object):