diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -233,6 +233,8 @@ self._trustusers = set() self._trustgroups = set() self.callhooks = True + # hold the root to use for each [paths] entry + self._path_to_root = {} # Insecure server connections requested. self.insecureconnections = False # Blocked time @@ -264,6 +266,7 @@ self._trustgroups = src._trustgroups.copy() self.environ = src.environ self.callhooks = src.callhooks + self._path_to_root = src._path_to_root self.insecureconnections = src.insecureconnections self._colormode = src._colormode self._terminfoparams = src._terminfoparams.copy() @@ -545,22 +548,26 @@ root = root or encoding.getcwd() for c in self._tcfg, self._ucfg, self._ocfg: for n, p in c.items(b'paths'): + old_p = p + s = self.configsource(b'paths', n) or b'none' + root_key = (n, p, s) + if root_key not in self._path_to_root: + self._path_to_root[root_key] = root # Ignore sub-options. if b':' in n: continue if not p: continue if b'%%' in p: - s = self.configsource(b'paths', n) or b'none' + if s is None: + s = 'none' self.warn( _(b"(deprecated '%%' in path %s=%s from %s)\n") % (n, p, s) ) p = p.replace(b'%%', b'%') - p = util.expandpath(p) - if not urlutil.hasscheme(p) and not os.path.isabs(p): - p = os.path.normpath(os.path.join(root, p)) - c.alter(b"paths", n, p) + if p != old_p: + c.alter(b"paths", n, p) if section in (None, b'ui'): # update ui options diff --git a/mercurial/utils/urlutil.py b/mercurial/utils/urlutil.py --- a/mercurial/utils/urlutil.py +++ b/mercurial/utils/urlutil.py @@ -637,11 +637,20 @@ def __init__(self, ui): dict.__init__(self) + home_path = os.path.expanduser(b'~') + for name, loc in ui.configitems(b'paths', ignoresub=True): # No location is the same as not existing. if not loc: continue - loc, sub_opts = ui.configsuboptions(b'paths', name) + _value, sub_opts = ui.configsuboptions(b'paths', name) + s = ui.configsource(b'paths', name) + root_key = (name, loc, s) + root = ui._path_to_root.get(root_key, home_path) + loc = os.path.expandvars(loc) + loc = os.path.expanduser(loc) + if not hasscheme(loc) and not os.path.isabs(loc): + loc = os.path.normpath(os.path.join(root, loc)) self[name] = [path(ui, name, rawloc=loc, suboptions=sub_opts)] for name, old_paths in sorted(self.items()): diff --git a/tests/test-config.t b/tests/test-config.t --- a/tests/test-config.t +++ b/tests/test-config.t @@ -337,8 +337,14 @@ > EOF $ hg showconfig paths + paths.foo=~/foo paths.foo:suboption=~/foo - paths.foo=$TESTTMP/foo + +note: The path expansion no longer happens at the config level, but the path is +still expanded: + + $ hg path | grep foo + foo = $TESTTMP/foo edit failure diff --git a/tests/test-globalopts.t b/tests/test-globalopts.t --- a/tests/test-globalopts.t +++ b/tests/test-globalopts.t @@ -74,6 +74,10 @@ 8580ff50825a tip $ echo '[paths]' >> $HGRCPATH $ echo 'relativetohome = a' >> $HGRCPATH + $ hg path | grep relativetohome + relativetohome = $TESTTMP/a + $ HOME=`pwd`/../ hg path | grep relativetohome + relativetohome = $TESTTMP/a $ HOME=`pwd`/../ hg -R relativetohome identify 8580ff50825a tip $ cd .. diff --git a/tests/test-hgrc.t b/tests/test-hgrc.t --- a/tests/test-hgrc.t +++ b/tests/test-hgrc.t @@ -255,7 +255,7 @@ > EOF $ hg showconfig --source paths plain: True - $TESTTMP/hgrc:17: paths.foo=$TESTTMP/bar + $TESTTMP/hgrc:17: paths.foo=bar Test we can skip the user configuration