Environments: store spack version/commit in spack.lock (#32801)
Add a section to the lock file to track the Spack version/commit that produced an environment. This should (eventually) enhance reproducibility, though we do not currently do anything with the information. It just adds to provenance at the moment. Changes include: - [x] adding the version/commit to `spack.lock` - [x] refactor `spack.main.get_version() - [x] fix a couple of environment lock file-related typos
This commit is contained in:
parent
b06d20be19
commit
8e18297cf2
@ -16,18 +16,24 @@
|
|||||||
The high-level format of a Spack lockfile hasn't changed much between versions, but the
|
The high-level format of a Spack lockfile hasn't changed much between versions, but the
|
||||||
contents have. Lockfiles are JSON-formatted and their top-level sections are:
|
contents have. Lockfiles are JSON-formatted and their top-level sections are:
|
||||||
|
|
||||||
1. ``_meta`` (object): this contains deatails about the file format, including:
|
1. ``_meta`` (object): this contains details about the file format, including:
|
||||||
* ``file-type``: always ``"spack-lockfile"``
|
* ``file-type``: always ``"spack-lockfile"``
|
||||||
* ``lockfile-version``: an integer representing the lockfile format version
|
* ``lockfile-version``: an integer representing the lockfile format version
|
||||||
* ``specfile-version``: an integer representing the spec format version (since
|
* ``specfile-version``: an integer representing the spec format version (since
|
||||||
``v0.17``)
|
``v0.17``)
|
||||||
|
|
||||||
2. ``roots`` (list): an ordered list of records representing the roots of the Spack
|
2. ``spack`` (object): optional, this identifies information about Spack
|
||||||
|
used to concretize the environment:
|
||||||
|
* ``type``: required, identifies form Spack version took (e.g., ``git``, ``release``)
|
||||||
|
* ``commit``: the commit if the version is from git
|
||||||
|
* ``version``: the Spack version
|
||||||
|
|
||||||
|
3. ``roots`` (list): an ordered list of records representing the roots of the Spack
|
||||||
environment. Each has two fields:
|
environment. Each has two fields:
|
||||||
* ``hash``: a Spack spec hash uniquely identifying the concrete root spec
|
* ``hash``: a Spack spec hash uniquely identifying the concrete root spec
|
||||||
* ``spec``: a string representation of the abstract spec that was concretized
|
* ``spec``: a string representation of the abstract spec that was concretized
|
||||||
|
|
||||||
3. ``concrete_specs``: a dictionary containing the specs in the environment.
|
4. ``concrete_specs``: a dictionary containing the specs in the environment.
|
||||||
|
|
||||||
Compatibility
|
Compatibility
|
||||||
-------------
|
-------------
|
||||||
@ -271,6 +277,8 @@
|
|||||||
Dependencies are keyed by ``hash`` (DAG hash) as well. There are no more ``build_hash``
|
Dependencies are keyed by ``hash`` (DAG hash) as well. There are no more ``build_hash``
|
||||||
fields in the specs, and there are no more issues with lockfiles being able to store
|
fields in the specs, and there are no more issues with lockfiles being able to store
|
||||||
multiple specs with the same DAG hash (because the DAG hash is now finer-grained).
|
multiple specs with the same DAG hash (because the DAG hash is now finer-grained).
|
||||||
|
An optional ``spack`` property may be included to track version information, such as
|
||||||
|
the commit or version.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: json
|
||||||
@ -278,8 +286,8 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"file-type": "spack-lockfile",
|
"file-type": "spack-lockfile",
|
||||||
"lockfile-version": 3,
|
"lockfile-version": 4,
|
||||||
"specfile-version": 2
|
"specfile-version": 3
|
||||||
},
|
},
|
||||||
"roots": [
|
"roots": [
|
||||||
{
|
{
|
||||||
@ -326,7 +334,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .environment import (
|
from .environment import (
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
import spack.error
|
import spack.error
|
||||||
import spack.hash_types as ht
|
import spack.hash_types as ht
|
||||||
import spack.hooks
|
import spack.hooks
|
||||||
|
import spack.main
|
||||||
import spack.paths
|
import spack.paths
|
||||||
import spack.repo
|
import spack.repo
|
||||||
import spack.schema.env
|
import spack.schema.env
|
||||||
@ -2072,6 +2073,14 @@ def _to_lockfile_dict(self):
|
|||||||
|
|
||||||
hash_spec_list = zip(self.concretized_order, self.concretized_user_specs)
|
hash_spec_list = zip(self.concretized_order, self.concretized_user_specs)
|
||||||
|
|
||||||
|
spack_dict = {"version": spack.spack_version}
|
||||||
|
spack_commit = spack.main.get_spack_commit()
|
||||||
|
if spack_commit:
|
||||||
|
spack_dict["type"] = "git"
|
||||||
|
spack_dict["commit"] = spack_commit
|
||||||
|
else:
|
||||||
|
spack_dict["type"] = "release"
|
||||||
|
|
||||||
# this is the lockfile we'll write out
|
# this is the lockfile we'll write out
|
||||||
data = {
|
data = {
|
||||||
# metadata about the format
|
# metadata about the format
|
||||||
@ -2080,6 +2089,8 @@ def _to_lockfile_dict(self):
|
|||||||
"lockfile-version": lockfile_format_version,
|
"lockfile-version": lockfile_format_version,
|
||||||
"specfile-version": spack.spec.SPECFILE_FORMAT_VERSION,
|
"specfile-version": spack.spec.SPECFILE_FORMAT_VERSION,
|
||||||
},
|
},
|
||||||
|
# spack version information
|
||||||
|
"spack": spack_dict,
|
||||||
# users specs + hashes are the 'roots' of the environment
|
# users specs + hashes are the 'roots' of the environment
|
||||||
"roots": [{"hash": h, "spec": str(s)} for h, s in hash_spec_list],
|
"roots": [{"hash": h, "spec": str(s)} for h, s in hash_spec_list],
|
||||||
# Concrete specs by hash, including dependencies
|
# Concrete specs by hash, including dependencies
|
||||||
|
@ -126,6 +126,36 @@ def add_all_commands(parser):
|
|||||||
parser.add_command(cmd)
|
parser.add_command(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def get_spack_commit():
|
||||||
|
"""Get the Spack git commit sha.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(str or None) the commit sha if available, otherwise None
|
||||||
|
"""
|
||||||
|
git_path = os.path.join(spack.paths.prefix, ".git")
|
||||||
|
if not os.path.exists(git_path):
|
||||||
|
return None
|
||||||
|
|
||||||
|
git = spack.util.git.git()
|
||||||
|
if not git:
|
||||||
|
return None
|
||||||
|
|
||||||
|
rev = git(
|
||||||
|
"-C",
|
||||||
|
spack.paths.prefix,
|
||||||
|
"rev-parse",
|
||||||
|
"HEAD",
|
||||||
|
output=str,
|
||||||
|
error=os.devnull,
|
||||||
|
fail_on_error=False,
|
||||||
|
)
|
||||||
|
if git.returncode != 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
match = re.match(r"[a-f\d]{7,}$", rev)
|
||||||
|
return match.group(0) if match else None
|
||||||
|
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
"""Get a descriptive version of this instance of Spack.
|
"""Get a descriptive version of this instance of Spack.
|
||||||
|
|
||||||
@ -134,25 +164,9 @@ def get_version():
|
|||||||
The commit sha is only added when available.
|
The commit sha is only added when available.
|
||||||
"""
|
"""
|
||||||
version = spack.spack_version
|
version = spack.spack_version
|
||||||
git_path = os.path.join(spack.paths.prefix, ".git")
|
commit = get_spack_commit()
|
||||||
if os.path.exists(git_path):
|
if commit:
|
||||||
git = spack.util.git.git()
|
version += " ({0})".format(commit)
|
||||||
if not git:
|
|
||||||
return version
|
|
||||||
rev = git(
|
|
||||||
"-C",
|
|
||||||
spack.paths.prefix,
|
|
||||||
"rev-parse",
|
|
||||||
"HEAD",
|
|
||||||
output=str,
|
|
||||||
error=os.devnull,
|
|
||||||
fail_on_error=False,
|
|
||||||
)
|
|
||||||
if git.returncode != 0:
|
|
||||||
return version
|
|
||||||
match = re.match(r"[a-f\d]{7,}$", rev)
|
|
||||||
if match:
|
|
||||||
version += " ({0})".format(match.group(0))
|
|
||||||
|
|
||||||
return version
|
return version
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import spack.environment as ev
|
import spack.environment as ev
|
||||||
|
from spack import spack_version
|
||||||
from spack.main import SpackCommand
|
from spack.main import SpackCommand
|
||||||
|
|
||||||
pytestmark = pytest.mark.usefixtures("config", "mutable_mock_repo")
|
pytestmark = pytest.mark.usefixtures("config", "mutable_mock_repo")
|
||||||
@ -54,3 +55,6 @@ def test_concretize_root_test_dependencies_are_concretized(unify, mutable_mock_e
|
|||||||
add("b")
|
add("b")
|
||||||
concretize("--test", "root")
|
concretize("--test", "root")
|
||||||
assert e.matching_spec("test-dependency")
|
assert e.matching_spec("test-dependency")
|
||||||
|
|
||||||
|
data = e._to_lockfile_dict()
|
||||||
|
assert data["spack"]["version"] == spack_version
|
||||||
|
Loading…
Reference in New Issue
Block a user