diff --git a/edenscm/mercurial/commands/debugmutation.py b/edenscm/mercurial/commands/debugmutation.py index 7a16092c7e..45e60e52f5 100644 --- a/edenscm/mercurial/commands/debugmutation.py +++ b/edenscm/mercurial/commands/debugmutation.py @@ -1,4 +1,4 @@ -# debugmutation.py - command processing for debugmutation* commands +# debugmutation.py - command processing for debug commands for mutation and visbility # # Copyright 2019 Facebook, Inc. # @@ -7,7 +7,7 @@ from __future__ import absolute_import -from .. import mutation, node as nodemod, pycompat, registrar, scmutil, util +from .. import mutation, node as nodemod, pycompat, registrar, scmutil, util, visibility from ..i18n import _ @@ -183,3 +183,25 @@ def debugmutationfromobsmarkers(ui, repo, **opts): with repo.lock(): count = mutation.recordentries(repo, entries, skipexisting=False) repo.ui.write(_("wrote %s entries\n") % count) + + +@command("debugvisibility", [], subonly=True) +def debugvisibility(ui, repo): + """control visibility tracking""" + + +subcmd = debugvisibility.subcommand() + + +@subcmd("start", []) +def debugvisibilitystart(ui, repo): + """start tracking commit visibility explicitly""" + visibility.starttracking(repo) + return 0 + + +@subcmd("stop", []) +def debugvisibilitystop(ui, repo): + """stop tracking commit visibility explicitly""" + visibility.stoptracking(repo) + return 0 diff --git a/edenscm/mercurial/configitems.py b/edenscm/mercurial/configitems.py index 573d34af88..c96785d9ae 100644 --- a/edenscm/mercurial/configitems.py +++ b/edenscm/mercurial/configitems.py @@ -506,7 +506,7 @@ coreconfigitem("ui", "enableincomingoutgoing", default=True) coreconfigitem("unsafe", "filtersuspectsymlink", default=True) coreconfigitem("unsafe", "wvfsauditorcache", default=False) coreconfigitem("verify", "skipflags", default=None) -coreconfigitem("visibility", "tracking", default="auto") +coreconfigitem("visibility", "enabled", default=False) coreconfigitem("web", "allowbz2", default=False) coreconfigitem("web", "allowgz", default=False) coreconfigitem("web", "allow-pull", alias=[("web", "allowpull")], default=True) diff --git a/edenscm/mercurial/help/config.txt b/edenscm/mercurial/help/config.txt index 68e3cf4aab..bc7d42a143 100644 --- a/edenscm/mercurial/help/config.txt +++ b/edenscm/mercurial/help/config.txt @@ -2325,29 +2325,15 @@ User interface controls. ``visibility`` -------------- -Controls how Mercurial determines commit visibility. +Controls how Mercurial determines commit visibility. Mercurial +can optionally track which commits are visible explicitly, or it +can determine them implicitly from obsolescence markers. -``forceobsolete`` - Force the use of obsolescence information for visibility, even if - the ``visibleheads`` requirement is set in the repo. - -``tracking`` - Whether to track commit visibility. (default: auto) - - ``off`` - Use obsolescence markers to determine visibility. Only commits - that have not been obsoleted are visible. - - ``on`` - Explicitly track visibility of commits using a set of visible - heads. Only commits that are ancestors of the visible heads are - visible. This adds the ``visibleheads`` requirement to the - repository store, so it cannot be used by versions of Mercurial - that do not track visibleheads. - - ``auto`` - Use visible heads if the repository store has the ``visibleheads`` - requirement, otherwise use ``obsolescence``. +``enabled`` + Set to true to use explicit tracking of commit visibility if + the ``visibleheads`` requirement is set in the repo. If False, + or if the ``visibleheads`` requirement is not set in the repo, + then obsolescence markers will be used to determine visibility. ``web`` diff --git a/edenscm/mercurial/localrepo.py b/edenscm/mercurial/localrepo.py index 2a8e0d2029..db4cf3b15a 100644 --- a/edenscm/mercurial/localrepo.py +++ b/edenscm/mercurial/localrepo.py @@ -774,7 +774,7 @@ class localrepository(object): @storecache("visibleheads") def _visibleheads(self): - return visibility.makevisibleheads(self.ui, self) + return visibility.visibleheads(self.ui, self) @storecache("obsstore") def obsstore(self): @@ -2656,4 +2656,9 @@ def newreporequirements(repo): def newrepostorerequirements(repo): - return set() + ui = repo.ui + requirements = set() + if ui.configbool("visibility", "enabled"): + requirements.add("visibleheads") + + return requirements diff --git a/edenscm/mercurial/visibility.py b/edenscm/mercurial/visibility.py index 7f22f2597c..f4cd809c44 100644 --- a/edenscm/mercurial/visibility.py +++ b/edenscm/mercurial/visibility.py @@ -9,16 +9,32 @@ from __future__ import absolute_import import errno -from edenscm.mercurial import error, node, util -from edenscm.mercurial.i18n import _ +from edenscm.mercurial import error, node def _convertfromobsolete(repo): """convert obsolete markers into a set of visible heads""" with repo.ui.configoverride( - {("mutation", "enabled"): False}, "convertfromobsolete" + {("mutation", "enabled"): False, ("visibility", "enabled"): False}, + "convertfromobsolete", ): - return set(repo.unfiltered().nodes("heads((not public()) - obsolete())")) + return set(repo.unfiltered().nodes("heads((not public()) - hidden())")) + + +def starttracking(repo): + if "visibleheads" not in repo.storerequirements: + with repo.lock(): + repo.storerequirements.add("visibleheads") + repo._writestorerequirements() + + +def stoptracking(repo): + if "visibleheads" in repo.storerequirements: + with repo.lock(): + repo.storerequirements.discard("visibleheads") + repo._writestorerequirements() + if repo.svfs.lexists("visibleheads"): + repo.svfs.tryunlink("visibleheads") # Supported file format version. @@ -145,71 +161,42 @@ class visibleheads(object): return hidden -def makevisibleheads(ui, repo): - tracking = ui.config("visibility", "tracking", "auto") - if tracking != "auto": - trackingbool = util.parsebool(tracking) - if trackingbool is None: - raise error.ConfigError( - _("visibility.tracking not valid ('%s' is not 'auto' or boolean)") - % tracking - ) - if trackingbool: - if "visibleheads" not in repo.storerequirements: - repo.storerequirements.add("visibleheads") - with repo.lock(): - repo._writestorerequirements() - else: - if "visibleheads" in repo.storerequirements: - repo.storerequirements.remove("visibleheads") - with repo.lock(): - repo._writestorerequirements() - if repo.svfs.lexists("visibleheads"): - repo.svfs.tryunlink("visibleheads") - if "visibleheads" in repo.storerequirements: - return visibleheads(ui, repo) - else: - return None - - def add(repo, newnodes): - vh = repo._visibleheads - if vh is not None: + if tracking(repo): with repo.lock(), repo.transaction("update-visibility") as tr: - vh.add(repo, newnodes, tr) + repo._visibleheads.add(repo, newnodes, tr) def remove(repo, oldnodes): - vh = repo._visibleheads - if vh is not None: + if tracking(repo): with repo.lock(), repo.transaction("update-visibility") as tr: - vh.remove(repo, oldnodes, tr) + repo._visibleheads.remove(repo, oldnodes, tr) def phaseadjust(repo, tr, newdraft=None, newpublic=None): - vh = repo._visibleheads - if vh is not None: - vh.phaseadjust(repo, tr, newdraft, newpublic) + if tracking(repo): + repo._visibleheads.phaseadjust(repo, tr, newdraft, newpublic) def heads(repo): - vh = repo._visibleheads - if vh is not None: - return vh.heads - return None + if tracking(repo): + return repo._visibleheads.heads def invisiblerevs(repo): """Returns the invisible mutable revs in this repo""" - vh = repo._visibleheads - if vh is not None: - return vh.invisiblerevs(repo) - return None + if tracking(repo): + return repo._visibleheads.invisiblerevs(repo) def tracking(repo): - return repo._visibleheads is not None + return "visibleheads" in repo.storerequirements def enabled(repo): - return tracking(repo) and not repo.ui.configbool("visibility", "forceobsolete") + # TODO(mbthomas): support bundlerepo + from . import bundlerepo # avoid import cycle + + if isinstance(repo, bundlerepo.bundlerepository): + return False + return tracking(repo) and repo.ui.configbool("visibility", "enabled") diff --git a/tests/test-completion.t b/tests/test-completion.t index fa300f4289..ea084835f1 100644 --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -136,6 +136,7 @@ Show debug commands if there are no other candidates debugtreestate debugupdatecaches debugupgraderepo + debugvisibility debugwalk debugwireargs @@ -331,6 +332,7 @@ Show all commands + options debugtreestate: debugupdatecaches: debugupgraderepo: optimize, run + debugvisibility: debugwalk: include, exclude debugwireargs: three, four, five, ssh, remotecmd, insecure files: rev, print0, include, exclude, template diff --git a/tests/test-help.t b/tests/test-help.t index f8805e1917..cc5a3a531b 100644 --- a/tests/test-help.t +++ b/tests/test-help.t @@ -1047,6 +1047,8 @@ Test list of internal help commands warm all known caches in the repository debugupgraderepo upgrade a repository to use different features + debugvisibility + control visibility tracking debugwalk show how files match on given patterns debugwireargs (no help text available) diff --git a/tests/test-mutation-infinitepush.t b/tests/test-mutation-infinitepush.t index c0a90ce0ec..f1dff17d44 100644 --- a/tests/test-mutation-infinitepush.t +++ b/tests/test-mutation-infinitepush.t @@ -1,14 +1,7 @@ $ enable amend rebase histedit fbhistedit - -We need obsmarkers for now, to allow unstable commits - $ enable obsstore - - $ cat >> $HGRCPATH < [mutation] - > record=true - > enabled=true - > date=0 0 - > EOF + $ setconfig experimental.evolution= + $ setconfig visibility.enabled=true + $ setconfig mutation.record=true mutation.enabled=true mutation.date="0 0" $ . "$TESTDIR/library.sh" $ . "$TESTDIR/infinitepush/library.sh" diff --git a/tests/test-mutation-pushrebase.t b/tests/test-mutation-pushrebase.t index 34e7b78c2a..de66d03879 100644 --- a/tests/test-mutation-pushrebase.t +++ b/tests/test-mutation-pushrebase.t @@ -1,16 +1,12 @@ #testcases nostackpush stackpush $ enable pushrebase amend $ setconfig experimental.evolution= + $ setconfig visibility.enabled=true + $ setconfig mutation.record=true mutation.enabled=true mutation.date="0 0" $ cat >> $HGRCPATH < [ui] > ssh = python "$RUNTESTDIR/dummyssh" - > [mutation] - > record=true - > enabled=true - > date=0 0 - > [visibility] - > tracking=on > [templatealias] > sl_mutation_names = dict(amend="Amended as", rebase="Rebased to", split="Split into", fold="Folded into", histedit="Histedited to", rewrite="Rewritten into", land="Landed as", pushrebase="Pushed as") > sl_mutations = "{join(mutations % '({get(sl_mutation_names, operation, "Rewritten using {operation} into")} {join(successors % "{node|short}", ", ")})', ' ')}" diff --git a/tests/test-mutation.t b/tests/test-mutation.t index 3b2e5c1771..85ceca7da7 100644 --- a/tests/test-mutation.t +++ b/tests/test-mutation.t @@ -1,16 +1,10 @@ $ enable amend rebase histedit fbhistedit phabdiff - $ setconfig ui.ssh="$PYTHON \"$TESTDIR/dummyssh\"" + $ setconfig ui.ssh="$PYTHON \"$TESTDIR/dummyssh\"" ui.interactive=true $ setconfig experimental.evolution= + $ setconfig visibility.enabled=true + $ setconfig mutation.record=true mutation.enabled=true mutation.date="0 0" $ cat >> $HGRCPATH < [mutation] - > record=true - > enabled=true - > date=0 0 - > [visibility] - > tracking=on - > [ui] - > interactive = true > [templatealias] > sl_mutation_names = dict(amend="Amended as", rebase="Rebased to", split="Split into", fold="Folded into", histedit="Histedited to", rewrite="Rewritten into", land="Landed as") > sl_mutations = "{join(mutations % '({get(sl_mutation_names, operation, "Rewritten using {operation} into")} {join(successors % "{node|short}", ", ")})', ' ')}" diff --git a/tests/test-visibility.t b/tests/test-visibility.t index 78464e5687..d0ab815767 100644 --- a/tests/test-visibility.t +++ b/tests/test-visibility.t @@ -1,6 +1,6 @@ $ enable amend rebase undo $ setconfig experimental.evolution= - $ setconfig visibility.tracking=on + $ setconfig visibility.enabled=true $ setconfig mutation.record=true mutation.enabled=true mutation.date="0 0" $ setconfig hint.ack=undo $ cat >> $HGRCPATH <