From 02b4019bc6579422c2ab27e9fbdc9abef93d94f3 Mon Sep 17 00:00:00 2001 From: Erik Flodin Date: Sun, 19 Jan 2025 23:13:37 +0100 Subject: [PATCH] Add support and tests for clone --recurse-submodules Including tests for clone --recursive. --- .github/workflows/test.yml | 1 + test/test_clone.py | 65 +++++++++++++++++++++++++++++++++++--- yadm | 15 +++++---- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf21503..78ca61e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -119,6 +119,7 @@ jobs: run: | git config --global user.email test@yadm.io git config --global user.name "Yadm Test" + git config --global protocol.file.allow always dos2unix yadm.1 .github/workflows/*.yml test/pinentry-mock chmod +x test/pinentry-mock diff --git a/test/test_clone.py b/test/test_clone.py index 83a96c8..7790d8a 100644 --- a/test/test_clone.py +++ b/test/test_clone.py @@ -108,6 +108,39 @@ def test_clone(runner, paths, yadm_cmd, repo_config, ds1, good_remote, repo_exis assert old_repo.exists() +@pytest.mark.usefixtures("remote_with_submodules") +@pytest.mark.parametrize("action", ["recursive", "recurse", "specific"]) +def test_clone_submodules(runner, paths, yadm_cmd, repo_config, action): + """Test clone operation with submodules""" + + # clear out the work path + paths.work.remove() + paths.work.mkdir() + + env = { + "GIT_CONFIG_COUNT": "1", + "GIT_CONFIG_KEY_0": "protocol.file.allow", + "GIT_CONFIG_VALUE_0": "always", + } + + args = ["clone", "-w", paths.work] + if action == "recursive": + args += ["--recursive"] + elif action == "recurse": + args += ["--recurse-submodules"] + elif action == "specific": + args += ["--recurse-submodules=a", "--recurse-submodules=d1/c"] + args += [f"file://{paths.remote}"] + run = runner(command=yadm_cmd(*args), env=env) + assert successful_clone(run, paths, repo_config) + + for path in ("a", "b", "d1/c"): + if action != "specific" or path != "b": + assert paths.work.join(path).join(".git").exists() + else: + assert not paths.work.join(path).join(".git").exists() + + @pytest.mark.usefixtures("remote") @pytest.mark.parametrize( "bs_exists, bs_param, answer", @@ -305,16 +338,38 @@ def remote(paths, ds1_repo_copy): """Function scoped remote (based on ds1)""" # pylint: disable=unused-argument # This is ignored because - # @pytest.mark.usefixtures('ds1_remote_copy') + # @pytest.mark.usefixtures('ds1_repo_copy') # cannot be applied to another fixture. paths.remote.remove() paths.repo.move(paths.remote) -def test_no_repo( - runner, - yadm_cmd, -): +@pytest.fixture() +def remote_with_submodules(tmpdir_factory, runner, paths, remote, ds1_work_copy): + """Function scoped remote with submodules (based on ds1)""" + # pylint: disable=unused-argument + # This is ignored because + # @pytest.mark.usefixtures('remote', 'ds1_work_copy') + # cannot be applied to another fixture. + submodule = tmpdir_factory.mktemp("submodule") + paths.remote.copy(submodule) + + env = os.environ.copy() + env["GIT_DIR"] = str(paths.remote) + + for path in ("a", "b", "d1/c"): + run = runner( + ["git", "-C", paths.work, "-c", "protocol.file.allow=always", "submodule", "add", submodule, path], + env=env, + report=False, + ) + assert run.success + + run = runner(["git", "-C", paths.work, "commit", "-m", '"Add submodules"'], env=env, report=False) + assert run.success + + +def test_no_repo(runner, yadm_cmd): """Test cloning without specifying a repo""" run = runner(command=yadm_cmd("clone", "-f")) assert run.failure diff --git a/yadm b/yadm index bf597b0..2a3ff87 100755 --- a/yadm +++ b/yadm @@ -754,7 +754,7 @@ function clone() { DO_BOOTSTRAP=1 local -a args local -i do_checkout=1 - local -i do_submodules=0 + local -a submodules while [[ $# -gt 0 ]]; do case "$1" in --bootstrap) # force bootstrap, without prompt @@ -769,10 +769,13 @@ function clone() { -n | --no-checkout) do_checkout=0 ;; - --recursive) - do_submodules=1 + --recursive | --recurse-submodules) + submodules+=(":/") ;; - --bare | --mirror | --recurse-submodules* | --separate-git-dir=*) + --recurse-submodules=*) + submodules+=(":/${1#*=}") + ;; + --bare | --mirror | --separate-git-dir=*) # ignore arguments without separate parameter ;; --separate-git-dir) @@ -839,8 +842,8 @@ function clone() { "$GIT_PROGRAM" checkout -- ":/$file" done - if [[ $do_submodules -ne 0 ]]; then - "$GIT_PROGRAM" submodule update --init --recursive + if [ ${#submodules[@]} -gt 0 ]; then + "$GIT_PROGRAM" submodule update --init --recursive -- "${submodules[@]}" fi if [ -n "$("$GIT_PROGRAM" ls-files --modified)" ]; then