Skip to content

Commit 017d1f8

Browse files
committed
Add --no-spack flag and clean up spack error messages
1 parent 52aed69 commit 017d1f8

File tree

7 files changed

+190
-37
lines changed

7 files changed

+190
-37
lines changed

docs/design/mache_deploy.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,16 @@ maintainers to do full shared-environment deployments when needed.
195195
“software” spack env)
196196
- `deploy.py` exposes CLI flags such as:
197197
- `--deploy-spack` (force-enable spack deployment)
198+
- `--no-spack` (disable all spack use for a single run)
198199
- `--spack-path <path>` (temporary override for `spack.spack_path`)
199200

200201
**Precedence**
201202

202-
1. If the user passes `--deploy-spack`, spack deployment is enabled regardless
203-
of the config default.
204-
2. Otherwise, fall back to the `config.yaml.j2` default.
203+
1. If the user passes `--no-spack`, all spack use is disabled for that run.
204+
2. Otherwise, if the user passes `--deploy-spack`, spack deployment is enabled
205+
regardless of the config default.
206+
3. Otherwise, fall back to the `config.yaml.j2` default for deployment and
207+
reuse any supported pre-existing spack environments in load scripts.
205208

206209
For spack checkout path resolution:
207210

docs/users_guide/deploy.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ Important settings:
174174
- `pixi.prefix`: required in practice.
175175
- `pixi.channels`: required and must be non-empty.
176176
- `spack.spack_path`: required when Spack support is enabled and no hook or
177-
CLI override provides it.
177+
CLI override provides it, unless the user disables Spack for that run with
178+
`--no-spack`.
178179
- `jigsaw.enabled`: optional.
179180
- `hooks`: optional and disabled unless explicitly configured.
180181

@@ -492,13 +493,16 @@ Fix:
492493

493494
Cause:
494495

495-
- Spack support was enabled but no path was provided in config, hooks, or the
496-
CLI.
496+
- Spack support was enabled for this run, but no path was provided in config,
497+
hooks, or the CLI.
497498

498499
Fix:
499500

500501
- Set `spack.spack_path`, write it in a hook through
501502
`ctx.runtime["spack"]["spack_path"]`, or pass `--spack-path`.
503+
- If this should be a Pixi-only run, pass `--no-spack`.
504+
- A `pre_spack` hook may also disable Spack for one run by returning
505+
`{"spack": {"supported": false, "software": {"supported": false}}}`.
502506

503507
### `project.version` is still `dynamic`
504508

@@ -521,4 +525,4 @@ Cause:
521525

522526
Fix:
523527

524-
- Use `source load_<software>*.sh` from `bash`.
528+
- Use `source load_<software>*.sh` from `bash`.

mache/deploy/run.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929
from .spack import (
3030
deploy_spack_envs,
3131
deploy_spack_software_env,
32+
get_effective_spack_config,
3233
load_existing_spack_envs,
3334
load_existing_spack_software_env,
35+
spack_disabled_for_run,
36+
spack_should_deploy_for_run,
3437
)
3538

3639

@@ -263,15 +266,20 @@ def run_deploy(args: argparse.Namespace) -> None:
263266
# Future wiring: spack stages (no-ops unless implemented/configured)
264267
hook_registry.run_hook('pre_spack', ctx)
265268

266-
spack_cfg = config.get('spack', {})
267-
if not isinstance(spack_cfg, dict):
268-
spack_cfg = {}
269+
if getattr(args, 'deploy_spack', False) and getattr(
270+
args, 'no_spack', False
271+
):
272+
raise ValueError(
273+
'Cannot combine --deploy-spack and --no-spack in the same run.'
274+
)
269275

270-
deploy_spack = bool(spack_cfg.get('deploy')) or bool(
271-
getattr(args, 'deploy_spack', False)
272-
)
276+
spack_cfg = get_effective_spack_config(ctx=ctx)
277+
deploy_spack = spack_should_deploy_for_run(ctx=ctx, spack_cfg=spack_cfg)
273278

274-
if deploy_spack:
279+
if spack_disabled_for_run(ctx=ctx):
280+
spack_results = []
281+
spack_software_env = None
282+
elif deploy_spack:
275283
spack_results = deploy_spack_envs(
276284
ctx=ctx,
277285
toolchain_pairs=toolchain_pairs,

mache/deploy/spack.py

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,57 @@ class SpackSoftwareEnvResult:
4646
path_setup: str
4747

4848

49+
def get_effective_spack_config(*, ctx: DeployContext) -> dict:
50+
"""Return deploy config merged with runtime Spack overrides."""
51+
52+
spack_cfg = ctx.config.get('spack', {})
53+
if not isinstance(spack_cfg, dict):
54+
spack_cfg = {}
55+
56+
merged = dict(spack_cfg)
57+
58+
software_cfg = merged.get('software', {})
59+
if software_cfg is None:
60+
software_cfg = {}
61+
if isinstance(software_cfg, dict):
62+
merged['software'] = dict(software_cfg)
63+
64+
runtime_spack = ctx.runtime.get('spack', {})
65+
if not isinstance(runtime_spack, dict):
66+
return merged
67+
68+
for key, value in runtime_spack.items():
69+
if key == 'software' and isinstance(value, dict):
70+
base = merged.get('software', {})
71+
if not isinstance(base, dict):
72+
base = {}
73+
merged['software'] = {**base, **value}
74+
else:
75+
merged[key] = value
76+
77+
return merged
78+
79+
80+
def spack_disabled_for_run(*, ctx: DeployContext) -> bool:
81+
"""Return True when the CLI explicitly disables all Spack use."""
82+
83+
return bool(getattr(ctx.args, 'no_spack', False))
84+
85+
86+
def spack_should_deploy_for_run(
87+
*, ctx: DeployContext, spack_cfg: dict
88+
) -> bool:
89+
"""Return True when Spack environments should be deployed for this run."""
90+
91+
if spack_disabled_for_run(ctx=ctx):
92+
return False
93+
94+
if bool(getattr(ctx.args, 'deploy_spack', False)):
95+
return True
96+
97+
return bool(spack_cfg.get('deploy'))
98+
99+
49100
def deploy_spack_software_env(
50101
*,
51102
ctx: DeployContext,
@@ -62,7 +113,7 @@ def deploy_spack_software_env(
62113
No CLI flags control this environment.
63114
"""
64115

65-
spack_cfg = ctx.config.get('spack', {})
116+
spack_cfg = get_effective_spack_config(ctx=ctx)
66117
if not isinstance(spack_cfg, dict):
67118
return None
68119

@@ -72,9 +123,7 @@ def deploy_spack_software_env(
72123
if not isinstance(software_cfg, dict):
73124
raise ValueError('spack.software must be a mapping if provided')
74125

75-
deploy_spack = bool(spack_cfg.get('deploy')) or bool(
76-
getattr(ctx.args, 'deploy_spack', False)
77-
)
126+
deploy_spack = spack_should_deploy_for_run(ctx=ctx, spack_cfg=spack_cfg)
78127

79128
software_supported = bool(software_cfg.get('supported'))
80129

@@ -210,7 +259,7 @@ def deploy_spack_envs(
210259
A list of SpackDeployResult, one per (compiler, mpi)
211260
"""
212261

213-
spack_cfg = ctx.config.get('spack', {})
262+
spack_cfg = get_effective_spack_config(ctx=ctx)
214263
if not isinstance(spack_cfg, dict):
215264
return []
216265

@@ -220,9 +269,7 @@ def deploy_spack_envs(
220269
if not isinstance(software_cfg, dict):
221270
raise ValueError('spack.software must be a mapping if provided')
222271

223-
deploy_spack = bool(spack_cfg.get('deploy')) or bool(
224-
getattr(ctx.args, 'deploy_spack', False)
225-
)
272+
deploy_spack = spack_should_deploy_for_run(ctx=ctx, spack_cfg=spack_cfg)
226273

227274
library_supported = bool(spack_cfg.get('supported'))
228275

@@ -364,7 +411,7 @@ def load_existing_spack_envs(
364411
) -> list[SpackDeployResult]:
365412
"""Load pre-existing Spack library environments for load scripts."""
366413

367-
spack_cfg = ctx.config.get('spack', {})
414+
spack_cfg = get_effective_spack_config(ctx=ctx)
368415
if not isinstance(spack_cfg, dict):
369416
return []
370417

@@ -374,15 +421,17 @@ def load_existing_spack_envs(
374421

375422
if not toolchain_pairs:
376423
raise ValueError(
377-
'Spack library environments are supported but no toolchain pairs '
378-
'were resolved. Provide toolchain.compiler/toolchain.mpi or '
379-
'--compiler/--mpi.'
424+
'Spack library environments are enabled for this run but no '
425+
'toolchain pairs were resolved. Provide toolchain.compiler/'
426+
'toolchain.mpi or --compiler/--mpi, or disable Spack for this '
427+
'run with --no-spack or a pre_spack hook.'
380428
)
381429

382430
spack_path = _resolve_spack_path(
383431
ctx=ctx,
384432
spack_cfg=spack_cfg,
385-
reason='support is enabled (load scripts require existing envs)',
433+
reason='support is enabled for this run (load scripts will reuse '
434+
'existing envs)',
386435
)
387436

388437
e3sm_hdf5_netcdf = _get_machine_bool(
@@ -446,7 +495,7 @@ def load_existing_spack_software_env(
446495
) -> SpackSoftwareEnvResult | None:
447496
"""Load a pre-existing Spack software environment for load scripts."""
448497

449-
spack_cfg = ctx.config.get('spack', {})
498+
spack_cfg = get_effective_spack_config(ctx=ctx)
450499
if not isinstance(spack_cfg, dict):
451500
return None
452501

@@ -462,13 +511,17 @@ def load_existing_spack_software_env(
462511

463512
if ctx.machine is None:
464513
raise ValueError(
465-
'Spack software environment is supported but machine is not known.'
514+
'Spack software environment is enabled for this run but machine '
515+
'is not known. Pass --no-spack or disable '
516+
'spack.software.supported '
517+
'in a pre_spack hook for Pixi-only runs.'
466518
)
467519

468520
spack_path = _resolve_spack_path(
469521
ctx=ctx,
470522
spack_cfg=spack_cfg,
471-
reason='support is enabled (load scripts require existing envs)',
523+
reason='support is enabled for this run (load scripts will reuse '
524+
'existing envs)',
472525
)
473526

474527
compiler, mpi = _resolve_software_toolchain(
@@ -568,7 +621,8 @@ def _resolve_spack_path(
568621
'--spack-path, '
569622
"ctx.runtime['spack']['spack_path']"
570623
' in a hook (preferred) or set spack.spack_path in '
571-
'deploy/config.yaml.j2'
624+
'deploy/config.yaml.j2. To bypass Spack entirely for this run, '
625+
'pass --no-spack.'
572626
)
573627
return os.path.abspath(os.path.expanduser(os.path.expandvars(spack_path)))
574628

mache/deploy/templates/cli_spec.json.j2

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@
4444
"help": "Deploy all supported Spack environments (overrides spack.deploy in deploy/config.yaml.j2).",
4545
"route": ["deploy", "run"]
4646
},
47+
{
48+
"flags": ["--no-spack"],
49+
"dest": "no_spack",
50+
"action": "store_true",
51+
"help": "Disable all Spack use for this run, including reuse of existing Spack environments.",
52+
"route": ["deploy", "run"]
53+
},
4754
{
4855
"flags": ["--spack-path"],
4956
"dest": "spack_path",

mache/deploy/templates/config.yaml.j2.j2

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ spack:
112112
#
113113
# This can be forced on at runtime with the `mache deploy run` CLI flag:
114114
# --deploy-spack
115+
#
116+
# Passing --no-spack disables all Spack use for a single run, including
117+
# reuse of pre-existing environments for load scripts.
115118
deploy: false
116119

117120
# Whether this target repository supports a Spack *library* environment.
@@ -142,12 +145,17 @@ spack:
142145
# In practice, most target repositories should set this dynamically in the
143146
# `pre_spack()` hook (e.g., based on machine config) by writing:
144147
# ctx.runtime['spack']['spack_path'] = <path>
148+
# Hooks may also disable Spack for a single run by returning:
149+
# ctx.runtime['spack']['supported'] = False
150+
# ctx.runtime['spack']['software']['supported'] = False
145151
# This config value is a fallback.
146152
#
147153
# Required (either via hook/runtime or here) when spack.deploy (or
148154
# --deploy-spack) is used and at least one supported spack environment is
149-
# enabled.
155+
# enabled, or when an existing Spack environment will be reused for load
156+
# scripts.
150157
# Can also be overridden temporarily via: --spack-path <path>
158+
# To bypass Spack entirely for one run, pass: --no-spack
151159
spack_path: null
152160

153161
# Prefix for spack environment names.

0 commit comments

Comments
 (0)