Skip to content

Commit 38b0a7d

Browse files
committed
make mirrors a cli argument, not part of system config
1 parent 4a1c01c commit 38b0a7d

8 files changed

Lines changed: 133 additions & 57 deletions

File tree

docs/build-caches.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
# Mirrors and Build Caches
22

33
Spack can use *mirrors* and *caches* to speed up image builds and to build on systems with limited or no internet access.
4-
They are configured in a single `mirrors.yaml` file in the [system configuration](cluster-config.md).
4+
They are configured in a single `mirrors.yaml` file that you supply on the command line:
5+
6+
```bash
7+
stack-config -b $build -r $recipe -s $system --mirror mirrors.yaml
8+
```
9+
10+
The file is not part of the [system configuration](cluster-config.md): mirror locations are usually specific to the person running the build, so each invocation provides its own.
11+
Paths inside the file (such as relative gpg key paths) are resolved relative to the directory containing the `mirrors.yaml`, so a self-contained mirror directory (the `mirrors.yaml` plus its keys) can be moved around freely.
512

613
A `mirrors.yaml` can describe four kinds of entry, each optional and each documented below:
714

docs/cluster-config.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ packages:
9393
version: ["git.59b6de6a91d9637809677c50cc48b607a91a9acb=main"]
9494
```
9595

96-
### Configuring Spack mirrors: `mirrors.yaml`
96+
### Configuring Spack mirrors
9797

98-
An optional `mirrors.yaml` connects Spack to local mirrors and caches, to speed up builds and to build on air-gapped systems.
99-
It can configure a build cache, a bootstrap mirror, read-only source mirrors, and a writable source cache.
98+
Mirrors and caches are **not** part of the system configuration.
99+
They are supplied per-invocation with `stack-config --mirror <file>`, because the locations involved (build caches, source caches) are often specific to the user running the build and may not be accessible to everyone using a system.
100100

101101
See [Mirrors and Build Caches](build-caches.md) for the full reference and examples.
102102

docs/configuring.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ The following flags are required:
1616

1717
The following flags are optional:
1818

19-
* `-c/--cache`: configure the [build cache](build-caches.md).
19+
* `--mirror`: path to a [mirrors.yaml](build-caches.md) file configuring build caches and mirrors.
20+
* `-c/--cache`: legacy build cache configuration file (deprecated; use `--mirror`).
2021
* `-m/--mount`: override the [mount point](installing.md) where the stack will be installed.
2122
* `--version`: print the stackinator version.
2223
* `-h/--help`: print help message.

memory.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

stackinator/main.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def log_header(args):
7474
root_logger.info(f" system : {args.system}")
7575
mount = args.mount or "default"
7676
root_logger.info(f" mount : {mount}")
77+
root_logger.info(f" mirror : {args.mirror}")
7778
root_logger.info(f" build cache: {args.cache}")
7879
root_logger.info(f" develop : {args.develop}")
7980

@@ -99,12 +100,18 @@ def make_argparser():
99100
parser.add_argument(
100101
"-m", "--mount", required=False, type=str, help="The mount point where the environment will be located."
101102
)
103+
parser.add_argument(
104+
"--mirror",
105+
required=False,
106+
type=str,
107+
help="Path to a mirrors.yaml file describing build caches and mirrors.",
108+
)
102109
parser.add_argument(
103110
"-c",
104111
"--cache",
105112
required=False,
106113
type=str,
107-
help="Buildcache location or name (from system config's mirrors.yaml).",
114+
help="Legacy build cache configuration file (deprecated; use --mirror).",
108115
)
109116
parser.add_argument("--develop", action="store_true", required=False)
110117

stackinator/mirror.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,32 +65,48 @@ def __init__(
6565
self,
6666
system_config_root: pathlib.Path,
6767
mount_path: pathlib.Path,
68+
mirror_file: Optional[pathlib.Path] = None,
6869
cmdline_cache: Optional[pathlib.Path] = None,
6970
):
7071
"""Load and fully resolve the mirror configuration.
7172
72-
Inputs are the system config's mirrors.yaml, the recipe mount path (used to
73-
make a build cache mount-specific), and an optional legacy cache.yaml passed
74-
on the command line (--cache).
73+
Mirrors are supplied with the --mirror command line option (mirror_file).
74+
mount_path is the recipe mount point (used to make a build cache mount-specific).
75+
cmdline_cache is an optional legacy cache.yaml passed on the command line (--cache).
76+
77+
Relative paths in the mirror file (e.g. gpg keys) are resolved relative to the
78+
directory containing the mirror file.
7579
"""
7680

7781
self._logger = root_logger
78-
self._system_config_root = system_config_root
7982
self._mount_path = mount_path
83+
self._mirror_dir = mirror_file.parent if mirror_file is not None else None
8084

8185
self.buildcache: Optional[Dict] = None
8286
self.bootstrap: Optional[Dict] = None
8387
self.source_mirrors: Dict[str, Dict] = {}
8488
self.source_cache: Optional[Dict] = None
8589

86-
# Load and schema-validate the system mirrors.yaml (absent file is fine).
87-
mirrors_path = system_config_root / "mirrors.yaml"
88-
if mirrors_path.exists():
90+
# The mirror configuration is supplied with --mirror, not the system
91+
# configuration. Reject a mirrors.yaml in the system config so it is not
92+
# silently ignored.
93+
if (system_config_root / "mirrors.yaml").exists():
94+
raise MirrorError(
95+
"A 'mirrors.yaml' in the system configuration is not supported.\n"
96+
"Provide the mirror configuration with the '--mirror' command line option."
97+
)
98+
99+
# Load and schema-validate the mirror file given on the command line. If none
100+
# was given there are no mirrors; an empty config still validates (and picks up
101+
# schema defaults such as an empty sourcemirror map).
102+
if mirror_file is not None:
103+
if not mirror_file.is_file():
104+
raise MirrorError(f"The mirror configuration file '{mirror_file}' does not exist.")
89105
try:
90-
with mirrors_path.open() as fid:
106+
with mirror_file.open() as fid:
91107
raw_mirrors = yaml.load(fid, Loader=yaml.SafeLoader)
92108
except (OSError, PermissionError) as err:
93-
raise MirrorError(f"Could not open/read mirrors.yaml file.\n{err}")
109+
raise MirrorError(f"Could not open/read mirror file '{mirror_file}'.\n{err}")
94110
else:
95111
raw_mirrors = {}
96112

@@ -241,15 +257,15 @@ def _validate_url(self, url: str, name: str):
241257
def _read_key(self, key: str, name: str) -> bytes:
242258
"""Resolve a key (a file path or base64 blob) to validated gpg key bytes.
243259
244-
A key is either a path - absolute, or relative to the system config - or a
245-
base64-encoded blob inlined in mirrors.yaml. The resulting bytes are checked
246-
to be genuine gpg key material before being accepted.
260+
A key is either a path - absolute, or relative to the mirror file's directory
261+
- or a base64-encoded blob inlined in the mirror file. The resulting bytes are
262+
checked to be genuine gpg key material before being accepted.
247263
"""
248264

249-
# if it is a path (absolute, or relative to the system config), read it
265+
# if it is a path (absolute, or relative to the mirror file), read it
250266
path = pathlib.Path(os.path.expandvars(key))
251267
if not path.is_absolute():
252-
path = self._system_config_root / path
268+
path = self._mirror_dir / path
253269

254270
if path.is_file():
255271
binary_key = path.read_bytes()

stackinator/recipe.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,13 @@ def __init__(self, args):
176176
)
177177
raise RuntimeError("Ivalid default-view in the recipe.")
178178

179-
# load the optional mirrors.yaml from system config, and add any additional
180-
# mirrors specified on the command line.
179+
# resolve the mirror configuration provided with --mirror. --cache is the
180+
# legacy path.
181181
self._logger.debug("Configuring mirrors.")
182182
self.mirrors = mirror.Mirrors(
183183
self.system_config_path,
184184
self.mount,
185+
pathlib.Path(args.mirror) if args.mirror else None,
185186
pathlib.Path(args.cache) if args.cache else None,
186187
)
187188

0 commit comments

Comments
 (0)