# HG changeset patch # User Pierre-Yves David # Date 2024-09-06 00:12:19 # Node ID 454feddab720ff77372dae0d6bb37d85d7fb8bc9 # Parent 4eccb65e444fce8f6b94060651866dcb331bf89f # Parent 6388fd855f66ab4491270ff9aac6ed2d84dce38e brancing: merge stable into default diff --git a/hgext/highlight/__init__.py b/hgext/highlight/__init__.py --- a/hgext/highlight/__init__.py +++ b/hgext/highlight/__init__.py @@ -105,4 +105,4 @@ def extsetup(ui): ) extensions.wrapfunction(webcommands, 'annotate', annotate_highlight) webcommands.highlightcss = generate_css - webcommands.__all__.append(b'highlightcss') + webcommands.__all__.append('highlightcss') diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1716,7 +1716,7 @@ def _chisteditmain(repo, rules, stdscr): ch = encoding.strtolocal(stdscr.getkey()) -def _chistedit(ui, repo, freeargs, opts): +def _chistedit(ui, repo, state, freeargs, opts): """interactively edit changeset history via a curses interface Provides a ncurses interface to histedit. Press ? in chistedit mode @@ -1776,7 +1776,7 @@ def _chistedit(ui, repo, freeargs, opts) for r in rules: fp.write(r) opts[b'commands'] = fp.name - return _texthistedit(ui, repo, freeargs, opts) + return _texthistedit(ui, repo, state, freeargs, opts) except KeyboardInterrupt: pass return -1 @@ -1915,20 +1915,20 @@ def histedit(ui, repo, *freeargs, **opts """ opts = pycompat.byteskwargs(opts) - # kludge: _chistedit only works for starting an edit, not aborting - # or continuing, so fall back to regular _texthistedit for those - # operations. - if ui.interface(b'histedit') == b'curses' and _getgoal(opts) == goalnew: - return _chistedit(ui, repo, freeargs, opts) - return _texthistedit(ui, repo, freeargs, opts) - - -def _texthistedit(ui, repo, freeargs, opts): state = histeditstate(repo) with repo.wlock() as wlock, repo.lock() as lock: state.wlock = wlock state.lock = lock - _histedit(ui, repo, state, freeargs, opts) + # kludge: _chistedit only works for starting an edit, not aborting + # or continuing, so fall back to regular _texthistedit for those + # operations. + if ui.interface(b'histedit') == b'curses' and _getgoal(opts) == goalnew: + return _chistedit(ui, repo, state, freeargs, opts) + return _texthistedit(ui, repo, state, freeargs, opts) + + +def _texthistedit(ui, repo, state, freeargs, opts): + _histedit(ui, repo, state, freeargs, opts) goalcontinue = b'continue' diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -49,6 +49,8 @@ from mercurial.upgrade_utils import ( actions as upgrade_actions, ) +from mercurial.utils import urlutil + from . import ( lfcommands, lfutil, @@ -1139,7 +1141,10 @@ def overrideclone(orig, ui, source, dest d = dest if d is None: d = hg.defaultdest(source) - if opts.get('all_largefiles') and not hg.islocal(d): + if opts.get('all_largefiles') and urlutil.url(d).scheme not in ( + b'file', + None, + ): raise error.Abort( _(b'--all-largefiles is incompatible with non-local destination %s') % d diff --git a/hgext/zeroconf/Zeroconf.py b/hgext/zeroconf/Zeroconf.py --- a/hgext/zeroconf/Zeroconf.py +++ b/hgext/zeroconf/Zeroconf.py @@ -89,7 +89,7 @@ import traceback from mercurial import pycompat -__all__ = [b"Zeroconf", b"ServiceInfo", b"ServiceBrowser"] +__all__ = ["Zeroconf", "ServiceInfo", "ServiceBrowser"] # hook for threads diff --git a/mercurial/cffi/bdiff.py b/mercurial/cffi/bdiff.py --- a/mercurial/cffi/bdiff.py +++ b/mercurial/cffi/bdiff.py @@ -21,11 +21,11 @@ lib = _bdiff.lib def blocks(sa: bytes, sb: bytes) -> List[Tuple[int, int, int, int]]: - a = ffi.new(b"struct bdiff_line**") - b = ffi.new(b"struct bdiff_line**") - ac = ffi.new(b"char[]", str(sa)) - bc = ffi.new(b"char[]", str(sb)) - l = ffi.new(b"struct bdiff_hunk*") + a = ffi.new("struct bdiff_line**") + b = ffi.new("struct bdiff_line**") + ac = ffi.new("char[]", bytes(sa)) + bc = ffi.new("char[]", bytes(sb)) + l = ffi.new("struct bdiff_hunk*") try: an = lib.bdiff_splitlines(ac, len(sa), a) bn = lib.bdiff_splitlines(bc, len(sb), b) @@ -49,11 +49,11 @@ def blocks(sa: bytes, sb: bytes) -> List def bdiff(sa: bytes, sb: bytes) -> bytes: - a = ffi.new(b"struct bdiff_line**") - b = ffi.new(b"struct bdiff_line**") - ac = ffi.new(b"char[]", str(sa)) - bc = ffi.new(b"char[]", str(sb)) - l = ffi.new(b"struct bdiff_hunk*") + a = ffi.new("struct bdiff_line**") + b = ffi.new("struct bdiff_line**") + ac = ffi.new("char[]", bytes(sa)) + bc = ffi.new("char[]", bytes(sb)) + l = ffi.new("struct bdiff_hunk*") try: an = lib.bdiff_splitlines(ac, len(sa), a) bn = lib.bdiff_splitlines(bc, len(sb), b) @@ -76,7 +76,7 @@ def bdiff(sa: bytes, sb: bytes) -> bytes lgt, ) ) - rl.append(str(ffi.buffer((b[0] + lb).l, lgt))) + rl.append(bytes(ffi.buffer((b[0] + lb).l, lgt))) la = h.a2 lb = h.b2 h = h.next diff --git a/mercurial/cffi/mpatch.py b/mercurial/cffi/mpatch.py --- a/mercurial/cffi/mpatch.py +++ b/mercurial/cffi/mpatch.py @@ -19,8 +19,8 @@ lib = _mpatch.lib @ffi.def_extern() def cffi_get_next_item(arg, pos): all, bins = ffi.from_handle(arg) - container = ffi.new(b"struct mpatch_flist*[1]") - to_pass = ffi.new(b"char[]", str(bins[pos])) + container = ffi.new("struct mpatch_flist*[1]") + to_pass = ffi.new("char[]", bytes(bins[pos])) all.append(to_pass) r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container) if r < 0: @@ -41,7 +41,7 @@ def patches(text: bytes, bins: List[byte if outlen < 0: lib.mpatch_lfree(patch) raise mpatchError(b"inconsistency detected") - buf = ffi.new(b"char[]", outlen) + buf = ffi.new("char[]", outlen) if lib.mpatch_apply(buf, text, len(text), patch) < 0: lib.mpatch_lfree(patch) raise mpatchError(b"error applying patches") diff --git a/mercurial/cffi/osutil.py b/mercurial/cffi/osutil.py --- a/mercurial/cffi/osutil.py +++ b/mercurial/cffi/osutil.py @@ -39,8 +39,8 @@ if pycompat.isdarwin: self.st_mtime = st_mtime self.st_size = st_size - tv_sec_ofs = ffi.offsetof(b"struct timespec", b"tv_sec") - buf = ffi.new(b"char[]", listdir_batch_size) + tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec") + buf = ffi.new("char[]", listdir_batch_size) def listdirinternal(dfd, req, stat, skip): ret = [] @@ -50,16 +50,16 @@ if pycompat.isdarwin: break if r == -1: raise OSError(ffi.errno, os.strerror(ffi.errno)) - cur = ffi.cast(b"val_attrs_t*", buf) + cur = ffi.cast("val_attrs_t*", buf) for i in range(r): lgt = cur.length - assert lgt == ffi.cast(b'uint32_t*', cur)[0] + assert lgt == ffi.cast('uint32_t*', cur)[0] ofs = cur.name_info.attr_dataoffset str_lgt = cur.name_info.attr_length - base_ofs = ffi.offsetof(b'val_attrs_t', b'name_info') + base_ofs = ffi.offsetof('val_attrs_t', 'name_info') name = bytes( ffi.buffer( - ffi.cast(b"char*", cur) + base_ofs + ofs, str_lgt - 1 + ffi.cast("char*", cur) + base_ofs + ofs, str_lgt - 1 ) ) tp = attrkinds[cur.obj_type] @@ -84,12 +84,12 @@ if pycompat.isdarwin: else: ret.append((name, tp)) cur = ffi.cast( - b"val_attrs_t*", int(ffi.cast(b"intptr_t", cur)) + lgt + "val_attrs_t*", int(ffi.cast("intptr_t", cur)) + lgt ) return ret def listdir(path, stat=False, skip=None): - req = ffi.new(b"struct attrlist*") + req = ffi.new("struct attrlist*") req.bitmapcount = lib.ATTR_BIT_MAP_COUNT req.commonattr = ( lib.ATTR_CMN_RETURNED_ATTRS diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py +++ b/mercurial/hgweb/hgweb_mod.py @@ -464,7 +464,7 @@ class hgweb: res.headers[b'ETag'] = tag - if cmd not in webcommands.__all__: + if pycompat.sysstr(cmd) not in webcommands.__all__: msg = b'no such method: %s' % cmd raise ErrorResponse(HTTP_BAD_REQUEST, msg) else: diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py +++ b/mercurial/hgweb/webcommands.py @@ -72,7 +72,7 @@ class webcommand: self.name = name def __call__(self, func): - __all__.append(self.name) + __all__.append(pycompat.sysstr(self.name)) commands[self.name] = func return func diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py --- a/mercurial/keepalive.py +++ b/mercurial/keepalive.py @@ -687,6 +687,6 @@ if __name__ == '__main__': N = int(sys.argv[1]) url = sys.argv[2] except (IndexError, ValueError): - print(b"%s " % sys.argv[0]) + print("%s " % sys.argv[0]) else: test(url, N) diff --git a/mercurial/lsprof.py b/mercurial/lsprof.py --- a/mercurial/lsprof.py +++ b/mercurial/lsprof.py @@ -6,7 +6,7 @@ Profiler = _lsprof.Profiler # PyPy doesn't expose profiler_entry from the module. profiler_entry = getattr(_lsprof, 'profiler_entry', None) -__all__ = [b'profile', b'Stats'] +__all__ = ['profile', 'Stats'] def profile(f, *args, **kwds): diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -528,7 +528,7 @@ def _filternarrowactions(narrowmatch, br """ # We mutate the items in the dict during iteration, so iterate # over a copy. - for f, action in mresult.filemap(): + for f, action in list(mresult.filemap()): if narrowmatch(f): pass elif not branchmerge: @@ -669,7 +669,7 @@ class mergeresult: return sum(len(self._actionmapping[a]) for a in actions) def filemap(self, sort=False): - if sorted: + if sort: for key, val in sorted(self._filemapping.items()): yield key, val else: diff --git a/mercurial/metadata.py b/mercurial/metadata.py --- a/mercurial/metadata.py +++ b/mercurial/metadata.py @@ -243,7 +243,7 @@ def compute_all_files_changes(ctx): return _process_linear(p1, ctx) elif p1.rev() == nullrev and p2.rev() != nullrev: # In the wild, one can encounter changeset where p1 is null but p2 is not - return _process_linear(p1, ctx, parent=2) + return _process_linear(p2, ctx, parent=2) elif p1.rev() == p2.rev(): # In the wild, one can encounter such "non-merge" return _process_linear(p1, ctx) diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -122,7 +122,7 @@ def split(stream): if not m.is_multipart(): yield msgfp(m) else: - ok_types = (b'text/plain', b'text/x-diff', b'text/x-patch') + ok_types = ('text/plain', 'text/x-diff', 'text/x-patch') for part in m.walk(): ct = part.get_content_type() if ct not in ok_types: diff --git a/mercurial/posix.py b/mercurial/posix.py --- a/mercurial/posix.py +++ b/mercurial/posix.py @@ -23,6 +23,7 @@ import unicodedata from typing import ( Any, AnyStr, + Callable, Iterable, Iterator, List, @@ -552,7 +553,7 @@ if pycompat.sysplatform == b'OpenVMS': return False -_needsshellquote: Optional[Match[bytes]] = None +_needsshellquote: Optional[Callable[[bytes], Optional[Match[bytes]]]] = None def shellquote(s: bytes) -> bytes: diff --git a/mercurial/statprof.py b/mercurial/statprof.py --- a/mercurial/statprof.py +++ b/mercurial/statprof.py @@ -126,7 +126,7 @@ from . import ( defaultdict = collections.defaultdict contextmanager = contextlib.contextmanager -__all__ = [b'start', b'stop', b'reset', b'display', b'profile'] +__all__ = ['start', 'stop', 'reset', 'display', 'profile'] skips = { "util.py:check", diff --git a/rust/Cargo.lock b/rust/Cargo.lock --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -734,9 +734,9 @@ checksum = "e2abad23fbc42b3700f2f279844d [[package]] name = "libc" -version = "0.2.137" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -1178,6 +1178,7 @@ dependencies = [ "hg-core", "home", "lazy_static", + "libc", "log", "logging_timer", "rayon", diff --git a/rust/rhg/Cargo.toml b/rust/rhg/Cargo.toml --- a/rust/rhg/Cargo.toml +++ b/rust/rhg/Cargo.toml @@ -24,3 +24,4 @@ shellexpand = { version = "3.1", feature whoami = "1.4" which = "4.3.0" rayon = "1.7.0" +libc = "0.2.155" diff --git a/rust/rhg/src/commands/status.rs b/rust/rhg/src/commands/status.rs --- a/rust/rhg/src/commands/status.rs +++ b/rust/rhg/src/commands/status.rs @@ -611,7 +611,11 @@ pub fn run(invocation: &crate::CliInvoca log::info!("not writing dirstate from `status`: lock is held") } Err(LockError::Other(HgError::IoError { error, .. })) - if error.kind() == io::ErrorKind::PermissionDenied => + if error.kind() == io::ErrorKind::PermissionDenied + || match error.raw_os_error() { + None => false, + Some(errno) => libc::EROFS == errno, + } => { // `hg status` on a read-only repository is fine } diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -1660,7 +1660,11 @@ if os.name == 'nt': # Allow compiler/linker flags to be added to Visual Studio builds. Passing # extra_link_args to distutils.extensions.Extension() doesn't have any # effect. - from distutils import msvccompiler + try: + # setuptools < 65.0 + from distutils import msvccompiler + except ImportError: + from distutils import _msvccompiler as msvccompiler msvccompilerclass = msvccompiler.MSVCCompiler diff --git a/tests/hgweberror.py b/tests/hgweberror.py --- a/tests/hgweberror.py +++ b/tests/hgweberror.py @@ -20,4 +20,4 @@ def raiseerror(web): def extsetup(ui): setattr(webcommands, 'raiseerror', raiseerror) - webcommands.__all__.append(b'raiseerror') + webcommands.__all__.append('raiseerror') diff --git a/tests/test-largefiles.t b/tests/test-largefiles.t --- a/tests/test-largefiles.t +++ b/tests/test-largefiles.t @@ -1076,6 +1076,11 @@ Ensure base clone command argument valid abort: --all-largefiles is incompatible with non-local destination ssh://localhost/a [255] + $ touch existing_destination + $ hg clone --all-largefiles a existing_destination + abort: destination 'existing_destination' already exists + [10] + Test pulling with --all-largefiles flag. Also test that the largefiles are downloaded from 'default' instead of 'default-push' when no source is specified (issue3584)