diff --git a/constructor/main.py b/constructor/main.py index f1490cf0e..76f483aea 100644 --- a/constructor/main.py +++ b/constructor/main.py @@ -68,7 +68,8 @@ def get_output_filename(info): def main_build(dir_path, output_dir='.', platform=cc_platform, verbose=True, cache_dir=DEFAULT_CACHE_DIR, - dry_run=False, conda_exe="conda.exe"): + dry_run=False, conda_exe="conda.exe", + config_filename="construct.yaml"): logger.info('platform: %s', platform) if not os.path.isfile(conda_exe): sys.exit("Error: Conda executable '%s' does not exist!" % conda_exe) @@ -78,7 +79,7 @@ def main_build(dir_path, output_dir='.', platform=cc_platform, except ValueError: sys.exit("Error: invalid platform string '%s'" % platform) - construct_path = join(dir_path, 'construct.yaml') + construct_path = join(dir_path, config_filename) info = construct_parse(construct_path, platform) construct_verify(info) info['CONSTRUCTOR_VERSION'] = __version__ @@ -357,6 +358,13 @@ def main(): action="store", metavar="CONDA_EXE") + p.add_argument('--config-filename', + help="path to construct YAML file ready by constructor", + action="store", + metavar="FILENAME", + dest="config_filename", + default="construct.yaml") + p.add_argument('dir_path', help="directory containing construct.yaml", action="store", @@ -381,6 +389,11 @@ def main(): dir_path = args.dir_path if not isdir(dir_path): p.error("no such directory: %s" % dir_path) + if os.sep in args.config_filename: + p.error("--config-filename can only be a filename, not a path") + full_config_path = os.path.join(dir_path, args.config_filename) + if not os.path.isfile(full_config_path): + p.error("no such file: %s" % full_config_path) conda_exe = args.conda_exe conda_exe_default_path = os.path.join(sys.prefix, "standalone_conda", "conda.exe") @@ -404,7 +417,8 @@ def main(): out_dir = normalize_path(args.output_dir) main_build(dir_path, output_dir=out_dir, platform=args.platform, verbose=args.verbose, cache_dir=args.cache_dir, - dry_run=args.dry_run, conda_exe=conda_exe) + dry_run=args.dry_run, conda_exe=conda_exe, + config_filename=args.config_filename) if __name__ == '__main__': diff --git a/examples/noconda/construct.yaml b/examples/noconda/constructor_input.yaml similarity index 100% rename from examples/noconda/construct.yaml rename to examples/noconda/constructor_input.yaml diff --git a/news/758-yaml-filename b/news/758-yaml-filename new file mode 100644 index 000000000..394550aea --- /dev/null +++ b/news/758-yaml-filename @@ -0,0 +1,19 @@ +### Enhancements + +* Add a new `--config-filename` argument to specify an input file not named `construct.yaml`. (#727 via #758) + +### Bug fixes + +* + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/test_examples.py b/tests/test_examples.py index 1e8f548ce..90ea18c75 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -8,7 +8,7 @@ from datetime import timedelta from functools import lru_cache from pathlib import Path -from typing import Iterable, Optional, Tuple +from typing import Generator, Iterable, Optional, Tuple import pytest from conda.base.context import context @@ -179,7 +179,13 @@ def _run_installer_sh(installer, install_dir, installer_input=None, timeout=420) return _execute(cmd, installer_input=installer_input, timeout=timeout) -def _run_installer_pkg(installer, install_dir, example_path=None, timeout=420): +def _run_installer_pkg( + installer, + install_dir, + example_path=None, + config_filename="construct.yaml", + timeout=420, +): if os.environ.get("CI"): # We want to run it in an arbitrary directory, but the options # are limited here... We can only install to $HOME :shrug: @@ -193,7 +199,7 @@ def _run_installer_pkg(installer, install_dir, example_path=None, timeout=420): "CurrentUserHomeDirectory", ] if example_path: - install_dir = calculate_install_dir(example_path / "construct.yaml") + install_dir = calculate_install_dir(example_path / config_filename) install_dir = Path(os.environ["HOME"]) / install_dir else: # This command only expands the PKG, but does not install @@ -222,6 +228,7 @@ def _run_installer( installer: Path, install_dir: Path, installer_input: Optional[str] = None, + config_filename="construct.yaml", check_sentinels=True, request=None, uninstall=True, @@ -234,7 +241,13 @@ def _run_installer( elif installer.suffix == ".pkg": if request and ON_CI: request.addfinalizer(lambda: shutil.rmtree(str(install_dir))) - _run_installer_pkg(installer, install_dir, example_path=example_path, timeout=timeout) + _run_installer_pkg( + installer, + install_dir, + example_path=example_path, + config_filename=config_filename, + timeout=timeout, + ) else: raise ValueError(f"Unknown installer type: {installer.suffix}") if check_sentinels: @@ -250,9 +263,10 @@ def create_installer( debug=CONSTRUCTOR_DEBUG, with_spaces=False, timeout=420, + config_filename="construct.yaml", extra_constructor_args: Iterable[str] = None, **env_vars, -) -> Tuple[Path, Path]: +) -> Generator[Tuple[Path, Path], None, None]: if sys.platform.startswith("win") and conda_exe and _is_micromamba(conda_exe): pytest.skip("Micromamba is not supported on Windows yet.") @@ -265,6 +279,8 @@ def create_installer( str(input_dir), "--output-dir", str(output_dir), + "--config-filename", + config_filename, ] if conda_exe: cmd.extend(["--conda-exe", conda_exe]) @@ -285,7 +301,7 @@ def _sort_by_extension(path): for installer in sorted(installers, key=_sort_by_extension): if installer.suffix == ".pkg" and ON_CI: install_dir = Path("~").expanduser() / calculate_install_dir( - input_dir / "construct.yaml" + input_dir / config_filename ) else: install_dir = ( @@ -383,8 +399,16 @@ def test_example_miniforge(tmp_path, request): def test_example_noconda(tmp_path, request): input_path = _example_path("noconda") - for installer, install_dir in create_installer(input_path, tmp_path, with_spaces=True): - _run_installer(input_path, installer, install_dir, request=request) + for installer, install_dir in create_installer( + input_path, tmp_path, config_filename="constructor_input.yaml", with_spaces=True + ): + _run_installer( + input_path, + installer, + install_dir, + config_filename="constructor_input.yaml", + request=request, + ) @pytest.mark.skipif(sys.platform != "darwin", reason="macOS only") @@ -525,28 +549,28 @@ def test_register_envs(tmp_path, request): assert str(install_dir) not in environments_txt -@pytest.mark.skipif(sys.platform != 'darwin', reason='MacOS only') -@pytest.mark.parametrize('domains', ({}, {'enable_anywhere': 'false', 'enable_localSystem': True})) +@pytest.mark.skipif(sys.platform != "darwin", reason="MacOS only") +@pytest.mark.parametrize("domains", ({}, {"enable_anywhere": "false", "enable_localSystem": True})) def test_pkg_distribution_domains(tmp_path, domains): - recipe_path = _example_path('osxpkg') - input_path = tmp_path / 'input' - output_path = tmp_path / 'output' + recipe_path = _example_path("osxpkg") + input_path = tmp_path / "input" + output_path = tmp_path / "output" shutil.copytree(str(recipe_path), str(input_path)) if domains: with open(input_path / "construct.yaml", "a") as cyml: - cyml.write('pkg_domains:\n') + cyml.write("pkg_domains:\n") for key, val in domains.items(): cyml.write(f" {key}: {val}\n") installer, install_dir = next(create_installer(input_path, output_path)) - cmd = ['pkgutil', '--expand', installer, output_path / "expanded"] + cmd = ["pkgutil", "--expand", installer, output_path / "expanded"] _execute(cmd) - domains_file = output_path / "expanded" / 'Distribution' + domains_file = output_path / "expanded" / "Distribution" assert domains_file.exists() tree = ET.parse(domains_file) - found = {key: val for key, val in tree.find('domains').items()} - defaults = {'enable_anywhere': 'true', 'enable_currentUserHome': 'true'} + found = {key: val for key, val in tree.find("domains").items()} + defaults = {"enable_anywhere": "true", "enable_currentUserHome": "true"} expected = {key: str(val).lower() for key, val in domains.items()} if domains else defaults assert expected == found @@ -574,4 +598,5 @@ def test_cross_osx_building(tmp_path): tmp_path, conda_exe=micromamba_arm64, extra_constructor_args=["--platform", "osx-arm64"], + config_filename="constructor_input.yaml", )