diff options
author | Oliver Breitwieser <oliver.breitwieser@kip.uni-heidelberg.de> | 2019-12-04 16:37:40 +0100 |
---|---|---|
committer | Peter Scheibel <scheibel1@llnl.gov> | 2020-05-04 14:39:25 -0700 |
commit | 1cff717ca86c031c912cf22a7e315d822ab83e46 (patch) | |
tree | 81159a9aa7f680acfc84bda51eaf296d7786e29a /lib | |
parent | dea5d913db9f98870eb4bd91ba1f8276e5e47d17 (diff) | |
download | spack-1cff717ca86c031c912cf22a7e315d822ab83e46.tar.gz spack-1cff717ca86c031c912cf22a7e315d822ab83e46.tar.bz2 spack-1cff717ca86c031c912cf22a7e315d822ab83e46.tar.xz spack-1cff717ca86c031c912cf22a7e315d822ab83e46.zip |
Fix git-related commands not working in worktrees
If spack is checked out in a git worktree (see [1]), all git-related
commands fail because the `spack_is_git_repo()`-check is not thorough
enough.
When developing in a feature-branch in a seperate worktree, this is
annoying as all unittests regarding git-related spack commands fail,
cluttering the test results with false-positives.
[1]: https://git-scm.com/docs/git-worktree
Change-Id: I94b573a2c0e058e9ccc169e7ee6561626fbb06fd
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/cmd/__init__.py | 23 | ||||
-rw-r--r-- | lib/spack/spack/test/cmd/is_git_repo.py | 67 |
2 files changed, 87 insertions, 3 deletions
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py index 594b5e3a8e..5172bdee07 100644 --- a/lib/spack/spack/cmd/__init__.py +++ b/lib/spack/spack/cmd/__init__.py @@ -9,6 +9,7 @@ import os import re import sys import argparse +import ruamel.yaml as yaml import six @@ -16,7 +17,7 @@ import llnl.util.tty as tty from llnl.util.lang import attr_setdefault, index_by from llnl.util.tty.colify import colify from llnl.util.tty.color import colorize -from llnl.util.filesystem import working_dir +from llnl.util.filesystem import join_path import spack.config import spack.error @@ -26,6 +27,7 @@ import spack.spec import spack.store import spack.util.spack_json as sjson import spack.util.string +from ruamel.yaml.error import MarkedYAMLError # cmd has a submodule called "list" so preserve the python list module @@ -433,8 +435,23 @@ def display_specs(specs, args=None, **kwargs): def spack_is_git_repo(): """Ensure that this instance of Spack is a git clone.""" - with working_dir(spack.paths.prefix): - return os.path.isdir('.git') + return is_git_repo(spack.paths.prefix) + + +def is_git_repo(path): + dotgit_path = join_path(path, '.git') + if os.path.isdir(dotgit_path): + # we are in a regular git repo + return True + if os.path.isfile(dotgit_path): + # we might be in a git worktree + try: + with open(dotgit_path, "rb") as f: + dotgit_content = yaml.load(f) + return os.path.isdir(dotgit_content.get("gitdir", dotgit_path)) + except MarkedYAMLError: + pass + return False class PythonNameError(spack.error.SpackError): diff --git a/lib/spack/spack/test/cmd/is_git_repo.py b/lib/spack/spack/test/cmd/is_git_repo.py new file mode 100644 index 0000000000..724925e5e4 --- /dev/null +++ b/lib/spack/spack/test/cmd/is_git_repo.py @@ -0,0 +1,67 @@ +# Copyright 2013-2020 Lawrence Livermore National Security, LLC and other +# Spack Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + +from __future__ import print_function + +import spack +import pytest + +from llnl.util.filesystem import mkdirp + +from spack.util.executable import which +from spack.version import ver + + +git = which("git") +git_required_version = '2.17.0' + + +def check_git_version(): + """Check if git version is new enough for worktree functionality. + Return True if requirements are met. + + The latest required functionality is `worktree remove` which was only added + in 2.17.0. + + Refer: + https://github.com/git/git/commit/cc73385cf6c5c229458775bc92e7dbbe24d11611 + """ + git_version = ver(git('--version', output=str).lstrip('git version ')) + return git_version >= ver(git_required_version) + + +pytestmark = pytest.mark.skipif( + not git or not check_git_version(), + reason="we need git to test if we are in a git repo" +) + + +@pytest.fixture(scope="function") +def git_tmp_worktree(tmpdir): + """Create new worktree in a temporary folder and monkeypatch + spack.paths.prefix to point to it. + """ + worktree_root = str(tmpdir.join("tmp_worktree")) + mkdirp(worktree_root) + + git("worktree", "add", "--detach", worktree_root, "HEAD") + + yield worktree_root + + git("worktree", "remove", "--force", worktree_root) + + +def test_is_git_repo_in_worktree(git_tmp_worktree): + """Verify that spack.cmd.spack_is_git_repo() can identify a git repository + in a worktree. + """ + assert spack.cmd.is_git_repo(git_tmp_worktree) + + +def test_spack_is_git_repo_nongit(tmpdir, monkeypatch): + """Verify that spack.cmd.spack_is_git_repo() correctly returns False if we + are in a non-git directory. + """ + assert not spack.cmd.is_git_repo(str(tmpdir)) |