Skip to content

Commit f91ec2e

Browse files
committed
Revert "Remove legacy yaml from buildcache fetch (spack#34347)"
This reverts commit b58ec9e.
1 parent 509a8ea commit f91ec2e

File tree

2 files changed

+102
-24
lines changed

2 files changed

+102
-24
lines changed

lib/spack/spack/binary_distribution.py

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,8 @@ def _fetch_spec_from_mirror(spec_url):
872872
return Spec.from_dict(specfile_json)
873873
if spec_url.endswith(".json"):
874874
return Spec.from_json(spec_file_contents)
875+
if spec_url.endswith(".yaml"):
876+
return Spec.from_yaml(spec_file_contents)
875877

876878
tp = multiprocessing.pool.ThreadPool(processes=concurrency)
877879
try:
@@ -946,6 +948,8 @@ def file_read_method(file_path):
946948
"*.spec.json.sig",
947949
"--include",
948950
"*.spec.json",
951+
"--include",
952+
"*.spec.yaml",
949953
cache_prefix,
950954
tmpspecsdir,
951955
]
@@ -955,7 +959,7 @@ def file_read_method(file_path):
955959
"Using aws s3 sync to download specs from {0} to {1}".format(cache_prefix, tmpspecsdir)
956960
)
957961
aws(*sync_command_args, output=os.devnull, error=os.devnull)
958-
file_list = fsys.find(tmpspecsdir, ["*.spec.json.sig", "*.spec.json"])
962+
file_list = fsys.find(tmpspecsdir, ["*.spec.json.sig", "*.spec.json", "*.spec.yaml"])
959963
read_fn = file_read_method
960964
except Exception:
961965
tty.warn("Failed to use aws s3 sync to retrieve specs, falling back to parallel fetch")
@@ -991,7 +995,9 @@ def url_read_method(url):
991995
file_list = [
992996
url_util.join(cache_prefix, entry)
993997
for entry in web_util.list_url(cache_prefix)
994-
if entry.endswith("spec.json") or entry.endswith("spec.json.sig")
998+
if entry.endswith(".yaml")
999+
or entry.endswith("spec.json")
1000+
or entry.endswith("spec.json.sig")
9951001
]
9961002
read_fn = url_read_method
9971003
except KeyError as inst:
@@ -1053,6 +1059,14 @@ def generate_package_index(cache_prefix, concurrency=32):
10531059
tty.error("Unable to generate package index, {0}".format(err))
10541060
return
10551061

1062+
if any(x.endswith(".yaml") for x in file_list):
1063+
msg = (
1064+
"The mirror in '{}' contains specs in the deprecated YAML format.\n\n\tSupport for "
1065+
"this format will be removed in v0.20, please regenerate the build cache with a "
1066+
"recent Spack\n"
1067+
).format(cache_prefix)
1068+
warnings.warn(msg)
1069+
10561070
tty.debug("Retrieving spec descriptor files from {0} to build index".format(cache_prefix))
10571071

10581072
tmpdir = tempfile.mkdtemp()
@@ -1179,20 +1193,28 @@ def _build_tarball(
11791193
specfile_name = tarball_name(spec, ".spec.json")
11801194
specfile_path = os.path.realpath(os.path.join(cache_prefix, specfile_name))
11811195
signed_specfile_path = "{0}.sig".format(specfile_path)
1196+
deprecated_specfile_path = specfile_path.replace(".spec.json", ".spec.yaml")
11821197

11831198
remote_specfile_path = url_util.join(
11841199
out_url, os.path.relpath(specfile_path, os.path.realpath(tmpdir))
11851200
)
11861201
remote_signed_specfile_path = "{0}.sig".format(remote_specfile_path)
1202+
remote_specfile_path_deprecated = url_util.join(
1203+
outdir, os.path.relpath(deprecated_specfile_path, os.path.realpath(tmpdir))
1204+
)
11871205

11881206
# If force and exists, overwrite. Otherwise raise exception on collision.
11891207
if force:
11901208
if web_util.url_exists(remote_specfile_path):
11911209
web_util.remove_url(remote_specfile_path)
11921210
if web_util.url_exists(remote_signed_specfile_path):
11931211
web_util.remove_url(remote_signed_specfile_path)
1194-
elif web_util.url_exists(remote_specfile_path) or web_util.url_exists(
1195-
remote_signed_specfile_path
1212+
if web_util.url_exists(remote_specfile_path_deprecated):
1213+
web_util.remove_url(remote_specfile_path_deprecated)
1214+
elif (
1215+
web_util.url_exists(remote_specfile_path)
1216+
or web_util.url_exists(remote_signed_specfile_path)
1217+
or web_util.url_exists(remote_specfile_path_deprecated)
11961218
):
11971219
raise NoOverwriteException(url_util.format(remote_specfile_path))
11981220

@@ -1248,10 +1270,12 @@ def _build_tarball(
12481270

12491271
with open(spec_file, "r") as inputfile:
12501272
content = inputfile.read()
1251-
if spec_file.endswith(".json"):
1273+
if spec_file.endswith(".yaml"):
1274+
spec_dict = yaml.load(content)
1275+
elif spec_file.endswith(".json"):
12521276
spec_dict = sjson.load(content)
12531277
else:
1254-
raise ValueError("{0} not a valid spec file type".format(spec_file))
1278+
raise ValueError("{0} not a valid spec file type (json or yaml)".format(spec_file))
12551279
spec_dict["buildcache_layout_version"] = 1
12561280
bchecksum = {}
12571281
bchecksum["hash_algorithm"] = "sha256"
@@ -1472,7 +1496,7 @@ def download_tarball(spec, unsigned=False, mirrors_for_spec=None):
14721496
# Assumes we care more about finding a spec file by preferred ext
14731497
# than by mirrory priority. This can be made less complicated as
14741498
# we remove support for deprecated spec formats and buildcache layouts.
1475-
for ext in ["json.sig", "json"]:
1499+
for ext in ["json.sig", "json", "yaml"]:
14761500
for mirror_to_try in mirrors_to_try:
14771501
specfile_url = "{0}.{1}".format(mirror_to_try["specfile"], ext)
14781502
spackfile_url = mirror_to_try["spackfile"]
@@ -1509,6 +1533,13 @@ def download_tarball(spec, unsigned=False, mirrors_for_spec=None):
15091533
# the remaining mirrors, looking for one we can use.
15101534
tarball_stage = try_fetch(spackfile_url)
15111535
if tarball_stage:
1536+
if ext == "yaml":
1537+
msg = (
1538+
"Reading {} from mirror.\n\n\tThe YAML format for buildcaches is "
1539+
"deprecated and will be removed in v0.20\n"
1540+
).format(spackfile_url)
1541+
warnings.warn(msg)
1542+
15121543
return {
15131544
"tarball_stage": tarball_stage,
15141545
"specfile_stage": local_specfile_stage,
@@ -1748,6 +1779,8 @@ def _extract_inner_tarball(spec, filename, extract_to, unsigned, remote_checksum
17481779
spackfile_path = os.path.join(stagepath, spackfile_name)
17491780
tarfile_name = tarball_name(spec, ".tar.gz")
17501781
tarfile_path = os.path.join(extract_to, tarfile_name)
1782+
deprecated_yaml_name = tarball_name(spec, ".spec.yaml")
1783+
deprecated_yaml_path = os.path.join(extract_to, deprecated_yaml_name)
17511784
json_name = tarball_name(spec, ".spec.json")
17521785
json_path = os.path.join(extract_to, json_name)
17531786
with closing(tarfile.open(spackfile_path, "r")) as tar:
@@ -1759,6 +1792,8 @@ def _extract_inner_tarball(spec, filename, extract_to, unsigned, remote_checksum
17591792

17601793
if os.path.exists(json_path):
17611794
specfile_path = json_path
1795+
elif os.path.exists(deprecated_yaml_path):
1796+
specfile_path = deprecated_yaml_path
17621797
else:
17631798
raise ValueError("Cannot find spec file for {0}.".format(extract_to))
17641799

@@ -1805,8 +1840,10 @@ def extract_tarball(spec, download_result, allow_root=False, unsigned=False, for
18051840
content = inputfile.read()
18061841
if specfile_path.endswith(".json.sig"):
18071842
spec_dict = Spec.extract_json_from_clearsig(content)
1808-
else:
1843+
elif specfile_path.endswith(".json"):
18091844
spec_dict = sjson.load(content)
1845+
else:
1846+
spec_dict = syaml.load(content)
18101847

18111848
bchecksum = spec_dict["binary_cache_checksum"]
18121849
filename = download_result["tarball_stage"].save_filename
@@ -1818,7 +1855,7 @@ def extract_tarball(spec, download_result, allow_root=False, unsigned=False, for
18181855
or int(spec_dict["buildcache_layout_version"]) < 1
18191856
):
18201857
# Handle the older buildcache layout where the .spack file
1821-
# contains a spec json, maybe an .asc file (signature),
1858+
# contains a spec json/yaml, maybe an .asc file (signature),
18221859
# and another tarball containing the actual install tree.
18231860
tmpdir = tempfile.mkdtemp()
18241861
try:
@@ -1969,12 +2006,17 @@ def try_direct_fetch(spec, mirrors=None):
19692006
"""
19702007
Try to find the spec directly on the configured mirrors
19712008
"""
2009+
deprecated_specfile_name = tarball_name(spec, ".spec.yaml")
19722010
specfile_name = tarball_name(spec, ".spec.json")
19732011
signed_specfile_name = tarball_name(spec, ".spec.json.sig")
19742012
specfile_is_signed = False
2013+
specfile_is_json = True
19752014
found_specs = []
19762015

19772016
for mirror in spack.mirror.MirrorCollection(mirrors=mirrors).values():
2017+
buildcache_fetch_url_yaml = url_util.join(
2018+
mirror.fetch_url, _build_cache_relative_path, deprecated_specfile_name
2019+
)
19782020
buildcache_fetch_url_json = url_util.join(
19792021
mirror.fetch_url, _build_cache_relative_path, specfile_name
19802022
)
@@ -1988,19 +2030,28 @@ def try_direct_fetch(spec, mirrors=None):
19882030
try:
19892031
_, _, fs = web_util.read_from_url(buildcache_fetch_url_json)
19902032
except (URLError, web_util.SpackWebError, HTTPError) as url_err_x:
1991-
tty.debug(
1992-
"Did not find {0} on {1}".format(
1993-
specfile_name, buildcache_fetch_url_signed_json
1994-
),
1995-
url_err,
1996-
level=2,
1997-
)
1998-
tty.debug(
1999-
"Did not find {0} on {1}".format(specfile_name, buildcache_fetch_url_json),
2000-
url_err_x,
2001-
level=2,
2002-
)
2003-
continue
2033+
try:
2034+
_, _, fs = web_util.read_from_url(buildcache_fetch_url_yaml)
2035+
specfile_is_json = False
2036+
except (URLError, web_util.SpackWebError, HTTPError) as url_err_y:
2037+
tty.debug(
2038+
"Did not find {0} on {1}".format(
2039+
specfile_name, buildcache_fetch_url_signed_json
2040+
),
2041+
url_err,
2042+
level=2,
2043+
)
2044+
tty.debug(
2045+
"Did not find {0} on {1}".format(specfile_name, buildcache_fetch_url_json),
2046+
url_err_x,
2047+
level=2,
2048+
)
2049+
tty.debug(
2050+
"Did not find {0} on {1}".format(specfile_name, buildcache_fetch_url_yaml),
2051+
url_err_y,
2052+
level=2,
2053+
)
2054+
continue
20042055
specfile_contents = codecs.getreader("utf-8")(fs).read()
20052056

20062057
# read the spec from the build cache file. All specs in build caches
@@ -2009,8 +2060,10 @@ def try_direct_fetch(spec, mirrors=None):
20092060
if specfile_is_signed:
20102061
specfile_json = Spec.extract_json_from_clearsig(specfile_contents)
20112062
fetched_spec = Spec.from_dict(specfile_json)
2012-
else:
2063+
elif specfile_is_json:
20132064
fetched_spec = Spec.from_json(specfile_contents)
2065+
else:
2066+
fetched_spec = Spec.from_yaml(specfile_contents)
20142067
fetched_spec._mark_concrete()
20152068

20162069
found_specs.append(
@@ -2221,7 +2274,7 @@ def needs_rebuild(spec, mirror_url):
22212274
specfile_path = os.path.join(cache_prefix, specfile_name)
22222275

22232276
# Only check for the presence of the json version of the spec. If the
2224-
# mirror only has the json version, or doesn't have the spec at all, we
2277+
# mirror only has the yaml version, or doesn't have the spec at all, we
22252278
# need to rebuild.
22262279
return not web_util.url_exists(specfile_path)
22272280

@@ -2329,6 +2382,7 @@ def download_single_spec(concrete_spec, destination, mirror_url=None):
23292382
"url": [
23302383
tarball_name(concrete_spec, ".spec.json.sig"),
23312384
tarball_name(concrete_spec, ".spec.json"),
2385+
tarball_name(concrete_spec, ".spec.yaml"),
23322386
],
23332387
"path": destination,
23342388
"required": True,

lib/spack/spack/test/bindist.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io
77
import os
88
import platform
9+
import shutil
910
import sys
1011
import urllib.error
1112
import urllib.request
@@ -71,6 +72,16 @@ def test_mirror(mirror_dir):
7172
mirror_cmd("rm", "--scope=site", "test-mirror-func")
7273

7374

75+
@pytest.fixture(scope="function")
76+
def test_legacy_mirror(mutable_config, tmpdir):
77+
mirror_dir = tmpdir.join("legacy_yaml_mirror")
78+
shutil.copytree(legacy_mirror_dir, mirror_dir.strpath)
79+
mirror_url = "file://%s" % mirror_dir
80+
mirror_cmd("add", "--scope", "site", "test-legacy-yaml", mirror_url)
81+
yield mirror_dir
82+
mirror_cmd("rm", "--scope=site", "test-legacy-yaml")
83+
84+
7485
@pytest.fixture(scope="module")
7586
def config_directory(tmpdir_factory):
7687
tmpdir = tmpdir_factory.mktemp("test_configs")
@@ -574,6 +585,19 @@ def test_update_sbang(tmpdir, test_mirror):
574585
uninstall_cmd("-y", "/%s" % new_spec.dag_hash())
575586

576587

588+
# Need one where the platform has been changed to the test platform.
589+
def test_install_legacy_yaml(test_legacy_mirror, install_mockery_mutable_config, mock_packages):
590+
install_cmd(
591+
"--no-check-signature",
592+
"--cache-only",
593+
"-f",
594+
legacy_mirror_dir
595+
+ "/build_cache/test-debian6-core2-gcc-4.5.0-zlib-"
596+
+ "1.2.11-t5mczux3tfqpxwmg7egp7axy2jvyulqk.spec.yaml",
597+
)
598+
uninstall_cmd("-y", "/t5mczux3tfqpxwmg7egp7axy2jvyulqk")
599+
600+
577601
def test_install_legacy_buildcache_layout(install_mockery_mutable_config):
578602
"""Legacy buildcache layout involved a nested archive structure
579603
where the .spack file contained a repeated spec.json and another

0 commit comments

Comments
 (0)