summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorOliver Breitwieser <oliver.breitwieser@kip.uni-heidelberg.de>2019-12-04 16:37:40 +0100
committerPeter Scheibel <scheibel1@llnl.gov>2020-05-04 14:39:25 -0700
commit1cff717ca86c031c912cf22a7e315d822ab83e46 (patch)
tree81159a9aa7f680acfc84bda51eaf296d7786e29a /lib
parentdea5d913db9f98870eb4bd91ba1f8276e5e47d17 (diff)
downloadspack-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__.py23
-rw-r--r--lib/spack/spack/test/cmd/is_git_repo.py67
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))