diff --git a/lib/spack/spack/cmd/common/arguments.py b/lib/spack/spack/cmd/common/arguments.py index 41a7024d285..a761d113696 100644 --- a/lib/spack/spack/cmd/common/arguments.py +++ b/lib/spack/spack/cmd/common/arguments.py @@ -504,11 +504,22 @@ class ConfigSetAction(argparse.Action): """ def __init__( - self, option_strings, dest, const, default=None, required=False, help=None, metavar=None + self, + option_strings, + dest, + const, + default=None, + required=False, + help=None, + metavar=None, + require_environment=False, ): # save the config option we're supposed to set self.config_path = dest + # save whether the option requires an active env + self.require_environment = require_environment + # destination is translated to a legal python identifier by # substituting '_' for ':'. dest = dest.replace(":", "_") @@ -524,6 +535,11 @@ def __init__( ) def __call__(self, parser, namespace, values, option_string): + if self.require_environment and not ev.active_environment(): + raise argparse.ArgumentTypeError( + f"argument '{self.option_strings[-1]}' requires an environment" + ) + # Retrieve the name of the config option and set it to # the const from the constructor or a value from the CLI. # Note that this is only called if the argument is actually @@ -545,6 +561,16 @@ def add_concretizer_args(subparser): Just substitute ``_`` for ``:``. """ subgroup = subparser.add_argument_group("concretizer arguments") + subgroup.add_argument( + "-f", + "--force", + action=ConfigSetAction, + require_environment=True, + dest="concretizer:force", + const=True, + default=False, + help="allow changes to concretized specs in spack.lock (in an env)", + ) subgroup.add_argument( "-U", "--fresh", diff --git a/lib/spack/spack/cmd/concretize.py b/lib/spack/spack/cmd/concretize.py index 7376b25009b..c6025434268 100644 --- a/lib/spack/spack/cmd/concretize.py +++ b/lib/spack/spack/cmd/concretize.py @@ -15,9 +15,6 @@ def setup_parser(subparser): - subparser.add_argument( - "-f", "--force", action="store_true", help="re-concretize even if already concretized" - ) subparser.add_argument( "--test", default=None, @@ -43,7 +40,7 @@ def concretize(parser, args): tests = False with env.write_transaction(): - concretized_specs = env.concretize(force=args.force, tests=tests) + concretized_specs = env.concretize(tests=tests) if not args.quiet: if concretized_specs: tty.msg(f"Concretized {plural(len(concretized_specs), 'spec')}:") diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 92bdc6871fe..a8291d3f679 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -1427,7 +1427,7 @@ def is_develop(self, spec): """Returns true when the spec is built from local sources""" return spec.name in self.dev_specs - def concretize(self, force=False, tests=False): + def concretize(self, tests=False): """Concretize user_specs in this environment. Only concretizes specs that haven't been concretized yet unless @@ -1437,8 +1437,6 @@ def concretize(self, force=False, tests=False): write out a lockfile containing concretized specs. Arguments: - force (bool): re-concretize ALL specs, even those that were - already concretized tests (bool or list or set): False to run no tests, True to test all packages, or a list of package names to run tests for some @@ -1446,7 +1444,7 @@ def concretize(self, force=False, tests=False): List of specs that have been concretized. Each entry is a tuple of the user spec and the corresponding concretized spec. """ - if force: + if spack.config.get("concretizer:force", False): # Clear previously concretized specs self.concretized_user_specs = [] self.concretized_order = [] diff --git a/lib/spack/spack/schema/concretizer.py b/lib/spack/spack/schema/concretizer.py index 7a866dfbbd7..3428461d73c 100644 --- a/lib/spack/spack/schema/concretizer.py +++ b/lib/spack/spack/schema/concretizer.py @@ -15,6 +15,7 @@ "type": "object", "additionalProperties": False, "properties": { + "force": {"type": "boolean", "default": False}, "reuse": { "oneOf": [ {"type": "boolean"},