diff --git a/.hgsigs b/.hgsigs --- a/.hgsigs +++ b/.hgsigs @@ -253,3 +253,4 @@ 5a8b5420103937fca97c584c5162178eed828ada c083d9776cb2fb6056715b2988d1ea48055f3162 0 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 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -269,3 +269,4 @@ 5a8b5420103937fca97c584c5162178eed828ada c083d9776cb2fb6056715b2988d1ea48055f3162 6.5.3 27055614b68538576fb0439007009acf93fe0a49 6.6rc0 26c57e7a0890b96e2c473b394de380d6753c9230 6.6 +71bd09bebbe36a09569cbfb388f371433360056b 6.6.1 diff --git a/contrib/perf.py b/contrib/perf.py --- a/contrib/perf.py +++ b/contrib/perf.py @@ -973,11 +973,10 @@ def perftags(ui, repo, **opts): "clear_cache_on_disk", _default_clear_on_disk_tags_cache, ) - clear_fnodes_fn = getattr( - tags, - "clear_cache_fnodes", - _default_clear_on_disk_tags_fnodes_cache, - ) + if getattr(tags, 'clear_cache_fnodes_is_working', False): + clear_fnodes_fn = tags.clear_cache_fnodes + else: + clear_fnodes_fn = _default_clear_on_disk_tags_fnodes_cache clear_fnodes_rev_fn = getattr( tags, "forget_fnodes", @@ -986,7 +985,7 @@ def perftags(ui, repo, **opts): clear_revs = [] if clear_fnode_revs: - clear_revs.extends(scmutil.revrange(repo, clear_fnode_revs)) + clear_revs.extend(scmutil.revrange(repo, clear_fnode_revs)) if update_last: revset = b'last(all(), %d)' % update_last diff --git a/hgext/phabricator.py b/hgext/phabricator.py --- a/hgext/phabricator.py +++ b/hgext/phabricator.py @@ -1926,7 +1926,9 @@ def querydrev(ui, spec): raise error.Abort(_(b'unknown symbol: %s') % tree[1]) elif op in {b'and_', b'add', b'sub'}: assert len(tree) == 3 - return getattr(operator, op)(walk(tree[1]), walk(tree[2])) + return getattr(operator, pycompat.sysstr(op))( + walk(tree[1]), walk(tree[2]) + ) elif op == b'group': return walk(tree[1]) elif op == b'ancestors': diff --git a/hgext/zeroconf/Zeroconf.py b/hgext/zeroconf/Zeroconf.py --- a/hgext/zeroconf/Zeroconf.py +++ b/hgext/zeroconf/Zeroconf.py @@ -1859,7 +1859,7 @@ if __name__ == '__main__': info = ServiceInfo( b"_http._tcp.local.", b"My Service Name._http._tcp.local.", - socket.inet_aton(b"127.0.0.1"), + socket.inet_aton("127.0.0.1"), 1234, 0, 0, diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -783,6 +783,7 @@ class _InnerRevlog: def split_inline(self, tr, header, new_index_file_path=None): """split the data of an inline revlog into an index and a data file""" + assert self._delay_buffer is None existing_handles = False if self._writinghandles is not None: existing_handles = True @@ -1165,14 +1166,15 @@ class _InnerRevlog: elif len(self.index) == 0: self._orig_index_file = self.index_file self.index_file = self._divert_index() - self._segmentfile.filename = self.index_file assert self._orig_index_file is not None assert self.index_file is not None if self.opener.exists(self.index_file): self.opener.unlink(self.index_file) return self.index_file else: - self._segmentfile._delay_buffer = self._delay_buffer = [] + self._delay_buffer = [] + if self.inline: + self._segmentfile._delay_buffer = self._delay_buffer return None def write_pending(self): @@ -1192,10 +1194,13 @@ class _InnerRevlog: ifh.seek(0, os.SEEK_END) ifh.write(b"".join(self._delay_buffer)) any_pending = True - self._segmentfile._delay_buffer = self._delay_buffer = None + self._delay_buffer = None + if self.inline: + self._segmentfile._delay_buffer = self._delay_buffer + else: + assert self._segmentfile._delay_buffer is None self._orig_index_file = self.index_file self.index_file = pending_index_file - self._segmentfile.filename = self.index_file return self.index_file, any_pending def finalize_pending(self): @@ -1221,7 +1226,6 @@ class _InnerRevlog: ) self.index_file = self._orig_index_file self._orig_index_file = None - self._segmentfile.filename = self.index_file else: msg = b"not delay or divert found on this revlog" raise error.ProgrammingError(msg) @@ -1305,6 +1309,10 @@ class revlog: trypending=False, try_split=False, canonical_parent_order=True, + data_config=None, + delta_config=None, + feature_config=None, + may_inline=True, # may inline new revlog ): """ create a revlog object @@ -1330,6 +1338,7 @@ class revlog: self.postfix = postfix self._trypending = trypending self._try_split = try_split + self._may_inline = may_inline self.opener = opener if persistentnodemap: self._nodemap_file = nodemaputil.get_nodemap_file(self) @@ -1337,19 +1346,25 @@ class revlog: assert target[0] in ALL_KINDS assert len(target) == 2 self.target = target - if b'feature-config' in self.opener.options: + if feature_config is not None: + self.feature_config = feature_config.copy() + elif b'feature-config' in self.opener.options: self.feature_config = self.opener.options[b'feature-config'].copy() else: self.feature_config = FeatureConfig() self.feature_config.censorable = censorable self.feature_config.canonical_parent_order = canonical_parent_order - if b'data-config' in self.opener.options: + if data_config is not None: + self.data_config = data_config.copy() + elif b'data-config' in self.opener.options: self.data_config = self.opener.options[b'data-config'].copy() else: self.data_config = DataConfig() self.data_config.check_ambig = checkambig self.data_config.mmap_large_index = mmaplargeindex - if b'delta-config' in self.opener.options: + if delta_config is not None: + self.delta_config = delta_config.copy() + elif b'delta-config' in self.opener.options: self.delta_config = self.opener.options[b'delta-config'].copy() else: self.delta_config = DeltaConfig() @@ -1401,7 +1416,9 @@ class revlog: elif b'revlogv2' in opts: new_header = REVLOGV2 elif b'revlogv1' in opts: - new_header = REVLOGV1 | FLAG_INLINE_DATA + new_header = REVLOGV1 + if self._may_inline: + new_header |= FLAG_INLINE_DATA if b'generaldelta' in opts: new_header |= FLAG_GENERALDELTA elif b'revlogv0' in self.opener.options: diff --git a/mercurial/revlogutils/rewrite.py b/mercurial/revlogutils/rewrite.py --- a/mercurial/revlogutils/rewrite.py +++ b/mercurial/revlogutils/rewrite.py @@ -72,11 +72,16 @@ def v1_censor(rl, tr, censornode, tombst radix=rl.radix, postfix=b'tmpcensored', censorable=True, + data_config=rl.data_config, + delta_config=rl.delta_config, + feature_config=rl.feature_config, + may_inline=rl._inline, ) - newrl._format_version = rl._format_version - newrl._format_flags = rl._format_flags - newrl.delta_config.general_delta = rl.delta_config.general_delta - newrl._parse_index = rl._parse_index + # inline splitting will prepare some transaction work that will get + # confused by the final file move. So if there is a risk of not being + # inline at the end, we prevent the new revlog to be inline in the first + # place. + assert not (newrl._inline and not rl._inline) for rev in rl.revs(): node = rl.node(rev) @@ -122,7 +127,10 @@ def v1_censor(rl, tr, censornode, tombst tr.addbackup(rl._datafile, location=b'store') rl.opener.rename(newrl._indexfile, rl._indexfile) - if not rl._inline: + if newrl._inline: + assert rl._inline + else: + assert not rl._inline rl.opener.rename(newrl._datafile, rl._datafile) rl.clearcaches() diff --git a/mercurial/tags.py b/mercurial/tags.py --- a/mercurial/tags.py +++ b/mercurial/tags.py @@ -916,9 +916,13 @@ def clear_cache_on_disk(repo): repo.cachevfs.tryunlink(_filename(repo)) +# a small attribute to help `hg perf::tags` to detect a fixed version. +clear_cache_fnodes_is_working = True + + def clear_cache_fnodes(repo): """function used by the perf extension to clear "file node cache""" - repo.cachevfs.tryunlink(_filename(repo)) + repo.cachevfs.tryunlink(_fnodescachefile) def forget_fnodes(repo, revs): diff --git a/mercurial/utils/procutil.py b/mercurial/utils/procutil.py --- a/mercurial/utils/procutil.py +++ b/mercurial/utils/procutil.py @@ -686,8 +686,9 @@ if pycompat.iswindows: # we can't use close_fds *and* redirect stdin. I'm not sure that we # need to because the detached process has no console connection. + stdin = None + try: - stdin = None if stdin_bytes is not None: stdin = pycompat.unnamedtempfile() stdin.write(stdin_bytes) diff --git a/relnotes/6.6 b/relnotes/6.6 --- a/relnotes/6.6 +++ b/relnotes/6.6 @@ -1,3 +1,16 @@ += Mercurial 6.6.1 = + +The first two patches fix aborted transactions that could happen since 6.6. + + * revlog: avoid exposing delayed index entry too widely in non-inline revlog + * revlog: avoid wrongly updating the data file location on "divert" + * tests: do not fail tests in a state with uncommitted .py file removal + * perf-tags: fix the --clear-fnode-cache-rev code + * perf-tags: fix clear_cache_fnodes to actually clear that cache + * censor: fix things around inlining + * Various Python 3 cleanups + * Various Windows test suite fixes + = Mercurial 6.6 = As usual, a *lot* of patches don't make it to this list. diff --git a/tests/common-pattern.py b/tests/common-pattern.py --- a/tests/common-pattern.py +++ b/tests/common-pattern.py @@ -170,6 +170,7 @@ substitutions = [ br'Cannot assign requested address', br'Can\'t assign requested address', # FormatMessage(WSAEADDRNOTAVAIL) + br'The requested address is not valid in its context', ), } diff --git a/tests/test-censor.t b/tests/test-censor.t --- a/tests/test-censor.t +++ b/tests/test-censor.t @@ -294,22 +294,40 @@ Can re-add file after being deleted + ce $ hg cat -r "$H2^^^" target | head -n 10 Tainted file now super sanitized -Can censor after revlog has expanded to no longer permit inline storage +Can censor enough revision to move back to inline storage - $ for x in `"$PYTHON" $TESTDIR/seq.py 0 50000` - > do - > echo "Password: hunter$x" >> target - > done + $ hg debugrevlogstats | grep target + rev-count data-size inl type target + 8 ??? no file target (glob) (revlogv2 !) + 8 ??? yes file target (glob) (revlogv1 !) + $ cat /dev/rand?m | dd status=none count=200 | f --hexdump > target $ hg ci -m 'add 100k passwords' $ H2=`hg id --debug -i` $ C5=$H2 $ hg revert -r "$H2^" target $ hg ci -m 'cleaned 100k passwords' $ H2=`hg id --debug -i` + $ hg debugrevlogstats | grep target + rev-count data-size inl type target + 10 ?????? no file target (glob) $ hg --config extensions.censor= censor -r $C5 target + +The important part is for the censor operation to not crash and the repository +to not be corrupted. Right now this involve keeping the revlog split. + + $ hg debugrevlogstats | grep target + rev-count data-size inl type target + 10 ??? no file target (glob) $ hg cat -r $C5 target | head -n 10 $ hg cat -r $H2 target | head -n 10 fresh start + $ hg verify + checking changesets + checking manifests + crosschecking files in changesets and manifests + checking files + checking dirstate + checked 12 changesets with 13 changes to 2 files Repo with censored nodes can be cloned and cloned nodes are censored @@ -341,7 +359,7 @@ Repo cloned before tainted content intro adding manifests adding file changes added 11 changesets with 11 changes to 2 files (+1 heads) - new changesets 186fb27560c3:683e4645fded + new changesets * (glob) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg update 4 2 files updated, 0 files merged, 0 files removed, 0 files unresolved @@ -401,7 +419,7 @@ Censored nodes can be bundled up and unb adding manifests adding file changes added 2 changesets with 2 changes to 2 files (+1 heads) - new changesets 075be80ac777:dcbaf17bf3a1 (2 drafts) + new changesets * (glob) (run 'hg heads .' to see heads, 'hg merge' to merge) $ hg cat -r $REV target | head -n 10 $ hg cat -r $CLEANREV target | head -n 10 @@ -458,7 +476,7 @@ Censored nodes can be imported on top of adding manifests adding file changes added 6 changesets with 5 changes to 2 files (+1 heads) - new changesets efbe78065929:683e4645fded (6 drafts) + new changesets * (glob) (run 'hg heads .' to see heads, 'hg merge' to merge) $ hg update $H2 2 files updated, 0 files merged, 0 files removed, 0 files unresolved diff --git a/tests/test-check-module-imports.t b/tests/test-check-module-imports.t --- a/tests/test-check-module-imports.t +++ b/tests/test-check-module-imports.t @@ -1,4 +1,4 @@ -#require test-repo hg10 +#require test-repo hg32 $ . "$TESTDIR/helpers-testrepo.sh" $ import_checker="$TESTDIR"/../contrib/import-checker.py @@ -14,12 +14,12 @@ these may expose other cycles. Known-bad files are excluded by -X as some of them would produce unstable outputs, which should be fixed later. -NOTE: the `hg locate` command here only works on files that are known to +NOTE: the `hg files` command here only works on files that are known to Mercurial. If you add an import of a new file and haven't yet `hg add`ed it, you will likely receive warnings about a direct import. - $ testrepohg locate 'set:**.py or grep(r"^#!.*?python")' \ - > 'tests/**.t' \ + $ testrepohg files 'set:**.py or grep(r"^#!.*?python")' \ + > 'glob:tests/**.t' \ > -X hgweb.cgi \ > -X setup.py \ > -X contrib/automation/ \ diff --git a/tests/test-tags.t b/tests/test-tags.t --- a/tests/test-tags.t +++ b/tests/test-tags.t @@ -72,7 +72,7 @@ Try corrupting the cache Create local tag with long name: - $ T=`hg identify --debug --id` + $ T=`hg identify -r . -T '{node}'` $ hg tag -l "This is a local tag with a really long name!" $ hg tags tip 0:acb14030fe0a