diff --git a/mercurial/utils/urlutil.py b/mercurial/utils/urlutil.py --- a/mercurial/utils/urlutil.py +++ b/mercurial/utils/urlutil.py @@ -20,6 +20,10 @@ urllibcompat, ) +from . import ( + stringutil, +) + if pycompat.TYPE_CHECKING: from typing import ( @@ -637,19 +641,30 @@ home_path = os.path.expanduser(b'~') - for name, loc in ui.configitems(b'paths', ignoresub=True): + for name, value in ui.configitems(b'paths', ignoresub=True): # No location is the same as not existing. - if not loc: + if not value: continue _value, sub_opts = ui.configsuboptions(b'paths', name) s = ui.configsource(b'paths', name) - root_key = (name, loc, s) + root_key = (name, value, 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)] + + multi_url = sub_opts.get(b'multi-urls') + if multi_url is not None and stringutil.parsebool(multi_url): + base_locs = stringutil.parselist(value) + else: + base_locs = [value] + + paths = [] + for loc in base_locs: + 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)) + p = path(ui, name, rawloc=loc, suboptions=sub_opts) + paths.append(p) + self[name] = paths for name, old_paths in sorted(self.items()): new_paths = [] @@ -748,6 +763,17 @@ return value +@pathsuboption(b'multi-urls', b'multi_urls') +def multiurls_pathoption(ui, path, value): + res = stringutil.parsebool(value) + if res is None: + ui.warn( + _(b'(paths.%s:multi-urls not a boolean; ignoring)\n') % path.name + ) + res = False + return res + + def _chain_path(base_path, ui, paths): """return the result of "path://" logic applied on a given path""" new_paths = [] diff --git a/tests/test-exchange-multi-source.t b/tests/test-exchange-multi-source.t --- a/tests/test-exchange-multi-source.t +++ b/tests/test-exchange-multi-source.t @@ -611,3 +611,177 @@ | % A 0 + +Testing multi-path definition +---------------------------- + + $ hg clone main-repo repo-paths --rev 0 + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets 4a2df7238c3b + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cp -R ./branch-E ./branch-E-paths + $ cp -R ./branch-G ./branch-G-paths + $ cp -R ./branch-H ./branch-H-paths + $ cat << EOF >> repo-paths/.hg/hgrc + > [paths] + > E=../branch-E-paths + > G=../branch-G-paths + > H=../branch-H-paths + > EHG=path://E,path://H,path://G + > EHG:multi-urls=yes + > GEH=path://G,path://E,path://H + > GEH:multi-urls=yes + > EOF + +Do various operations and verify that order matters + + $ hg -R repo-paths push EHG --force + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + [1] + $ hg -R repo-paths push GEH --force + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + [1] + $ hg -R repo-paths push EHG GEH --force + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + [1] + $ hg -R repo-paths pull EHG + pulling from $TESTTMP/branch-E-paths + searching for changes + adding changesets + adding manifests + adding file changes + added 4 changesets with 4 changes to 4 files + new changesets 27547f69f254:a603bfb5a83e + (run 'hg update' to get a working copy) + pulling from $TESTTMP/branch-H-paths + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + new changesets 40faebb2ec45 + (run 'hg heads' to see heads, 'hg merge' to merge) + pulling from $TESTTMP/branch-G-paths + searching for changes + adding changesets + adding manifests + adding file changes + added 2 changesets with 2 changes to 2 files (+1 heads) + new changesets 2f3a4c5c1417:c521a06b234b + (run 'hg heads .' to see heads, 'hg merge' to merge) + $ hg -R repo-paths pull GEH + pulling from $TESTTMP/branch-G-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-E-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-H-paths + searching for changes + no changes found + $ hg -R repo-paths pull EHG GEH + pulling from $TESTTMP/branch-E-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-H-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-G-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-G-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-E-paths + searching for changes + no changes found + pulling from $TESTTMP/branch-H-paths + searching for changes + no changes found + $ hg -R repo-paths push EHG --force + pushing to $TESTTMP/branch-E-paths + searching for changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 3 changes to 3 files (+2 heads) + pushing to $TESTTMP/branch-H-paths + searching for changes + adding changesets + adding manifests + adding file changes + added 4 changesets with 4 changes to 4 files (+2 heads) + pushing to $TESTTMP/branch-G-paths + searching for changes + adding changesets + adding manifests + adding file changes + added 4 changesets with 4 changes to 4 files (+2 heads) + $ hg -R repo-paths push GEH --force + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + [1] + $ hg -R repo-paths push EHG GEH --force + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-G-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-E-paths + searching for changes + no changes found + pushing to $TESTTMP/branch-H-paths + searching for changes + no changes found + [1] diff --git a/tests/test-paths.t b/tests/test-paths.t --- a/tests/test-paths.t +++ b/tests/test-paths.t @@ -388,3 +388,128 @@ abort: cannot use `path://unknown`, "unknown" is not a known path [255] +Test path pointing to multiple urls +=================================== + +Simple cases +------------ +- one layer +- one list +- no special option + + $ cat << EOF > .hg/hgrc + > [paths] + > one-path=foo + > multiple-path=foo,bar,baz,https://example.org/ + > multiple-path:multi-urls=yes + > EOF + $ hg path + gpath1 = http://hg.example.com/ + multiple-path = $TESTTMP/chained_path/foo + multiple-path:multi-urls = yes + multiple-path = $TESTTMP/chained_path/bar + multiple-path:multi-urls = yes + multiple-path = $TESTTMP/chained_path/baz + multiple-path:multi-urls = yes + multiple-path = https://example.org/ + multiple-path:multi-urls = yes + one-path = $TESTTMP/chained_path/foo + +Reference to a list +------------------- + + $ cat << EOF >> .hg/hgrc + > ref-to-multi=path://multiple-path + > EOF + $ hg path | grep ref-to-multi + ref-to-multi = $TESTTMP/chained_path/foo + ref-to-multi:multi-urls = yes + ref-to-multi = $TESTTMP/chained_path/bar + ref-to-multi:multi-urls = yes + ref-to-multi = $TESTTMP/chained_path/baz + ref-to-multi:multi-urls = yes + ref-to-multi = https://example.org/ + ref-to-multi:multi-urls = yes + +List with a reference +--------------------- + + $ cat << EOF >> .hg/hgrc + > multi-with-ref=path://one-path, ssh://babar@savannah/celeste-ville + > multi-with-ref:multi-urls=yes + > EOF + $ hg path | grep multi-with-ref + multi-with-ref = $TESTTMP/chained_path/foo + multi-with-ref:multi-urls = yes + multi-with-ref = ssh://babar@savannah/celeste-ville + multi-with-ref:multi-urls = yes + +List with a reference to a list +------------------------------- + + $ cat << EOF >> .hg/hgrc + > multi-to-multi-ref = path://multiple-path, ssh://celeste@savannah/celeste-ville + > multi-to-multi-ref:multi-urls = yes + > EOF + $ hg path | grep multi-to-multi-ref + multi-to-multi-ref = $TESTTMP/chained_path/foo + multi-to-multi-ref:multi-urls = yes + multi-to-multi-ref = $TESTTMP/chained_path/bar + multi-to-multi-ref:multi-urls = yes + multi-to-multi-ref = $TESTTMP/chained_path/baz + multi-to-multi-ref:multi-urls = yes + multi-to-multi-ref = https://example.org/ + multi-to-multi-ref:multi-urls = yes + multi-to-multi-ref = ssh://celeste@savannah/celeste-ville + multi-to-multi-ref:multi-urls = yes + +individual suboptions are inherited +----------------------------------- + + $ cat << EOF >> .hg/hgrc + > with-pushurl = foo + > with-pushurl:pushurl = http://foo.bar/ + > with-pushrev = bar + > with-pushrev:pushrev = draft() + > with-both = toto + > with-both:pushurl = http://ta.ta + > with-both:pushrev = secret() + > ref-all-no-opts = path://with-pushurl, path://with-pushrev, path://with-both + > ref-all-no-opts:multi-urls = yes + > with-overwrite = path://with-pushurl, path://with-pushrev, path://with-both + > with-overwrite:multi-urls = yes + > with-overwrite:pushrev = public() + > EOF + $ hg path | grep with-pushurl + with-pushurl = $TESTTMP/chained_path/foo + with-pushurl:pushurl = http://foo.bar/ + $ hg path | grep with-pushrev + with-pushrev = $TESTTMP/chained_path/bar + with-pushrev:pushrev = draft() + $ hg path | grep with-both + with-both = $TESTTMP/chained_path/toto + with-both:pushrev = secret() + with-both:pushurl = http://ta.ta/ + $ hg path | grep ref-all-no-opts + ref-all-no-opts = $TESTTMP/chained_path/foo + ref-all-no-opts:multi-urls = yes + ref-all-no-opts:pushurl = http://foo.bar/ + ref-all-no-opts = $TESTTMP/chained_path/bar + ref-all-no-opts:multi-urls = yes + ref-all-no-opts:pushrev = draft() + ref-all-no-opts = $TESTTMP/chained_path/toto + ref-all-no-opts:multi-urls = yes + ref-all-no-opts:pushrev = secret() + ref-all-no-opts:pushurl = http://ta.ta/ + $ hg path | grep with-overwrite + with-overwrite = $TESTTMP/chained_path/foo + with-overwrite:multi-urls = yes + with-overwrite:pushrev = public() + with-overwrite:pushurl = http://foo.bar/ + with-overwrite = $TESTTMP/chained_path/bar + with-overwrite:multi-urls = yes + with-overwrite:pushrev = public() + with-overwrite = $TESTTMP/chained_path/toto + with-overwrite:multi-urls = yes + with-overwrite:pushrev = public() + with-overwrite:pushurl = http://ta.ta/