From fcf11d1062c3538da28a326a5482bffbef75d281 Mon Sep 17 00:00:00 2001 From: "Alejandro R. Mosteo" Date: Fri, 25 Aug 2023 10:26:55 +0200 Subject: [PATCH] Tests for compiler in build hash input --- src/alire/alire-toolchains-solutions.adb | 30 ++++++++-- testsuite/drivers/builds.py | 8 +++ .../gnat_external/gnat_external-external.toml | 12 ++++ .../gn/gnat_native/gnat_native-7777.0.0.toml | 11 ++++ .../gn/gnat_native/gnat_native-8888.0.0.toml | 15 +++++ .../he/hello/hello-1.0.0.toml | 16 ++++++ .../he/hello/hello-1.0.1.toml | 29 ++++++++++ .../fixtures/build_hash_index/index.toml | 1 + .../li/libhello/libhello-1.0.0.toml | 23 ++++++++ .../ma/make/make-external.toml | 8 +++ .../tests/build/hashes/compiler-input/test.py | 56 +++++++++++++++++++ .../build/hashes/compiler-input/test.yaml | 4 ++ .../build/hashes/compiler-missing/test.py | 19 +++++++ .../build/hashes/compiler-missing/test.yaml | 4 ++ .../build/hashes/hashing-inputs/test.yaml | 2 +- testsuite/tests/config/shared-deps/test.yaml | 2 +- .../dockerized/misc/default-cache/test.py | 2 +- 17 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 testsuite/fixtures/build_hash_index/gn/gnat_external/gnat_external-external.toml create mode 100644 testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-7777.0.0.toml create mode 100644 testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-8888.0.0.toml create mode 100644 testsuite/fixtures/build_hash_index/he/hello/hello-1.0.0.toml create mode 100644 testsuite/fixtures/build_hash_index/he/hello/hello-1.0.1.toml create mode 100644 testsuite/fixtures/build_hash_index/index.toml create mode 100644 testsuite/fixtures/build_hash_index/li/libhello/libhello-1.0.0.toml create mode 100644 testsuite/fixtures/build_hash_index/ma/make/make-external.toml create mode 100644 testsuite/tests/build/hashes/compiler-input/test.py create mode 100644 testsuite/tests/build/hashes/compiler-input/test.yaml create mode 100644 testsuite/tests/build/hashes/compiler-missing/test.py create mode 100644 testsuite/tests/build/hashes/compiler-missing/test.yaml diff --git a/src/alire/alire-toolchains-solutions.adb b/src/alire/alire-toolchains-solutions.adb index 661b65660..11a53119c 100644 --- a/src/alire/alire-toolchains-solutions.adb +++ b/src/alire/alire-toolchains-solutions.adb @@ -2,6 +2,7 @@ with AAA.Strings; with Alire.Index; with Alire.Root; +with Alire.Solver; package body Alire.Toolchains.Solutions is @@ -75,6 +76,26 @@ package body Alire.Toolchains.Solutions is function Compiler (Solution : Alire.Solutions.Solution) return Releases.Release is + + -------------------------- + -- Environment_Compiler -- + -------------------------- + + function Environment_Compiler return Releases.Release is + begin + Index.Detect_Externals (GNAT_Crate, Root.Platform_Properties); + return Solver.Find (GNAT_External_Crate, + Policy => Solver.Default_Options.Age); + exception + when Query_Unsuccessful => + Raise_Checked_Error + (Errors.New_Wrapper + .Wrap ("Unable to determine compiler version.") + .Wrap ("Check that the workspace solution is complete " + & "and a compiler is available.") + .Get); + end Environment_Compiler; + begin if not Solution.Depends_On (GNAT_Crate) then declare @@ -83,11 +104,10 @@ package body Alire.Toolchains.Solutions is Deploy => False); begin if not With_GNAT.Depends_On (GNAT_Crate) then - Raise_Checked_Error - (Errors.New_Wrapper - .Wrap ("Unable to determine compiler version.") - .Wrap ("Check that the workspace solution is complete.") - .Get); + -- This means that no compiler (or None) has been selected + -- with `alr toolchain`, so we return whichever one is in + -- the environment. + return Environment_Compiler; else return Compiler (With_GNAT); end if; diff --git a/testsuite/drivers/builds.py b/testsuite/drivers/builds.py index ed1bee964..7a2f73d50 100644 --- a/testsuite/drivers/builds.py +++ b/testsuite/drivers/builds.py @@ -4,9 +4,17 @@ from glob import glob import os +from shutil import rmtree from drivers.alr import alr_builds_dir +def clear_builds_dir() -> None: + """ + Clear the shared build directory + """ + rmtree(path()) + + def find_dir(crate_name: str) -> str: """ Find the build dir of a crate in the shared build directory diff --git a/testsuite/fixtures/build_hash_index/gn/gnat_external/gnat_external-external.toml b/testsuite/fixtures/build_hash_index/gn/gnat_external/gnat_external-external.toml new file mode 100644 index 000000000..f1171a6ba --- /dev/null +++ b/testsuite/fixtures/build_hash_index/gn/gnat_external/gnat_external-external.toml @@ -0,0 +1,12 @@ +description = "GNAT is a compiler for the Ada programming language" +name = "gnat_external" + +maintainers = ["alejandro@mosteo.com"] +maintainers-logins = ["mosteo"] + +[[external]] +kind = "version-output" +# We look for make instead that should be always installed. +version-command = ["make", "--version"] +version-regexp = ".*Make ([\\d\\.]+).*" +provides = "gnat" diff --git a/testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-7777.0.0.toml b/testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-7777.0.0.toml new file mode 100644 index 000000000..f1a79578f --- /dev/null +++ b/testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-7777.0.0.toml @@ -0,0 +1,11 @@ +description = "Fake GNAT native crate" +name = "gnat_native" +version = "7777.0.0" +maintainers = ["alejandro@mosteo.com"] +maintainers-logins = ["mylogin"] +provides = ["gnat=7777.0"] + +# Test dynamic expression, but for all OSes +[origin."case(os)"."..."] +url = "file:../../../crates/libhello_1.0.0.tgz" +hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] diff --git a/testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-8888.0.0.toml b/testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-8888.0.0.toml new file mode 100644 index 000000000..242786d5f --- /dev/null +++ b/testsuite/fixtures/build_hash_index/gn/gnat_native/gnat_native-8888.0.0.toml @@ -0,0 +1,15 @@ +description = "Fake GNAT native crate" +name = "gnat_native" +version = "8888.0.0" +maintainers = ["alejandro@mosteo.com"] +maintainers-logins = ["mylogin"] +provides = ["gnat=8888.0"] + +# Although the compiler is fake, we use this path in some tests +environment.'case(os)'.'windows'.TEST_PATH.append = '${CRATE_ROOT}\bin' +environment.'case(os)'.'...'.TEST_PATH.append = '${CRATE_ROOT}/bin' + +# Test dynamic expression, but for all OSes +[origin."case(os)"."..."] +url = "file:../../../crates/libhello_1.0.0.tgz" +hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"] diff --git a/testsuite/fixtures/build_hash_index/he/hello/hello-1.0.0.toml b/testsuite/fixtures/build_hash_index/he/hello/hello-1.0.0.toml new file mode 100644 index 000000000..bf47cfcae --- /dev/null +++ b/testsuite/fixtures/build_hash_index/he/hello/hello-1.0.0.toml @@ -0,0 +1,16 @@ +description = "\"Hello, world!\" demonstration project" +long-description = "This is an example of long description in a multi-line string.\n\nMarkdown formating `can` be used to have \"nice\" display on the website.\n" +name = "hello" +version = "1.0.0" +website = "example.com" +authors = ["Bob", "Alice"] +licenses = "GPL-3.0-only OR MIT" +maintainers = ["alejandro@mosteo.com", "bob@example.com"] +maintainers-logins = ["mylogin"] +tags = ["tag1", "other-tag"] + +[[depends-on]] +libhello = "^1.0" + +[origin] +url = "file:../../../crates/hello_1.0.0" diff --git a/testsuite/fixtures/build_hash_index/he/hello/hello-1.0.1.toml b/testsuite/fixtures/build_hash_index/he/hello/hello-1.0.1.toml new file mode 100644 index 000000000..e67e218c6 --- /dev/null +++ b/testsuite/fixtures/build_hash_index/he/hello/hello-1.0.1.toml @@ -0,0 +1,29 @@ +description = "\"Hello, world!\" demonstration project" +long-description = "This is an example of long description in a multi-line string.\n\nMarkdown formating `can` be used to have \"nice\" display on the website.\n" +name = "hello" +version = "1.0.1" +website = "example.com" +authors = ["Bob", "Alice"] +licenses = "GPL-3.0-only OR MIT" +maintainers = ["alejandro@mosteo.com", "bob@example.com"] +maintainers-logins = ["mylogin"] +tags = ["tag1", "other-tag"] + +[[depends-on]] +libhello = "^1.0" + +[configuration.variables] +Var1={type="Boolean"} +Var2={type="String", default="str"} +Var3={type="Enum", values=["A", "B"], default="A"} +Var4={type="Integer", default=0} +Var5={type="Integer", first=-1, last=1, default=0} +Var7={type="Real", default=0.0} +Var6={type="Real", first=-1.0, last=1.0, default=0.0} + +[configuration.values] +hello.Var1=true # So far it is possible for a crate to set its own var +libhello.Var1=false + +[origin] +url = "file:../../../crates/hello_1.0.1" diff --git a/testsuite/fixtures/build_hash_index/index.toml b/testsuite/fixtures/build_hash_index/index.toml new file mode 100644 index 000000000..bad265e4f --- /dev/null +++ b/testsuite/fixtures/build_hash_index/index.toml @@ -0,0 +1 @@ +version = "1.1" diff --git a/testsuite/fixtures/build_hash_index/li/libhello/libhello-1.0.0.toml b/testsuite/fixtures/build_hash_index/li/libhello/libhello-1.0.0.toml new file mode 100644 index 000000000..c46f09fab --- /dev/null +++ b/testsuite/fixtures/build_hash_index/li/libhello/libhello-1.0.0.toml @@ -0,0 +1,23 @@ +description = "\"Hello, world!\" demonstration project support library" +name = "libhello" +version = "1.0.0" +maintainers = ["alejandro@mosteo.com"] +maintainers-logins = ["mylogin"] +tags = ["libhello-tag1"] + +[configuration.variables] +Var1={type="Boolean", default=true} + +[gpr-externals] +TEST_GPR_EXTERNAL = ["gpr_ext_A", "gpr_ext_B", "gpr_ext_C"] +TEST_FREEFORM_UNSET = "" # to test build hashing with an unset var + +[gpr-set-externals] +TEST_GPR_EXTERNAL = "gpr_ext_B" +TEST_UNDECLARED = "used_by_another_crate" + +[environment] +TEST_ENV.set = "myenv" + +[origin] +url = "file:../../../crates/libhello_1.0.0" diff --git a/testsuite/fixtures/build_hash_index/ma/make/make-external.toml b/testsuite/fixtures/build_hash_index/ma/make/make-external.toml new file mode 100644 index 000000000..eaf4b23eb --- /dev/null +++ b/testsuite/fixtures/build_hash_index/ma/make/make-external.toml @@ -0,0 +1,8 @@ +description = "Utility for directing compilation" +name = "make" +maintainers = ["alejandro@mosteo.com"] +maintainers-logins = ["mylogin"] + +[[external]] +kind = "system" +origin = [] # Empty on purpose to ensure unavailable in tests diff --git a/testsuite/tests/build/hashes/compiler-input/test.py b/testsuite/tests/build/hashes/compiler-input/test.py new file mode 100644 index 000000000..7633bc40d --- /dev/null +++ b/testsuite/tests/build/hashes/compiler-input/test.py @@ -0,0 +1,56 @@ +""" +Check compiler version in hashing input +""" + +import sys + +from drivers.alr import run_alr, init_local_crate, alr_with +from drivers.asserts import assert_match, match_solution +from drivers.builds import clear_builds_dir, hash_input + + +def check_hash(signature: str) -> None: + """ + Check that the given signature is present in the hash inputs + """ + assert_match(f".*{signature}.*", hash_input("crate_real")) + + +run_alr("config", "--set", "--global", "dependencies.shared", "true") + +# Select the default preferred compiler, in this index is gnat_native=8888 +run_alr("toolchain", "--select") + +# Init a crate without explicit compiler dependency +init_local_crate("xxx") +alr_with("crate_real") # A regular crate in the index +run_alr("update") # Ensure the hash inputs are written to disk + +# Check the expected compiler is in the hash inputs +check_hash("version:gnat_native=8888.0.0") + + +# Next, check with an explicit compiler in the dependencies. Note that we give +# the virtual dependency, but the actual native one is used for the hash. + +# Clear the build cache so we are able to locate the new hash +clear_builds_dir() +alr_with("gnat=7777") # Downgrade the compiler with an explicit dependency +run_alr("update") + +# Check the expected compiler is in the hash inputs +check_hash("version:gnat_native=7777.0.0") + + +# Finally, check that having two explicit dependencies on the compiler (one +# virtual and another real) does not cause a conflict in compiler detection. +# The same compiler as in the previous step should be used for the hash. + +clear_builds_dir() +alr_with("gnat_native") +run_alr("update") +check_hash("version:gnat_native=7777.0.0") + + +print('SUCCESS') +sys.exit(0) diff --git a/testsuite/tests/build/hashes/compiler-input/test.yaml b/testsuite/tests/build/hashes/compiler-input/test.yaml new file mode 100644 index 000000000..8185c03b5 --- /dev/null +++ b/testsuite/tests/build/hashes/compiler-input/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + toolchain_index: + in_fixtures: true diff --git a/testsuite/tests/build/hashes/compiler-missing/test.py b/testsuite/tests/build/hashes/compiler-missing/test.py new file mode 100644 index 000000000..caa3f7f56 --- /dev/null +++ b/testsuite/tests/build/hashes/compiler-missing/test.py @@ -0,0 +1,19 @@ +""" +Check that when no compiler is available we cannot compute the build hash +""" + + +from drivers.alr import run_alr, init_local_crate +from drivers.asserts import assert_match + +# The index in this test has no compilers configured; hence we cannot locate +# even the default external compiler. + +run_alr("config", "--set", "--global", "dependencies.shared", "true") + +# Init a crate without explicit compiler dependency +init_local_crate("xxx") +p = run_alr("with", "libhello", complain_on_error=False) # This should fail +assert_match(".*Unable to determine compiler version", p.out) + +print("SUCCESS") diff --git a/testsuite/tests/build/hashes/compiler-missing/test.yaml b/testsuite/tests/build/hashes/compiler-missing/test.yaml new file mode 100644 index 000000000..8929d590a --- /dev/null +++ b/testsuite/tests/build/hashes/compiler-missing/test.yaml @@ -0,0 +1,4 @@ +driver: python-script +indexes: + basic_index: + in_fixtures: true diff --git a/testsuite/tests/build/hashes/hashing-inputs/test.yaml b/testsuite/tests/build/hashes/hashing-inputs/test.yaml index 872fc1274..8e25447d9 100644 --- a/testsuite/tests/build/hashes/hashing-inputs/test.yaml +++ b/testsuite/tests/build/hashes/hashing-inputs/test.yaml @@ -1,3 +1,3 @@ driver: python-script indexes: - basic_index: {} + build_hash_index: {} diff --git a/testsuite/tests/config/shared-deps/test.yaml b/testsuite/tests/config/shared-deps/test.yaml index 872fc1274..8e25447d9 100644 --- a/testsuite/tests/config/shared-deps/test.yaml +++ b/testsuite/tests/config/shared-deps/test.yaml @@ -1,3 +1,3 @@ driver: python-script indexes: - basic_index: {} + build_hash_index: {} diff --git a/testsuite/tests/dockerized/misc/default-cache/test.py b/testsuite/tests/dockerized/misc/default-cache/test.py index 1a2367a4c..1c5e0a74d 100644 --- a/testsuite/tests/dockerized/misc/default-cache/test.py +++ b/testsuite/tests/dockerized/misc/default-cache/test.py @@ -36,7 +36,7 @@ # Shared builds # We hardcode this hash so we detect unwilling changes to our hashing scheme -hash = "e66592c9a181de97dc3a342cf76378f6ffa6667d7c1864c74d98bec8ffaf4f3d" +hash = "7b5ad18029d4984b4076f4910c699700e7a325ab0c3dc786ccf89c3c6035212f" assert \ os.path.isdir(f"{base}/builds/crate_real_1.0.0_filesystem_{hash}"), \ f"Shared build not found at the expected location: f{contents(base)}"