# HG changeset patch # User Raphaël Gomès # Date 1679350574 -3600 # Node ID c5e93c915ab668abf3eb695e6a6df0c91643eb5a # Parent dd42156b6441f6b8356100b4228fa16fbf95f669# Parent 972f3e5c94b835fc0640674e2baf0aeaf4f43c3a branching: merge stable into default diff -r dd42156b6441 -r c5e93c915ab6 .hgsigs --- a/.hgsigs Thu Mar 09 13:02:13 2023 -0600 +++ b/.hgsigs Mon Mar 20 23:16:14 2023 +0100 @@ -239,3 +239,4 @@ c890d8b8bc59b18e5febf60caada629df5356ee2 0 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 diff -r dd42156b6441 -r c5e93c915ab6 .hgtags --- a/.hgtags Thu Mar 09 13:02:13 2023 -0600 +++ b/.hgtags Mon Mar 20 23:16:14 2023 +0100 @@ -255,3 +255,4 @@ c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2 8830004967ad865ead89c28a410405a6e71e0796 6.3.3 +05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0 diff -r dd42156b6441 -r c5e93c915ab6 contrib/import-checker.py --- a/contrib/import-checker.py Thu Mar 09 13:02:13 2023 -0600 +++ b/contrib/import-checker.py Mon Mar 20 23:16:14 2023 +0100 @@ -232,6 +232,7 @@ yield 'importlib.abc' # python3 only yield 'importlib.machinery' # python3 only yield 'importlib.util' # python3 only + yield 'packaging.version' for m in 'fcntl', 'grp', 'pwd', 'termios': # Unix only yield m for m in 'cPickle', 'datetime': # in Python (not C) on PyPy diff -r dd42156b6441 -r c5e93c915ab6 hgext/histedit.py --- a/hgext/histedit.py Thu Mar 09 13:02:13 2023 -0600 +++ b/hgext/histedit.py Mon Mar 20 23:16:14 2023 +0100 @@ -1427,11 +1427,11 @@ for y in range(0, length): line = output[y] if diffcolors: - if line and line[0] == b'+': + if line.startswith(b'+'): win.addstr( y, 0, line, curses.color_pair(COLOR_DIFF_ADD_LINE) ) - elif line and line[0] == b'-': + elif line.startswith(b'-'): win.addstr( y, 0, line, curses.color_pair(COLOR_DIFF_DEL_LINE) ) diff -r dd42156b6441 -r c5e93c915ab6 hgext/narrow/narrowbundle2.py --- a/hgext/narrow/narrowbundle2.py Thu Mar 09 13:02:13 2023 -0600 +++ b/hgext/narrow/narrowbundle2.py Mon Mar 20 23:16:14 2023 +0100 @@ -6,7 +6,6 @@ # GNU General Public License version 2 or any later version. -import errno import struct from mercurial.i18n import _ @@ -20,10 +19,10 @@ repair, requirements, scmutil, + transaction, util, wireprototypes, ) -from mercurial.utils import stringutil _NARROWACL_SECTION = b'narrowacl' _CHANGESPECPART = b'narrow:changespec' @@ -295,16 +294,7 @@ finally: f.close() - # remove undo files - for undovfs, undofile in repo.undofiles(): - try: - undovfs.unlink(undofile) - except OSError as e: - if e.errno != errno.ENOENT: - ui.warn( - _(b'error removing %s: %s\n') - % (undovfs.join(undofile), stringutil.forcebytestr(e)) - ) + transaction.cleanup_undo_files(repo.ui.warn, repo.vfs_map) # Remove partial backup only if there were no exceptions op._widen_uninterr.__exit__(None, None, None) diff -r dd42156b6441 -r c5e93c915ab6 mercurial/cext/dirs.c --- a/mercurial/cext/dirs.c Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/cext/dirs.c Mon Mar 20 23:16:14 2023 +0100 @@ -13,7 +13,11 @@ #include "util.h" +#if PY_VERSION_HEX >= 0x030C00A5 +#define PYLONG_VALUE(o) ((PyLongObject *)o)->long_value.ob_digit[0] +#else #define PYLONG_VALUE(o) ((PyLongObject *)o)->ob_digit[0] +#endif /* * This is a multiset of directory names, built from the files that diff -r dd42156b6441 -r c5e93c915ab6 mercurial/commands.py --- a/mercurial/commands.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/commands.py Mon Mar 20 23:16:14 2023 +0100 @@ -2507,7 +2507,7 @@ """ opts = pycompat.byteskwargs(opts) - context = repo.dirstate.changing_files + context = lambda repo: repo.dirstate.changing_files(repo) rev = opts.get(b'at_rev') ctx = None if rev: @@ -6019,7 +6019,7 @@ Returns 0 on success, 1 if errors are encountered. """ opts = pycompat.byteskwargs(opts) - context = repo.dirstate.changing_files + context = lambda repo: repo.dirstate.changing_files(repo) rev = opts.get(b'at_rev') ctx = None if rev: diff -r dd42156b6441 -r c5e93c915ab6 mercurial/dirstate.py --- a/mercurial/dirstate.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/dirstate.py Mon Mar 20 23:16:14 2023 +0100 @@ -200,6 +200,12 @@ self._cwd def refresh(self): + # XXX if this happens, you likely did not enter the `changing_xxx` + # using `repo.dirstate`, so a later `repo.dirstate` accesss might call + # `refresh`. + if self.is_changing_any: + msg = "refreshing the dirstate in the middle of a change" + raise error.ProgrammingError(msg) if '_branch' in vars(self): del self._branch if '_map' in vars(self) and self._map.may_need_refresh(): diff -r dd42156b6441 -r c5e93c915ab6 mercurial/interfaces/repository.py --- a/mercurial/interfaces/repository.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/interfaces/repository.py Mon Mar 20 23:16:14 2023 +0100 @@ -1524,6 +1524,10 @@ """Name of the repoview that is active on this repo.""" ) + vfs_map = interfaceutil.Attribute( + """a bytes-key → vfs mapping used by transaction and others""" + ) + wvfs = interfaceutil.Attribute( """VFS used to access the working directory.""" ) diff -r dd42156b6441 -r c5e93c915ab6 mercurial/localrepo.py --- a/mercurial/localrepo.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/localrepo.py Mon Mar 20 23:16:14 2023 +0100 @@ -1565,6 +1565,14 @@ return checksvfs + @property + def vfs_map(self): + return { + b'': self.svfs, + b'plain': self.vfs, + b'store': self.svfs, + } + def close(self): self._writecaches() @@ -2410,12 +2418,11 @@ self.hook(b'pretxnopen', throw=True, txnname=desc, txnid=txnid) self._writejournal(desc) - renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()] if report: rp = report else: rp = self.ui.warn - vfsmap = {b'plain': self.vfs, b'store': self.svfs} # root of .hg/ + vfsmap = self.vfs_map # we must avoid cyclic reference between repo and transaction. reporef = weakref.ref(self) # Code to track tag movement @@ -2568,13 +2575,15 @@ vfsmap, b"journal", b"undo", - aftertrans(renames), + lambda: None, self.store.createmode, validator=validate, releasefn=releasefn, checkambigfiles=_cachedfiles, name=desc, ) + for vfs_id, path in self._journalfiles(): + tr.add_journal(vfs_id, path) tr.changes[b'origrepolen'] = len(self) tr.changes[b'obsmarkers'] = set() tr.changes[b'phases'] = [] @@ -2704,10 +2713,7 @@ with self.lock(): if self.svfs.exists(b"journal"): self.ui.status(_(b"rolling back interrupted transaction\n")) - vfsmap = { - b'': self.svfs, - b'plain': self.vfs, - } + vfsmap = self.vfs_map transaction.rollback( self.svfs, vfsmap, @@ -2775,7 +2781,7 @@ return 0 self.destroying() - vfsmap = {b'plain': self.vfs, b'': self.svfs} + vfsmap = self.vfs_map skip_journal_pattern = None if not parentgone: skip_journal_pattern = RE_SKIP_DIRSTATE_ROLLBACK @@ -2945,6 +2951,7 @@ known good state).""" unfi = self.unfiltered() if 'dirstate' in unfi.__dict__: + assert not self.dirstate.is_changing_any del unfi.__dict__['dirstate'] def invalidate(self, clearfilecache=False): @@ -3542,24 +3549,6 @@ self._sidedata_computers[kind][category] = (keys, computer, flags) -# used to avoid circular references so destructors work -def aftertrans(files): - renamefiles = [tuple(t) for t in files] - - def a(): - for vfs, src, dest in renamefiles: - # if src and dest refer to a same file, vfs.rename is a no-op, - # leaving both src and dest on disk. delete dest to make sure - # the rename couldn't be such a no-op. - vfs.tryunlink(dest) - try: - vfs.rename(src, dest) - except FileNotFoundError: # journal file does not yet exist - pass - - return a - - def undoname(fn: bytes) -> bytes: base, name = os.path.split(fn) assert name.startswith(b'journal') diff -r dd42156b6441 -r c5e93c915ab6 mercurial/match.py --- a/mercurial/match.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/match.py Mon Mar 20 23:16:14 2023 +0100 @@ -196,14 +196,14 @@ ... return match(util.localpath(root), *args, **kwargs) Usually a patternmatcher is returned: - >>> _match(b'/foo', b'.', [b're:.*\.c$', b'path:foo/a', b'*.py']) + >>> _match(b'/foo', b'.', [br're:.*\.c$', b'path:foo/a', b'*.py']) Combining 'patterns' with 'include' (resp. 'exclude') gives an intersectionmatcher (resp. a differencematcher): - >>> type(_match(b'/foo', b'.', [b're:.*\.c$'], include=[b'path:lib'])) + >>> type(_match(b'/foo', b'.', [br're:.*\.c$'], include=[b'path:lib'])) - >>> type(_match(b'/foo', b'.', [b're:.*\.c$'], exclude=[b'path:build'])) + >>> type(_match(b'/foo', b'.', [br're:.*\.c$'], exclude=[b'path:build'])) Notice that, if 'patterns' is empty, an alwaysmatcher is returned: @@ -212,7 +212,7 @@ The 'default' argument determines which kind of pattern is assumed if a pattern has no prefix: - >>> _match(b'/foo', b'.', [b'.*\.c$'], default=b're') + >>> _match(b'/foo', b'.', [br'.*\.c$'], default=b're') >>> _match(b'/foo', b'.', [b'main.py'], default=b'relpath') @@ -223,7 +223,7 @@ name) matches againset one of the patterns given at initialization. There are two ways of doing this check. - >>> m = _match(b'/foo', b'', [b're:.*\.c$', b'relpath:a']) + >>> m = _match(b'/foo', b'', [br're:.*\.c$', b'relpath:a']) 1. Calling the matcher with a file name returns True if any pattern matches that file name: diff -r dd42156b6441 -r c5e93c915ab6 mercurial/repair.py --- a/mercurial/repair.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/repair.py Mon Mar 20 23:16:14 2023 +0100 @@ -7,8 +7,6 @@ # GNU General Public License version 2 or any later version. -import errno - from .i18n import _ from .node import ( hex, @@ -26,11 +24,11 @@ phases, requirements, scmutil, + transaction, util, ) from .utils import ( hashutil, - stringutil, urlutil, ) @@ -270,19 +268,7 @@ bmchanges = [(m, repo[newbmtarget].node()) for m in updatebm] repo._bookmarks.applychanges(repo, tr, bmchanges) - # remove undo files - for undovfs, undofile in repo.undofiles(): - try: - undovfs.unlink(undofile) - except OSError as e: - if e.errno != errno.ENOENT: - ui.warn( - _(b'error removing %s: %s\n') - % ( - undovfs.join(undofile), - stringutil.forcebytestr(e), - ) - ) + transaction.cleanup_undo_files(repo.ui.warn, repo.vfs_map) except: # re-raises if backupfile: diff -r dd42156b6441 -r c5e93c915ab6 mercurial/statprof.py --- a/mercurial/statprof.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/statprof.py Mon Mar 20 23:16:14 2023 +0100 @@ -540,7 +540,11 @@ for stat in stats: site = stat.site - sitelabel = b'%s:%d:%s' % (site.filename(), site.lineno, site.function) + sitelabel = b'%s:%d:%s' % ( + site.filename(), + site.lineno or -1, + site.function, + ) fp.write( b'%6.2f %9.2f %9.2f %s\n' % ( @@ -613,7 +617,7 @@ stattuple = ( stat.selfpercent(), stat.selfseconds(), - stat.site.lineno, + stat.site.lineno or -1, source, ) diff -r dd42156b6441 -r c5e93c915ab6 mercurial/streamclone.py --- a/mercurial/streamclone.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/streamclone.py Mon Mar 20 23:16:14 2023 +0100 @@ -7,7 +7,6 @@ import contextlib -import errno import os import struct @@ -24,14 +23,12 @@ requirements as requirementsmod, scmutil, store, + transaction, util, ) from .revlogutils import ( nodemap, ) -from .utils import ( - stringutil, -) def new_stream_clone_requirements(default_requirements, streamed_requirements): @@ -935,15 +932,4 @@ dest_repo.store.write(tr) # clean up transaction file as they do not make sense - undo_files = [(dest_repo.svfs, b'undo.backupfiles')] - undo_files.extend(dest_repo.undofiles()) - for undovfs, undofile in undo_files: - try: - undovfs.unlink(undofile) - except OSError as e: - if e.errno != errno.ENOENT: - msg = _(b'error removing %s: %s\n') - path = undovfs.join(undofile) - e_msg = stringutil.forcebytestr(e) - msg %= (path, e_msg) - dest_repo.ui.warn(msg) + transaction.cleanup_undo_files(dest_repo.ui.warn, dest_repo.vfs_map) diff -r dd42156b6441 -r c5e93c915ab6 mercurial/transaction.py --- a/mercurial/transaction.py Thu Mar 09 13:02:13 2023 -0600 +++ b/mercurial/transaction.py Mon Mar 20 23:16:14 2023 +0100 @@ -11,6 +11,8 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. +import errno +import os from .i18n import _ from . import ( @@ -38,6 +40,61 @@ return _active +UNDO_BACKUP = b'%s.backupfiles' + +UNDO_FILES_MAY_NEED_CLEANUP = [ + # legacy entries that might exists on disk from previous version: + (b'store', b'%s.narrowspec'), + (b'plain', b'%s.narrowspec.dirstate'), + (b'plain', b'%s.branch'), + (b'plain', b'%s.bookmarks'), + (b'store', b'%s.phaseroots'), + (b'plain', b'%s.dirstate'), + # files actually in uses today: + (b'plain', b'%s.desc'), + # Always delete undo last to make sure we detect that a clean up is needed if + # the process is interrupted. + (b'store', b'%s'), +] + + +def cleanup_undo_files(report, vfsmap, undo_prefix=b'undo'): + """remove "undo" files used by the rollback logic + + This is useful to prevent rollback running in situation were it does not + make sense. For example after a strip. + """ + backup_listing = UNDO_BACKUP % undo_prefix + + backup_entries = [] + undo_files = [] + svfs = vfsmap[b'store'] + try: + with svfs(backup_listing) as f: + backup_entries = read_backup_files(report, f) + except OSError as e: + if e.errno != errno.ENOENT: + msg = _(b'could not read %s: %s\n') + msg %= (svfs.join(backup_listing), stringutil.forcebytestr(e)) + report(msg) + + for location, f, backup_path, c in backup_entries: + if location in vfsmap and backup_path: + undo_files.append((vfsmap[location], backup_path)) + + undo_files.append((svfs, backup_listing)) + for location, undo_path in UNDO_FILES_MAY_NEED_CLEANUP: + undo_files.append((vfsmap[location], undo_path % undo_prefix)) + for undovfs, undofile in undo_files: + try: + undovfs.unlink(undofile) + except OSError as e: + if e.errno != errno.ENOENT: + msg = _(b'error removing %s: %s\n') + msg %= (undovfs.join(undofile), stringutil.forcebytestr(e)) + report(msg) + + def _playback( journal, report, @@ -152,6 +209,7 @@ self._offsetmap = {} self._newfiles = set() self._journal = journalname + self._journal_files = [] self._undoname = undoname self._queue = [] # A callback to do something just after releasing transaction. @@ -632,10 +690,25 @@ scope)""" self._abort() + @active + def add_journal(self, vfs_id, path): + self._journal_files.append((vfs_id, path)) + def _writeundo(self): """write transaction data for possible future undo call""" if self._undoname is None: return + cleanup_undo_files( + self._report, + self._vfsmap, + undo_prefix=self._undoname, + ) + + def undoname(fn: bytes) -> bytes: + base, name = os.path.split(fn) + assert name.startswith(self._journal) + new_name = name.replace(self._journal, self._undoname, 1) + return os.path.join(base, new_name) undo_backup_path = b"%s.backupfiles" % self._undoname undobackupfile = self._opener.open(undo_backup_path, b'w') @@ -653,13 +726,20 @@ ) continue vfs = self._vfsmap[l] - base, name = vfs.split(b) - assert name.startswith(self._journal), name - uname = name.replace(self._journal, self._undoname, 1) - u = vfs.reljoin(base, uname) + u = undoname(b) util.copyfile(vfs.join(b), vfs.join(u), hardlink=True) undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c)) undobackupfile.close() + for vfs, src in self._journal_files: + dest = undoname(src) + # if src and dest refer to a same file, vfs.rename is a no-op, + # leaving both src and dest on disk. delete dest to make sure + # the rename couldn't be such a no-op. + vfs.tryunlink(dest) + try: + vfs.rename(src, dest) + except FileNotFoundError: # journal file does not yet exist + pass def _abort(self): entries = self.readjournal() @@ -737,6 +817,32 @@ ) +def read_backup_files(report, fp): + """parse an (already open) backup file an return contained backup entries + + entries are in the form: (location, file, backupfile, xxx) + + :location: the vfs identifier (vfsmap's key) + :file: original file path (in the vfs) + :backupfile: path of the backup (in the vfs) + :cache: a boolean currently always set to False + """ + lines = fp.readlines() + backupentries = [] + if lines: + ver = lines[0][:-1] + if ver != (b'%d' % version): + report(BAD_VERSION_MSG) + else: + for line in lines[1:]: + if line: + # Shave off the trailing newline + line = line[:-1] + l, f, b, c = line.split(b'\0') + backupentries.append((l, f, b, bool(c))) + return backupentries + + def rollback( opener, vfsmap, @@ -776,19 +882,8 @@ backupjournal = b"%s.backupfiles" % file if opener.exists(backupjournal): - fp = opener.open(backupjournal) - lines = fp.readlines() - if lines: - ver = lines[0][:-1] - if ver != (b'%d' % version): - report(BAD_VERSION_MSG) - else: - for line in lines[1:]: - if line: - # Shave off the trailing newline - line = line[:-1] - l, f, b, c = line.split(b'\0') - backupentries.append((l, f, b, bool(c))) + with opener.open(backupjournal) as fp: + backupentries = read_backup_files(report, fp) if skip_journal_pattern is not None: keep = lambda x: not skip_journal_pattern.match(x[1]) backupentries = [x for x in backupentries if keep(x)] diff -r dd42156b6441 -r c5e93c915ab6 relnotes/6.4 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/relnotes/6.4 Mon Mar 20 23:16:14 2023 +0100 @@ -0,0 +1,144 @@ += Mercurial 6.4rc0 = + +== New Features == + + * There is a new internal merge tool called `internal:union-other-first`. + It works like `internal:union` but add other side on top of local. + * Pullbundles are enabled by default + * delta-find: add a way to control the number of bases tested at the same time + * changelog-v2: add a configuration to disable rank computation + * debug: add an option to display statistic about a bundling operation + * debug: add an option to display statistic about a unbundling operation + * delta-find: add a delta-reuse policy that blindly accepts incoming deltas + * debug: add debug-revlog-stats command + * dirstate: add narrow support to `verify` + * verify: also check dirstate + * commit: add --draft option to use draft phase + * amend: add a --draft option to set phase to draft + * debug: add a config to abort update early + * rhg: implement checkexec to support weird filesystems + * debugshell: allow commands to be specified as a CLI argument + * rhg-files: add support for narrow when specifying a revision + * rust-narrow: enable narrow support for plain `rhg files` + +== Bug Fixes == + +Aside from the following (unordered) commits which made it through a manual filter, there are a bunch of typing improvements and fixes, removal of deprecated code and general code cleanup. + + * lfs: improve an exception message for blob corruption detected on transfer + * revlog: use the user facing filename as the display_id for filelogs + * rust-status: query fs traversal metadata lazily + * shelve: add Shelf.changed_files for resolving changed files in a plugin + * demandimport: ensure lazyloaderex sets loader attributes (issue6725) + * typing: fix a syntax error in mercurial/cext/bdiff.pyi + * cffi: fix a bytes vs str issue on macOS when listing directories + * changelog-v2: fix the docket `struct` + * schemes: fix a broken check for drive letter conflicts + * worker: avoid reading 1 byte at a time from the OS pipe + * rust-narrow: fix loop that never loops + * setup: Ensure target directory exists with building rust extension + * dirstate: invalidate changes when parent-change fails + * dirstate: warn about non-explicitly rolledback parent-change + * dirstate: write dirstate on successful exit of changing_parents context + * largefile: make sure we hold the lock when updating the second dirstate + * dirstate: enforce holding the lock while doing any changes + * run-tests: stop ignoring venv-installed packages + * transaction: run abort callback in all cases + * transaction: quietly rollback if no other changes than temporary files + * debugrebuilddirstate: double check that no transaction is open + * dirstate: do not write an empty dirstate just for backup + * locking: take the `wlock` for the full `hg add` duration + * locking: take the `wlock` for the full `hg remove` duration + * locking: take the `wlock` for the full `hg forget` duration + * locking: take the `wlock` for the full `hg addremove` duration + * locking: grab the wlock before touching the dirstate in `perfdirstatewrite` + * locking: hold the wlock for the full duration of the "keyword demo" + * mq: properly take the wlock during the full qfold operation + * dirstate: invalidate the dirstate change on transaction failure + * status: fix post status writing + * status: fix post status invalidation + * dirstate: avoid transaction backup/restore if we do not hold the lock + * rollback: explicitly skip dirstate rollback when applicable + * dirstate-guard: remove the feature + * dirstate: make `restorebackup` more robust when it is a noop + * dirstate: generalize the dirstate's invalidation on transaction abort + * dirstate: detect potential fishy transaction patterns while changing + * mq: write the dirstate before stripping + * dirstate: explicitly backup the datafile + * localrepo: enforce a clean dirstate when the transaction open + * localrepo: "blindly" do a dirstate backup at the end of the transaction + * dirstate: remove the dedicated backup logic + * rhg: fix a bug in path_encode + * dirstate: invalidate on all exceptions + * large-files: make sure we write newly initialized standin file early + * dirstate: warn if dirty when starting an edition + * dirstate: track that changes are pending in a transaction + * dirstate: distinct transaction callback from largefile + * automv: lock the repository before searching for renames + * dirstate: only reload the dirstate when it may have changed + * dirstate: cleanup the `_map` property cache + * status: invalidate dirstate on LockError + * dirstate: check that dirstate is clean at the initial context opening + * dirstate: have `running_status` write the dirstate when holding the lock + * dirstate: have `running_status` warn when exiting with a dirty dirstate + * narrow: widden the lock context in `tracking` + * narrow: enforce that narrow spec is written within a transaction + * transaction: no longer explicitly cache phaseroots + * transaction: no longer explicitly cache bookmarks + * transaction: use the standard transaction mechanism to backup branch + * bundlerepo: handle changegroup induced phase movement in the associated method + * bundlerepo: apply phase data stored in the bundle instead of assuming `draft` + * config-item: declare undeclared path suboption + * narrow: read pending file when applicable + +== Backwards Compatibility Changes == + * rust: upgrade supported Rust toolchain version + * rust: move all crates in the main workspace to edition 2021 + * hg-core: upgrade `zstd` dependency + * hg-core: upgrade `clap` dependency + * hg-core: upgrade all remaining dependencies + * hg-cpython: upgrade dependencies + * rhg: upgrade `clap` dependency + * rhg: upgrade the remainder of the dependencies + +== Internal API Changes == + + * Many APIs around the dirstate have been made much stricter with regards to + locking and transaction handling + * Some dirstate APIs have been renamed/removed + * In both cases, you should get loud complaints in your tests if you do + something wrong. + +== Miscellaneous == + + * pullbundle support no longer requires setting a server-side option, + providing a .hg/pullbundles.manifest according to the syntax specified in + 'hg help -e clonebundles' is enough. + * debug-delta-find: add a --source option + * delta-find: add debug information about reuse of cached data + * delta-find: set the default candidate chunk size to 10 + * attr: vendor 22.1.0 + * configitems: add a default value for "merge-tools.xxx.regappend" + * debugrevlog: display total stored information + * emitrevision: if we need to compute a delta on the fly, try p1 or p2 first + * emitrevision: consider ancestors revision to emit as available base + * find-delta: pass the cache-delta usage policy alongside the cache-delta + * delta-find: use a smarter object for snapshot caching + * delta-find: use sets instead of list in the snapshot cache + * delta-find: make sure we only use newer full snapshot as candidate + * delta-find: use a single snapshot cache when applying a group to an object + * bundleoperation: optionnaly record the `remote` that produced the bundle + * bundle: when forcing acceptance of incoming delta also accept snapshot + * bundle: emit full snapshot as is, without doing a redelta + * pathutil: slightly faster path audit in the common case + * merge: don't pay for pathconflicts if there are none + * merge: short-circuit the _checkfs loop upon getting ENOENT + * merge: disable the whole filesystem access loop if [_realfs] is false + * merge: cache the fs checks made during [_checkunknownfiles] + * rust: use `logging_timer` instead of `micro_timer` + * rust: run `cargo clippy` + * makefile: add `cargo clippy` to tests if cargo is available + * heptapod-ci: add `clippy` to the CI + * convert: use a priority queue for sorting commits, to make sorting faster + * delta-find: adjust the default candidate group chunk size + * delta-find: declare the "paths..*:pulled-delta-reuse-policy option \ No newline at end of file diff -r dd42156b6441 -r c5e93c915ab6 relnotes/next --- a/relnotes/next Thu Mar 09 13:02:13 2023 -0600 +++ b/relnotes/next Mon Mar 20 23:16:14 2023 +0100 @@ -2,9 +2,6 @@ == New Features == - * There is a new internal merge tool called `internal:union-other-first`. - It works like `internal:union` but add other side on top of local. - == Default Format Change == These changes affect newly created repositories (or new clones) done with @@ -19,7 +16,3 @@ == Internal API Changes == == Miscellaneous == - - * pullbundle support no longer requires setting a server-side option, - providing a .hg/pullbundles.manifest according to the syntax specified in - 'hg help -e clonebundles' is enough. diff -r dd42156b6441 -r c5e93c915ab6 rust/Cargo.lock --- a/rust/Cargo.lock Thu Mar 09 13:02:13 2023 -0600 +++ b/rust/Cargo.lock Mon Mar 20 23:16:14 2023 +0100 @@ -1023,9 +1023,9 @@ [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -1033,9 +1033,9 @@ [[package]] name = "rayon-core" -version = "1.10.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -1425,18 +1425,18 @@ [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.12.3+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "6.0.4+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "7afb4b54b8910cf5447638cb54bf4e8a65cbedd783af98b98c62ffe91f185543" dependencies = [ "libc", "zstd-sys", @@ -1444,10 +1444,11 @@ [[package]] name = "zstd-sys" -version = "2.0.1+zstd.1.5.2" +version = "2.0.7+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" dependencies = [ "cc", "libc", + "pkg-config", ] diff -r dd42156b6441 -r c5e93c915ab6 rust/hg-core/Cargo.toml --- a/rust/hg-core/Cargo.toml Thu Mar 09 13:02:13 2023 -0600 +++ b/rust/hg-core/Cargo.toml Mon Mar 20 23:16:14 2023 +0100 @@ -24,7 +24,7 @@ rand = "0.8.5" rand_pcg = "0.3.1" rand_distr = "0.4.3" -rayon = "1.6.1" +rayon = "1.7.0" regex = "1.7.0" sha-1 = "0.10.0" twox-hash = "1.6.3" @@ -34,10 +34,8 @@ crossbeam-channel = "0.5.6" log = "0.4.17" memmap2 = { version = "0.5.8", features = ["stable_deref_trait"] } -zstd = "0.11.2" +zstd = "0.12" format-bytes = "0.3.0" -# once_cell 1.15 uses edition 2021, while the heptapod CI -# uses an old version of Cargo that doesn't support it. once_cell = "1.16.0" # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until diff -r dd42156b6441 -r c5e93c915ab6 rust/hg-core/src/dirstate_tree/on_disk.rs --- a/rust/hg-core/src/dirstate_tree/on_disk.rs Thu Mar 09 13:02:13 2023 -0600 +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs Mon Mar 20 23:16:14 2023 +0100 @@ -415,9 +415,9 @@ fn synthesize_unix_mode(&self) -> u32 { let file_type = if self.flags().contains(Flags::MODE_IS_SYMLINK) { - libc::S_IFLNK + libc::S_IFLNK as u32 } else { - libc::S_IFREG + libc::S_IFREG as u32 }; let permissions = if self.flags().contains(Flags::MODE_EXEC_PERM) { 0o755 diff -r dd42156b6441 -r c5e93c915ab6 rust/hg-core/src/dirstate_tree/status.rs --- a/rust/hg-core/src/dirstate_tree/status.rs Thu Mar 09 13:02:13 2023 -0600 +++ b/rust/hg-core/src/dirstate_tree/status.rs Mon Mar 20 23:16:14 2023 +0100 @@ -244,7 +244,7 @@ match self.parent { None => false, Some(parent) => { - *(parent.cache.get_or_init(|| { + *(self.cache.get_or_init(|| { parent.force(ignore_fn) || ignore_fn(self.path) })) } @@ -433,16 +433,21 @@ return Ok(children_all_have_dirstate_node_or_are_ignored); } + let readdir_succeeded; let mut fs_entries = if let Ok(entries) = self.read_dir( directory_hg_path, &directory_entry.fs_path, is_at_repo_root, ) { + readdir_succeeded = true; entries } else { // Treat an unreadable directory (typically because of insufficient // permissions) like an empty directory. `self.read_dir` has // already called `self.io_error` so a warning will be emitted. + // We still need to remember that there was an error so that we + // know not to cache this result. + readdir_succeeded = false; Vec::new() }; @@ -495,6 +500,7 @@ Ok(has_dirstate_node_or_is_ignored) }) .try_reduce(|| true, |a, b| Ok(a && b)) + .map(|res| res && readdir_succeeded) } fn traverse_fs_and_dirstate<'ancestor>( diff -r dd42156b6441 -r c5e93c915ab6 rust/hg-core/src/vfs.rs --- a/rust/hg-core/src/vfs.rs Thu Mar 09 13:02:13 2023 -0600 +++ b/rust/hg-core/src/vfs.rs Mon Mar 20 23:16:14 2023 +0100 @@ -193,3 +193,13 @@ r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32 } } + +/// Similar to what Cargo does; although detecting NFS (or non-local +/// file systems) _should_ be possible on other operating systems, +/// we'll just assume that mmap() works there, for now; after all, +/// _some_ functionality is better than a compile error, i.e. none at +/// all +#[cfg(not(target_os = "linux"))] +pub(crate) fn is_on_nfs_mount(_path: impl AsRef) -> bool { + false +} diff -r dd42156b6441 -r c5e93c915ab6 rust/rhg/Cargo.toml --- a/rust/rhg/Cargo.toml Thu Mar 09 13:02:13 2023 -0600 +++ b/rust/rhg/Cargo.toml Mon Mar 20 23:16:14 2023 +0100 @@ -22,4 +22,4 @@ format-bytes = "0.3.0" users = "0.11.0" which = "4.3.0" -rayon = "1.6.1" +rayon = "1.7.0" diff -r dd42156b6441 -r c5e93c915ab6 tests/common-pattern.py --- a/tests/common-pattern.py Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/common-pattern.py Mon Mar 20 23:16:14 2023 +0100 @@ -136,6 +136,11 @@ # FormatMessage(ERROR_FILE_NOT_FOUND) br'The system cannot find the file specified', ), + br'$EACCES$': ( + br'Permission denied \(os error 13\)', + # strerror + br'Permission denied', + ), br'$ENOTDIR$': ( # strerror() br'Not a directory', diff -r dd42156b6441 -r c5e93c915ab6 tests/run-tests.py --- a/tests/run-tests.py Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/run-tests.py Mon Mar 20 23:16:14 2023 +0100 @@ -54,6 +54,7 @@ import json import multiprocessing import os +import packaging.version as version import platform import queue import random @@ -72,12 +73,6 @@ import uuid import xml.dom.minidom as minidom -try: - # PEP 632 recommend the use of `packaging.version` to replace the - # deprecated `distutil.version`. So lets do it. - import packaging.version as version -except ImportError: - import distutils.version as version if sys.version_info < (3, 5, 0): print( @@ -799,8 +794,8 @@ try: import coverage - covver = version.StrictVersion(coverage.__version__).version - if covver < (3, 3): + covver = version.Version(coverage.__version__) + if covver < version.Version("3.3"): parser.error('coverage options require coverage 3.3 or later') except ImportError: parser.error('coverage options now require the coverage package') diff -r dd42156b6441 -r c5e93c915ab6 tests/test-blackbox.t --- a/tests/test-blackbox.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-blackbox.t Mon Mar 20 23:16:14 2023 +0100 @@ -322,8 +322,8 @@ #if unix-permissions $ chmod -w .hg $ hg log -r. -T '{rev}\n' --config blackbox.maxsize=1 --debug - warning: cannot rename '$TESTTMP/blackboxtest3/.hg/blackbox.log.1' to '$TESTTMP/blackboxtest3/.hg/blackbox.log': Permission denied - warning: cannot write to blackbox.log: Permission denied + warning: cannot rename '$TESTTMP/blackboxtest3/.hg/blackbox.log.1' to '$TESTTMP/blackboxtest3/.hg/blackbox.log': $EACCES$ + warning: cannot write to blackbox.log: $EACCES$ 1 $ chmod +w .hg #endif @@ -470,15 +470,16 @@ > raise RuntimeError('raise') > EOF - $ cat >> $HGRCPATH << EOF + + $ hg init $TESTTMP/blackbox-exception-only --config blackbox.track=commandexception + $ cat >> $TESTTMP/blackbox-exception-only/.hg/hgrc << EOF > [blackbox] > track = commandexception > [extensions] > raise=$TESTTMP/raise.py > EOF + $ cd $TESTTMP/blackbox-exception-only - $ hg init $TESTTMP/blackbox-exception-only - $ cd $TESTTMP/blackbox-exception-only #if chg (chg exits 255 because it fails to receive an exit code) @@ -495,3 +496,25 @@ $ tail -2 .hg/blackbox.log RuntimeError: raise + $ cd .. + +Check we did not broke `hg mv` +------------------------------ +(we did in 6.4rc) + +basic setup + + $ hg init blackbox-file-move + $ cd blackbox-file-move + $ echo foo > foo + $ hg add foo + $ hg commit -m 'foo' + +copy a file + + $ hg copy foo bar + +move a file + + $ hg mv foo goo + diff -r dd42156b6441 -r c5e93c915ab6 tests/test-clone.t --- a/tests/test-clone.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-clone.t Mon Mar 20 23:16:14 2023 +0100 @@ -633,7 +633,7 @@ $ mkdir a $ chmod 000 a $ hg clone a b - abort: Permission denied: *$TESTTMP/fail/a/.hg* (glob) + abort: $EACCES$: *$TESTTMP/fail/a/.hg* (glob) [255] Inaccessible destination @@ -641,7 +641,7 @@ $ hg init b $ cd b $ hg clone . ../a - abort: Permission denied: *../a* (glob) + abort: $EACCES$: *../a* (glob) [255] $ cd .. $ chmod 700 a diff -r dd42156b6441 -r c5e93c915ab6 tests/test-convert.t --- a/tests/test-convert.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-convert.t Mon Mar 20 23:16:14 2023 +0100 @@ -468,7 +468,7 @@ $ chmod 000 bogusdir $ hg convert a bogusdir - abort: Permission denied: *bogusdir* (glob) + abort: $EACCES$: *bogusdir* (glob) [255] user permissions should succeed diff -r dd42156b6441 -r c5e93c915ab6 tests/test-empty.t --- a/tests/test-empty.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-empty.t Mon Mar 20 23:16:14 2023 +0100 @@ -40,7 +40,6 @@ hgrc requires store - undo.backup.branch wcache Should be empty (except for the "basic" requires): diff -r dd42156b6441 -r c5e93c915ab6 tests/test-hardlinks.t --- a/tests/test-hardlinks.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-hardlinks.t Mon Mar 20 23:16:14 2023 +0100 @@ -141,8 +141,6 @@ 1 r3/.hg/store/phaseroots 1 r3/.hg/store/requires 1 r3/.hg/store/undo - 1 r3/.hg/store/undo.backup.fncache (repofncache !) - 1 r3/.hg/store/undo.backup.phaseroots 1 r3/.hg/store/undo.backupfiles Push to repo r1 should break up most hardlinks in r2: @@ -253,8 +251,6 @@ 2 r4/.hg/store/phaseroots 2 r4/.hg/store/requires 2 r4/.hg/store/undo - 2 r4/.hg/store/undo.backup.fncache (repofncache !) - 2 r4/.hg/store/undo.backup.phaseroots 2 r4/.hg/store/undo.backupfiles [24] r4/.hg/undo.backup.branch (re) 2 r4/\.hg/undo\.backup\.dirstate (re) @@ -308,8 +304,6 @@ 2 r4/.hg/store/phaseroots 2 r4/.hg/store/requires 2 r4/.hg/store/undo - 2 r4/.hg/store/undo.backup.fncache (repofncache !) - 2 r4/.hg/store/undo.backup.phaseroots 2 r4/.hg/store/undo.backupfiles [23] r4/.hg/undo.backup.branch (re) 2 r4/\.hg/undo\.backup\.dirstate (re) diff -r dd42156b6441 -r c5e93c915ab6 tests/test-help.t --- a/tests/test-help.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-help.t Mon Mar 20 23:16:14 2023 +0100 @@ -1988,7 +1988,7 @@ $ "$PYTHON" < def escape(s): - > return b''.join(b'\\u%x' % ord(uc) for uc in s.decode('cp932')) + > return b''.join(br'\\u%x' % ord(uc) for uc in s.decode('cp932')) > # translation of "record" in ja_JP.cp932 > upper = b"\x8bL\x98^" > # str.lower()-ed section name should be treated as different one diff -r dd42156b6441 -r c5e93c915ab6 tests/test-hgrc.t --- a/tests/test-hgrc.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-hgrc.t Mon Mar 20 23:16:14 2023 +0100 @@ -59,7 +59,7 @@ #if unix-permissions no-root $ chmod u-r $TESTTMP/included $ hg showconfig section - config error at $TESTTMP/hgrc:2: cannot include $TESTTMP/included (Permission denied*) (glob) + config error at $TESTTMP/hgrc:2: cannot include $TESTTMP/included ($EACCES$*) (glob) [255] #endif diff -r dd42156b6441 -r c5e93c915ab6 tests/test-journal-exists.t --- a/tests/test-journal-exists.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-journal-exists.t Mon Mar 20 23:16:14 2023 +0100 @@ -47,7 +47,7 @@ $ hg -R foo unbundle repo.hg adding changesets - abort: Permission denied: '$TESTTMP/repo/foo/.hg/store/.00changelog.i-*' (glob) + abort: $EACCES$: '$TESTTMP/repo/foo/.hg/store/.00changelog.i-*' (glob) [255] $ if test -f foo/.hg/store/journal; then echo 'journal exists :-('; fi diff -r dd42156b6441 -r c5e93c915ab6 tests/test-largefiles-cache.t --- a/tests/test-largefiles-cache.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-largefiles-cache.t Mon Mar 20 23:16:14 2023 +0100 @@ -189,7 +189,6 @@ $ find src/.hg/largefiles/* | egrep "(dirstate|$hash)" | sort src/.hg/largefiles/dirstate src/.hg/largefiles/e2fb5f2139d086ded2cb600d5a91a196e76bf020 - src/.hg/largefiles/undo.backup.dirstate Verify that backwards compatibility is maintained for old storage layout $ mv src/.hg/largefiles/$hash share_dst/.hg/largefiles diff -r dd42156b6441 -r c5e93c915ab6 tests/test-lock-badness.t --- a/tests/test-lock-badness.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-lock-badness.t Mon Mar 20 23:16:14 2023 +0100 @@ -135,7 +135,7 @@ $ hg -R b push a pushing to a searching for changes - abort: could not lock repository a: Permission denied + abort: could not lock repository a: $EACCES$ [20] $ chmod 700 a/.hg/store diff -r dd42156b6441 -r c5e93c915ab6 tests/test-minirst.py --- a/tests/test-minirst.py Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-minirst.py Mon Mar 20 23:16:14 2023 +0100 @@ -154,7 +154,7 @@ debugformats('options', options) -fields = b""" +fields = br""" :a: First item. :ab: Second item. Indentation and wrapping is handled automatically. diff -r dd42156b6441 -r c5e93c915ab6 tests/test-permissions.t --- a/tests/test-permissions.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-permissions.t Mon Mar 20 23:16:14 2023 +0100 @@ -24,7 +24,7 @@ $ chmod -r .hg/store/data/a.i $ hg verify -q - abort: Permission denied: '$TESTTMP/t/.hg/store/data/a.i' + abort: $EACCES$: '$TESTTMP/t/.hg/store/data/a.i' [255] $ chmod +r .hg/store/data/a.i @@ -36,7 +36,7 @@ $ echo barber > a $ hg commit -m "2" trouble committing a! - abort: Permission denied: '$TESTTMP/t/.hg/store/data/a.i' + abort: $EACCES$: '$TESTTMP/t/.hg/store/data/a.i' [255] $ chmod -w . @@ -64,7 +64,7 @@ (fsmonitor makes "hg status" avoid accessing to "dir") $ hg status - dir: Permission denied* (glob) + dir: $EACCES$* (glob) M a #endif diff -r dd42156b6441 -r c5e93c915ab6 tests/test-persistent-nodemap.t --- a/tests/test-persistent-nodemap.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-persistent-nodemap.t Mon Mar 20 23:16:14 2023 +0100 @@ -811,8 +811,7 @@ - manifest $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' - undo.backup.00changelog.n - undo.backup.00manifest.n + [1] $ hg debugnodemap --metadata @@ -858,8 +857,6 @@ 00changelog.n 00manifest-*.nd (glob) 00manifest.n - undo.backup.00changelog.n - undo.backup.00manifest.n $ hg debugnodemap --metadata uid: * (glob) diff -r dd42156b6441 -r c5e93c915ab6 tests/test-push-race.t --- a/tests/test-push-race.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-push-race.t Mon Mar 20 23:16:14 2023 +0100 @@ -50,6 +50,10 @@ > limit = 100 > test_default_timeout = os.environ.get('HGTEST_TIMEOUT_DEFAULT') > test_timeout = os.environ.get('HGTEST_TIMEOUT') + > if test_default_timeout is not None: + > test_default_timeout = int(test_default_timeout) + > if test_timeout is not None: + > test_timeout = int(test_timeout) > if ( > test_default_timeout is not None > and test_timeout is not None diff -r dd42156b6441 -r c5e93c915ab6 tests/test-repair-strip.t --- a/tests/test-repair-strip.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-repair-strip.t Mon Mar 20 23:16:14 2023 +0100 @@ -53,9 +53,9 @@ transaction abort! failed to truncate data/b.i rollback failed - please run hg recover - (failure reason: [Errno *] Permission denied .hg/store/data/b.i') (glob) + (failure reason: [Errno *] $EACCES$ .hg/store/data/b.i') (glob) strip failed, backup bundle - abort: Permission denied .hg/store/data/b.i' + abort: $EACCES$ .hg/store/data/b.i' % after update 0, strip 2 abandoned transaction found - run hg recover checking changesets @@ -89,7 +89,7 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: a - abort: Permission denied .hg/store/data/b.i' + abort: $EACCES$ .hg/store/data/b.i' % after update 0, strip 2 checking changesets checking manifests @@ -110,9 +110,9 @@ transaction abort! failed to truncate 00manifest.i rollback failed - please run hg recover - (failure reason: [Errno *] Permission denied .hg/store/00manifest.i') (glob) + (failure reason: [Errno *] $EACCES$ .hg/store/00manifest.i') (glob) strip failed, backup bundle - abort: Permission denied .hg/store/00manifest.i' + abort: $EACCES$ .hg/store/00manifest.i' % after update 0, strip 2 abandoned transaction found - run hg recover checking changesets diff -r dd42156b6441 -r c5e93c915ab6 tests/test-ssh-bundle1.t --- a/tests/test-ssh-bundle1.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-ssh-bundle1.t Mon Mar 20 23:16:14 2023 +0100 @@ -403,9 +403,9 @@ $ hg push --ssh "sh ../ssh.sh" pushing to ssh://user@dummy/*/remote (glob) searching for changes - remote: Permission denied + remote: $EACCES$ remote: abort: pretxnopen.hg-ssh hook failed - remote: Permission denied + remote: $EACCES$ remote: pushkey-abort: prepushkey.hg-ssh hook failed updating 6c0482d977a3 to public failed! [1] diff -r dd42156b6441 -r c5e93c915ab6 tests/test-ssh-repoerror.t --- a/tests/test-ssh-repoerror.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-ssh-repoerror.t Mon Mar 20 23:16:14 2023 +0100 @@ -13,7 +13,7 @@ $ chmod a-rx no-read $ hg id ssh://user@dummy/no-read - remote: abort: Permission denied: *$TESTTMP/no-read/.hg* (glob) + remote: abort: $EACCES$: *$TESTTMP/no-read/.hg* (glob) abort: no suitable response from remote hg [255] @@ -31,7 +31,7 @@ > done $ hg id ssh://user@dummy/other - remote: abort: Permission denied: '$TESTTMP/other/.hg/requires' + remote: abort: $EACCES$: '$TESTTMP/other/.hg/requires' abort: no suitable response from remote hg [255] @@ -47,7 +47,7 @@ $ chmod a-rx deep $ hg id ssh://user@dummy/deep/nested - remote: abort: Permission denied: *$TESTTMP/deep/nested/.hg* (glob) + remote: abort: $EACCES$: *$TESTTMP/deep/nested/.hg* (glob) abort: no suitable response from remote hg [255] diff -r dd42156b6441 -r c5e93c915ab6 tests/test-ssh.t --- a/tests/test-ssh.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-ssh.t Mon Mar 20 23:16:14 2023 +0100 @@ -456,7 +456,7 @@ $ hg push --ssh "sh ../ssh.sh" pushing to ssh://user@dummy/*/remote (glob) searching for changes - remote: Permission denied + remote: $EACCES$ remote: pretxnopen.hg-ssh hook failed abort: push failed on remote [100] diff -r dd42156b6441 -r c5e93c915ab6 tests/test-status-committed-and-ignored.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-status-committed-and-ignored.t Mon Mar 20 23:16:14 2023 +0100 @@ -0,0 +1,33 @@ +#testcases dirstate-v1 dirstate-v2 + +#if dirstate-v2 + $ cat >> $HGRCPATH << EOF + > [format] + > use-dirstate-v2=1 + > [storage] + > dirstate-v2.slow-path=allow + > EOF +#endif + + $ rm -rf r + + $ hg init r + $ cd r + $ mkdir d1 + $ mkdir d2 + $ touch d1/f d2/f + $ hg commit -Am '.' + adding d1/f + adding d2/f + $ echo 'syntax:re' >> .hgignore + $ echo '^d1$' >> .hgignore + $ hg commit -Am "ignore d1" + adding .hgignore + +Now d1 is a directory that's both committed and ignored. +Untracked files in d2 are still shown, but ones in d1 are ignored: + + $ touch d1/g + $ touch d2/g + $ RAYON_NUM_THREADS=1 hg status + ? d2/g diff -r dd42156b6441 -r c5e93c915ab6 tests/test-status-eacces.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-status-eacces.t Mon Mar 20 23:16:14 2023 +0100 @@ -0,0 +1,45 @@ +#testcases dirstate-v1 dirstate-v2 + +#if dirstate-v2 + $ cat >> $HGRCPATH << EOF + > [format] + > use-dirstate-v2=1 + > [storage] + > dirstate-v2.slow-path=allow + > EOF +#endif + + +The proliferation of status implementations can be confusing: +- The pure python implementation: +(no-rhg pure !) +- The C implementation: +(no-rhg no-rust no-pure !) +- The two rust implementations: +(rhg !) +(no-rhg rust !) + + $ hg init repo1 + $ cd repo1 + $ mkdir d1 + $ touch d1/x + $ hg commit -Am. + adding d1/x + $ touch d1/y + $ chmod -r d1 + $ hg status + d1: $EACCES$ + ! d1/x (rhg !) + ! d1/x (no-rhg rust !) + $ hg status + d1: $EACCES$ + ! d1/x (rust !) + ! d1/x (no-rust rhg !) + $ chmod +r d1 + $ hg status + ? d1/y + + $ touch d1/z + $ hg status + ? d1/y + ? d1/z diff -r dd42156b6441 -r c5e93c915ab6 tests/test-status.t --- a/tests/test-status.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-status.t Mon Mar 20 23:16:14 2023 +0100 @@ -849,7 +849,7 @@ $ chmod 0 subdir $ hg status --include subdir - subdir: Permission denied + subdir: $EACCES$ R subdir/removed ! subdir/clean ! subdir/deleted diff -r dd42156b6441 -r c5e93c915ab6 tests/test-template-map.t --- a/tests/test-template-map.t Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/test-template-map.t Mon Mar 20 23:16:14 2023 +0100 @@ -1260,7 +1260,7 @@ $ touch q $ chmod 0 q $ hg log --style ./q - abort: Permission denied: './q' + abort: $EACCES$: './q' [255] #endif @@ -1309,7 +1309,7 @@ $ echo 'changeset = q' >> t #if unix-permissions no-root $ hg log --style ./t - abort: template file ./q: Permission denied + abort: template file ./q: $EACCES$ [255] $ rm -f q #endif diff -r dd42156b6441 -r c5e93c915ab6 tests/testlib/persistent-nodemap-race-ext.py --- a/tests/testlib/persistent-nodemap-race-ext.py Thu Mar 09 13:02:13 2023 -0600 +++ b/tests/testlib/persistent-nodemap-race-ext.py Mon Mar 20 23:16:14 2023 +0100 @@ -1,4 +1,4 @@ -"""Create the race condition for issue6554 +r"""Create the race condition for issue6554 The persistent nodemap issues had an issue where a second writer could overwrite the data that a previous write just wrote. The would break the append