Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cli option to supply path to the construct yaml file (supersedes #728) #758

Merged
merged 15 commits into from
Mar 5, 2024
20 changes: 17 additions & 3 deletions constructor/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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__
Expand Down Expand Up @@ -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",
Expand All @@ -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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

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")
Expand All @@ -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__':
Expand Down
19 changes: 19 additions & 0 deletions news/758-yaml-filename
Original file line number Diff line number Diff line change
@@ -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

* <news item>

### Deprecations

* <news item>

### Docs

* <news item>

### Other

* <news item>
61 changes: 43 additions & 18 deletions tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand All @@ -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.")

Expand All @@ -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])
Expand All @@ -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 = (
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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",
)
Loading