diff --git a/aliBuild b/aliBuild index dc1c56f2..16ab091d 100755 --- a/aliBuild +++ b/aliBuild @@ -57,7 +57,7 @@ def doMain(args, parser): error(e.message) exit(1) - if args.action == "version": + if args.action == "version" or args.action == None: print("aliBuild version: {version} ({arch})".format( version=__version__ or "unknown", arch=args.architecture or "unknown")) sys.exit(0) diff --git a/alibuild_helpers/build.py b/alibuild_helpers/build.py index c6817a78..72ec011c 100644 --- a/alibuild_helpers/build.py +++ b/alibuild_helpers/build.py @@ -4,8 +4,8 @@ from alibuild_helpers.analytics import report_event from alibuild_helpers.log import debug, info, banner, warning from alibuild_helpers.log import dieOnError -from alibuild_helpers.cmd import execute, DockerRunner, BASH, install_wrapper_script -from alibuild_helpers.utilities import prunePaths, symlink, call_ignoring_oserrors, topological_sort +from alibuild_helpers.cmd import execute, DockerRunner, BASH, install_wrapper_script, getstatusoutput +from alibuild_helpers.utilities import prunePaths, symlink, call_ignoring_oserrors, topological_sort, detectArch from alibuild_helpers.utilities import resolve_store_path from alibuild_helpers.utilities import parseDefaults, readDefaults from alibuild_helpers.utilities import getPackageList, asList @@ -1112,6 +1112,29 @@ def doBuild(args, parser): """) buildErrMsg += "".join("\n ( cd %s && git pull --rebase )" % dp for dp in updatablePkgs) + # Gather build info for the error message + try: + safe_args = { + "pkgname", "defaults", "architecture", "forceUnknownArch", + "develPrefix", "jobs", "noSystem", "noDevel", "forceTracked", "plugin", + "disable", "annotate", "onlyDeps", "docker" + } + args_str = " ".join(f"--{k}={v}" for k, v in vars(args).items() if v and k in safe_args) + detected_arch = detectArch() + buildErrMsg += dedent(f""" + Build info: + OS: {detected_arch} + Using aliBuild from alibuild@{__version__ or "unknown"} recipes in alidist@{os.environ["ALIBUILD_ALIDIST_HASH"][:10]} + Build arguments: {args_str} + """) + + if detected_arch.startswith("osx"): + buildErrMsg += f'XCode version: {getstatusoutput("xcodebuild -version")[1]}' + + except Exception as exc: + warning("Failed to gather build info", exc_info=exc) + + dieOnError(err, buildErrMsg.strip()) # We need to create 2 sets of links, once with the full requires, diff --git a/alibuild_helpers/utilities.py b/alibuild_helpers/utilities.py index ef90d2df..88ca6077 100644 --- a/alibuild_helpers/utilities.py +++ b/alibuild_helpers/utilities.py @@ -493,27 +493,28 @@ def getPackageList(packages, specs, configDir, preferSystem, noSystem, if re.match(replacement_matcher, key): replacement = spec["prefer_system_replacement_specs"][replacement_matcher] break - dieOnError(replacement is None, "Could not find named replacement spec for " - "%s: %s" % (spec["package"], key)) - assert(replacement) - # We must keep the package name the same, since it is used to - # specify dependencies. - replacement["package"] = spec["package"] - # The version is required for all specs. What we put there will - # influence the package's hash, so allow the user to override it. - replacement.setdefault("version", requested_version) - spec = replacement - # Allows generalising the version based on the actual key provided - spec["version"] = spec["version"].replace("%(key)s", key) - recipe = replacement.get("recipe", "") - # If there's an explicitly-specified recipe, we're still building - # the package. If not, aliBuild will still "build" it, but it's - # basically instantaneous, so report to the user that we're taking - # it from the system. - if recipe: - ownPackages.add(spec["package"]) + if replacement: + # We must keep the package name the same, since it is used to + # specify dependencies. + replacement["package"] = spec["package"] + # The version is required for all specs. What we put there will + # influence the package's hash, so allow the user to override it. + replacement.setdefault("version", requested_version) + spec = replacement + # Allows generalising the version based on the actual key provided + spec["version"] = spec["version"].replace("%(key)s", key) + recipe = replacement.get("recipe", "") + # If there's an explicitly-specified recipe, we're still building + # the package. If not, aliBuild will still "build" it, but it's + # basically instantaneous, so report to the user that we're taking + # it from the system. + if recipe: + ownPackages.add(spec["package"]) + else: + systemPackages.add(spec["package"]) else: - systemPackages.add(spec["package"]) + warning(f"Could not find named replacement spec for {spec['package']}: {key}, " + "falling back to building the package ourselves.") dieOnError(("system_requirement" in spec) and recipe.strip("\n\t "), "System requirements %s cannot have a recipe" % spec["package"]) diff --git a/tests/test_packagelist.py b/tests/test_packagelist.py index e3601c0e..4813446c 100644 --- a/tests/test_packagelist.py +++ b/tests/test_packagelist.py @@ -154,17 +154,20 @@ def test_replacement_recipe_given(self) -> None: self.assertNotIn("with-replacement-recipe", systemPkgs) self.assertIn("with-replacement-recipe", ownPkgs) - @mock.patch("alibuild_helpers.utilities.dieOnError") - def test_missing_replacement_spec(self, mock_dieOnError) -> None: - """Check an error is thrown when the replacement spec is not found.""" - assert_msg = "Could not find named replacement spec for missing-spec: missing_tag" - # Change the behaviour from sys.exit to a regular exception. Without it - # we don't stop execution properly and other asserts might trigger - mock_dieOnError.side_effect = lambda cond, _: (_ for _ in ()).throw(Exception("dieOnError called")) if cond else None - with self.assertRaises(Exception, msg=assert_msg) as context: - specs, systemPkgs, ownPkgs, failedReqs, validDefaults = \ - getPackageListWithDefaults(["missing-spec"]) - self.assertEqual(str(context.exception), "dieOnError called", msg=assert_msg) + @mock.patch("alibuild_helpers.utilities.warning") + def test_missing_replacement_spec(self, mock_warning): + """Check a warning is displayed when the replacement spec is not found.""" + warning_msg = "falling back to building the package ourselves" + warning_exists = False + def side_effect(msg, *args, **kwargs): + nonlocal warning_exists + if warning_msg in str(msg): + warning_exists = True + mock_warning.side_effect = side_effect + specs, systemPkgs, ownPkgs, failedReqs, validDefaults = \ + getPackageListWithDefaults(["missing-spec"]) + self.assertTrue(warning_exists) + @mock.patch("alibuild_helpers.utilities.getRecipeReader", new=MockReader)