Have fetcher respect the commit variant

Ensure that if a commit variant is on the spec fetch operations
use the commit
This commit is contained in:
Philip Sakievich 2025-02-19 13:10:02 -07:00 committed by psakiev
parent 011da2d44a
commit 9c575ef310
4 changed files with 46 additions and 12 deletions

View File

@ -1591,12 +1591,14 @@ def for_package_version(pkg, version=None):
version = pkg.version version = pkg.version
# if it's a commit, we must use a GitFetchStrategy # if it's a commit, we must use a GitFetchStrategy
if isinstance(version, spack.version.GitVersion): commit_sha = pkg.spec.variants.get("commit", None)
if isinstance(version, spack.version.GitVersion) or commit_sha:
if not hasattr(pkg, "git"): if not hasattr(pkg, "git"):
raise spack.error.FetchError( raise spack.error.FetchError(
f"Cannot fetch git version for {pkg.name}. Package has no 'git' attribute" f"Cannot fetch git version for {pkg.name}. Package has no 'git' attribute"
) )
# Populate the version with comparisons to other commits # Populate the version with comparisons to other commits
if isinstance(version, spack.version.GitVersion):
version.attach_lookup(spack.version.git_ref_lookup.GitRefLookup(pkg.name)) version.attach_lookup(spack.version.git_ref_lookup.GitRefLookup(pkg.name))
# For GitVersion, we have no way to determine whether a ref is a branch or tag # For GitVersion, we have no way to determine whether a ref is a branch or tag
@ -1605,16 +1607,34 @@ def for_package_version(pkg, version=None):
# We call all non-commit refs tags in this context, at the cost of a slight # We call all non-commit refs tags in this context, at the cost of a slight
# performance hit for branches on older versions of git. # performance hit for branches on older versions of git.
# Branches cannot be cached, so we tell the fetcher not to cache tags/branches # Branches cannot be cached, so we tell the fetcher not to cache tags/branches
# TODO(psakiev) eventually we should only need to clone based on the commit
ref_type = None
ref_value = None
if commit_sha:
ref_type = "commit"
ref_value = commit_sha.value
else:
ref_type = "commit" if version.is_commit else "tag" ref_type = "commit" if version.is_commit else "tag"
kwargs = {"git": pkg.git, ref_type: version.ref, "no_cache": True} ref_value = version.ref
kwargs = {ref_type: ref_value, "no_cache": True}
kwargs["git"] = pkg.git
version_attrs = pkg.versions.get(version)
if version_attrs and version_attrs.get("git"):
kwargs["git"] = version_attrs["git"]
kwargs["submodules"] = getattr(pkg, "submodules", False) kwargs["submodules"] = getattr(pkg, "submodules", False)
# if the ref_version is a known version from the package, use that version's # if the ref_version is a known version from the package, use that version's
# submodule specifications # submodule specifications
if hasattr(pkg.version, "ref_version"):
ref_version_attributes = pkg.versions.get(pkg.version.ref_version) ref_version_attributes = pkg.versions.get(pkg.version.ref_version)
if ref_version_attributes: if ref_version_attributes:
kwargs["submodules"] = ref_version_attributes.get("submodules", kwargs["submodules"]) kwargs["submodules"] = ref_version_attributes.get(
"submodules", kwargs["submodules"]
)
kwargs["git"] = ref_version_attributes.get("git", kwargs["git"])
fetcher = GitFetchStrategy(**kwargs) fetcher = GitFetchStrategy(**kwargs)
return fetcher return fetcher

View File

@ -4141,7 +4141,7 @@ def build_specs(self, function_tuples):
spack.version.git_ref_lookup.GitRefLookup(spec.fullname) spack.version.git_ref_lookup.GitRefLookup(spec.fullname)
) )
# check for commits mush happen after all version adaptations are complete # check for commits must happen after all version adaptations are complete
for s in self._specs.values(): for s in self._specs.values():
_specs_with_commits(s) _specs_with_commits(s)
@ -4278,9 +4278,6 @@ def _specs_with_commits(spec):
if not (has_commit_var or has_git_version): if not (has_commit_var or has_git_version):
return return
if "dev_path" in spec.variants:
assert False
# Specs with commit variants # Specs with commit variants
# - variant value satsifies commit regex # - variant value satsifies commit regex
# - paired to a GitVersion or version that is associated with a branch/tag # - paired to a GitVersion or version that is associated with a branch/tag

View File

@ -3317,7 +3317,6 @@ def _ensure_cache_hits(self, problem: str):
(f"git-ref-package@2.1.6 commit={'a' * 40}", False, AssertionError), (f"git-ref-package@2.1.6 commit={'a' * 40}", False, AssertionError),
(f"git-ref-package@git.2.1.6=2.1.6 commit={'a' * 40}", True, None), (f"git-ref-package@git.2.1.6=2.1.6 commit={'a' * 40}", True, None),
(f"git-ref-package@2.1.6 commit={'a' * 40}", False, AssertionError), (f"git-ref-package@2.1.6 commit={'a' * 40}", False, AssertionError),
(f"git-ref-package@main commit={'a' * 40} dev_path=/foo/bar/", False, AssertionError),
], ],
) )
def test_spec_containing_commit_variant(spec_str, should_pass, error_type): def test_spec_containing_commit_variant(spec_str, should_pass, error_type):

View File

@ -4,6 +4,7 @@
import copy import copy
import os import os
import pathlib
import shutil import shutil
import pytest import pytest
@ -19,6 +20,7 @@
from spack.fetch_strategy import GitFetchStrategy from spack.fetch_strategy import GitFetchStrategy
from spack.spec import Spec from spack.spec import Spec
from spack.stage import Stage from spack.stage import Stage
from spack.variant import SingleValuedVariant
from spack.version import Version from spack.version import Version
_mock_transport_error = "Mock HTTP transport error" _mock_transport_error = "Mock HTTP transport error"
@ -429,3 +431,19 @@ def test_git_sparse_paths_partial_clone(
# fixture file is in the sparse-path expansion tree # fixture file is in the sparse-path expansion tree
assert os.path.isfile(t.file) assert os.path.isfile(t.file)
@pytest.mark.disable_clean_stage_check
def test_commit_variant_clone(
git, default_mock_concretization, mutable_mock_repo, mock_git_version_info, monkeypatch
):
repo_path, filename, commits = mock_git_version_info
test_commit = commits[-1]
s = default_mock_concretization("git-test")
args = {"git": pathlib.Path(repo_path).as_uri()}
monkeypatch.setitem(s.package.versions, Version("git"), args)
s.variants["commit"] = SingleValuedVariant("commit", test_commit)
s.package.do_stage()
with working_dir(s.package.stage.source_path):
assert git("rev-parse", "HEAD", output=str, error=str).strip() == test_commit