Skip to content

Commit 2a97ab8

Browse files
IsabelParedesmarcoestersjaimergppre-commit-ci[bot]
authored
Add support for mirrored channels (#1008)
Co-authored-by: Marco Esters <mesters@anaconda.com> Co-authored-by: jaimergp <jaimergp@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 05b6fa7 commit 2a97ab8

9 files changed

Lines changed: 159 additions & 1 deletion

File tree

CONSTRUCT.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,27 @@ channels_remap:
8181
8282
At least one channel must be supplied, either in `channels` or `channels_remap`.
8383

84+
### `mirrored_channels`
85+
86+
A mapping of channels to their mirror URLs. Each channel maps to a list of
87+
mirror URLs that will be used as fallbacks. The mirrored channels will be
88+
included in the `.condarc` file of the installer.
89+
90+
Requires `mamba` to be listed in the `base` environment, and `write_condarc`
91+
to be `True`.
92+
93+
Example use:
94+
95+
```yaml
96+
mirrored_channels:
97+
conda-forge:
98+
- "https://conda.anaconda.org/conda-forge"
99+
- "https://conda.anaconda.org/conda-forge-mirror"
100+
defaults:
101+
- "https://repo.anaconda.com/pkgs/main"
102+
- "https://repo.anaconda.com/pkgs/main-mirror"
103+
```
104+
84105
### `specs`
85106

86107
A list of package specifications; e.g. `python 2.7*`, `pyzmq` or `numpy >=1.8`.

constructor/_schema.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,27 @@ class ConstructorConfiguration(BaseModel):
247247
248248
At least one channel must be supplied, either in `channels` or `channels_remap`.
249249
"""
250+
mirrored_channels: dict[NonEmptyStr, list[NonEmptyStr]] = {}
251+
"""
252+
A mapping of channels to their mirror URLs. Each channel maps to a list of
253+
mirror URLs that will be used as fallbacks. The mirrored channels will be
254+
included in the `.condarc` file of the installer.
255+
256+
Requires `mamba` to be listed in the `base` environment, and `write_condarc`
257+
to be `True`.
258+
259+
Example use:
260+
261+
```yaml
262+
mirrored_channels:
263+
conda-forge:
264+
- "https://conda.anaconda.org/conda-forge"
265+
- "https://conda.anaconda.org/conda-forge-mirror"
266+
defaults:
267+
- "https://repo.anaconda.com/pkgs/main"
268+
- "https://repo.anaconda.com/pkgs/main-mirror"
269+
```
270+
"""
250271
specs: list[NonEmptyStr] | NonEmptyStr = []
251272
"""
252273
A list of package specifications; e.g. `python 2.7*`, `pyzmq` or `numpy >=1.8`.

constructor/data/construct.schema.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,22 @@
871871
"description": "A list of packages with menu items to be installed. The packages must have necessary metadata in `Menu/<package name>.json`. By default, all menu items found in the installation will be created; supplying this list allows a subset to be selected instead. If an empty list is supplied, no shortcuts will be created.\nIf all environments (`extra_envs` included) set `menu_packages` to an empty list, no UI options about shortcuts will be offered to the user.\nNote: This option is not fully implemented when `micromamba` is used as the `--conda-exe` binary. The only accepted value is an empty list (`[]`).",
872872
"title": "Menu Packages"
873873
},
874+
"mirrored_channels": {
875+
"additionalProperties": {
876+
"items": {
877+
"minLength": 1,
878+
"type": "string"
879+
},
880+
"type": "array"
881+
},
882+
"default": {},
883+
"description": "A mapping of channels to their mirror URLs. Each channel maps to a list of mirror URLs that will be used as fallbacks. The mirrored channels will be included in the `.condarc` file of the installer.\nRequires `mamba` to be listed in the `base` environment, and `write_condarc` to be `True`.\nExample use:\n```yaml\nmirrored_channels:\n conda-forge:\n - \"https://conda.anaconda.org/conda-forge\"\n - \"https://conda.anaconda.org/conda-forge-mirror\"\n defaults:\n - \"https://repo.anaconda.com/pkgs/main\"\n - \"https://repo.anaconda.com/pkgs/main-mirror\"\n```",
884+
"propertyNames": {
885+
"minLength": 1
886+
},
887+
"title": "Mirrored Channels",
888+
"type": "object"
889+
},
874890
"name": {
875891
"description": "Name of the installer. Names may be composed of letters, numbers, underscores, dashes, and periods, but must not begin or end with a dash or period.",
876892
"minLength": 1,

constructor/utils.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,19 @@ def if_repl(match):
130130

131131

132132
def add_condarc(info):
133+
from .conda_interface import MatchSpec # prevent circular import
134+
133135
condarc = info.get("condarc")
134136
if condarc is None:
135137
# The legacy approach
136138
write_condarc = info.get("write_condarc")
137139
default_channels = info.get("conda_default_channels")
138140
channel_alias = info.get("conda_channel_alias")
139141
channels = info.get("channels")
140-
if not (write_condarc and (default_channels or channels or channel_alias)):
142+
mirrored_channels = info.get("mirrored_channels")
143+
if not (
144+
write_condarc and (default_channels or channels or channel_alias or mirrored_channels)
145+
):
141146
return
142147
condarc = {}
143148
if default_channels:
@@ -146,6 +151,14 @@ def add_condarc(info):
146151
condarc["channels"] = channels
147152
if channel_alias:
148153
condarc["channel_alias"] = channel_alias
154+
if mirrored_channels:
155+
if "mamba" in {MatchSpec(spec).name for spec in info.get("specs", ())}:
156+
condarc["mirrored_channels"] = mirrored_channels
157+
else:
158+
logger.warning(
159+
"The 'mirrored_channels' key is only supported by mamba. "
160+
"It will not be included in the installer."
161+
)
149162
if isinstance(condarc, dict):
150163
condarc = yaml_to_string(condarc)
151164
yield "# ----- add condarc"

docs/source/construct-yaml.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,27 @@ channels_remap:
8181
8282
At least one channel must be supplied, either in `channels` or `channels_remap`.
8383

84+
### `mirrored_channels`
85+
86+
A mapping of channels to their mirror URLs. Each channel maps to a list of
87+
mirror URLs that will be used as fallbacks. The mirrored channels will be
88+
included in the `.condarc` file of the installer.
89+
90+
Requires `mamba` to be listed in the `base` environment, and `write_condarc`
91+
to be `True`.
92+
93+
Example use:
94+
95+
```yaml
96+
mirrored_channels:
97+
conda-forge:
98+
- "https://conda.anaconda.org/conda-forge"
99+
- "https://conda.anaconda.org/conda-forge-mirror"
100+
defaults:
101+
- "https://repo.anaconda.com/pkgs/main"
102+
- "https://repo.anaconda.com/pkgs/main-mirror"
103+
```
104+
84105
### `specs`
85106

86107
A list of package specifications; e.g. `python 2.7*`, `pyzmq` or `numpy >=1.8`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# yaml-language-server: $schema=../../constructor/data/construct.schema.json
2+
"$schema": "../../constructor/data/construct.schema.json"
3+
4+
name: Mirrors
5+
version: X
6+
7+
channels:
8+
- conda-forge
9+
10+
mirrored_channels:
11+
conda-forge:
12+
- "https://conda.anaconda.org/conda-forge"
13+
- "https://conda.anaconda.org/mirror1"
14+
- "https://conda.anaconda.org/mirror2"
15+
16+
write_condarc: True
17+
18+
specs:
19+
- python
20+
- mamba

news/1008-mirrored-channels-schema

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
### Enhancements
2+
3+
* Add support for `mirrored_channels` in `construct.yaml`. These mirrored channels are included in the resulting `.condarc` file if one is created. (#1008)
4+
5+
### Bug fixes
6+
7+
* <news item>
8+
9+
### Deprecations
10+
11+
* <news item>
12+
13+
### Docs
14+
15+
* <news item>
16+
17+
### Other
18+
19+
* <news item>

tests/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ pytest
22
pytest-cov
33
coverage
44
jinja2
5+
ruamel.yaml

tests/test_examples.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from conda.base.context import context
2020
from conda.core.prefix_data import PrefixData
2121
from conda.models.version import VersionOrder as Version
22+
from ruamel.yaml import YAML
2223

2324
from constructor.utils import StandaloneExe, identify_conda_exe
2425

@@ -473,6 +474,31 @@ def test_example_extra_files(tmp_path, request):
473474
_run_installer(input_path, installer, install_dir, request=request)
474475

475476

477+
def test_example_mirrored_channels(tmp_path, request):
478+
input_path = _example_path("mirrored_channels")
479+
for installer, install_dir in create_installer(input_path, tmp_path):
480+
_run_installer(input_path, installer, install_dir, request=request, uninstall=False)
481+
482+
expected_condarc = {
483+
"channels": ["conda-forge"],
484+
"mirrored_channels": {
485+
"conda-forge": [
486+
"https://conda.anaconda.org/conda-forge",
487+
"https://conda.anaconda.org/mirror1",
488+
"https://conda.anaconda.org/mirror2",
489+
]
490+
},
491+
}
492+
493+
condarc_file = install_dir / ".condarc"
494+
assert condarc_file.exists()
495+
496+
with open(condarc_file) as file:
497+
condarc_data = YAML().load(file)
498+
499+
assert condarc_data == expected_condarc
500+
501+
476502
@pytest.mark.xfail(
477503
(
478504
CONDA_EXE == StandaloneExe.CONDA

0 commit comments

Comments
 (0)