changeset 52427:8c509a70b6fa

config: gather the path to edit through rcutil Using the common logic helps to reduce potential error when it changes
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 23 Oct 2024 02:05:03 +0200
parents 22129ce9f86d
children 8431296a93e8
files mercurial/configuration/__init__.py mercurial/configuration/command.py mercurial/configuration/rcutil.py
diffstat 3 files changed, 42 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/configuration/__init__.py	Wed Oct 23 01:32:33 2024 +0200
+++ b/mercurial/configuration/__init__.py	Wed Oct 23 02:05:03 2024 +0200
@@ -26,6 +26,11 @@
     LEVEL_SHARED,
     LEVEL_NON_SHARED,
 )
+# levels that can works without a repository
+NO_REPO_EDIT_LEVELS = (
+    LEVEL_USER,
+    LEVEL_GLOBAL,
+)
 
 ConfigItemT = Tuple[bytes, bytes, bytes, bytes]
 ResourceIDT = Tuple[bytes, bytes]
--- a/mercurial/configuration/command.py	Wed Oct 23 01:32:33 2024 +0200
+++ b/mercurial/configuration/command.py	Wed Oct 23 02:05:03 2024 +0200
@@ -16,17 +16,13 @@
     requirements,
     ui as uimod,
     util,
-    vfs as vfsmod,
 )
 
 from . import (
     ConfigLevelT,
     EDIT_LEVELS,
-    LEVEL_GLOBAL,
-    LEVEL_LOCAL,
-    LEVEL_NON_SHARED,
     LEVEL_SHARED,
-    LEVEL_USER,
+    NO_REPO_EDIT_LEVELS,
     rcutil,
 )
 
@@ -55,21 +51,14 @@
 def edit_config(ui: uimod.ui, repo, level: ConfigLevelT) -> None:
     """let the user edit configuration file for the given level"""
 
-    if level == LEVEL_USER:
-        paths = rcutil.userrcpath()
-    elif level == LEVEL_GLOBAL:
-        paths = rcutil.systemrcpath()
-    elif level == LEVEL_LOCAL:
-        if not repo:
-            raise error.InputError(_(b"can't use --local outside a repository"))
-        paths = [repo.vfs.join(b'hgrc')]
-    elif level == LEVEL_NON_SHARED:
-        paths = [repo.vfs.join(b'hgrc-not-shared')]
-    elif level == LEVEL_SHARED:
+    # validate input
+    if repo is None and level not in NO_REPO_EDIT_LEVELS:
+        msg = b"can't use --%s outside a repository" % pycompat.bytestr(level)
+        raise error.InputError(_(msg))
+    if level == LEVEL_SHARED:
         if not repo.shared():
-            raise error.InputError(
-                _(b"repository is not shared; can't use --shared")
-            )
+            msg = _(b"repository is not shared; can't use --shared")
+            raise error.InputError(msg)
         if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
             raise error.InputError(
                 _(
@@ -77,24 +66,32 @@
                     b"unable to edit shared source repository config"
                 )
             )
-        paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
-    else:
+
+    # find rc files paths
+    repo_path = None
+    if repo is not None:
+        repo_path = repo.root
+    all_rcs = rcutil.all_rc_components(repo_path)
+    rc_by_level = {}
+    for lvl, rc_type, values in all_rcs:
+        if rc_type != b'path':
+            continue
+        rc_by_level.setdefault(lvl, []).append(values)
+
+    if level not in rc_by_level:
         msg = 'unknown config level: %s' % level
         raise error.ProgrammingError(msg)
 
+    paths = rc_by_level[level]
     for f in paths:
         if os.path.exists(f):
             break
     else:
-        if LEVEL_GLOBAL:
-            samplehgrc = uimod.samplehgrcs[b'global']
-        elif LEVEL_LOCAL:
-            samplehgrc = uimod.samplehgrcs[b'local']
-        else:
-            samplehgrc = uimod.samplehgrcs[b'user']
+        samplehgrc = uimod.samplehgrcs.get(level)
 
         f = paths[0]
-        util.writefile(f, util.tonativeeol(samplehgrc))
+        if samplehgrc is not None:
+            util.writefile(f, util.tonativeeol(samplehgrc))
 
     editor = ui.geteditor()
     ui.system(
--- a/mercurial/configuration/rcutil.py	Wed Oct 23 01:32:33 2024 +0200
+++ b/mercurial/configuration/rcutil.py	Wed Oct 23 02:05:03 2024 +0200
@@ -87,11 +87,12 @@
     ]
 
 
-def rccomponents() -> List[ComponentT]:
+def rccomponents(use_hgrcpath=True) -> List[ComponentT]:
     """return an ordered [(type, obj)] about where to load configs.
 
     respect $HGRCPATH. if $HGRCPATH is empty, only .hg/hgrc of current repo is
-    used. if $HGRCPATH is not set, the platform default will be used.
+    used. if $HGRCPATH is not set, the platform default will be used. If
+    `use_hgrcpath` is False, it is never used.
 
     if a directory is provided, *.rc files under it will be used.
 
@@ -105,7 +106,7 @@
     _rccomponents = []
     comp = _rccomponents.append
 
-    if b'HGRCPATH' in encoding.environ:
+    if b'HGRCPATH' in encoding.environ and use_hgrcpath:
         # assume HGRCPATH is all about user configs so environments can be
         # overridden.
         comp(envrc)
@@ -171,6 +172,14 @@
     return components
 
 
+def all_rc_components(repo_path: Optional[bytes]):
+    components = []
+    components.extend(rccomponents(use_hgrcpath=False))
+    if repo_path is not None:
+        components.extend(repo_components(repo_path))
+    return components
+
+
 def defaultpagerenv() -> Dict[bytes, bytes]:
     """return a dict of default environment variables and their values,
     intended to be set before starting a pager.