Switch to explicit lockfile and build metapackage from an env yaml.
This commit is contained in:
parent
be10dc29cd
commit
3e3da4374e
|
@ -0,0 +1,2 @@
|
||||||
|
# github helper pieces to make some files not show up in diffs automatically
|
||||||
|
installer_specs/*.lock linguist-generated=true
|
|
@ -64,14 +64,14 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PLATFORM: ${{ matrix.PLATFORM }}
|
PLATFORM: ${{ matrix.PLATFORM }}
|
||||||
run: |
|
run: |
|
||||||
python build_metapackage.py installer_specs/$DISTNAME-$PLATFORM.txt
|
python build_metapackage.py
|
||||||
|
|
||||||
- name: Copy lock file and list built installers and packages
|
- name: Copy lock file and list built installers and packages
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
PLATFORM: ${{ matrix.PLATFORM }}
|
PLATFORM: ${{ matrix.PLATFORM }}
|
||||||
run: |
|
run: |
|
||||||
cp installer_specs/$DISTNAME-$PLATFORM.txt dist/
|
cp installer_specs/$DISTNAME-$PLATFORM.lock dist/
|
||||||
ls -lhR dist
|
ls -lhR dist
|
||||||
|
|
||||||
- name: Test installer (sh)
|
- name: Test installer (sh)
|
||||||
|
|
|
@ -104,15 +104,15 @@ To install a particular release version, substitute the desired version number a
|
||||||
|
|
||||||
mamba install -c ryanvolz radioconda=20NN.NN.NN
|
mamba install -c ryanvolz radioconda=20NN.NN.NN
|
||||||
|
|
||||||
### Install from environment file
|
### Install from environment lock file
|
||||||
|
|
||||||
You can also install from the released environment file (on Windows):
|
You can also install from the released environment lock file (on Windows):
|
||||||
|
|
||||||
mamba install --file https://github.com/ryanvolz/radioconda/releases/latest/download/radioconda-win-64.txt
|
mamba install --file https://github.com/ryanvolz/radioconda/releases/latest/download/radioconda-win-64.lock
|
||||||
|
|
||||||
(on Linux/macOS):
|
(on Linux/macOS):
|
||||||
|
|
||||||
mamba install --file https://github.com/ryanvolz/radioconda/releases/latest/download/radioconda-$(conda info | sed -n -e 's/^.*platform : //p').txt
|
mamba install --file https://github.com/ryanvolz/radioconda/releases/latest/download/radioconda-$(conda info | sed -n -e 's/^.*platform : //p').lock
|
||||||
|
|
||||||
## Additional Installation for Device Support
|
## Additional Installation for Device Support
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,49 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
from typing import List
|
||||||
|
|
||||||
comment_re = re.compile(r"^\s*#\s*(?P<comment>.*)\s*$")
|
import yaml
|
||||||
key_value_re = re.compile(r"^(?P<key>.*):\s*(?P<value>.*)\s*$")
|
|
||||||
|
|
||||||
|
|
||||||
def read_lock_file(lock_file: pathlib.Path) -> dict:
|
def read_env_file(
|
||||||
with lock_file.open("r") as f:
|
env_file: pathlib.Path,
|
||||||
lines = f.read().splitlines()
|
fallback_name: str,
|
||||||
|
fallback_version: str,
|
||||||
|
fallback_platform: str,
|
||||||
|
fallback_channels: List[str],
|
||||||
|
) -> dict:
|
||||||
|
with env_file.open("r") as f:
|
||||||
|
env_dict = yaml.safe_load(f)
|
||||||
|
|
||||||
lock_dict = dict(specs=[])
|
env_dict.setdefault("name", fallback_name)
|
||||||
for line in lines:
|
env_dict.setdefault("version", fallback_version)
|
||||||
comment_match = comment_re.match(line)
|
env_dict.setdefault("platform", fallback_platform)
|
||||||
if comment_match:
|
env_dict.setdefault("channels", fallback_channels)
|
||||||
m = key_value_re.match(comment_match.group("comment"))
|
|
||||||
if m:
|
|
||||||
lock_dict[m.group("key")] = m.group("value")
|
|
||||||
else:
|
|
||||||
lock_dict["specs"].append(line)
|
|
||||||
|
|
||||||
return lock_dict
|
return env_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_conda_metapackage_cmdline(
|
||||||
|
env_dict: dict, home: str, license_id: str, summary: str
|
||||||
|
):
|
||||||
|
cmdline = [
|
||||||
|
"conda",
|
||||||
|
"metapackage",
|
||||||
|
env_dict["name"],
|
||||||
|
env_dict["version"],
|
||||||
|
"--no-anaconda-upload",
|
||||||
|
"--home",
|
||||||
|
home,
|
||||||
|
"--license",
|
||||||
|
license_id,
|
||||||
|
"--summary",
|
||||||
|
summary,
|
||||||
|
]
|
||||||
|
for channel in env_dict["channels"]:
|
||||||
|
cmdline.extend(["--channel", channel])
|
||||||
|
cmdline.extend(["--dependencies"] + env_dict["dependencies"])
|
||||||
|
|
||||||
|
return cmdline
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -54,12 +77,12 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"lock_file",
|
"env_file",
|
||||||
type=pathlib.Path,
|
type=pathlib.Path,
|
||||||
nargs="?",
|
nargs="?",
|
||||||
default=here / "installer_specs" / f"{distname}-{platform}.txt",
|
default=here / "installer_specs" / f"{distname}-{platform}.yml",
|
||||||
help=(
|
help=(
|
||||||
"Environment lock file for a particular platform"
|
"Environment yaml file for a particular platform"
|
||||||
" (name ends in the platform identifier)."
|
" (name ends in the platform identifier)."
|
||||||
" (default: %(default)s)"
|
" (default: %(default)s)"
|
||||||
),
|
),
|
||||||
|
@ -92,45 +115,32 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
args, metapackage_args = parser.parse_known_args()
|
args, metapackage_args = parser.parse_known_args()
|
||||||
|
|
||||||
lock_dict = read_lock_file(args.lock_file)
|
env_dict = read_env_file(
|
||||||
|
args.env_file,
|
||||||
|
fallback_name=distname,
|
||||||
|
fallback_version="0",
|
||||||
|
fallback_platform=platform,
|
||||||
|
fallback_channels=["conda-forge"],
|
||||||
|
)
|
||||||
|
|
||||||
name = lock_dict.get("name", distname)
|
cmdline = get_conda_metapackage_cmdline(
|
||||||
version = lock_dict.get("version", "0")
|
env_dict=env_dict, home=args.home, license_id=args.license, summary=args.summary
|
||||||
platform = lock_dict.get("platform", platform)
|
)
|
||||||
|
cmdline.extend(metapackage_args)
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["CONDA_SUBDIR"] = platform
|
env["CONDA_SUBDIR"] = env_dict["platform"]
|
||||||
|
|
||||||
channels = [c.strip() for c in lock_dict.get("channels", "conda-forge").split(",")]
|
proc = subprocess.run(cmdline, env=env)
|
||||||
|
|
||||||
conda_metapackage_cmdline = [
|
|
||||||
"conda",
|
|
||||||
"metapackage",
|
|
||||||
name,
|
|
||||||
version,
|
|
||||||
"--no-anaconda-upload",
|
|
||||||
"--home",
|
|
||||||
args.home,
|
|
||||||
"--license",
|
|
||||||
args.license,
|
|
||||||
"--summary",
|
|
||||||
args.summary,
|
|
||||||
]
|
|
||||||
for channel in channels:
|
|
||||||
conda_metapackage_cmdline.extend(["--channel", channel])
|
|
||||||
conda_metapackage_cmdline.extend(["--dependencies"] + lock_dict["specs"])
|
|
||||||
conda_metapackage_cmdline.extend(metapackage_args)
|
|
||||||
|
|
||||||
proc = subprocess.run(conda_metapackage_cmdline, env=env)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proc.check_returncode()
|
proc.check_returncode()
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
bldpkgs_dir = pathlib.Path(conda_build_config.bldpkgs_dir)
|
bldpkgs_dir = pathlib.Path(conda_build_config.croot) / env_dict["platform"]
|
||||||
pkg_paths = list(bldpkgs_dir.glob(f"{name}-{version}*.bz2"))
|
pkg_paths = list(bldpkgs_dir.glob(f"{env_dict['name']}-{env_dict['version']}*.bz2"))
|
||||||
pkg_out_dir = args.output_dir / platform
|
pkg_out_dir = args.output_dir / env_dict["platform"]
|
||||||
pkg_out_dir.mkdir(parents=True, exist_ok=True)
|
pkg_out_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
for pkg in pkg_paths:
|
for pkg in pkg_paths:
|
||||||
|
|
74
rerender.py
74
rerender.py
|
@ -32,26 +32,51 @@ def lock_env_spec(
|
||||||
return locked_env_spec
|
return locked_env_spec
|
||||||
|
|
||||||
|
|
||||||
def write_lock_file(
|
def write_env_file(
|
||||||
lock_spec: conda_lock.src_parser.LockSpecification,
|
env_spec: conda_lock.src_parser.LockSpecification,
|
||||||
lock_file_path: pathlib.Path,
|
file_path: pathlib.Path,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
version: Optional[str] = None,
|
version: Optional[str] = None,
|
||||||
channels: Optional[List[str]] = None,
|
|
||||||
):
|
):
|
||||||
lockfile_contents = [
|
env_dict = dict(
|
||||||
f"# platform: {lock_spec.platform}",
|
name=name,
|
||||||
f"# env_hash: {lock_spec.env_hash()}",
|
version=version,
|
||||||
]
|
platform=env_spec.platform,
|
||||||
|
channels=env_spec.channels,
|
||||||
|
dependencies=env_spec.specs,
|
||||||
|
)
|
||||||
if name:
|
if name:
|
||||||
lockfile_contents.append(f"# name: {name}")
|
env_dict["name"] = name
|
||||||
if version:
|
if version:
|
||||||
lockfile_contents.append(f"# version: {version}")
|
env_dict["version"] = version
|
||||||
if channels:
|
with file_path.open("w") as f:
|
||||||
lockfile_contents.append(f"# channels: {','.join(channels)}")
|
yaml.safe_dump(env_dict, stream=f)
|
||||||
lockfile_contents.extend(lock_spec.specs)
|
|
||||||
with lock_file_path.open("w") as f:
|
return env_dict
|
||||||
f.write("\n".join(lockfile_contents))
|
|
||||||
|
|
||||||
|
def write_lock_file(
|
||||||
|
lock_spec: conda_lock.src_parser.LockSpecification,
|
||||||
|
file_path: pathlib.Path,
|
||||||
|
conda_exe: str,
|
||||||
|
):
|
||||||
|
lockfile_contents = conda_lock.conda_lock.create_lockfile_from_spec(
|
||||||
|
channels=lock_spec.channels, conda=conda_exe, spec=lock_spec
|
||||||
|
)
|
||||||
|
|
||||||
|
def sanitize_lockfile_line(line):
|
||||||
|
line = line.strip()
|
||||||
|
if line == "":
|
||||||
|
return "#"
|
||||||
|
else:
|
||||||
|
return line
|
||||||
|
|
||||||
|
lockfile_contents = [sanitize_lockfile_line(ln) for ln in lockfile_contents]
|
||||||
|
|
||||||
|
with file_path.open("w") as f:
|
||||||
|
f.write("\n".join(lockfile_contents) + "\n")
|
||||||
|
|
||||||
|
return lockfile_contents
|
||||||
|
|
||||||
|
|
||||||
def render_constructor(
|
def render_constructor(
|
||||||
|
@ -151,14 +176,19 @@ def render_platforms(
|
||||||
# lock the full environment specification to specific versions and builds
|
# lock the full environment specification to specific versions and builds
|
||||||
locked_env_spec = lock_env_spec(env_spec, conda_exe)
|
locked_env_spec = lock_env_spec(env_spec, conda_exe)
|
||||||
|
|
||||||
# write the full environment specification to a lock file
|
# write the full environment specification to a yaml file (to build metapackage)
|
||||||
lock_file_path = output_dir / f"{output_name}.txt"
|
locked_env_dict = write_env_file(
|
||||||
write_lock_file(
|
env_spec=locked_env_spec,
|
||||||
locked_env_spec,
|
file_path=output_dir / f"{output_name}.yml",
|
||||||
lock_file_path,
|
|
||||||
name=env_name,
|
name=env_name,
|
||||||
version=version,
|
version=version,
|
||||||
channels=locked_env_spec.channels,
|
)
|
||||||
|
|
||||||
|
# write the full environment specification to a lock file (to install from file)
|
||||||
|
lockfile_contents = write_lock_file(
|
||||||
|
lock_spec=locked_env_spec,
|
||||||
|
file_path=output_dir / f"{output_name}.lock",
|
||||||
|
conda_exe=conda_exe,
|
||||||
)
|
)
|
||||||
|
|
||||||
# add installer-only (base environment) packages and lock those too
|
# add installer-only (base environment) packages and lock those too
|
||||||
|
@ -200,6 +230,8 @@ def render_platforms(
|
||||||
# aggregate output
|
# aggregate output
|
||||||
rendered_platforms[output_name] = dict(
|
rendered_platforms[output_name] = dict(
|
||||||
locked_env_spec=locked_env_spec,
|
locked_env_spec=locked_env_spec,
|
||||||
|
locked_env_dict=locked_env_dict,
|
||||||
|
lockfile_contents=lockfile_contents,
|
||||||
locked_installer_spec=locked_installer_spec,
|
locked_installer_spec=locked_installer_spec,
|
||||||
constructor_dict=constructor_dict,
|
constructor_dict=constructor_dict,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue