Skip to content

Commit b8833b0

Browse files
authored
Merge pull request #374 from xylar/updates-for-unified
Refactor mache.deploy for E3SM-Unified deployment support
2 parents 41566d0 + f01e607 commit b8833b0

File tree

12 files changed

+715
-93
lines changed

12 files changed

+715
-93
lines changed

docs/users_guide/deploy.md

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,17 @@ Important settings:
199199
- `machines.path`: optional path to target-owned machine config files.
200200
- `pixi.prefix`: required in practice.
201201
- `pixi.channels`: required and must be non-empty.
202+
- `pixi.login_mpi`: optional alternate MPI setting for login nodes. When set,
203+
`mache deploy run` may create a second pixi environment for login-node use
204+
and the generated load script will auto-select between the login and compute
205+
environments.
206+
- `pixi.login_prefix`: optional install path for that login-node pixi
207+
environment. If omitted, mache reuses `pixi.prefix` when the login and
208+
compute MPI settings match, or defaults to `<pixi.prefix>_login` when they
209+
differ.
202210
- `permissions.group`: optional shared-filesystem group to apply after a
203211
successful deploy. If unset, `mache deploy run` falls back to merged machine
204-
config `[deploy] group`, then legacy `[e3sm_unified] group`.
212+
config `[deploy] group`.
205213
- `permissions.world_readable`: optional boolean controlling whether deployed
206214
files are readable outside the shared group. Hooks may override both values
207215
through `ctx.runtime["permissions"]`.
@@ -557,12 +565,15 @@ created.
557565
5. Resolves toolchain pairs for Spack.
558566
6. Renders `deploy/pixi.toml.j2` into the install prefix and runs
559567
`pixi install`.
560-
7. Optionally installs a development copy of `mache` when a fork/branch was
568+
7. Optionally creates a second login-node pixi environment when
569+
`pixi.login_mpi` is configured or a hook sets `ctx.runtime["pixi"]`
570+
accordingly.
571+
8. Optionally installs a development copy of `mache` when a fork/branch was
561572
requested.
562-
8. Optionally builds and installs JIGSAW.
563-
9. Optionally deploys or loads Spack environments.
564-
10. Optionally installs the target software in editable mode.
565-
11. Writes one or more `load_<software>*.sh` scripts.
573+
9. Optionally builds and installs JIGSAW.
574+
10. Optionally deploys or loads Spack environments.
575+
11. Optionally installs the target software in editable mode.
576+
12. Writes one or more `load_<software>*.sh` scripts.
566577

567578
When a toolchain pair is selected, script names include machine, compiler,
568579
and MPI tags, for example:
@@ -572,6 +583,11 @@ and MPI tags, for example:
572583
Those load scripts are the main artifact a downstream user consumes after the
573584
deployment completes.
574585

586+
When a login pixi environment is configured, the generated load script chooses
587+
the login environment on login nodes and the compute environment inside common
588+
batch jobs such as Slurm, PBS, or Cobalt. Spack activation remains compute-only
589+
in that split-environment case.
590+
575591
## The command-line contract
576592

577593
There are really two CLIs involved:
@@ -621,8 +637,10 @@ Examples from the current contract:
621637
- `--bootstrap-only` is deploy-only.
622638
- `--machine` is deploy-plus-run.
623639
- `--mache-version` is bootstrap-plus-run.
624-
- `--pixi`, `--prefix`, `--recreate`, `--quiet`, `--mache-fork`, and
640+
- `--pixi`, `--pixi-path`, `--recreate`, `--quiet`, `--mache-fork`, and
625641
`--mache-branch` are routed across all relevant phases.
642+
- `--prefix` is still accepted as a deprecated compatibility alias for
643+
`--pixi-path`.
626644

627645
### How `deploy/custom_cli_spec.json` works
628646

mache/deploy/bootstrap.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
)
3131
BOOTSTRAP_SETUPTOOLS_SPEC = '>=60'
3232
BOOTSTRAP_WHEEL_SPEC = '*'
33+
CONDA_FORGE_LABEL_ROOT = 'https://conda.anaconda.org/conda-forge/label'
34+
MACHE_DEV_LABEL = f'{CONDA_FORGE_LABEL_ROOT}/mache_dev'
3335

3436

3537
def check_call(
@@ -409,6 +411,8 @@ def _run(log_filename):
409411
if args.recreate and (bootstrap_dir / '.pixi').exists():
410412
shutil.rmtree(bootstrap_dir / '.pixi')
411413

414+
_write_bootstrap_pixi_config(bootstrap_dir=bootstrap_dir)
415+
412416
# Create/update the bootstrap env
413417
if args.mache_fork is not None and args.mache_branch is not None:
414418
_clone_mache_repo(
@@ -488,11 +492,13 @@ def _parse_args():
488492
'on PATH.',
489493
)
490494
parser.add_argument(
495+
'--pixi-path',
491496
'--prefix',
492-
dest='prefix',
493-
help='Install the environment into this prefix (directory). '
497+
dest='pixi_path',
498+
help='Install the pixi environment at this path (directory). '
494499
'This is a deploy-time option; bootstrap accepts it for CLI '
495-
'contract compatibility but does not use it.',
500+
'contract compatibility but does not use it. `--prefix` is '
501+
'deprecated.',
496502
)
497503
parser.add_argument(
498504
'--recreate',
@@ -766,10 +772,11 @@ def _write_bootstrap_pixi_toml_with_mache(
766772
python_version,
767773
):
768774
name = f'{software}-mache-bootstrap'
775+
channels = _get_bootstrap_channels_for_mache_version(mache_version)
769776
lines = [
770777
'[workspace]',
771778
f'name = "{name}"',
772-
'channels = ["conda-forge"]',
779+
f'channels = [{", ".join(json.dumps(c) for c in channels)}]',
773780
f'platforms = ["{_get_pixi_platform()}"]',
774781
'channel-priority = "strict"',
775782
'',
@@ -782,6 +789,30 @@ def _write_bootstrap_pixi_toml_with_mache(
782789
pixi_toml_path.write_text('\n'.join(lines) + '\n', encoding='utf-8')
783790

784791

792+
def _write_bootstrap_pixi_config(*, bootstrap_dir: Path) -> None:
793+
config_dir = bootstrap_dir / '.pixi'
794+
config_dir.mkdir(parents=True, exist_ok=True)
795+
config_toml = config_dir / 'config.toml'
796+
lines = [
797+
'# Keep conda-forge label channels on Anaconda because prefix.dev',
798+
'# does not currently mirror public conda-forge labels such as ',
799+
'# mache_dev.',
800+
'[mirrors]',
801+
f'"{CONDA_FORGE_LABEL_ROOT}" = [',
802+
f' "{CONDA_FORGE_LABEL_ROOT}",',
803+
']',
804+
]
805+
config_toml.write_text('\n'.join(lines) + '\n', encoding='utf-8')
806+
807+
808+
def _get_bootstrap_channels_for_mache_version(mache_version: str) -> List[str]:
809+
normalized = str(mache_version).strip().lower()
810+
if 'rc' in normalized:
811+
return [MACHE_DEV_LABEL, 'conda-forge']
812+
813+
return ['conda-forge']
814+
815+
785816
def _format_pixi_version_specifier(version: str) -> str:
786817
"""Return a pixi version specifier from a mache version pin.
787818

mache/deploy/machine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def get_known_mache_machines(*, package: str = 'mache.machines') -> set[str]:
3232
if not name.endswith('.cfg'):
3333
continue
3434
machine = name[:-4]
35-
if machine == 'default':
35+
if machine == 'default' or machine.startswith('default-'):
3636
continue
3737
known.add(machine)
3838
return known
@@ -70,7 +70,7 @@ def get_known_target_machines(*, machines_path: str | None) -> set[str]:
7070
if not entry.endswith('.cfg'):
7171
continue
7272
machine = entry[:-4]
73-
if machine == 'default':
73+
if machine == 'default' or machine.startswith('default-'):
7474
continue
7575
known.add(machine)
7676
return known

0 commit comments

Comments
 (0)