From fcc6bf93f7b336919220b77c5e7402deacabe60d Mon Sep 17 00:00:00 2001 From: Lukas Zachar Date: Fri, 15 Jul 2022 18:51:27 +0200 Subject: [PATCH] Shallow git clone if no reference is used If later `fetch_repo()` specifies ref, git fetch --unshallow is called to obtain whole history. Fixes: #169 --- fmf/utils.py | 24 +++++++++++++++++++++--- tests/unit/test_utils.py | 9 +++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/fmf/utils.py b/fmf/utils.py index 598c9d09..4318d828 100644 --- a/fmf/utils.py +++ b/fmf/utils.py @@ -720,9 +720,13 @@ def fetch_repo(url, ref=None, destination=None, env=None): # Write PID to lockfile so we know which process got it with open(lock.lock_file, 'w') as lock_file: lock_file.write(str(os.getpid())) - # Clone the repository + # Clone the repository, use depth=1 when ref is not used + if ref is None: + depth = ['--depth=1'] + else: + depth = [] if not os.path.isdir(os.path.join(destination, '.git')): - run(['git', 'clone', url, destination], cwd=cache, env=env) + run(['git', 'clone'] + depth + [url, destination], cwd=cache, env=env) # Detect the default branch if 'ref' not provided if ref is None: ref = default_branch(destination) @@ -735,7 +739,21 @@ def fetch_repo(url, ref=None, destination=None, env=None): if age >= CACHE_EXPIRATION: run(['git', 'fetch'], cwd=destination) # Checkout branch - run(['git', 'checkout', '-f', ref], cwd=destination, env=env) + try: + run(['git', 'checkout', '-f', ref], cwd=destination, env=env) + except subprocess.CalledProcessError as error: + # Another way to check for shallow clone is to call + # `git rev-parse --is-shallow-repository` but it prints true/false + if os.path.isfile(os.path.join(destination, '.git', 'shallow')): + # Make fetch get all remote refs (branches...) + run(["git", "config", "remote.origin.fetch", + "+refs/heads/*:refs/remotes/origin/*"], cwd=destination) + # Fetch the whole history + run(['git', 'fetch', '--unshallow'], cwd=destination) + run(['git', 'checkout', '-f', ref], cwd=destination, env=env) + else: + # History is already fetched so ref is wrong (no need to retry) + raise error # Reset to origin to get possible changes but no exit code check # ref could be tag or commit where it is expected to fail run(['git', 'reset', '--hard', "origin/{0}".format(ref)], diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 05f1dcd6..c5c079c4 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -215,6 +215,15 @@ def test_switch_branches(self): output, _ = run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], repo) assert 'main' in output + def test_shallow_clone(self, tmpdir): + fetched_to = utils.fetch_repo(GIT_REPO, destination=str(tmpdir)) + out, _ = run(["git", "rev-parse", "--is-shallow-repository"], fetched_to) + assert 'true' in out + + fetched_to = utils.fetch_repo(GIT_REPO, destination=str(tmpdir), ref='fedora') + out, _ = run(["git", "rev-parse", "--is-shallow-repository"], fetched_to) + assert 'false' in out + def test_fetch_valid_id(self): repo = utils.fetch_repo(GIT_REPO, '0.10') assert utils.os.path.isfile(utils.os.path.join(repo, 'fmf.spec'))