##// END OF EJS Templates
interfaces: make the `peer` mixin not a Protocol to fix Python 3.10 failures...
interfaces: make the `peer` mixin not a Protocol to fix Python 3.10 failures I can't find any documentation on this, but it appears that Protocol class attributes don't get inherited in subclasses that explicitly subclass a Protocol until Python 3.11, which caused a ton of failures in CI on macOS and Windows (which both test using Python 3.9). The problem started with 1df97507c6b8, and typically manifested as most tests failing to access `ui` on various `peer` classes. Here's a short proof of concept: from __future__ import annotations from typing import ( Protocol, ) class peer(Protocol): limitedarguments: bool = False def __init__(self, arg1, arg2, remotehidden: bool = False) -> None: self.arg1 = arg1 self.arg2 = arg2 class subclass(peer): def __init__(self, arg1, arg2): super(subclass, self).__init__(arg1, arg2, False) sub = subclass(1, 2) print("sub.arg1 is %r" % sub.arg1) When run with Python 3.8.10, 3.9.13, and 3.10.11, the result is: $ py -3.8 prot-test.py Traceback (most recent call last): File "prot-test.py", line 20, in <module> print("sub.arg1 is %r" % sub.arg1) AttributeError: 'subclass' object has no attribute 'arg1' On Python 3.11.9, 3.12.7, and 3.13.0, the result is: $ py -3.11 ../prot-test.py sub.arg1 is 1 Explicitly adding annotations to `peer` like `limitedarguments` didn't help.

File last commit:

r53348:f5d134e5 default
r53403:199b0e62 default
Show More
scmutil.py
2529 lines | 83.0 KiB | text/x-python | PythonLexer
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 # scmutil.py - Mercurial core utility functions
#
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright Olivia Mackall <olivia@selenic.com>
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 #
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Matt Harbison
typing: add `from __future__ import annotations` to most files...
r52756 from __future__ import annotations
Gregory Szorc
scmutil: use absolute_import
r27482
Manuel Jacob
node: stop converting binascii.Error to TypeError in bin()...
r50143 import binascii
Gregory Szorc
scmutil: use absolute_import
r27482 import errno
import glob
import os
Martin von Zweigbergk
add: pass around uipathfn and use instead of m.rel() (API)...
r41799 import posixpath
Gregory Szorc
scmutil: use absolute_import
r27482 import re
Yuya Nishihara
extdata: use subprocess so we don't have to chdir() manually
r34462 import subprocess
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622 import typing
obsolete: reports the number of local changeset obsoleted when unbundling...
r33249 import weakref
Gregory Szorc
scmutil: use absolute_import
r27482
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 from typing import (
Callable,
Dict,
Iterable,
Iterator,
List,
Optional,
Set,
Tuple,
)
Gregory Szorc
scmutil: use absolute_import
r27482 from .i18n import _
Yuya Nishihara
scmutil: introduce binnode(ctx) as paired function with intrev(ctx)...
r32656 from .node import (
Martin von Zweigbergk
scmutil: handle full hex nodeids in revsymbol()...
r37546 bin,
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 hex,
Martin von Zweigbergk
repo: look up nullrev context by revnum, not symbolic name...
r39930 nullrev,
Yuya Nishihara
scmutil: extract helper functions that returns human-readable change id...
r34328 short,
Yuya Nishihara
scmutil: introduce binnode(ctx) as paired function with intrev(ctx)...
r32656 wdirrev,
)
Augie Fackler
scmutil: convert status data object from a tuple to an attrs (API)...
r44053 from .thirdparty import attr
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622
# Force pytype to use the non-vendored package
if typing.TYPE_CHECKING:
# noinspection PyPackageRequirements
import attr
Gregory Szorc
scmutil: use absolute_import
r27482 from . import (
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103 copies as copiesmod,
Gregory Szorc
scmutil: use absolute_import
r27482 encoding,
error,
match as matchmod,
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 obsolete,
obsolete: reports the number of local changeset obsoleted when unbundling...
r33249 obsutil,
Gregory Szorc
scmutil: use absolute_import
r27482 pathutil,
phases,
Martin von Zweigbergk
shortest: use nodetree for finding shortest node within revset...
r39262 policy,
Pulkit Goyal
py3: make scmutil.rcpath() return bytes...
r30305 pycompat,
Pulkit Goyal
scmutil: introduce filterrequirements() to split reqs into wc and store ones...
r46054 requirements as requirementsmod,
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 revsetlang,
Gregory Szorc
scmutil: use absolute_import
r27482 similar,
Boris Feld
pullreport: skip filtered revs instead of obsolete ones...
r39933 smartset,
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 typelib,
Matt Mackall
extdata: add extdatasource reader...
r34457 url,
Gregory Szorc
scmutil: use absolute_import
r27482 util,
Mark Thomas
scmutil: handle conflicting files and dirs in origbackuppath...
r34544 vfs,
Gregory Szorc
scmutil: use absolute_import
r27482 )
Kevin Bullock
scmutil: split platform-specific bits into their own modules...
r18690
Matt Harbison
scmutil: explicitly subclass the `Status` protocol...
r53348 from .interfaces import status as istatus
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from .utils import (
Augie Fackler
core: migrate uses of hashlib.sha1 to hashutil.sha1...
r44517 hashutil,
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 procutil,
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 stringutil,
)
Jun Wu
codemod: use pycompat.iswindows...
r34646 if pycompat.iswindows:
Gregory Szorc
scmutil: use absolute_import
r27482 from . import scmwindows as scmplatform
Kevin Bullock
scmutil: split platform-specific bits into their own modules...
r18690 else:
Gregory Szorc
scmutil: use absolute_import
r27482 from . import scmposix as scmplatform
Kevin Bullock
scmutil: split platform-specific bits into their own modules...
r18690
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 if typing.TYPE_CHECKING:
from . import (
ui as uimod,
)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 parsers = policy.importmod('parsers')
Georges Racinet
rust-index: use the new method in shortesthexnodeidprefix...
r44465 rustrevlog = policy.importrust('revlog')
Martin von Zweigbergk
shortest: use nodetree for finding shortest node within revset...
r39262
Yuya Nishihara
scmutil: extend termwidth() to return terminal height, renamed to termsize()...
r30314 termsize = scmplatform.termsize
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
scmutil: convert status data object from a tuple to an attrs (API)...
r44053 @attr.s(slots=True, repr=False)
Matt Harbison
scmutil: explicitly subclass the `Status` protocol...
r53348 class status(istatus.Status):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Struct with a list of files per status.
Augie Fackler
scmutil: convert status data object from a tuple to an attrs (API)...
r44053
The 'deleted', 'unknown' and 'ignored' properties are only
relevant to the working copy.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Martin von Zweigbergk
status: create class for status lists...
r22913
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 modified = attr.ib(default=attr.Factory(list), type=List[bytes])
added = attr.ib(default=attr.Factory(list), type=List[bytes])
removed = attr.ib(default=attr.Factory(list), type=List[bytes])
deleted = attr.ib(default=attr.Factory(list), type=List[bytes])
unknown = attr.ib(default=attr.Factory(list), type=List[bytes])
ignored = attr.ib(default=attr.Factory(list), type=List[bytes])
clean = attr.ib(default=attr.Factory(list), type=List[bytes])
def __iter__(self) -> Iterator[List[bytes]]:
Augie Fackler
scmutil: convert status data object from a tuple to an attrs (API)...
r44053 yield self.modified
yield self.added
yield self.removed
yield self.deleted
yield self.unknown
yield self.ignored
yield self.clean
Martin von Zweigbergk
status: create class for status lists...
r22913
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def __repr__(self) -> str:
Augie Fackler
formatting: blacken the codebase...
r43346 return (
r'<status modified=%s, added=%s, removed=%s, deleted=%s, '
r'unknown=%s, ignored=%s, clean=%s>'
) % tuple(pycompat.sysstr(stringutil.pprint(v)) for v in self)
Martin von Zweigbergk
status: create class for status lists...
r22913
Augie Fackler
itersubrepos: move to scmutil to break a direct import cycle
r20392 def itersubrepos(ctx1, ctx2):
"""find subrepos in ctx1 or ctx2"""
# Create a (subpath, ctx) mapping where we prefer subpaths from
# ctx1. The subpaths from ctx2 are important when the .hgsub file
# has been modified (in ctx2) but not yet committed (in ctx1).
subpaths = dict.fromkeys(ctx2.substate, ctx2)
subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
Matt Harbison
scmutil: consistently return subrepos relative to ctx1 from itersubrepos()...
r25418
missing = set()
for subpath in ctx2.substate:
if subpath not in ctx1.substate:
del subpaths[subpath]
missing.add(subpath)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for subpath, ctx in sorted(subpaths.items()):
Augie Fackler
itersubrepos: move to scmutil to break a direct import cycle
r20392 yield subpath, ctx.sub(subpath)
Matt Harbison
scmutil: consistently return subrepos relative to ctx1 from itersubrepos()...
r25418 # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
# status and diff will have an accurate result when it does
# 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
# against itself.
for subpath in missing:
yield subpath, ctx2.nullsub(subpath, ctx1)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def nochangesfound(ui: "uimod.ui", repo, excluded=None) -> None:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Report no changes for push/pull, excluded is None or a list of
Patrick Mezard
discovery: add extinct changesets to outgoing.excluded...
r17248 nodes excluded from the push/pull.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Patrick Mezard
discovery: add extinct changesets to outgoing.excluded...
r17248 secretlist = []
if excluded:
for n in excluded:
ctx = repo[n]
if ctx.phase() >= phases.secret and not ctx.extinct():
secretlist.append(n)
Matt Mackall
scmutil: unify some 'no changes found' messages...
r15993 if secretlist:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.status(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"no changes found (ignored %d secret changesets)\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % len(secretlist)
)
Matt Mackall
scmutil: unify some 'no changes found' messages...
r15993 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b"no changes found\n"))
Matt Mackall
scmutil: unify some 'no changes found' messages...
r15993
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def callcatch(ui: "uimod.ui", func: Callable[[], int]) -> int:
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 """call func() with global exception handling
return func() if no exception happens. otherwise do some error handling
and return an exit code accordingly. does not handle all exceptions.
"""
Martin von Zweigbergk
errors: add config that lets user get more detailed exit codes...
r46430 coarse_exit_code = -1
detailed_exit_code = -1
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 try:
Yuya Nishihara
dispatch: print traceback in scmutil.callcatch() if --traceback specified...
r32041 try:
return func()
Augie Fackler
formatting: blacken the codebase...
r43346 except: # re-raises
Yuya Nishihara
dispatch: print traceback in scmutil.callcatch() if --traceback specified...
r32041 ui.traceback()
raise
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 # Global exception handling, alphabetically
# Mercurial-specific first, followed by built-in and library exceptions
except error.LockHeld as inst:
Martin von Zweigbergk
errors: set detailed exit code to 20 for locking errors...
r46432 detailed_exit_code = 20
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 if inst.errno == errno.ETIMEDOUT:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 reason = _(b'timed out waiting for lock held by %r') % (
Augie Fackler
formatting: blacken the codebase...
r43346 pycompat.bytestr(inst.locker)
)
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 reason = _(b'lock held by %r') % inst.locker
Augie Fackler
formatting: blacken the codebase...
r43346 ui.error(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"abort: %s: %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (inst.desc or stringutil.forcebytestr(inst.filename), reason)
)
FUJIWARA Katsunori
lock: avoid unintentional lock acquisition at failure of readlock...
r32089 if not inst.locker:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b"(lock might be very busy)\n"))
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except error.LockUnavailable as inst:
Martin von Zweigbergk
errors: set detailed exit code to 20 for locking errors...
r46432 detailed_exit_code = 20
Augie Fackler
formatting: blacken the codebase...
r43346 ui.error(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"abort: could not lock %s: %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (
inst.desc or stringutil.forcebytestr(inst.filename),
encoding.strtolocal(inst.strerror),
)
)
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except error.RepoError as inst:
Martin von Zweigbergk
errors: use detailed exit code for RepoLookupError...
r49191 if isinstance(inst, error.RepoLookupError):
detailed_exit_code = 10
Martin von Zweigbergk
errors: remove trailing "!" from some error messages for consistency...
r46518 ui.error(_(b"abort: %s\n") % inst)
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 if inst.hint:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b"(%s)\n") % inst.hint)
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except error.ResponseError as inst:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b"abort: %s") % inst.args[0])
Augie Fackler
scmutil: avoid using basestring and add explicit handling of unicodes...
r36679 msg = inst.args[1]
if isinstance(msg, type(u'')):
msg = pycompat.sysbytes(msg)
Valentin Gatien-Baron
wireprotov1peer: don't raise internal errors in some cases...
r47430 if msg is None:
ui.error(b"\n")
elif not isinstance(msg, bytes):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(b" %r\n" % (msg,))
Augie Fackler
scmutil: fix oversight in b76248e51605c6 where I forgot to use msg...
r36713 elif not msg:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b" empty string\n"))
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(b"\n%r\n" % pycompat.bytestr(stringutil.ellipsis(msg)))
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except error.CensoredNodeError as inst:
Martin von Zweigbergk
errors: remove trailing "!" from some error messages for consistency...
r46518 ui.error(_(b"abort: file censored %s\n") % inst)
Yuya Nishihara
revlog: map rev(wdirid) to WdirUnsupported exception...
r32657 except error.WdirUnsupported:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b"abort: working directory revision cannot be specified\n"))
Martin von Zweigbergk
errors: catch the new Error class in scmutil and chgserver...
r48073 except error.Error as inst:
Martin von Zweigbergk
errors: let each Abort subclass define its error code...
r48069 if inst.detailed_exit_code is not None:
detailed_exit_code = inst.detailed_exit_code
Martin von Zweigbergk
errors: make InterventionRequired subclass Abort...
r48071 if inst.coarse_exit_code is not None:
coarse_exit_code = inst.coarse_exit_code
Martin von Zweigbergk
errors: format "abort: " text in a new Abort.format() method...
r46497 ui.error(inst.format())
Martin von Zweigbergk
worker: raise exception instead of calling sys.exit() with child's code...
r46429 except error.WorkerError as inst:
# Don't print a message -- the worker already should have
return inst.status_code
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except ImportError as inst:
Martin von Zweigbergk
errors: remove trailing "!" from some error messages for consistency...
r46518 ui.error(_(b"abort: %s\n") % stringutil.forcebytestr(inst))
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 m = stringutil.forcebytestr(inst).split()[-1]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if m in b"mpatch bdiff".split():
ui.error(_(b"(did you forget to compile extensions?)\n"))
elif m in b"zlib".split():
ui.error(_(b"(is your Python install correct?)\n"))
Martin von Zweigbergk
errors: catch urllib errors specifically instead of using safehasattr()...
r46442 except util.urlerr.httperror as inst:
Martin von Zweigbergk
errors: set detailed exit code to 100 for some remote errors...
r46443 detailed_exit_code = 100
Martin von Zweigbergk
errors: catch urllib errors specifically instead of using safehasattr()...
r46442 ui.error(_(b"abort: %s\n") % stringutil.forcebytestr(inst))
except util.urlerr.urlerror as inst:
Martin von Zweigbergk
errors: set detailed exit code to 100 for some remote errors...
r46443 detailed_exit_code = 100
Martin von Zweigbergk
errors: catch urllib errors specifically instead of using safehasattr()...
r46442 try: # usually it is in the form (errno, strerror)
reason = inst.reason.args[1]
except (AttributeError, IndexError):
# it might be anything, for example a string
reason = inst.reason
Gregory Szorc
py3: use str instead of pycompat.unicode...
r49789 if isinstance(reason, str):
Martin von Zweigbergk
errors: catch urllib errors specifically instead of using safehasattr()...
r46442 # SSLError of Python 2.7.9 contains a unicode
reason = encoding.unitolocal(reason)
ui.error(_(b"abort: error: %s\n") % stringutil.forcebytestr(reason))
Yuya Nishihara
dispatch: unify handler of IOError and OSError...
r41466 except (IOError, OSError) as inst:
safehasattr: drop usage in favor of hasattr...
r51821 if hasattr(inst, "args") and inst.args and inst.args[0] == errno.EPIPE:
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 pass
Augie Fackler
formatting: blacken the codebase...
r43346 elif getattr(inst, "strerror", None): # common IOError or OSError
Yuya Nishihara
dispatch: quote filename in IOError as well...
r41465 if getattr(inst, "filename", None) is not None:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.error(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"abort: %s: '%s'\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (
encoding.strtolocal(inst.strerror),
stringutil.forcebytestr(inst.filename),
)
)
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b"abort: %s\n") % encoding.strtolocal(inst.strerror))
Augie Fackler
formatting: blacken the codebase...
r43346 else: # suspicious IOError
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 raise
except MemoryError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.error(_(b"abort: out of memory\n"))
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520 except SystemExit as inst:
# Commands shouldn't sys.exit directly, but give a return code.
# Just in case catch this and and pass exit code to caller.
Martin von Zweigbergk
errors: add config that lets user get more detailed exit codes...
r46430 detailed_exit_code = 254
coarse_exit_code = inst.code
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520
Martin von Zweigbergk
errors: add config that lets user get more detailed exit codes...
r46430 if ui.configbool(b'ui', b'detailed-exit-code'):
return detailed_exit_code
else:
return coarse_exit_code
Jun Wu
dispatch: move part of callcatch to scmutil...
r30520
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def checknewlabel(repo, lbl: bytes, kind) -> None:
Durham Goode
translations: change label integer error to not specify the kind of label...
r19070 # Do not use the "kind" parameter in ui output.
# It makes strings difficult to translate.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if lbl in [b'tip', b'.', b'null']:
Martin von Zweigbergk
errors: use InputError for errors about bad label names (tags etc)...
r46449 raise error.InputError(_(b"the name '%s' is reserved") % lbl)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for c in (b':', b'\0', b'\n', b'\r'):
Kevin Bullock
scmutil: add bad character checking to checknewlabel...
r17821 if c in lbl:
Martin von Zweigbergk
errors: use InputError for errors about bad label names (tags etc)...
r46449 raise error.InputError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"%r cannot be used in a name") % pycompat.bytestr(c)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Durham Goode
bookmark: don't allow integers as bookmark/branch/tag names...
r18566 try:
int(lbl)
av6
scmutil: make checknewlabel() allow "_" in otherwise numeric names (issue6737)
r50863 if b'_' in lbl:
# If label contains underscores, Python might consider it an
# integer (with "_" as visual separators), but we do not.
# See PEP 515 - Underscores in Numeric Literals.
raise ValueError
Martin von Zweigbergk
errors: use InputError for errors about bad label names (tags etc)...
r46449 raise error.InputError(_(b"cannot use an integer as a name"))
Durham Goode
bookmark: don't allow integers as bookmark/branch/tag names...
r18566 except ValueError:
pass
Boris Feld
label: enforce the lack of leading or trailing white space...
r36162 if lbl.strip() != lbl:
Martin von Zweigbergk
errors: use InputError for errors about bad label names (tags etc)...
r46449 raise error.InputError(
_(b"leading or trailing whitespace in name %r") % lbl
)
Kevin Bullock
scmutil: add function to validate new branch, tag, and bookmark names...
r17817
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def checkfilename(f: bytes) -> None:
Adrian Buehlmann
move checkfilename from util to scmutil...
r13974 '''Check that the filename f is an acceptable filename for a tracked file'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'\r' in f or b'\n' in f:
Martin von Zweigbergk
errors: use InputError for errors about bad paths...
r46448 raise error.InputError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"'\\n' and '\\r' disallowed in filenames: %r")
Augie Fackler
formatting: blacken the codebase...
r43346 % pycompat.bytestr(f)
)
Adrian Buehlmann
move checkfilename from util to scmutil...
r13974
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def checkportable(ui: "uimod.ui", f: bytes) -> None:
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 '''Check if filename f is portable and warn or abort depending on config'''
Adrian Buehlmann
move checkfilename from util to scmutil...
r13974 checkfilename(f)
Adrian Buehlmann
scmutil: introduce casecollisionauditor...
r14138 abort, warn = checkportabilityalert(ui)
if abort or warn:
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 msg = util.checkwinfilename(f)
if msg:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b"%s: %s" % (msg, procutil.shellquote(f))
Adrian Buehlmann
scmutil: introduce casecollisionauditor...
r14138 if abort:
Martin von Zweigbergk
errors: use InputError for errors about bad paths...
r46448 raise error.InputError(msg)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.warn(_(b"warning: %s\n") % msg)
Kevin Gessner
add: notify when adding a file that would cause a case-folding collision...
r14068
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def checkportabilityalert(ui: "uimod.ui") -> Tuple[bool, bool]:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """check if the user's config requests nothing, a warning, or abort for
non-portable filenames"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 val = ui.config(b'ui', b'portablefilenames')
Kevin Gessner
scmutil: refactor ui.portablefilenames processing...
r14067 lval = val.lower()
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 bval = stringutil.parsebool(val)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 abort = pycompat.iswindows or lval == b'abort'
warn = bval or lval == b'warn'
if bval is None and not (warn or abort or lval == b'ignore'):
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 raise error.ConfigError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"ui.portablefilenames value is invalid ('%s')") % val
Augie Fackler
formatting: blacken the codebase...
r43346 )
Kevin Gessner
scmutil: refactor ui.portablefilenames processing...
r14067 return abort, warn
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class casecollisionauditor:
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def __init__(self, ui: "uimod.ui", abort: bool, dirstate) -> None:
Adrian Buehlmann
scmutil: introduce casecollisionauditor...
r14138 self._ui = ui
self._abort = abort
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 allfiles = b'\0'.join(dirstate)
self._loweredfiles = set(encoding.lower(allfiles).split(b'\0'))
Joshua Redstone
scmutil: 25% speedup in casecollisionauditor...
r17201 self._dirstate = dirstate
# The purpose of _newfiles is so that we don't complain about
# case collisions if someone were to call this object with the
# same filename twice.
self._newfiles = set()
Kevin Gessner
scmutil: refactor ui.portablefilenames processing...
r14067
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def __call__(self, f: bytes) -> None:
FUJIWARA Katsunori
scmutil: skip checks in "casecollisionauditor" if filename is already checked...
r20006 if f in self._newfiles:
return
FUJIWARA Katsunori
i18n: use UTF-8 string to lower filename for case collision check...
r14980 fl = encoding.lower(f)
FUJIWARA Katsunori
scmutil: skip checks in "casecollisionauditor" if filename is already checked...
r20006 if fl in self._loweredfiles and f not in self._dirstate:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'possible case-folding collision for %s') % f
Adrian Buehlmann
scmutil: introduce casecollisionauditor...
r14138 if self._abort:
Martin von Zweigbergk
errors: use detailed exit code for detected case-collision...
r49190 raise error.StateError(msg)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._ui.warn(_(b"warning: %s\n") % msg)
Joshua Redstone
scmutil: 25% speedup in casecollisionauditor...
r17201 self._loweredfiles.add(fl)
self._newfiles.add(f)
Adrian Buehlmann
move opener from util to scmutil
r13970
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def combined_filtered_and_obsolete_hash(
repo, maxrev, needobsolete: bool = False
):
Gregory Szorc
repoview: move function for computing filtered hash...
r24723 """build hash of filtered revisions in the current repoview.
Multiple caches perform up-to-date validation by checking that the
tiprev and tipnode stored in the cache file match the current repository.
However, this is not sufficient for validating repoviews because the set
of revisions in the view may change without the repository tiprev and
tipnode changing.
av6
branchmap: skip obsolete revisions while computing heads...
r49536 This function hashes all the revs filtered from the view (and, optionally,
all obsolete revs) up to maxrev and returns that SHA-1 digest.
Gregory Szorc
repoview: move function for computing filtered hash...
r24723 """
cl = repo.changelog
av6
branchmap: skip obsolete revisions while computing heads...
r49536 if needobsolete:
obsrevs = obsolete.getrevs(repo, b'obsolete')
if not cl.filteredrevs and not obsrevs:
return None
av6
scmutil: obsrevs is already a frozenset...
r49575 key = (maxrev, hash(cl.filteredrevs), hash(obsrevs))
av6
branchmap: skip obsolete revisions while computing heads...
r49536 else:
if not cl.filteredrevs:
return None
key = maxrev
obsrevs = frozenset()
result = cl._filteredrevs_hashcache.get(key)
if not result:
filteredhash: split the computation of revision sets...
r52418 revs, obs_revs = _filtered_and_obs_revs(repo, maxrev)
if needobsolete:
revs = revs | obs_revs
revs = sorted(revs)
Kyle Lippincott
branchmap: add a cache validation cache, avoid expensive re-hash on every use...
r46088 if revs:
filteredhash: move the hashing in its own function...
r52417 result = _hash_revs(revs)
av6
branchmap: skip obsolete revisions while computing heads...
r49536 cl._filteredrevs_hashcache[key] = result
return result
Gregory Szorc
repoview: move function for computing filtered hash...
r24723
Augie Fackler
formatting: blacken the codebase...
r43346
branchcache: store filtered hash and obsolete hash independently for V3...
r52422 def filtered_and_obsolete_hash(repo, maxrev):
"""build hashs of filtered and obsolete revisions in the current repoview.
Multiple caches perform up-to-date validation by checking that the
tiprev and tipnode stored in the cache file match the current repository.
However, this is not sufficient for validating repoviews because the set
of revisions in the view may change without the repository tiprev and
tipnode changing.
This function hashes all the revs filtered from the view up to maxrev and
returns that SHA-1 digest. The obsolete revisions hashed are only the
non-filtered one.
"""
cl = repo.changelog
obs_set = obsolete.getrevs(repo, b'obsolete')
key = (maxrev, hash(cl.filteredrevs), hash(obs_set))
result = cl._filteredrevs_hashcache.get(key)
if result is None:
filtered_hash = None
obs_hash = None
filtered_revs, obs_revs = _filtered_and_obs_revs(repo, maxrev)
if filtered_revs:
filtered_hash = _hash_revs(filtered_revs)
if obs_revs:
obs_hash = _hash_revs(obs_revs)
result = (filtered_hash, obs_hash)
cl._filteredrevs_hashcache[key] = result
return result
filteredhash: split the computation of revision sets...
r52418 def _filtered_and_obs_revs(repo, max_rev):
"""return the set of filtered and non-filtered obsolete revision"""
cl = repo.changelog
obs_set = obsolete.getrevs(repo, b'obsolete')
filtered_set = cl.filteredrevs
if cl.filteredrevs:
obs_set = obs_set - cl.filteredrevs
if max_rev < (len(cl) - 1):
# there might be revision to filter out
filtered_set = set(r for r in filtered_set if r <= max_rev)
obs_set = set(r for r in obs_set if r <= max_rev)
return (filtered_set, obs_set)
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _hash_revs(revs: Iterable[int]) -> bytes:
filteredhash: move the hashing in its own function...
r52417 """return a hash from a list of revision numbers"""
s = hashutil.sha1()
for rev in revs:
s.update(b'%d;' % rev)
return s.digest()
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def walkrepos(
path,
followsym: bool = False,
seen_dirs: Optional[List[bytes]] = None,
recurse: bool = False,
) -> Iterable[bytes]:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """yield every hg repository under path, always recursively.
The recurse flag will only control recursion into repo working dirs"""
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 def errhandler(err):
if err.filename == path:
raise err
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
walkrepos: use getattr instead of hasattr for samestat
r14961 samestat = getattr(os.path, 'samestat', None)
if followsym and samestat is not None:
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
scmutil: rename local function _add_dir_if_not_there
r14227 def adddir(dirlst, dirname):
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 dirstat = os.stat(dirname)
Martin von Zweigbergk
walkrepos: don't reimplement any()...
r36356 match = any(samestat(dirstat, lstdirstat) for lstdirstat in dirlst)
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 if not match:
dirlst.append(dirstat)
return not match
Augie Fackler
formatting: blacken the codebase...
r43346
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 else:
followsym = False
if (seen_dirs is None) and followsym:
seen_dirs = []
Adrian Buehlmann
scmutil: rename local function _add_dir_if_not_there
r14227 adddir(seen_dirs, path)
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
dirs.sort()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'.hg' in dirs:
Augie Fackler
formatting: blacken the codebase...
r43346 yield root # found a repository
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 qroot = os.path.join(root, b'.hg', b'patches')
if os.path.isdir(os.path.join(qroot, b'.hg')):
Augie Fackler
formatting: blacken the codebase...
r43346 yield qroot # we have a patch queue repo here
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 if recurse:
# avoid recursing inside the .hg directory
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dirs.remove(b'.hg')
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 else:
Augie Fackler
formatting: blacken the codebase...
r43346 dirs[:] = [] # don't descend further
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 elif followsym:
newdirs = []
for d in dirs:
fname = os.path.join(root, d)
Adrian Buehlmann
scmutil: rename local function _add_dir_if_not_there
r14227 if adddir(seen_dirs, fname):
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 if os.path.islink(fname):
for hgname in walkrepos(fname, True, seen_dirs):
yield hgname
else:
newdirs.append(d)
dirs[:] = newdirs
Adrian Buehlmann
move rcpath from util to scmutil
r13984
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def binnode(ctx) -> bytes:
Yuya Nishihara
scmutil: introduce binnode(ctx) as paired function with intrev(ctx)...
r32656 """Return binary node id for a given basectx"""
node = ctx.node()
if node is None:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 return ctx.repo().nodeconstants.wdirid
Yuya Nishihara
scmutil: introduce binnode(ctx) as paired function with intrev(ctx)...
r32656 return node
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def intrev(ctx) -> int:
Yuya Nishihara
scmutil: pass ctx object to intrev()...
r32654 """Return integer for a given basectx that can be used in comparison or
Yuya Nishihara
scmutil: add function to help handling workingctx in arithmetic operation...
r24582 arithmetic operation"""
Yuya Nishihara
scmutil: pass ctx object to intrev()...
r32654 rev = ctx.rev()
Yuya Nishihara
scmutil: add function to help handling workingctx in arithmetic operation...
r24582 if rev is None:
Yuya Nishihara
changeset_printer: use node.wdirrev to calculate meaningful parentrevs...
r25739 return wdirrev
Yuya Nishihara
scmutil: add function to help handling workingctx in arithmetic operation...
r24582 return rev
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def formatchangeid(ctx) -> bytes:
Yuya Nishihara
scmutil: extract helper functions that returns human-readable change id...
r34328 """Format changectx as '{rev}:{node|formatnode}', which is the default
Yuya Nishihara
cmdutil: drop aliases for logcmdutil functions (API)...
r35906 template provided by logcmdutil.changesettemplater"""
Yuya Nishihara
scmutil: extract helper functions that returns human-readable change id...
r34328 repo = ctx.repo()
return formatrevnode(repo.ui, intrev(ctx), binnode(ctx))
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def formatrevnode(ui: "uimod.ui", rev: int, node: bytes) -> bytes:
Yuya Nishihara
scmutil: extract helper functions that returns human-readable change id...
r34328 """Format given revision and node depending on the current verbosity"""
if ui.debugflag:
hexfunc = hex
else:
hexfunc = short
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'%d:%s' % (rev, hexfunc(node))
Yuya Nishihara
scmutil: extract helper functions that returns human-readable change id...
r34328
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def resolvehexnodeidprefix(repo, prefix: bytes):
Martin von Zweigbergk
revisions: parse "x123" as "nodeid starting with 123" without prefixhexnode...
r45324 if prefix.startswith(b'x'):
Martin von Zweigbergk
revisions: allow "x123" to refer to nodeid prefix "123"...
r38891 prefix = prefix[1:]
Martin von Zweigbergk
lookup: add option to disambiguate prefix within revset...
r38878 try:
# Uses unfiltered repo because it's faster when prefix is ambiguous/
# This matches the shortesthexnodeidprefix() function below.
node = repo.unfiltered().changelog._partialmatch(prefix)
except error.AmbiguousPrefixLookupError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revset = repo.ui.config(
b'experimental', b'revisions.disambiguatewithin'
)
Martin von Zweigbergk
lookup: add option to disambiguate prefix within revset...
r38878 if revset:
# Clear config to avoid infinite recursion
Augie Fackler
formatting: blacken the codebase...
r43346 configoverrides = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b'experimental', b'revisions.disambiguatewithin'): None
Augie Fackler
formatting: blacken the codebase...
r43346 }
Martin von Zweigbergk
lookup: add option to disambiguate prefix within revset...
r38878 with repo.ui.configoverride(configoverrides):
revs = repo.anyrevs([revset], user=True)
matches = []
for rev in revs:
node = repo.changelog.node(rev)
if hex(node).startswith(prefix):
matches.append(node)
if len(matches) == 1:
return matches[0]
raise
Martin von Zweigbergk
context: extract partial nodeid lookup method to scmutil...
r37522 if node is None:
return
repo.changelog.rev(node) # make sure node isn't filtered
return node
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def mayberevnum(repo, prefix: bytes) -> bool:
Martin von Zweigbergk
shortest: make isrev() a top-level function...
r38890 """Checks if the given prefix may be mistaken for a revision number"""
try:
i = int(prefix)
# if we are a pure int, then starting with zero will not be
# confused as a rev; or, obviously, if the int is larger
Kyle Lippincott
revisions: when using prefixhexnode, ensure we prefix "0"...
r40377 # than the value of the tip rev. We still need to disambiguate if
# prefix == '0', since that *is* a valid revnum.
if (prefix != b'0' and prefix[0:1] == b'0') or i >= len(repo):
Martin von Zweigbergk
shortest: make isrev() a top-level function...
r38890 return False
return True
except ValueError:
return False
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def shortesthexnodeidprefix(repo, node: bytes, minlength: int = 1, cache=None):
Martin von Zweigbergk
shortest: cache disambiguation revset...
r38889 """Find the shortest unambiguous prefix that matches hexnode.
If "cache" is not None, it must be a dictionary that can be used for
caching between calls to this method.
"""
Martin von Zweigbergk
scmutil: make shortesthexnodeidprefix() use unfiltered repo...
r37726 # _partialmatch() of filtered changelog could take O(len(repo)) time,
# which would be unacceptably slow. so we look for hash collision in
# unfiltered space, which means some hashes may be slightly longer.
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990
Augie Fackler
formatting: blacken the codebase...
r43346 minlength = max(minlength, 1)
Martin von Zweigbergk
shortest: never emit 0-length prefix even if unique...
r40439
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def disambiguate(prefix: bytes):
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 """Disambiguate against revnums."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.ui.configbool(b'experimental', b'revisions.prefixhexnode'):
Martin von Zweigbergk
shortest: use 'x' prefix to disambiguate from revnum if configured...
r38892 if mayberevnum(repo, prefix):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b'x' + prefix
Martin von Zweigbergk
shortest: use 'x' prefix to disambiguate from revnum if configured...
r38892 else:
return prefix
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 hexnode = hex(node)
Martin von Zweigbergk
shortest: avoid magic number "41"...
r38000 for length in range(len(prefix), len(hexnode) + 1):
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 prefix = hexnode[:length]
Martin von Zweigbergk
shortest: make isrev() a top-level function...
r38890 if not mayberevnum(repo, prefix):
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 return prefix
Martin von Zweigbergk
shortest: make isrev() a top-level function...
r38890 cl = repo.unfiltered().changelog
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revset = repo.ui.config(b'experimental', b'revisions.disambiguatewithin')
Martin von Zweigbergk
scmutil: make shortest() respect disambiguation revset...
r38879 if revset:
Martin von Zweigbergk
shortest: cache disambiguation revset...
r38889 revs = None
if cache is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revs = cache.get(b'disambiguationrevset')
Martin von Zweigbergk
shortest: cache disambiguation revset...
r38889 if revs is None:
revs = repo.anyrevs([revset], user=True)
if cache is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cache[b'disambiguationrevset'] = revs
Martin von Zweigbergk
scmutil: make shortest() respect disambiguation revset...
r38879 if cl.rev(node) in revs:
hexnode = hex(node)
Martin von Zweigbergk
shortest: use nodetree for finding shortest node within revset...
r39262 nodetree = None
if cache is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 nodetree = cache.get(b'disambiguationnodetree')
Georges Racinet
rust-revlog: using the ad-hoc `NodeTree` in scmutil...
r52145 is_invalidated = getattr(nodetree, 'is_invalidated', lambda: False)
if is_invalidated():
nodetree = None
Martin von Zweigbergk
shortest: use nodetree for finding shortest node within revset...
r39262 if not nodetree:
Georges Racinet
rust-revlog: using the ad-hoc `NodeTree` in scmutil...
r52145 if hasattr(parsers, 'nodetree') and isinstance(
cl.index, parsers.index
):
Georges Racinet
rust-index: use the new method in shortesthexnodeidprefix...
r44465 index = cl.index
nodetree = parsers.nodetree(index, len(revs))
Georges Racinet
rust-revlog: using the ad-hoc `NodeTree` in scmutil...
r52145 elif getattr(cl.index, 'is_rust', False):
nodetree = rustrevlog.NodeTree(cl.index)
Martin von Zweigbergk
shortest: use nodetree for finding shortest node within revset...
r39262 if nodetree is not None:
Georges Racinet
rust-revlog: using the ad-hoc `NodeTree` in scmutil...
r52145 for r in revs:
nodetree.insert(r)
if cache is not None:
cache[b'disambiguationnodetree'] = nodetree
Martin von Zweigbergk
shortest: use nodetree for finding shortest node within revset...
r39262 length = max(nodetree.shortest(node), minlength)
prefix = hexnode[:length]
return disambiguate(prefix)
Martin von Zweigbergk
scmutil: make shortest() respect disambiguation revset...
r38879 for length in range(minlength, len(hexnode) + 1):
matches = []
prefix = hexnode[:length]
for rev in revs:
otherhexnode = repo[rev].hex()
if prefix == otherhexnode[:length]:
matches.append(otherhexnode)
if len(matches) == 1:
return disambiguate(prefix)
Martin von Zweigbergk
shortest: don't keep checking for longer prefix if node doesn't exist (API)...
r37882 try:
Martin von Zweigbergk
shortest: move revnum-disambiguation out of revlog...
r37990 return disambiguate(cl.shortest(node, minlength))
Martin von Zweigbergk
shortest: don't keep checking for longer prefix if node doesn't exist (API)...
r37882 except error.LookupError:
raise error.RepoLookupError()
Martin von Zweigbergk
scmutil: introduce shortesthexnodeidprefix()...
r37698
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def isrevsymbol(repo, symbol: bytes) -> bool:
Martin von Zweigbergk
scmutil: document that isrevsymbol() raises on ambiguous node prefix...
r37695 """Checks if a symbol exists in the repo.
Martin von Zweigbergk
revlog: use specialized exception for ambiguous prefix lookup...
r38877 See revsymbol() for details. Raises error.AmbiguousPrefixLookupError if the
symbol is an ambiguous nodeid prefix.
Martin von Zweigbergk
scmutil: document that isrevsymbol() raises on ambiguous node prefix...
r37695 """
Martin von Zweigbergk
revset: use revsymbol() for checking if a symbol is valid...
r37368 try:
revsymbol(repo, symbol)
return True
except error.RepoLookupError:
return False
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def revsymbol(repo, symbol: bytes):
Martin von Zweigbergk
scmutil: add method for looking up a context given a revision symbol...
r37289 """Returns a context given a single revision symbol (as string).
This is similar to revsingle(), but accepts only a single revision symbol,
i.e. things like ".", "tip", "1234", "deadbeef", "my-bookmark" work, but
not "max(public())".
"""
if not isinstance(symbol, bytes):
Augie Fackler
formatting: blacken the codebase...
r43346 msg = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"symbol (%s of type %s) was not a string, did you mean "
b"repo[symbol]?" % (symbol, type(symbol))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
scmutil: add method for looking up a context given a revision symbol...
r37289 raise error.ProgrammingError(msg)
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if symbol in (b'.', b'tip', b'null'):
Martin von Zweigbergk
context: handle stringified ints in revsymbol()...
r37545 return repo[symbol]
try:
r = int(symbol)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'%d' % r != symbol:
Martin von Zweigbergk
context: handle stringified ints in revsymbol()...
r37545 raise ValueError
l = len(repo.changelog)
if r < 0:
r += l
if r < 0 or r >= l and r != wdirrev:
raise ValueError
return repo[r]
except error.FilteredIndexError:
raise
except (ValueError, OverflowError, IndexError):
pass
Joerg Sonnenberger
core: don't hard-code hex node lengths...
r47815 if len(symbol) == 2 * repo.nodeconstants.nodelen:
Martin von Zweigbergk
scmutil: handle full hex nodeids in revsymbol()...
r37546 try:
node = bin(symbol)
rev = repo.changelog.rev(node)
return repo[rev]
except error.FilteredLookupError:
raise
Manuel Jacob
node: stop converting binascii.Error to TypeError in bin()...
r50143 except (binascii.Error, LookupError):
Martin von Zweigbergk
scmutil: handle full hex nodeids in revsymbol()...
r37546 pass
Martin von Zweigbergk
context: handle namespaces in revsymbol()...
r37547 # look up bookmarks through the name interface
try:
node = repo.names.singlenode(repo, symbol)
rev = repo.changelog.rev(node)
return repo[rev]
except KeyError:
pass
Martin von Zweigbergk
scmutil: use resolvehexnodeidprefix() from revsymbol()...
r37697 node = resolvehexnodeidprefix(repo, symbol)
Martin von Zweigbergk
context: handle partial nodeids in revsymbol()...
r37548 if node is not None:
rev = repo.changelog.rev(node)
return repo[rev]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.RepoLookupError(_(b"unknown revision '%s'") % symbol)
Martin von Zweigbergk
context: handle stringified ints in revsymbol()...
r37545
Martin von Zweigbergk
scmutil: handle full hex nodeids in revsymbol()...
r37546 except error.WdirUnsupported:
return repo[None]
Augie Fackler
formatting: blacken the codebase...
r43346 except (
error.FilteredIndexError,
error.FilteredLookupError,
error.FilteredRepoLookupError,
):
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403 raise _filterederror(repo, symbol)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _filterederror(repo, changeid: bytes) -> error.FilteredRepoLookupError:
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403 """build an exception to be raised about a filtered changeid
This is extracted in a function to help extensions (eg: evolve) to
experiment with various message variants."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.filtername.startswith(b'visible'):
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403 # Check if the changeset is obsolete
unfilteredrepo = repo.unfiltered()
ctx = revsymbol(unfilteredrepo, changeid)
# If the changeset is obsolete, enrich the message with the reason
# that made this changeset not visible
if ctx.obsolete():
msg = obsutil._getfilteredreason(repo, changeid, ctx)
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b"hidden revision '%s'") % changeid
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 hint = _(b'use --hidden to access hidden revisions')
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403
return error.FilteredRepoLookupError(msg, hint=hint)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b"filtered revision '%s' (not in '%s' subset)")
Martin von Zweigbergk
context: move handling of filtering error to revsymbol() (API)...
r37403 msg %= (changeid, repo.filtername)
return error.FilteredRepoLookupError(msg)
Martin von Zweigbergk
scmutil: add method for looking up a context given a revision symbol...
r37289
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 def revsingle(repo, revspec, default=b'.', localalias=None):
Matt Mackall
revsingle: fix silly API issue (issue2992)
r19509 if not revspec and revspec != 0:
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319 return repo[default]
Jun Wu
rebase: initial support for multiple destinations...
r34007 l = revrange(repo, [revspec], localalias=localalias)
Pierre-Yves David
revset-limit: use boolean testing instead of `len(revs) < 1`...
r22814 if not l:
Martin von Zweigbergk
errors: use InputError for some invalid revsets and such...
r48844 raise error.InputError(_(b'empty revision set'))
Pierre-Yves David
revsingle: use `last` instead of direct indexing...
r22815 return repo[l.last()]
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _pairspec(revspec) -> bool:
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 tree = revsetlang.parse(revspec)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return tree and tree[0] in (
b'range',
b'rangepre',
b'rangepost',
b'rangeall',
)
Yuya Nishihara
revpair: restrict odd-range handling to top-level x:y expression (issue4774)...
r26020
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319 def revpair(repo, revs):
if not revs:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return repo[b'.'], repo[None]
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319
l = revrange(repo, revs)
Martin von Zweigbergk
revpair: clarify check for empty revset...
r41415 if not l:
Martin von Zweigbergk
errors: use InputError for some invalid revsets and such...
r48844 raise error.InputError(_(b'empty revision range'))
Martin von Zweigbergk
revpair: clarify check for empty revset...
r41415
Martin von Zweigbergk
revpair: simplify revpair by always relying on smartset.first/last...
r41414 first = l.first()
second = l.last()
Pierre-Yves David
revpair: smartset compatibility...
r20862
Augie Fackler
formatting: blacken the codebase...
r43346 if (
first == second
and len(revs) >= 2
and not all(revrange(repo, [r]) for r in revs)
):
Martin von Zweigbergk
errors: use InputError for some invalid revsets and such...
r48844 raise error.InputError(_(b'empty revision on one side of range'))
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319
Yuya Nishihara
revpair: restrict odd-range handling to top-level x:y expression (issue4774)...
r26020 # if top-level is range expression, the result must always be a pair
if first == second and len(revs) == 1 and not _pairspec(revs[0]):
Martin von Zweigbergk
scmutil: make revpair() return context objects (API)...
r37269 return repo[first], repo[None]
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319
Martin von Zweigbergk
scmutil: make revpair() return context objects (API)...
r37269 return repo[first], repo[second]
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
rebase: initial support for multiple destinations...
r34007 def revrange(repo, specs, localalias=None):
Gregory Szorc
scmutil: improve documentation of revset APIs...
r29417 """Execute 1 to many revsets and return the union.
This is the preferred mechanism for executing revsets using user-specified
config options, such as revset aliases.
The revsets specified by ``specs`` will be executed via a chained ``OR``
expression. If ``specs`` is empty, an empty result is returned.
``specs`` can contain integers, in which case they are assumed to be
revision numbers.
It is assumed the revsets are already formatted. If you have arguments
Yuya Nishihara
revset: split language services to revsetlang module (API)...
r31024 that need to be expanded in the revset, call ``revsetlang.formatspec()``
Gregory Szorc
scmutil: improve documentation of revset APIs...
r29417 and pass the result as an element of ``specs``.
Specifying a single revset is allowed.
Matt Harbison
doc: fix references to `revset.abstractsmartset`...
r44532 Returns a ``smartset.abstractsmartset`` which is a list-like interface over
Gregory Szorc
scmutil: improve documentation of revset APIs...
r29417 integer revisions.
"""
Yuya Nishihara
revrange: evaluate all revset specs at once...
r25928 allspecs = []
Gregory Szorc
scmutil: improve documentation of revset APIs...
r29417 for spec in specs:
Yuya Nishihara
revrange: drop old-style parser in favor of revset (API)...
r25904 if isinstance(spec, int):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 spec = revsetlang.formatspec(b'%d', spec)
Yuya Nishihara
revrange: evaluate all revset specs at once...
r25928 allspecs.append(spec)
Jun Wu
rebase: initial support for multiple destinations...
r34007 return repo.anyrevs(allspecs, user=True, localalias=localalias)
Matt Mackall
scmutil: fold in wdutil
r14320
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def increasingwindows(
windowsize: int = 8, sizelimit: int = 512
) -> Iterable[int]:
Yuya Nishihara
scmutil: move walkchangerevs() from cmdutil...
r46312 while True:
yield windowsize
if windowsize < sizelimit:
windowsize *= 2
def walkchangerevs(repo, revs, makefilematcher, prepare):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Iterate over files and the revs in a "windowed" way.
Yuya Nishihara
scmutil: move walkchangerevs() from cmdutil...
r46312
Callers most commonly need to iterate backwards over the history
in which they are interested. Doing so has awful (quadratic-looking)
performance, so we use iterators in a "windowed" way.
We walk a window of revisions in the desired order. Within the
window, we first walk forwards to gather data, then in the desired
order (usually backwards) to display it.
This function returns an iterator yielding contexts. Before
yielding each context, the iterator will first call the prepare
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 function on each context in the window in forward order."""
Yuya Nishihara
scmutil: move walkchangerevs() from cmdutil...
r46312
if not revs:
return []
change = repo.__getitem__
def iterate():
it = iter(revs)
stopiteration = False
for windowsize in increasingwindows():
nrevs = []
Manuel Jacob
py3: replace `pycompat.xrange` by `range`
r50179 for i in range(windowsize):
Yuya Nishihara
scmutil: move walkchangerevs() from cmdutil...
r46312 rev = next(it, None)
if rev is None:
stopiteration = True
break
nrevs.append(rev)
for rev in sorted(nrevs):
ctx = change(rev)
prepare(ctx, makefilematcher(ctx))
for rev in nrevs:
yield change(rev)
if stopiteration:
break
return iterate()
Yuya Nishihara
changeset_printer: move _meaningful_parentrevs() to scmutil...
r26433 def meaningfulparents(repo, ctx):
"""Return list of meaningful (or all if debug) parentrevs for rev.
For merges (two non-nullrev revisions) both parents are meaningful.
Otherwise the first parent revision is considered meaningful if it
is not the preceding revision.
"""
parents = ctx.parents()
if len(parents) > 1:
return parents
if repo.ui.debugflag:
Martin von Zweigbergk
repo: look up nullrev context by revnum, not symbolic name...
r39930 return [parents[0], repo[nullrev]]
Yuya Nishihara
scmutil: pass ctx object to intrev()...
r32654 if parents[0].rev() >= intrev(ctx) - 1:
Yuya Nishihara
changeset_printer: move _meaningful_parentrevs() to scmutil...
r26433 return []
return parents
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def getuipathfn(
repo,
legacyrelativevalue: bool = False,
forcerelativevalue: Optional[bool] = None,
) -> typelib.UiPathFn:
Martin von Zweigbergk
config: introduce a new value for ui.relative-paths getting old behavior...
r41716 """Return a function that produced paths for presenting to the user.
The returned function takes a repo-relative path and produces a path
that can be presented in the UI.
Depending on the value of ui.relative-paths, either a repo-relative or
cwd-relative path will be produced.
legacyrelativevalue is the value to use if ui.relative-paths=legacy
If forcerelativevalue is not None, then that value will be used regardless
of what ui.relative-paths is set to.
"""
if forcerelativevalue is not None:
relative = forcerelativevalue
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 config = repo.ui.config(b'ui', b'relative-paths')
if config == b'legacy':
Martin von Zweigbergk
config: introduce a new value for ui.relative-paths getting old behavior...
r41716 relative = legacyrelativevalue
else:
relative = stringutil.parsebool(config)
if relative is None:
raise error.ConfigError(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"ui.relative-paths is not a boolean ('%s')") % config
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
config: introduce a new value for ui.relative-paths getting old behavior...
r41716
Martin von Zweigbergk
status: extract helper for producing relative or absolute path for UI...
r41632 if relative:
cwd = repo.getcwd()
Valentin Gatien-Baron
scmutil: speed up relativization of paths when it's a no-op...
r45385 if cwd != b'':
Valentin Gatien-Baron
scmutil: clarify getuipathfn comment...
r45420 # this branch would work even if cwd == b'' (ie cwd = repo
# root), but its generality makes the returned function slower
Valentin Gatien-Baron
scmutil: speed up relativization of paths when it's a no-op...
r45385 pathto = repo.pathto
return lambda f: pathto(f, cwd)
if repo.ui.configbool(b'ui', b'slash'):
Martin von Zweigbergk
windows: use util.localpath for repo-relative paths in getuipathfn()...
r41833 return lambda f: f
Martin von Zweigbergk
status: extract helper for producing relative or absolute path for UI...
r41632 else:
Martin von Zweigbergk
windows: use util.localpath for repo-relative paths in getuipathfn()...
r41833 return util.localpath
Martin von Zweigbergk
status: extract helper for producing relative or absolute path for UI...
r41632
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def subdiruipathfn(
subpath: bytes, uipathfn: typelib.UiPathFn
) -> typelib.UiPathFn:
Martin von Zweigbergk
add: pass around uipathfn and use instead of m.rel() (API)...
r41799 '''Create a new uipathfn that treats the file as relative to subpath.'''
return lambda f: uipathfn(posixpath.join(subpath, f))
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def anypats(pats, opts) -> bool:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Checks if any patterns, including --include and --exclude were given.
Martin von Zweigbergk
addremove: pass around uipathfn and use instead of m.uipath() (API)...
r41801
Some commands (e.g. addremove) use this condition for deciding whether to
print absolute or relative paths.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return bool(pats or opts.get(b'include') or opts.get(b'exclude'))
Martin von Zweigbergk
addremove: pass around uipathfn and use instead of m.uipath() (API)...
r41801
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def expandpats(pats: Iterable[bytes]) -> List[bytes]:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Expand bare globs when running on windows.
On posix we assume it already has already been done by sh."""
Matt Mackall
scmutil: fold in wdutil
r14320 if not util.expandglobs:
return list(pats)
ret = []
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 for kindpat in pats:
kind, pat = matchmod._patsplit(kindpat, None)
Matt Mackall
scmutil: fold in wdutil
r14320 if kind is None:
try:
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 globbed = glob.glob(pat)
Matt Mackall
scmutil: fold in wdutil
r14320 except re.error:
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 globbed = [pat]
Matt Mackall
scmutil: fold in wdutil
r14320 if globbed:
ret.extend(globbed)
continue
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 ret.append(kindpat)
Matt Mackall
scmutil: fold in wdutil
r14320 return ret
Augie Fackler
formatting: blacken the codebase...
r43346
def matchandpats(
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 ctx,
pats=(),
opts=None,
globbed: bool = False,
default: bytes = b'relpath',
badfn=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Return a matcher and the patterns that were used.
Matt Harbison
scmutil: add an optional parameter to matcher factories for a bad() override...
r25467 The matcher will warn about bad matches, unless an alternate badfn callback
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 is provided."""
Pierre-Yves David
match: remove a mutable default argument...
r26326 if opts is None:
opts = {}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not globbed and default == b'relpath':
Matt Mackall
scmutil: fold in wdutil
r14320 pats = expandpats(pats or [])
Matt Mackall
scmutil: match now accepts a context or a repo
r14670
Martin von Zweigbergk
scmutil: respect ui.relative-paths in default match.badfn...
r41814 uipathfn = getuipathfn(ctx.repo(), legacyrelativevalue=True)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
scmutil: add an optional parameter to matcher factories for a bad() override...
r25467 def bad(f, msg):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ctx.repo().ui.warn(b"%s: %s\n" % (uipathfn(f), msg))
Matt Harbison
scmutil: use the optional badfn argument when building a matcher
r25466
Matt Harbison
scmutil: add an optional parameter to matcher factories for a bad() override...
r25467 if badfn is None:
badfn = bad
Augie Fackler
formatting: blacken the codebase...
r43346 m = ctx.match(
pats,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 opts.get(b'include'),
opts.get(b'exclude'),
Augie Fackler
formatting: blacken the codebase...
r43346 default,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 listsubrepos=opts.get(b'subrepos'),
Augie Fackler
formatting: blacken the codebase...
r43346 badfn=badfn,
)
Matt Harbison
scmutil: use the optional badfn argument when building a matcher
r25466
Martin von Zweigbergk
matcher: make e.g. 'relpath:.' lead to fast paths...
r24447 if m.always():
pats = []
Patrick Mezard
graphlog: restore FILE glob expansion on Windows...
r16171 return m, pats
Augie Fackler
formatting: blacken the codebase...
r43346
def match(
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 ctx,
pats=(),
opts=None,
globbed: bool = False,
default: bytes = b'relpath',
badfn=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 '''Return a matcher that will warn about bad matches.'''
Matt Harbison
scmutil: add an optional parameter to matcher factories for a bad() override...
r25467 return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
Matt Mackall
scmutil: fold in wdutil
r14320
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Mackall
scmutil: fold in wdutil
r14320 def matchall(repo):
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 '''Return a matcher that will efficiently match everything.'''
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 return matchmod.always()
Matt Mackall
scmutil: fold in wdutil
r14320
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def matchfiles(repo, files, badfn=None) -> matchmod.exactmatcher:
Mads Kiilerich
match: improve documentation - docstrings and more descriptive variable naming...
r21111 '''Return a matcher that will efficiently match exactly these files.'''
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 return matchmod.exact(files, badfn=badfn)
Matt Mackall
scmutil: fold in wdutil
r14320
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def parsefollowlinespattern(repo, rev, pat: bytes, msg: bytes) -> bytes:
Denis Laxalde
revset: extract a parsefollowlinespattern helper function...
r34855 """Return a file name from `pat` pattern suitable for usage in followlines
logic.
"""
if not matchmod.patkind(pat):
return pathutil.canonpath(repo.root, repo.getcwd(), pat)
else:
ctx = repo[rev]
m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=ctx)
files = [f for f in ctx if m(f)]
if len(files) != 1:
raise error.ParseError(msg)
return files[0]
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def getorigvfs(ui: "uimod.ui", repo):
Boris Feld
revert: extract origvfs logic in a sub-function...
r40783 """return a vfs suitable to save 'orig' file
return None if no special directory is configured"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 origbackuppath = ui.config(b'ui', b'origbackuppath')
Boris Feld
revert: extract origvfs logic in a sub-function...
r40783 if not origbackuppath:
return None
return vfs.vfs(repo.wvfs.join(origbackuppath))
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def backuppath(ui: "uimod.ui", repo, filepath: bytes) -> bytes:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """customize where working copy backup files (.orig files) are created
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735
Fetch user defined path from config file: [ui] origbackuppath = <path>
Fall back to default (filepath with .orig suffix) if not specified
filepath is repo-relative
Returns an absolute path
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735 origvfs = getorigvfs(ui, repo)
if origvfs is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return repo.wjoin(filepath + b".orig")
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735
origbackupdir = origvfs.dirname(filepath)
if not origvfs.isdir(origbackupdir) or origvfs.islink(origbackupdir):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.note(_(b'creating directory: %s\n') % origvfs.join(origbackupdir))
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735
# Remove any files that conflict with the backup file's path
Martin von Zweigbergk
utils: move finddirs() to pathutil...
r44032 for f in reversed(list(pathutil.finddirs(filepath))):
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735 if origvfs.isfileorlink(f):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.note(_(b'removing conflicting file: %s\n') % origvfs.join(f))
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735 origvfs.unlink(f)
break
origvfs.makedirs(origbackupdir)
if origvfs.isdir(filepath) and not origvfs.islink(filepath):
Augie Fackler
formatting: blacken the codebase...
r43346 ui.note(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'removing conflicting directory: %s\n') % origvfs.join(filepath)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
scmutil: introduce a new backuppath() to replace origpath()...
r41735 origvfs.rmtree(filepath, forcibly=True)
return origvfs.join(filepath)
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class _containsnode:
Jun Wu
scmutil: make cleanupnodes delete divergent bookmarks...
r33331 """proxy __contains__(node) to container.__contains__ which accepts revs"""
def __init__(self, repo, revcontainer):
self._torev = repo.changelog.rev
self._revcontains = revcontainer.__contains__
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def __contains__(self, node) -> bool:
Jun Wu
scmutil: make cleanupnodes delete divergent bookmarks...
r33331 return self._revcontains(self._torev(node))
Augie Fackler
formatting: blacken the codebase...
r43346
def cleanupnodes(
repo,
replacements,
operation,
moves=None,
metadata=None,
fixphase=False,
targetphase=None,
backup=True,
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 ) -> None:
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 """do common cleanups when old nodes are replaced by new nodes
That includes writing obsmarkers or stripping nodes, and moving bookmarks.
(we might also want to move working directory parent in the future)
Jun Wu
rebase: move bookmarks with --keep (issue5682)...
r34364 By default, bookmark moves are calculated automatically from 'replacements',
but 'moves' can be used to override that. Also, 'moves' may include
additional bookmark moves that should not have associated obsmarkers.
Martin von Zweigbergk
cleanupnodes: rename "mapping" to "replacements"...
r34363 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
have replacements. operation is a string, like "rebase".
Pulkit Goyal
scmutil: add capability to cleanupnodes to take obsmarker metadata...
r34794
metadata is dictionary containing metadata to be stored in obsmarker if
obsolescence is enabled.
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 """
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 assert fixphase or targetphase is None
Jun Wu
rebase: move bookmarks with --keep (issue5682)...
r34364 if not replacements and not moves:
return
# translate mapping's other forms
safehasattr: drop usage in favor of hasattr...
r51821 if not hasattr(replacements, 'items'):
Boris Feld
scmutil: accept multiple predecessors in 'replacements' (API)...
r39927 replacements = {(n,): () for n in replacements}
else:
# upgrading non tuple "source" to tuple ones for BC
repls = {}
for key, value in replacements.items():
if not isinstance(key, tuple):
key = (key,)
repls[key] = value
replacements = repls
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088
Martin von Zweigbergk
cleanupnodes: trust caller when "moves" is not None...
r40890 # Unfiltered repo is needed since nodes in replacements might be hidden.
unfi = repo.unfiltered()
Martin von Zweigbergk
cleanupnodes: separate out bookmark destination calculation from actual update...
r34362 # Calculate bookmark movements
Jun Wu
rebase: move bookmarks with --keep (issue5682)...
r34364 if moves is None:
moves = {}
Martin von Zweigbergk
cleanupnodes: trust caller when "moves" is not None...
r40890 for oldnodes, newnodes in replacements.items():
for oldnode in oldnodes:
if oldnode in moves:
continue
if len(newnodes) > 1:
# usually a split, take the one with biggest rev number
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newnode = next(unfi.set(b'max(%ln)', newnodes)).node()
Martin von Zweigbergk
cleanupnodes: trust caller when "moves" is not None...
r40890 elif len(newnodes) == 0:
# move bookmark backwards
allreplaced = []
for rep in replacements:
allreplaced.extend(rep)
Augie Fackler
formatting: blacken the codebase...
r43346 roots = list(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 unfi.set(b'max((::%n) - %ln)', oldnode, allreplaced)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
cleanupnodes: trust caller when "moves" is not None...
r40890 if roots:
newnode = roots[0].node()
else:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 newnode = repo.nullid
Boris Feld
scmutil: accept multiple predecessors in 'replacements' (API)...
r39927 else:
Martin von Zweigbergk
cleanupnodes: trust caller when "moves" is not None...
r40890 newnode = newnodes[0]
moves[oldnode] = newnode
Martin von Zweigbergk
cleanupnodes: separate out bookmark destination calculation from actual update...
r34362
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 allnewnodes = [n for ns in replacements.values() for n in ns]
toretract = {}
toadvance = {}
if fixphase:
precursors = {}
Boris Feld
scmutil: accept multiple predecessors in 'replacements' (API)...
r39927 for oldnodes, newnodes in replacements.items():
for oldnode in oldnodes:
for newnode in newnodes:
precursors.setdefault(newnode, []).append(oldnode)
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442
allnewnodes.sort(key=lambda n: unfi[n].rev())
newphases = {}
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 def phase(ctx):
return newphases.get(ctx.node(), ctx.phase())
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 for newnode in allnewnodes:
ctx = unfi[newnode]
Martin von Zweigbergk
cleanupnodes: preserve phase of parents of new nodes...
r38451 parentphase = max(phase(p) for p in ctx.parents())
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 if targetphase is None:
Augie Fackler
formatting: blacken the codebase...
r43346 oldphase = max(
unfi[oldnode].phase() for oldnode in precursors[newnode]
)
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 newphase = max(oldphase, parentphase)
else:
Martin von Zweigbergk
cleanupnodes: preserve phase of parents of new nodes...
r38451 newphase = max(targetphase, parentphase)
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 newphases[newnode] = newphase
if newphase > ctx.phase():
toretract.setdefault(newphase, []).append(newnode)
elif newphase < ctx.phase():
toadvance.setdefault(newphase, []).append(newnode)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.transaction(b'cleanup') as tr:
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 # Move bookmarks
bmarks = repo._bookmarks
Boris Feld
bookmark: use 'divergent2delete' in 'scmutil.cleanupnode'
r33511 bmarkchanges = []
Martin von Zweigbergk
cleanupnodes: separate out bookmark destination calculation from actual update...
r34362 for oldnode, newnode in moves.items():
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 oldbmarks = repo.nodebookmarks(oldnode)
if not oldbmarks:
continue
Augie Fackler
formatting: blacken the codebase...
r43346 from . import bookmarks # avoid import cycle
repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'moving bookmarks %r from %s to %s\n'
Augie Fackler
formatting: blacken the codebase...
r43346 % (
pycompat.rapply(pycompat.maybebytestr, oldbmarks),
hex(oldnode),
hex(newnode),
)
)
Jun Wu
scmutil: make cleanupnodes delete divergent bookmarks...
r33331 # Delete divergent bookmarks being parents of related newnodes
Augie Fackler
formatting: blacken the codebase...
r43346 deleterevs = repo.revs(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'parents(roots(%ln & (::%n))) - parents(%n)',
Augie Fackler
formatting: blacken the codebase...
r43346 allnewnodes,
newnode,
oldnode,
)
Jun Wu
scmutil: make cleanupnodes delete divergent bookmarks...
r33331 deletenodes = _containsnode(repo, deleterevs)
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 for name in oldbmarks:
Boris Feld
bookmark: use 'divergent2delete' in 'scmutil.cleanupnode'
r33511 bmarkchanges.append((name, newnode))
for b in bookmarks.divergent2delete(repo, deletenodes, name):
bmarkchanges.append((b, None))
if bmarkchanges:
bmarks.applychanges(repo, tr, bmarkchanges)
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 for phase, nodes in toretract.items():
phases.retractboundary(repo, tr, phase, nodes)
for phase, nodes in toadvance.items():
phases.advanceboundary(repo, tr, phase, nodes)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mayusearchived = repo.ui.config(b'experimental', b'cleanup-as-archived')
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 # Obsolete or strip nodes
if obsolete.isenabled(repo, obsolete.createmarkersopt):
# If a node is already obsoleted, and we want to obsolete it
# without a successor, skip that obssolete request since it's
# unnecessary. That's the "if s or not isobs(n)" check below.
# Also sort the node in topology order, that might be useful for
# some obsstore logic.
Boris Feld
cleanupnodes: update comment to drop mention of filtering...
r40077 # NOTE: the sorting might belong to createmarkers.
Jun Wu
scmutil: make cleanupnodes handle filtered node...
r33330 torev = unfi.changelog.rev
Boris Feld
scmutil: accept multiple predecessors in 'replacements' (API)...
r39927 sortfunc = lambda ns: torev(ns[0][0])
Boris Feld
scmutil: expand long "one-liner"...
r39926 rels = []
Boris Feld
scmutil: accept multiple predecessors in 'replacements' (API)...
r39927 for ns, s in sorted(replacements.items(), key=sortfunc):
Boris Feld
cleanupnodes: pass multiple predecessors to `createmarkers` directly
r39959 rel = (tuple(unfi[n] for n in ns), tuple(unfi[m] for m in s))
rels.append(rel)
Jun Wu
rebase: move bookmarks with --keep (issue5682)...
r34364 if rels:
Augie Fackler
formatting: blacken the codebase...
r43346 obsolete.createmarkers(
repo, rels, operation=operation, metadata=metadata
)
phase: introduce a dedicated function to check for the archived phase...
r50345 elif phases.supportarchived(repo) and mayusearchived:
Boris Feld
rewriting: add an option for rewrite commands to use the archived phase...
r41961 # this assume we do not have "unstable" nodes above the cleaned ones
allreplaced = set()
for ns in replacements.keys():
allreplaced.update(ns)
if backup:
Augie Fackler
formatting: blacken the codebase...
r43346 from . import repair # avoid import cycle
Boris Feld
rewriting: add an option for rewrite commands to use the archived phase...
r41961 node = min(allreplaced, key=repo.changelog.rev)
Augie Fackler
formatting: blacken the codebase...
r43346 repair.backupbundle(
repo, allreplaced, allreplaced, node, operation
)
Boris Feld
rewriting: add an option for rewrite commands to use the archived phase...
r41961 phases.retractboundary(repo, tr, phases.archived, allreplaced)
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088 else:
Augie Fackler
formatting: blacken the codebase...
r43346 from . import repair # avoid import cycle
Boris Feld
scmutil: accept multiple predecessors in 'replacements' (API)...
r39927 tostrip = list(n for ns in replacements for n in ns)
Jun Wu
rebase: move bookmarks with --keep (issue5682)...
r34364 if tostrip:
Augie Fackler
formatting: blacken the codebase...
r43346 repair.delayedstrip(
repo.ui, repo, tostrip, operation, backup=backup
)
Jun Wu
scmutil: add a cleanupnodes method for developers...
r33088
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def addremove(
repo,
matcher,
prefix: bytes,
uipathfn: typelib.UiPathFn,
opts=None,
open_tr=None,
) -> int:
Pierre-Yves David
addremove: remove a mutable default argument...
r26329 if opts is None:
opts = {}
Matt Harbison
scmutil: pass a matcher to scmutil.addremove() instead of a list of patterns...
r23533 m = matcher
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dry_run = opts.get(b'dry_run')
Yuya Nishihara
addremove: pass command-level similarity value down to scmutil.addremove()...
r37322 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 similarity = float(opts.get(b'similarity') or 0)
Yuya Nishihara
addremove: pass command-level similarity value down to scmutil.addremove()...
r37322 except ValueError:
Martin von Zweigbergk
errors: use InputError for bad --similarity value...
r48845 raise error.InputError(_(b'similarity must be a number'))
Yuya Nishihara
addremove: pass command-level similarity value down to scmutil.addremove()...
r37322 if similarity < 0 or similarity > 100:
Martin von Zweigbergk
errors: use InputError for bad --similarity value...
r48845 raise error.InputError(_(b'similarity must be between 0 and 100'))
Yuya Nishihara
addremove: pass command-level similarity value down to scmutil.addremove()...
r37322 similarity /= 100.0
Matt Harbison
scmutil: pass a matcher to scmutil.addremove() instead of a list of patterns...
r23533
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 ret = 0
wctx = repo[None]
for subpath in sorted(wctx.substate):
Hannes Oldenburg
subrepo: cleanup of subrepo filematcher logic...
r29802 submatch = matchmod.subdirmatcher(subpath, m)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'subrepos') or m.exact(subpath) or any(submatch.files()):
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 sub = wctx.sub(subpath)
Martin von Zweigbergk
subrepo: adjust subrepo prefix before calling subrepo.addremove() (API)...
r41778 subprefix = repo.wvfs.reljoin(prefix, subpath)
Martin von Zweigbergk
addremove: pass around uipathfn and use instead of m.uipath() (API)...
r41801 subuipathfn = subdiruipathfn(subpath, uipathfn)
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 try:
Martin von Zweigbergk
addremove: pass around uipathfn and use instead of m.uipath() (API)...
r41801 if sub.addremove(submatch, subprefix, subuipathfn, opts):
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 ret = 1
except error.LookupError:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.status(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"skipping missing subrepository: %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % uipathfn(subpath)
)
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537
Matt Mackall
addremove: return 1 if we failed to handle any explicit files
r16167 rejected = []
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def badfn(f: bytes, msg: bytes) -> None:
Matt Harbison
addremove: warn when addremove fails to operate on a named path...
r23534 if f in m.files():
Matt Harbison
addremove: replace match.bad() monkey patching with match.badmatch()...
r25434 m.bad(f, msg)
Matt Harbison
addremove: warn when addremove fails to operate on a named path...
r23534 rejected.append(f)
Matt Mackall
addremove: return 1 if we failed to handle any explicit files
r16167
Matt Harbison
addremove: replace match.bad() monkey patching with match.badmatch()...
r25434 badmatch = matchmod.badmatch(m, badfn)
Augie Fackler
formatting: blacken the codebase...
r43346 added, unknown, deleted, removed, forgotten = _interestingfiles(
repo, badmatch
)
Siddharth Agarwal
scmutil.addremove: pull ui.status printing out of the loop...
r18863
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 unknownset = set(unknown + forgotten)
Siddharth Agarwal
scmutil.addremove: pull ui.status printing out of the loop...
r18863 toprint = unknownset.copy()
toprint.update(deleted)
for abs in sorted(toprint):
if repo.ui.verbose or not m.exact(abs):
if abs in unknownset:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = _(b'adding %s\n') % uipathfn(abs)
label = b'ui.addremove.added'
Siddharth Agarwal
scmutil.addremove: pull ui.status printing out of the loop...
r18863 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = _(b'removing %s\n') % uipathfn(abs)
label = b'ui.addremove.removed'
Boris Feld
addremove: add labels for messages about added and removed files...
r39123 repo.ui.status(status, label=label)
Siddharth Agarwal
scmutil.addremove: pull ui.status printing out of the loop...
r18863
Augie Fackler
formatting: blacken the codebase...
r43346 renames = _findrenames(
repo, m, added + unknown, removed + deleted, similarity, uipathfn
)
Matt Mackall
scmutil: fold in wdutil
r14320
commit: use `dirstate.change_files` to scope the associated `addremove`...
r50924 if not dry_run and (unknown or forgotten or deleted or renames):
if open_tr is not None:
open_tr()
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 _markchanges(repo, unknown + forgotten, deleted, renames)
Matt Mackall
scmutil: fold in wdutil
r14320
Matt Mackall
addremove: return 1 if we failed to handle any explicit files
r16167 for f in rejected:
if f in m.files():
return 1
Matt Harbison
commit: propagate --addremove to subrepos if -S is specified (issue3759)...
r23537 return ret
Matt Mackall
addremove: return 1 if we failed to handle any explicit files
r16167
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def marktouched(repo, files, similarity: float = 0.0) -> int:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Assert that files have somehow been operated upon. files are relative to
the repo root."""
Matt Harbison
scmutil: add an optional parameter to matcher factories for a bad() override...
r25467 m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154 rejected = []
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154
if repo.ui.verbose:
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 unknownset = set(unknown + forgotten)
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154 toprint = unknownset.copy()
toprint.update(deleted)
for abs in sorted(toprint):
if abs in unknownset:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = _(b'adding %s\n') % abs
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 status = _(b'removing %s\n') % abs
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154 repo.ui.status(status)
Martin von Zweigbergk
addremove: use uipathfn instead of m.rel() for recorded similatity message...
r41811 # TODO: We should probably have the caller pass in uipathfn and apply it to
Martin von Zweigbergk
scmutil: fix a comment that doesn't match the code...
r41846 # the messages above too. legacyrelativevalue=True is consistent with how
Martin von Zweigbergk
addremove: use uipathfn instead of m.rel() for recorded similatity message...
r41811 # it used to work.
Martin von Zweigbergk
addremove: respect ui.relative-paths...
r41834 uipathfn = getuipathfn(repo, legacyrelativevalue=True)
Augie Fackler
formatting: blacken the codebase...
r43346 renames = _findrenames(
repo, m, added + unknown, removed + deleted, similarity, uipathfn
)
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 _markchanges(repo, unknown + forgotten, deleted, renames)
Siddharth Agarwal
scmutil: add a function to mark that files have been operated on...
r19154
for f in rejected:
if f in m.files():
return 1
return 0
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _interestingfiles(
repo, matcher
) -> Tuple[List[bytes], List[bytes], List[bytes], List[bytes], List[bytes]]:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Walk dirstate with matcher, looking for files that addremove would care
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150 about.
This is different from dirstate.status because it doesn't care about
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 whether files are modified or clean."""
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 added, unknown, deleted, removed, forgotten = [], [], [], [], []
Yuya Nishihara
pathauditor: disable cache of audited paths by default (issue5628)...
r33722 audit_path = pathutil.pathauditor(repo.root, cached=True)
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150
ctx = repo[None]
dirstate = repo.dirstate
Martin von Zweigbergk
narrow: move remaining narrow-limited dirstate walks to core...
r40123 matcher = repo.narrowmatch(matcher, includeexact=True)
Augie Fackler
formatting: blacken the codebase...
r43346 walkresults = dirstate.walk(
matcher,
subrepos=sorted(ctx.substate),
unknown=True,
ignored=False,
full=False,
)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for abs, st in walkresults.items():
dirstate-item: use item's property instead of `state` in addremove...
r48910 entry = dirstate.get_entry(abs)
if (not entry.any_tracked) and audit_path.check(abs):
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150 unknown.append(abs)
dirstate-item: use item's property instead of `state` in addremove...
r48910 elif (not entry.removed) and not st:
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150 deleted.append(abs)
dirstate-item: use item's property instead of `state` in addremove...
r48910 elif entry.removed and st:
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 forgotten.append(abs)
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150 # for finding renames
dirstate-item: use item's property instead of `state` in addremove...
r48910 elif entry.removed and not st:
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150 removed.append(abs)
dirstate-item: use item's property instead of `state` in addremove...
r48910 elif entry.added:
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150 added.append(abs)
Martin von Zweigbergk
addremove: add back forgotten files (BC)...
r23259 return added, unknown, deleted, removed, forgotten
Siddharth Agarwal
scmutil.addremove: factor out dirstate walk into another function...
r19150
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _findrenames(
repo, matcher, added, removed, similarity, uipathfn: typelib.UiPathFn
) -> Dict[bytes, bytes]:
Siddharth Agarwal
scmutil.addremove: factor out code to find renames...
r19152 '''Find renames from removed files to added ones.'''
renames = {}
if similarity > 0:
Augie Fackler
formatting: blacken the codebase...
r43346 for old, new, score in similar.findrenames(
repo, added, removed, similarity
):
if (
repo.ui.verbose
or not matcher.exact(old)
or not matcher.exact(new)
):
repo.ui.status(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'recording removal of %s as rename to %s '
b'(%d%% similar)\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (uipathfn(old), uipathfn(new), score * 100)
)
Siddharth Agarwal
scmutil.addremove: factor out code to find renames...
r19152 renames[new] = old
return renames
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _markchanges(repo, unknown, deleted, renames) -> None:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """Marks the files in unknown as added, the files in deleted as removed,
and the files in renames as copied."""
Siddharth Agarwal
scmutil.addremove: factor out code to mark added/removed/renames...
r19153 wctx = repo[None]
Bryan O'Sullivan
with: use context manager in _markchanges
r27851 with repo.wlock():
Siddharth Agarwal
scmutil.addremove: factor out code to mark added/removed/renames...
r19153 wctx.forget(deleted)
wctx.add(unknown)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for new, old in renames.items():
Siddharth Agarwal
scmutil.addremove: factor out code to mark added/removed/renames...
r19153 wctx.copy(old, new)
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
templatekw: move getrenamedfn() to scmutil (API)...
r41947 def getrenamedfn(repo, endrev=None):
Martin von Zweigbergk
copies: extract function for deciding whether to use changeset-centric algos...
r42284 if copiesmod.usechangesetcentricalgo(repo):
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
getrenamedfn: get copy data from context object if configured...
r42283 def getrenamed(fn, rev):
ctx = repo[rev]
p1copies = ctx.p1copies()
if fn in p1copies:
return p1copies[fn]
p2copies = ctx.p2copies()
if fn in p2copies:
return p2copies[fn]
return None
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
getrenamedfn: get copy data from context object if configured...
r42283 return getrenamed
Martin von Zweigbergk
templatekw: move getrenamedfn() to scmutil (API)...
r41947 rcache = {}
if endrev is None:
endrev = len(repo)
def getrenamed(fn, rev):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """looks up all renames for a file (up to endrev) the first
Martin von Zweigbergk
templatekw: move getrenamedfn() to scmutil (API)...
r41947 time the file is given. It indexes on the changerev and only
parses the manifest if linkrev != changerev.
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 Returns rename info for fn at changerev rev."""
Martin von Zweigbergk
templatekw: move getrenamedfn() to scmutil (API)...
r41947 if fn not in rcache:
rcache[fn] = {}
fl = repo.file(fn)
for i in fl:
lr = fl.linkrev(i)
renamed = fl.renamed(fl.node(i))
rcache[fn][lr] = renamed and renamed[0]
if lr >= endrev:
break
if rev in rcache[fn]:
return rcache[fn][rev]
# If linkrev != rev (i.e. rev not found in rcache) fallback to
# filectx logic.
try:
return repo[rev][fn].copysource()
except error.LookupError:
return None
return getrenamed
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
copies: create helper for getting all copies for changeset...
r42703 def getcopiesfn(repo, endrev=None):
if copiesmod.usechangesetcentricalgo(repo):
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
copies: create helper for getting all copies for changeset...
r42703 def copiesfn(ctx):
if ctx.p2copies():
allcopies = ctx.p1copies().copy()
# There should be no overlap
allcopies.update(ctx.p2copies())
return sorted(allcopies.items())
else:
return sorted(ctx.p1copies().items())
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
copies: create helper for getting all copies for changeset...
r42703 else:
getrenamed = getrenamedfn(repo, endrev)
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
copies: create helper for getting all copies for changeset...
r42703 def copiesfn(ctx):
copies = []
for fn in ctx.files():
rename = getrenamed(fn, ctx.rev())
if rename:
copies.append((fn, rename))
return copies
return copiesfn
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def dirstatecopy(
ui: "uimod.ui",
repo,
wctx,
src,
dst,
dryrun: bool = False,
cwd: Optional[bytes] = None,
) -> None:
Matt Mackall
scmutil: fold in wdutil
r14320 """Update the dirstate to reflect the intent of copying src to dst. For
different reasons it might not end with dst being marked as copied from src.
"""
origsrc = repo.dirstate.copied(src) or src
Augie Fackler
formatting: blacken the codebase...
r43346 if dst == origsrc: # copying back a copy?
dirstate-item: use item's property when computing a copies...
r48915 entry = repo.dirstate.get_entry(dst)
if (entry.added or not entry.tracked) and not dryrun:
copy: use `set_tracked` instead of `normallookup` in `dirstatecopy`...
r48529 repo.dirstate.set_tracked(dst)
Matt Mackall
scmutil: fold in wdutil
r14320 else:
dirstate-item: use item's property when computing a copies...
r48915 if repo.dirstate.get_entry(origsrc).added and origsrc == src:
Matt Mackall
scmutil: fold in wdutil
r14320 if not ui.quiet:
Augie Fackler
formatting: blacken the codebase...
r43346 ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"%s has not been committed yet, so no copy "
b"data will be stored for %s.\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd))
)
dirstate-item: use item's property when computing a copies...
r48915 if not repo.dirstate.get_entry(dst).tracked and not dryrun:
Matt Mackall
scmutil: fold in wdutil
r14320 wctx.add([dst])
elif not dryrun:
wctx.copy(origsrc, dst)
Adrian Buehlmann
introduce new function scmutil.readrequires...
r14482
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def movedirstate(repo, newctx, match=None) -> None:
Martin von Zweigbergk
scmutil: document matcher argument of movedirstate()...
r42104 """Move the dirstate to newctx and adjust it as necessary.
A matcher can be provided as an optimization. It is probably a bug to pass
a matcher that doesn't match all the differences between the parent of the
working copy and newctx.
"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 oldctx = repo[b'.']
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103 ds = repo.dirstate
Martin von Zweigbergk
movedirstate: get copies from dirstate before setting parents...
r44490 copies = dict(ds.copies())
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 ds.setparents(newctx.node(), repo.nullid)
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103 s = newctx.status(oldctx, match=match)
dirstate: add a function to update tracking status while "moving" parents...
r48392
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103 for f in s.modified:
dirstate: rename `update_file_reference` to `update_file_p1`...
r48493 ds.update_file_p1(f, p1_tracked=True)
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103
for f in s.added:
dirstate: rename `update_file_reference` to `update_file_p1`...
r48493 ds.update_file_p1(f, p1_tracked=False)
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103
for f in s.removed:
dirstate: rename `update_file_reference` to `update_file_p1`...
r48493 ds.update_file_p1(f, p1_tracked=True)
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103
# Merge old parent and old working dir copies
oldcopies = copiesmod.pathcopies(newctx, oldctx, match)
oldcopies.update(copies)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 copies = {dst: oldcopies.get(src, src) for dst, src in oldcopies.items()}
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103 # Adjust the dirstate copies
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for dst, src in copies.items():
dirstate-item: use `added` instead of `state` when moving dirstate...
r48917 if src not in newctx or dst in newctx or not ds.get_entry(dst).added:
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103 src = None
ds.copy(src, dst)
localrepo: also fastpath access to working copy parents when possible...
r44563 repo._quick_access_changeid_invalidate()
Martin von Zweigbergk
uncommit: move _movedirstate() to scmutil for reuse...
r42103
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
scmutil: introduce filterrequirements() to split reqs into wc and store ones...
r46054 def filterrequirements(requirements):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """filters the requirements into two sets:
Pulkit Goyal
scmutil: introduce filterrequirements() to split reqs into wc and store ones...
r46054
wcreq: requirements which should be written in .hg/requires
storereq: which should be written in .hg/store/requires
Returns (wcreq, storereq)
"""
Pulkit Goyal
share: introduce config option to store requires in .hg/store...
r46055 if requirementsmod.SHARESAFE_REQUIREMENT in requirements:
Pulkit Goyal
scmutil: introduce filterrequirements() to split reqs into wc and store ones...
r46054 wc, store = set(), set()
for r in requirements:
if r in requirementsmod.WORKING_DIR_REQUIREMENTS:
wc.add(r)
else:
store.add(r)
return wc, store
return requirements, None
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def istreemanifest(repo) -> bool:
Kyle Lippincott
black: make codebase compatible with black v21.4b2 and v20.8b1...
r47856 """returns whether the repository is using treemanifest or not"""
Pulkit Goyal
scmutil: introduce function to check whether repo uses treemanifest or not...
r46129 return requirementsmod.TREEMANIFEST_REQUIREMENT in repo.requirements
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 def writereporequirements(repo, requirements=None, maywritestore=True) -> None:
Pulkit Goyal
scmutil: improve documentation of writereporequirements()...
r46859 """writes requirements for the repo
Requirements are written to .hg/requires and .hg/store/requires based
on whether share-safe mode is enabled and which requirements are wdir
requirements and which are store requirements
"""
Pulkit Goyal
scmutil: add writereporequirements() and route requires writing through it...
r45666 if requirements:
repo.requirements = requirements
Pulkit Goyal
scmutil: introduce filterrequirements() to split reqs into wc and store ones...
r46054 wcreq, storereq = filterrequirements(repo.requirements)
if wcreq is not None:
writerequires(repo.vfs, wcreq)
if storereq is not None:
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 writerequires(repo.svfs, storereq, maywrite=maywritestore)
Pulkit Goyal
scmutil: try-delete `.hg/store/requires` if store requirements are empty...
r46531 elif repo.ui.configbool(b'format', b'usestore'):
# only remove store requires if we are using store
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 if maywritestore:
repo.svfs.tryunlink(b'requires')
Pulkit Goyal
scmutil: add writereporequirements() and route requires writing through it...
r45666
Arseniy Alekseyev
scmutil: add `readrequires` next to `writerequires`...
r52695 def readrequires(vfs, allowmissing):
"""reads the require file present at root of this vfs
and return a set of requirements
If allowmissing is True, we suppress FileNotFoundError if raised"""
# requires file contains a newline-delimited list of
# features/capabilities the opener (us) must have in order to use
# the repository. This file was introduced in Mercurial 0.9.2,
# which means very old repositories may not have one. We assume
# a missing file translates to no requirements.
read = vfs.tryread if allowmissing else vfs.read
return set(read(b'requires').splitlines())
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 def writerequires(opener, requirements, maywrite=True) -> None:
Arseniy Alekseyev
scmutils: read the requires file before writing to avoid unnecessary rewrite...
r52697 on_disk = readrequires(opener, True)
if not (on_disk == set(requirements)):
Arseniy Alekseyev
sparse: reliably avoid writing to store without a lock...
r52699 if not maywrite:
raise error.Abort(_(b"store requirements are not as expected"))
Arseniy Alekseyev
scmutils: read the requires file before writing to avoid unnecessary rewrite...
r52697 with opener(b'requires', b'w', atomictemp=True) as fp:
for r in sorted(requirements):
fp.write(b"%s\n" % r)
Drew Gottlieb
requires: move requires file writing func from localrepo to scmutil...
r24934
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class filecachesubentry:
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 _cacheable: Optional[bool] = None
def __init__(self, path, stat: bool):
Idan Kamara
scmutil: introduce filecache...
r14928 self.path = path
Idan Kamara
filecache: allow filecacheentry to be created without stating in __init__...
r18315 self.cachestat = None
self._cacheable = None
Idan Kamara
scmutil: introduce filecache...
r14928
Idan Kamara
filecache: allow filecacheentry to be created without stating in __init__...
r18315 if stat:
Siddharth Agarwal
scmutil: rename filecacheentry to filecachesubentry...
r20043 self.cachestat = filecachesubentry.stat(self.path)
Idan Kamara
filecache: allow filecacheentry to be created without stating in __init__...
r18315
if self.cachestat:
self._cacheable = self.cachestat.cacheable()
else:
# None means we don't know yet
self._cacheable = None
Idan Kamara
scmutil: introduce filecache...
r14928
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def refresh(self) -> None:
Idan Kamara
scmutil: introduce filecache...
r14928 if self.cacheable():
Siddharth Agarwal
scmutil: rename filecacheentry to filecachesubentry...
r20043 self.cachestat = filecachesubentry.stat(self.path)
Idan Kamara
scmutil: introduce filecache...
r14928
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def cacheable(self) -> bool:
Idan Kamara
scmutil: introduce filecache...
r14928 if self._cacheable is not None:
return self._cacheable
# we don't know yet, assume it is for now
return True
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def changed(self) -> bool:
Idan Kamara
scmutil: introduce filecache...
r14928 # no point in going further if we can't cache it
if not self.cacheable():
return True
Siddharth Agarwal
scmutil: rename filecacheentry to filecachesubentry...
r20043 newstat = filecachesubentry.stat(self.path)
Idan Kamara
scmutil: introduce filecache...
r14928
# we may not know if it's cacheable yet, check again now
if newstat and self._cacheable is None:
self._cacheable = newstat.cacheable()
# check again
if not self._cacheable:
return True
if self.cachestat != newstat:
self.cachestat = newstat
return True
else:
return False
@staticmethod
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def stat(path: bytes) -> Optional[typelib.CacheStat]:
cachestat: avoid creating cachestat for http path...
r52995 # TODO have a cleaner approach on httpstaticrepo side
if path.startswith(b'https://') or path.startswith(b'http://'):
return util.uncacheable_cachestat()
Idan Kamara
scmutil: introduce filecache...
r14928 try:
return util.cachestat(path)
Manuel Jacob
py3: catch FileNotFoundError instead of checking errno == ENOENT
r50201 except FileNotFoundError:
cachestat: avoid creating cachestat for http path...
r52995 return None
Idan Kamara
scmutil: introduce filecache...
r14928
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class filecacheentry:
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def __init__(self, paths, stat: bool = True) -> None:
Siddharth Agarwal
scmutil: introduce a filecacheentry that can watch multiple paths
r20044 self._entries = []
for path in paths:
self._entries.append(filecachesubentry(path, stat))
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def changed(self) -> bool:
Siddharth Agarwal
scmutil: introduce a filecacheentry that can watch multiple paths
r20044 '''true if any entry has changed'''
for entry in self._entries:
if entry.changed():
return True
return False
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def refresh(self) -> None:
Siddharth Agarwal
scmutil: introduce a filecacheentry that can watch multiple paths
r20044 for entry in self._entries:
entry.refresh()
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class filecache:
Gregory Szorc
scmutil: rewrite docstring for filecache...
r38698 """A property like decorator that tracks files under .hg/ for updates.
Idan Kamara
scmutil: introduce filecache...
r14928
Gregory Szorc
scmutil: rewrite docstring for filecache...
r38698 On first access, the files defined as arguments are stat()ed and the
results cached. The decorated function is called. The results are stashed
away in a ``_filecache`` dict on the object whose method is decorated.
Idan Kamara
scmutil: introduce filecache...
r14928
Yuya Nishihara
filecache: unimplement __set__() and __delete__() (API)...
r40454 On subsequent access, the cached result is used as it is set to the
instance dictionary.
Gregory Szorc
scmutil: rewrite docstring for filecache...
r38698
Yuya Nishihara
filecache: unimplement __set__() and __delete__() (API)...
r40454 On external property set/delete operations, the caller must update the
corresponding _filecache entry appropriately. Use __class__.<attr>.set()
instead of directly setting <attr>.
Idan Kamara
scmutil: introduce filecache...
r14928
Yuya Nishihara
filecache: unimplement __set__() and __delete__() (API)...
r40454 When using the property API, the cached data is always used if available.
No stat() is performed to check if the file has changed.
Siddharth Agarwal
scmutil.filecache: support watching over multiple files
r20045
Gregory Szorc
scmutil: rewrite docstring for filecache...
r38698 Others can muck about with the state of the ``_filecache`` dict. e.g. they
can populate an entry before the property's getter is called. In this case,
entries in ``_filecache`` will be used during property operations,
if available. If the underlying file changes, it is up to external callers
to reflect this by e.g. calling ``delattr(obj, attr)`` to remove the cached
method result as well as possibly calling ``del obj._filecache[attr]`` to
remove the ``filecacheentry``.
"""
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 paths: Tuple[bytes, ...]
def __init__(self, *paths: bytes) -> None:
Siddharth Agarwal
scmutil.filecache: support watching over multiple files
r20045 self.paths = paths
Idan Kamara
filecache: refactor path join logic to a function...
r16198
Raphaël Gomès
branching: merge stable into default
r48855 def tracked_paths(self, obj):
return [self.join(obj, path) for path in self.paths]
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def join(self, obj, fname: bytes):
Siddharth Agarwal
scmutil.filecache: support watching over multiple files
r20045 """Used to compute the runtime path of a cached file.
Idan Kamara
filecache: refactor path join logic to a function...
r16198
Users should subclass filecache and provide their own version of this
function to call the appropriate join function on 'obj' (an instance
of the class that its member function was decorated).
"""
Pierre-Yves David
filecache: make 'join' abstract...
r31285 raise NotImplementedError
Idan Kamara
scmutil: introduce filecache...
r14928
def __call__(self, func):
self.func = func
Augie Fackler
scmutil: clean up bytes/string cache decorator mess on Python 3 again...
r37886 self.sname = func.__name__
localrepo: purge filecache attribute using there unicode name...
r51812 # XXX We should be using a unicode string instead of bytes for the main
# name (and the _filecache key). The fact we use bytes is a remains
# from Python2, since the name is derived from an attribute name a
# `str` is a better fit now that we support Python3 only
Augie Fackler
scmutil: clean up bytes/string cache decorator mess on Python 3 again...
r37886 self.name = pycompat.sysbytes(self.sname)
Idan Kamara
scmutil: introduce filecache...
r14928 return self
def __get__(self, obj, type=None):
Martijn Pieters
scmutil: allow access to filecache descriptor on class...
r29373 # if accessed on the class, return the descriptor itself.
if obj is None:
return self
Yuya Nishihara
filecache: unimplement __set__() and __delete__() (API)...
r40454
assert self.sname not in obj.__dict__
Idan Kamara
scmutil: update cached copy when filecached attribute is assigned (issue3263)...
r16115
Idan Kamara
scmutil: introduce filecache...
r14928 entry = obj._filecache.get(self.name)
if entry:
if entry.changed():
entry.obj = self.func(obj)
else:
Raphaël Gomès
branching: merge stable into default
r48855 paths = self.tracked_paths(obj)
Idan Kamara
scmutil: introduce filecache...
r14928
# We stat -before- creating the object so our cache doesn't lie if
# a writer modified between the time we read and stat
Siddharth Agarwal
scmutil.filecache: support watching over multiple files
r20045 entry = filecacheentry(paths, True)
Idan Kamara
scmutil: introduce filecache...
r14928 entry.obj = self.func(obj)
obj._filecache[self.name] = entry
Augie Fackler
scmutil: clean up bytes/string cache decorator mess on Python 3 again...
r37886 obj.__dict__[self.sname] = entry.obj
Idan Kamara
scmutil: introduce filecache...
r14928 return entry.obj
Idan Kamara
scmutil: update cached copy when filecached attribute is assigned (issue3263)...
r16115
Yuya Nishihara
filecache: unimplement __set__() and __delete__() (API)...
r40454 # don't implement __set__(), which would make __dict__ lookup as slow as
# function call.
def set(self, obj, value):
Idan Kamara
filecache: create an entry in _filecache when __set__ is called for a missing one...
r18316 if self.name not in obj._filecache:
# we add an entry for the missing value because X in __dict__
# implies X in _filecache
Raphaël Gomès
branching: merge stable into default
r48855 paths = self.tracked_paths(obj)
Siddharth Agarwal
scmutil.filecache: support watching over multiple files
r20045 ce = filecacheentry(paths, False)
Idan Kamara
filecache: create an entry in _filecache when __set__ is called for a missing one...
r18316 obj._filecache[self.name] = ce
else:
ce = obj._filecache[self.name]
Augie Fackler
formatting: blacken the codebase...
r43346 ce.obj = value # update cached copy
obj.__dict__[self.sname] = value # update copy returned by obj.x
Idan Kamara
scmutil: update cached copy when filecached attribute is assigned (issue3263)...
r16115
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def extdatasource(repo, source: bytes):
Matt Mackall
extdata: add extdatasource reader...
r34457 """Gather a map of rev -> value dict from the specified source
A source spec is treated as a URL, with a special case shell: type
for parsing the output from a shell command.
The data is parsed as a series of newline-separated records where
each record is a revision specifier optionally followed by a space
and a freeform string value. If the revision is known locally, it
is converted to a rev, otherwise the record is skipped.
Note that both key and value are treated as UTF-8 and converted to
the local encoding. This allows uniformity between local and
remote data sources.
"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 spec = repo.ui.config(b"extdata", source)
Matt Mackall
extdata: add extdatasource reader...
r34457 if not spec:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"unknown extdata source '%s'") % source)
Matt Mackall
extdata: add extdatasource reader...
r34457
data = {}
Yuya Nishihara
extdata: use subprocess so we don't have to chdir() manually
r34462 src = proc = None
Matt Mackall
extdata: add extdatasource reader...
r34457 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if spec.startswith(b"shell:"):
Yuya Nishihara
extdata: use subprocess so we don't have to chdir() manually
r34462 # external commands should be run relative to the repo root
cmd = spec[6:]
Augie Fackler
formatting: blacken the codebase...
r43346 proc = subprocess.Popen(
procutil.tonativestr(cmd),
shell=True,
bufsize=-1,
close_fds=procutil.closefds,
stdout=subprocess.PIPE,
cwd=procutil.tonativestr(repo.root),
)
Yuya Nishihara
extdata: use subprocess so we don't have to chdir() manually
r34462 src = proc.stdout
else:
# treat as a URL or file
src = url.open(repo.ui, spec)
Yuya Nishihara
extdata: just use iterator to read lines one by one
r34461 for l in src:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b" " in l:
k, v = l.strip().split(b" ", 1)
Matt Mackall
extdata: add extdatasource reader...
r34457 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 k, v = l.strip(), b""
Matt Mackall
extdata: add extdatasource reader...
r34457
k = encoding.tolocal(k)
Yuya Nishihara
extdata: ignore ambiguous identifier as well
r34460 try:
Martin von Zweigbergk
extdatasource: use revsymbol() for converting to node...
r37378 data[revsingle(repo, k).rev()] = encoding.tolocal(v)
Martin von Zweigbergk
errors: raise InputError if an ambiguous revision id prefix is used...
r46731 except (error.LookupError, error.RepoLookupError, error.InputError):
Augie Fackler
formatting: blacken the codebase...
r43346 pass # we ignore data for nodes that don't exist locally
Matt Mackall
extdata: add extdatasource reader...
r34457 finally:
Yuya Nishihara
extdata: use subprocess so we don't have to chdir() manually
r34462 if proc:
Augie Fackler
extdata: avoid crashing inside subprocess when we get a revset parse error...
r42776 try:
proc.communicate()
except ValueError:
# This happens if we started iterating src and then
# get a parse error on a line. It should be safe to ignore.
pass
Yuya Nishihara
extdata: use subprocess so we don't have to chdir() manually
r34462 if src:
src.close()
Yuya Nishihara
extdata: abort if external command exits with non-zero status (BC)...
r35413 if proc and proc.returncode != 0:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"extdata command '%s' failed: %s")
Augie Fackler
formatting: blacken the codebase...
r43346 % (cmd, procutil.explainexit(proc.returncode))
)
Matt Mackall
extdata: add extdatasource reader...
r34457
return data
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class progress:
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 ui: "uimod.ui"
pos: Optional[int] # None once complete
topic: bytes
unit: bytes
total: Optional[int]
debug: bool
def __init__(
self,
ui: "uimod.ui",
updatebar,
topic: bytes,
unit: bytes = b"",
total: Optional[int] = None,
) -> None:
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 self.ui = ui
self.pos = 0
self.topic = topic
self.unit = unit
self.total = total
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.debug = ui.configbool(b'progress', b'debug')
Martin von Zweigbergk
progress: check what type of progress bar to use only once per topic...
r41181 self._updatebar = updatebar
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364
Martin von Zweigbergk
progress: make the progress helper a context manager...
r38393 def __enter__(self):
Danny Hooper
scmutil: fix __enter__ in progress context manager...
r38522 return self
Martin von Zweigbergk
progress: make the progress helper a context manager...
r38393
def __exit__(self, exc_type, exc_value, exc_tb):
self.complete()
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def update(
self, pos: int, item: bytes = b"", total: Optional[int] = None
) -> None:
Martin von Zweigbergk
progress: enforce use of complete() on the helper class...
r38438 assert pos is not None
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 if total:
self.total = total
self.pos = pos
Yuya Nishihara
progress: change _updatebar() to take parameters as arguments...
r41245 self._updatebar(self.topic, self.pos, item, self.unit, self.total)
Martin von Zweigbergk
progress: split up _print() method in bar-updating and debug-printing...
r41180 if self.debug:
self._printdebug(item)
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def increment(
self, step: int = 1, item: bytes = b"", total: Optional[int] = None
) -> None:
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 self.update(self.pos + step, item, total)
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def complete(self) -> None:
Martin von Zweigbergk
progress: write ui.progress() in terms of ui.makeprogress()...
r41178 self.pos = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.unit = b""
Martin von Zweigbergk
progress: write ui.progress() in terms of ui.makeprogress()...
r41178 self.total = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._updatebar(self.topic, self.pos, b"", self.unit, self.total)
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _printdebug(self, item: bytes) -> None:
Matt Harbison
scmutil: fix an unbound variable with progressbar debug enabled...
r44520 unit = b''
Martin von Zweigbergk
progress: write ui.progress() in terms of ui.makeprogress()...
r41178 if self.unit:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 unit = b' ' + self.unit
Martin von Zweigbergk
progress: write ui.progress() in terms of ui.makeprogress()...
r41178 if item:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 item = b' ' + item
Martin von Zweigbergk
progress: write ui.progress() in terms of ui.makeprogress()...
r41178
if self.total:
pct = 100.0 * self.pos / self.total
Augie Fackler
formatting: blacken the codebase...
r43346 self.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%s:%s %d/%d%s (%4.2f%%)\n'
Augie Fackler
formatting: blacken the codebase...
r43346 % (self.topic, item, self.pos, self.total, unit, pct)
)
Martin von Zweigbergk
progress: write ui.progress() in terms of ui.makeprogress()...
r41178 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.debug(b'%s:%s %d%s\n' % (self.topic, item, self.pos, unit))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def gdinitconfig(ui: "uimod.ui"):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """helper function to know if a repo should be created as general delta"""
Pierre-Yves David
format: introduce 'format.usegeneraldelta`...
r26907 # experimental config: format.generaldelta
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return ui.configbool(b'format', b'generaldelta') or ui.configbool(
b'format', b'usegeneraldelta'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pierre-Yves David
scmutil: extract general delta config handling in a function...
r26906
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def gddeltaconfig(ui: "uimod.ui"):
reuse-delta-base: improves some documentation...
r50561 """helper function to know if incoming deltas should be optimized
The `format.generaldelta` config is an old form of the config that also
implies that incoming delta-bases should be never be trusted. This function
exists for this purpose.
"""
Pierre-Yves David
scmutil: extract general delta config handling in a function...
r26906 # experimental config: format.generaldelta
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return ui.configbool(b'format', b'generaldelta')
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class simplekeyvaluefile:
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 """A simple file with key=value lines
Keys must be alphanumerics and start with a letter, values must not
contain '\n' characters"""
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 firstlinekey = b'__firstline'
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def __init__(self, vfs, path: bytes, keys=None) -> None:
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 self.vfs = vfs
self.path = path
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def read(self, firstlinenonkeyval: bool = False):
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 """Read the contents of a simple key-value file
'firstlinenonkeyval' indicates whether the first line of file should
be treated as a key-value pair or reuturned fully under the
__firstline key."""
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 lines = self.vfs.readlines(self.path)
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 d = {}
if firstlinenonkeyval:
if not lines:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e = _(b"empty simplekeyvalue file")
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 raise error.CorruptedState(e)
# we don't want to include '\n' in the __firstline
d[self.firstlinekey] = lines[0][:-1]
del lines[0]
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 try:
Kostia Balytskyi
scmutil: add simplekeyvaluefile reading test...
r32269 # the 'if line.strip()' part prevents us from failing on empty
# lines which only contain '\n' therefore are not skipped
# by 'if line'
Augie Fackler
formatting: blacken the codebase...
r43346 updatedict = dict(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 line[:-1].split(b'=', 1) for line in lines if line.strip()
Augie Fackler
formatting: blacken the codebase...
r43346 )
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 if self.firstlinekey in updatedict:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e = _(b"%r can't be used as a key")
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 raise error.CorruptedState(e % self.firstlinekey)
d.update(updatedict)
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 except ValueError as e:
Emmanuel Leblond
py3: fix exception message encoding in scmutil.py's simplekeyvaluefile.read...
r43682 raise error.CorruptedState(stringutil.forcebytestr(e))
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 return d
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def write(self, data, firstline: Optional[bytes] = None) -> None:
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 """Write key=>value mapping to a file
data is a dict. Keys must be alphanumerical and start with a letter.
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 Values must not contain newline characters.
If 'firstline' is not None, it is written to file before
everything else, as it is, not in a key=value form"""
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 lines = []
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 if firstline is not None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lines.append(b'%s\n' % firstline)
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 for k, v in data.items():
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 if k == self.firstlinekey:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e = b"key name '%s' is reserved" % self.firstlinekey
Kostia Balytskyi
scmutil: make simplekeyvaluefile able to have a non-key-value first line...
r32270 raise error.ProgrammingError(e)
Pulkit Goyal
py3: slice on bytes to prevent getting the ascii values...
r35931 if not k[0:1].isalpha():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e = b"keys must start with a letter in a key-value file"
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 raise error.ProgrammingError(e)
if not k.isalnum():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 e = b"invalid key name in a simple key-value file"
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 raise error.ProgrammingError(e)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'\n' in v:
e = b"invalid value in a simple key-value file"
Kostia Balytskyi
scmutil: add a simple key-value file helper...
r31553 raise error.ProgrammingError(e)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lines.append(b"%s=%s\n" % (k, v))
with self.vfs(self.path, mode=b'wb', atomictemp=True) as fp:
fp.write(b''.join(lines))
obsolete: reports the number of local changeset obsoleted when unbundling...
r33249
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 _reportobsoletedsource: List[bytes] = [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'debugobsolete',
b'pull',
b'push',
b'serve',
b'unbundle',
Boris Feld
transaction-summary: display the summary for all transactions...
r33541 ]
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 _reportnewcssource: List[bytes] = [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'pull',
b'unbundle',
Denis Laxalde
transaction-summary: show the range of new revisions upon pull/unbundle (BC)...
r34662 ]
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def prefetchfiles(repo, revmatches) -> None:
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 """Invokes the registered file prefetch functions, allowing extensions to
ensure the corresponding files are available locally, before the command
Rodrigo Damazio Bovendorp
scmutil: allowing different files to be prefetched per revision...
r45632 uses them.
Args:
revmatches: a list of (revision, match) tuples to indicate the files to
fetch at each revision. If any of the match elements is None, it matches
all files.
"""
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780
Rodrigo Damazio Bovendorp
scmutil: allowing different files to be prefetched per revision...
r45632 def _matcher(m):
if m:
assert isinstance(m, matchmod.basematcher)
# The command itself will complain about files that don't exist, so
# don't duplicate the message.
return matchmod.badmatch(m, lambda fn, msg: None)
else:
return matchall(repo)
revbadmatches = [(rev, _matcher(match)) for (rev, match) in revmatches]
fileprefetchhooks(repo, revbadmatches)
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 # a list of (repo, revs, match) prefetch functions
Matt Harbison
cmdutil: convert the prefetchfiles() hook to a callback mechanism (API)...
r36154 fileprefetchhooks = util.hooks()
Martin von Zweigbergk
evolution: report new unstable changesets...
r35727 # A marker that tells the evolve extension to suppress its own reporting
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 _reportstroubledchangesets: bool = True
def registersummarycallback(
repo, otr, txnname: bytes = b'', as_validator: bool = False
) -> None:
obsolete: reports the number of local changeset obsoleted when unbundling...
r33249 """register a callback to issue a summary after the transaction is closed
Pulkit Goyal
scmutil: add option to register summary callbacks as transaction validators...
r45032
If as_validator is true, then the callbacks are registered as transaction
validators instead
obsolete: reports the number of local changeset obsoleted when unbundling...
r33249 """
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
scmutil: factor out transaction name lookup in registersummarycallback()...
r34620 def txmatch(sources):
return any(txnname.startswith(source) for source in sources)
Denis Laxalde
scmutil: factor out building of transaction summary callback...
r34621 categories = []
def reportsummary(func):
"""decorator for report callbacks."""
Boris Feld
tr-summary: keep a weakref to the unfiltered repository...
r35140 # The repoview life cycle is shorter than the one of the actual
# underlying repository. So the filtered object can die before the
# weakref is used leading to troubles. We keep a reference to the
# unfiltered object and restore the filtering when retrieving the
# repository through the weakref.
filtername = repo.filtername
reporef = weakref.ref(repo.unfiltered())
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
scmutil: factor out building of transaction summary callback...
r34621 def wrapped(tr):
Denis Laxalde
scmutil: factor out transaction name lookup in registersummarycallback()...
r34620 repo = reporef()
Boris Feld
tr-summary: keep a weakref to the unfiltered repository...
r35140 if filtername:
Matt Harbison
scmutil: add assertions to help pytype...
r44120 assert repo is not None # help pytype
Boris Feld
tr-summary: keep a weakref to the unfiltered repository...
r35140 repo = repo.filtered(filtername)
Denis Laxalde
scmutil: factor out building of transaction summary callback...
r34621 func(repo, tr)
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newcat = b'%02i-txnreport' % len(categories)
Pulkit Goyal
scmutil: add option to register summary callbacks as transaction validators...
r45032 if as_validator:
otr.addvalidator(newcat, wrapped)
else:
otr.addpostclose(newcat, wrapped)
Denis Laxalde
scmutil: factor out building of transaction summary callback...
r34621 categories.append(newcat)
return wrapped
changegroup: move message about added changes to transaction summary...
r43167 @reportsummary
def reportchangegroup(repo, tr):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cgchangesets = tr.changes.get(b'changegroup-count-changesets', 0)
cgrevisions = tr.changes.get(b'changegroup-count-revisions', 0)
cgfiles = tr.changes.get(b'changegroup-count-files', 0)
cgheads = tr.changes.get(b'changegroup-count-heads', 0)
changegroup: move message about added changes to transaction summary...
r43167 if cgchangesets or cgrevisions or cgfiles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 htext = b""
changegroup: move message about added changes to transaction summary...
r43167 if cgheads:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 htext = _(b" (%+d heads)") % cgheads
msg = _(b"added %d changesets with %d changes to %d files%s\n")
Pulkit Goyal
scmutil: add option to register summary callbacks as transaction validators...
r45032 if as_validator:
msg = _(b"adding %d changesets with %d changes to %d files%s\n")
Matt Harbison
scmutil: add assertions to help pytype...
r44120 assert repo is not None # help pytype
changegroup: move message about added changes to transaction summary...
r43167 repo.ui.status(msg % (cgchangesets, cgrevisions, cgfiles, htext))
Denis Laxalde
scmutil: factor out building of transaction summary callback...
r34621 if txmatch(_reportobsoletedsource):
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
scmutil: factor out building of transaction summary callback...
r34621 @reportsummary
def reportobsoleted(repo, tr):
Denis Laxalde
scmutil: factor out transaction name lookup in registersummarycallback()...
r34620 obsoleted = obsutil.getobsoleted(repo, tr)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newmarkers = len(tr.changes.get(b'obsmarkers', ()))
transaction: issue "new obsmarkers" message at the end of the transaction...
r43164 if newmarkers:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.status(_(b'%i new obsolescence markers\n') % newmarkers)
Denis Laxalde
scmutil: factor out transaction name lookup in registersummarycallback()...
r34620 if obsoleted:
Pulkit Goyal
scmutil: add option to register summary callbacks as transaction validators...
r45032 msg = _(b'obsoleted %i changesets\n')
if as_validator:
msg = _(b'obsoleting %i changesets\n')
repo.ui.status(msg % len(obsoleted))
Denis Laxalde
transaction-summary: show the range of new revisions upon pull/unbundle (BC)...
r34662
Augie Fackler
formatting: blacken the codebase...
r43346 if obsolete.isenabled(
repo, obsolete.createmarkersopt
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ) and repo.ui.configbool(
b'experimental', b'evolution.report-instabilities'
):
Martin von Zweigbergk
evolution: report new unstable changesets...
r35727 instabilitytypes = [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b'orphan', b'orphan'),
(b'phase-divergent', b'phasedivergent'),
(b'content-divergent', b'contentdivergent'),
Martin von Zweigbergk
evolution: report new unstable changesets...
r35727 ]
def getinstabilitycounts(repo):
filtered = repo.changelog.filteredrevs
counts = {}
for instability, revset in instabilitytypes:
Augie Fackler
formatting: blacken the codebase...
r43346 counts[instability] = len(
set(obsolete.getrevs(repo, revset)) - filtered
)
Martin von Zweigbergk
evolution: report new unstable changesets...
r35727 return counts
oldinstabilitycounts = getinstabilitycounts(repo)
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
evolution: report new unstable changesets...
r35727 @reportsummary
def reportnewinstabilities(repo, tr):
newinstabilitycounts = getinstabilitycounts(repo)
for instability, revset in instabilitytypes:
Augie Fackler
formatting: blacken the codebase...
r43346 delta = (
newinstabilitycounts[instability]
- oldinstabilitycounts[instability]
)
Pulkit Goyal
scmutil: move construction of instability count message to separate fn...
r38474 msg = getinstabilitymessage(delta, instability)
if msg:
repo.ui.warn(msg)
Martin von Zweigbergk
evolution: report new unstable changesets...
r35727
Denis Laxalde
transaction-summary: show the range of new revisions upon pull/unbundle (BC)...
r34662 if txmatch(_reportnewcssource):
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
transaction-summary: show the range of new revisions upon pull/unbundle (BC)...
r34662 @reportsummary
def reportnewcs(repo, tr):
"""Report the range of new revisions pulled/unbundled."""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 origrepolen = tr.changes.get(b'origrepolen', len(repo))
Boris Feld
pullreport: skip or rework some early return...
r39934 unfi = repo.unfiltered()
if origrepolen >= len(unfi):
Denis Laxalde
transaction-summary: show the range of new revisions upon pull/unbundle (BC)...
r34662 return
Boris Feld
pullreport: skip filtered revs instead of obsolete ones...
r39933 # Compute the bounds of new visible revisions' range.
revs = smartset.spanset(repo, start=origrepolen)
Boris Feld
pullreport: skip or rework some early return...
r39934 if revs:
minrev, maxrev = repo[revs.min()], repo[revs.max()]
Denis Laxalde
transaction-summary: show the range of new revisions upon pull/unbundle (BC)...
r34662
Boris Feld
pullreport: skip or rework some early return...
r39934 if minrev == maxrev:
revrange = minrev
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revrange = b'%s:%s' % (minrev, maxrev)
draft = len(repo.revs(b'%ld and draft()', revs))
secret = len(repo.revs(b'%ld and secret()', revs))
Boris Feld
pullreport: skip or rework some early return...
r39934 if not (draft or secret):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'new changesets %s\n') % revrange
Boris Feld
pullreport: skip or rework some early return...
r39934 elif draft and secret:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'new changesets %s (%d drafts, %d secrets)\n')
Boris Feld
pullreport: skip or rework some early return...
r39934 msg %= (revrange, draft, secret)
elif draft:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'new changesets %s (%d drafts)\n')
Boris Feld
pullreport: skip or rework some early return...
r39934 msg %= (revrange, draft)
elif secret:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'new changesets %s (%d secrets)\n')
Boris Feld
pullreport: skip or rework some early return...
r39934 msg %= (revrange, secret)
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 errormsg = b'entered unreachable condition'
Boris Feld
pullreport: skip or rework some early return...
r39934 raise error.ProgrammingError(errormsg)
repo.ui.status(msg)
Matt Harbison
convert: allow the sink object to be wrapped when the extension isn't loaded...
r35169
Boris Feld
pullreport: issue a message about "extinct" pulled changesets...
r39935 # search new changesets directly pulled as obsolete
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 duplicates = tr.changes.get(b'revduplicates', ())
Augie Fackler
formatting: blacken the codebase...
r43346 obsadded = unfi.revs(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'(%d: + %ld) and obsolete()', origrepolen, duplicates
Augie Fackler
formatting: blacken the codebase...
r43346 )
Boris Feld
pullreport: issue a message about "extinct" pulled changesets...
r39935 cl = repo.changelog
extinctadded = [r for r in obsadded if r not in cl]
if extinctadded:
# They are not just obsolete, but obsolete and invisible
# we call them "extinct" internally but the terms have not been
# exposed to users.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = b'(%d other changesets obsolete on arrival)\n'
Boris Feld
pullreport: issue a message about "extinct" pulled changesets...
r39935 repo.ui.status(msg % len(extinctadded))
Denis Laxalde
transaction-summary: show phase changes statistics in pull/unbundle...
r38189 @reportsummary
def reportphasechanges(repo, tr):
"""Report statistics of phase changes for changesets pre-existing
pull/unbundle.
"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 origrepolen = tr.changes.get(b'origrepolen', len(repo))
Joerg Sonnenberger
transactions: convert changes['phases'] to list of ranges...
r45036 published = []
for revs, (old, new) in tr.changes.get(b'phases', []):
if new != phases.public:
continue
published.extend(rev for rev in revs if rev < origrepolen)
Denis Laxalde
transaction-summary: show phase changes statistics in pull/unbundle...
r38189 if not published:
return
Pulkit Goyal
scmutil: add option to register summary callbacks as transaction validators...
r45032 msg = _(b'%d local changesets published\n')
if as_validator:
msg = _(b'%d local changesets will be published\n')
repo.ui.status(msg % len(published))
Augie Fackler
formatting: blacken the codebase...
r43346
Denis Laxalde
transaction-summary: show phase changes statistics in pull/unbundle...
r38189
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def getinstabilitymessage(delta: int, instability: bytes) -> Optional[bytes]:
Pulkit Goyal
scmutil: move construction of instability count message to separate fn...
r38474 """function to return the message to show warning about new instabilities
exists as a separate function so that extension can wrap to show more
information like how to fix instabilities"""
if delta > 0:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return _(b'%i new %s changesets\n') % (delta, instability)
Pulkit Goyal
scmutil: move construction of instability count message to separate fn...
r38474
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def nodesummaries(repo, nodes, maxnumnodes: int = 4) -> bytes:
Boris Feld
scmutil: extra utility to display a reasonable amount of nodes...
r35185 if len(nodes) <= maxnumnodes or repo.ui.verbose:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return b' '.join(short(h) for h in nodes)
first = b' '.join(short(h) for h in nodes[:maxnumnodes])
return _(b"%s and %d others") % (first, len(nodes) - maxnumnodes)
Boris Feld
scmutil: extra utility to display a reasonable amount of nodes...
r35185
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def enforcesinglehead(repo, tr, desc: bytes, accountclosed, filtername) -> None:
Boris Feld
server: introduce a 'experimental.single-head-per-branch' option...
r35186 """check that no named branch has multiple heads"""
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if desc in (b'strip', b'repair'):
Boris Feld
server: introduce a 'experimental.single-head-per-branch' option...
r35186 # skip the logic during strip
return
Joerg Sonnenberger
singlehead: introduce option to restrict to public changes...
r46712 visible = repo.filtered(filtername)
Boris Feld
server: introduce a 'experimental.single-head-per-branch' option...
r35186 # possible improvement: we could restrict the check to affected branch
singlehead: introduce special handling of closed heads...
r43239 bm = visible.branchmap()
for name in bm:
heads = bm.branchheads(name, closed=accountclosed)
Boris Feld
server: introduce a 'experimental.single-head-per-branch' option...
r35186 if len(heads) > 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'rejecting multiple heads on branch "%s"')
Boris Feld
server: introduce a 'experimental.single-head-per-branch' option...
r35186 msg %= name
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 hint = _(b'%d heads: %s')
Boris Feld
server: introduce a 'experimental.single-head-per-branch' option...
r35186 hint %= (len(heads), nodesummaries(repo, heads))
raise error.Abort(msg, hint=hint)
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
convert: allow the sink object to be wrapped when the extension isn't loaded...
r35169 def wrapconvertsink(sink):
"""Allow extensions to wrap the sink returned by convcmd.convertsink()
before it is used, whether or not the convert extension was formally loaded.
"""
return sink
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def unhidehashlikerevs(repo, specs, hiddentype: bytes):
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 """parse the user specs and unhide changesets whose hash or revision number
is passed.
hiddentype can be: 1) 'warn': warn while unhiding changesets
2) 'nowarn': don't warn while unhiding changesets
returns a repo object with the required changesets unhidden
"""
Kyle Lippincott
directaccess: fix uses of commands.status() that don't go through flag parsing...
r49291 if not specs:
return repo
Augie Fackler
formatting: blacken the codebase...
r43346 if not repo.filtername or not repo.ui.configbool(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'experimental', b'directaccess'
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 return repo
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.filtername not in (b'visible', b'visible-hidden'):
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 return repo
symbols = set()
for spec in specs:
try:
tree = revsetlang.parse(spec)
Augie Fackler
formatting: blacken the codebase...
r43346 except error.ParseError: # will be reported by scmutil.revrange()
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 continue
symbols.update(revsetlang.gethashlikesymbols(tree))
if not symbols:
return repo
revs = _getrevsfromsymbols(repo, symbols)
if not revs:
return repo
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if hiddentype == b'warn':
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 unfi = repo.unfiltered()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 revstr = b", ".join([pycompat.bytestr(unfi[l]) for l in revs])
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"warning: accessing hidden changesets for write "
b"operation: %s\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% revstr
)
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512
Pulkit Goyal
scmutil: use a tuple of possible values instead of using startswith()...
r35515 # we have to use new filtername to separate branch/tags cache until we can
# disbale these cache when revisions are dynamically pinned.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 return repo.filtered(b'visible-hidden', revs)
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def _getrevsfromsymbols(repo, symbols) -> Set[int]:
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 """parse the list of symbols and returns a set of revision numbers of hidden
changesets present in symbols"""
revs = set()
unfi = repo.unfiltered()
unficl = unfi.changelog
cl = repo.changelog
tiprev = len(unficl)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 allowrevnums = repo.ui.configbool(b'experimental', b'directaccess.revnums')
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 for s in symbols:
try:
n = int(s)
if n <= tiprev:
if not allowrevnums:
continue
else:
if n not in cl:
revs.add(n)
continue
except ValueError:
pass
try:
Martin von Zweigbergk
directaccess: use resolvehexnodeidprefix() instead of _partialmatch()...
r37885 s = resolvehexnodeidprefix(unfi, s)
Yuya Nishihara
directaccess: do not abort by 'ff...' hash...
r37112 except (error.LookupError, error.WdirUnsupported):
Pulkit Goyal
scmutil: add utility fn to return repo object with user passed revs unhidden...
r35512 s = None
if s is not None:
rev = unficl.rev(s)
if rev not in cl:
revs.add(rev)
return revs
David Demelier
scmutil: move repair.stripbmrevset as scmutil.bookmarkrevs (API)
r38146
Augie Fackler
formatting: blacken the codebase...
r43346
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def bookmarkrevs(repo, mark: bytes):
Yuya Nishihara
scmutil: document that bookmarkrevs() ignores non-head bookmark branch...
r46654 """Select revisions reachable by a given bookmark
If the bookmarked revision isn't a head, an empty set will be returned.
David Demelier
scmutil: move repair.stripbmrevset as scmutil.bookmarkrevs (API)
r38146 """
Yuya Nishihara
scmutil: extract function that builds revset expr to select bookmark branch...
r46655 return repo.revs(format_bookmark_revspec(mark))
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def format_bookmark_revspec(mark: bytes) -> bytes:
Yuya Nishihara
scmutil: extract function that builds revset expr to select bookmark branch...
r46655 """Build a revset expression to select revisions reachable by a given
bookmark"""
Yuya Nishihara
log: do not accept string-matcher pattern as -u/-b/-B parameter...
r46657 mark = b'literal:' + mark
Yuya Nishihara
scmutil: extract function that builds revset expr to select bookmark branch...
r46655 return revsetlang.formatspec(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"ancestors(bookmark(%s)) - "
b"ancestors(head() and not bookmark(%s)) - "
b"ancestors(bookmark() and not bookmark(%s))",
Augie Fackler
formatting: blacken the codebase...
r43346 mark,
mark,
mark,
)
hgweb: move ismember from `hgweb.common` to `scmutil`...
r51314
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 def ismember(ui: "uimod.ui", username: bytes, userlist: List[bytes]) -> bool:
hgweb: move ismember from `hgweb.common` to `scmutil`...
r51314 """Check if username is a member of userlist.
If userlist has a single '*' member, all users are considered members.
Can be overridden by extensions to provide more complex authorization
schemes.
"""
return userlist == [b'*'] or username in userlist
usage: add configuration option to adjust resources usage...
r52176
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 RESOURCE_HIGH: int = 3
RESOURCE_MEDIUM: int = 2
RESOURCE_LOW: int = 1
RESOURCE_DEFAULT: int = 0
RESOURCE_MAPPING: Dict[bytes, int] = {
usage: add configuration option to adjust resources usage...
r52176 b'default': RESOURCE_DEFAULT,
b'low': RESOURCE_LOW,
b'medium': RESOURCE_MEDIUM,
b'high': RESOURCE_HIGH,
}
Matt Harbison
typing: add trivial type hints to `mercurial.scmutil`...
r52625 DEFAULT_RESOURCE: int = RESOURCE_MEDIUM
def get_resource_profile(
ui: "uimod.ui", dimension: Optional[bytes] = None
) -> int:
usage: add configuration option to adjust resources usage...
r52176 """return the resource profile for a dimension
If no dimension is specified, the generic value is returned"""
generic_name = ui.config(b'usage', b'resources')
value = RESOURCE_MAPPING.get(generic_name, RESOURCE_DEFAULT)
if value == RESOURCE_DEFAULT:
value = DEFAULT_RESOURCE
if dimension is not None:
sub_name = ui.config(b'usage', b'resources.%s' % dimension)
sub_value = RESOURCE_MAPPING.get(sub_name, RESOURCE_DEFAULT)
if sub_value != RESOURCE_DEFAULT:
value = sub_value
return value