dispatch: change cwd when loading local config
authorArun Kulshreshtha <akulshreshtha@janestreet.com>
Wed, 10 Aug 2022 15:01:50 -0400
changeset 49420 3681a47611b8
parent 49419 2edb41ed6c49
child 49421 a974c52fb79a
dispatch: change cwd when loading local config Previously, the `_getlocal` function would not correctly load the repo config when given a relative `rpath` and an alternate cwd via the `wd` parameter. Normally when `--cwd` is specified, hg changes to the given directory before attempting to load the local config (and therefore does not specify a `wd`). The only time the function is called with `wd` set is when hg is running as a command server (e.g., with chg), in which case each forked worker process will attempt to configure itself via `_getlocal` before responding to the client. When given a relative repo path, the worker fails to load the repo config, detects a config mismatch with the client, and enters a redirect/respawn loop. To fix this, we can simply change to the desired working directory during config loading. (Note that simply concatenating `wd` and `rpath` won't work in all cases. The repo path could be something more complicated than a simple relative path, such as a `union:` repo.)
mercurial/dispatch.py
tests/test-chg.t
--- a/mercurial/dispatch.py	Mon Aug 08 17:27:49 2022 +0200
+++ b/mercurial/dispatch.py	Wed Aug 10 15:01:50 2022 -0400
@@ -952,14 +952,22 @@
 
     Takes paths in [cwd]/.hg/hgrc into account."
     """
+    try:
+        cwd = encoding.getcwd()
+    except OSError as e:
+        raise error.Abort(
+            _(b"error getting current working directory: %s")
+            % encoding.strtolocal(e.strerror)
+        )
+
+    # If using an alternate wd, temporarily switch to it so that relative
+    # paths are resolved correctly during config loading.
+    oldcwd = None
     if wd is None:
-        try:
-            wd = encoding.getcwd()
-        except OSError as e:
-            raise error.Abort(
-                _(b"error getting current working directory: %s")
-                % encoding.strtolocal(e.strerror)
-            )
+        wd = cwd
+    else:
+        oldcwd = cwd
+        os.chdir(wd)
 
     path = cmdutil.findrepo(wd) or b""
     if not path:
@@ -979,6 +987,9 @@
             lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
             lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
 
+    if oldcwd:
+        os.chdir(oldcwd)
+
     return path, lui
 
 
--- a/tests/test-chg.t	Mon Aug 08 17:27:49 2022 +0200
+++ b/tests/test-chg.t	Wed Aug 10 15:01:50 2022 -0400
@@ -432,6 +432,20 @@
   YYYY/MM/DD HH:MM:SS (PID)> log -R cached
   YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in  ...s)
 
+Test that -R is interpreted relative to --cwd.
+
+  $ hg init repo1
+  $ mkdir -p a/b
+  $ hg init a/b/repo2
+  $ printf "[alias]\ntest=repo1\n" >> repo1/.hg/hgrc
+  $ printf "[alias]\ntest=repo2\n" >> a/b/repo2/.hg/hgrc
+  $ cd a
+  $ chg --cwd .. -R repo1 show alias.test
+  repo1
+  $ chg --cwd . -R b/repo2 show alias.test
+  repo2
+  $ cd ..
+
 Test that chg works (sets to the user's actual LC_CTYPE) even when python
 "coerces" the locale (py3.7+)