-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #714 from nkaretnikov/constructor-artifacts-657
Generate `constructor` artifacts
- Loading branch information
Showing
21 changed files
with
443 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 122 additions & 0 deletions
122
conda-store-server/conda_store_server/action/generate_constructor_installer.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import os | ||
import pathlib | ||
import sys | ||
import tempfile | ||
import warnings | ||
|
||
import yaml | ||
from conda_store_server import action, schema | ||
from conda_store_server.action.utils import logged_command | ||
|
||
|
||
def get_installer_platform(): | ||
# This is how the default platform name is generated internally by | ||
# constructor. For example: osx-arm64, linux-64, win-64. | ||
# https://github.com/conda/constructor/blob/main/CONSTRUCT.md#available-platforms | ||
# Note: constructor is cross-friendly, see: | ||
# https://github.com/conda-incubator/conda-store/pull/714#discussion_r1465115323 | ||
from conda.base.context import context | ||
|
||
return context.subdir | ||
|
||
|
||
@action.action | ||
def action_generate_constructor_installer( | ||
context, | ||
conda_command: str, | ||
specification: schema.CondaSpecification, | ||
installer_dir: pathlib.Path, | ||
version: str, | ||
): | ||
def write_file(filename, s): | ||
with open(filename, "w") as f: | ||
context.log.info(f"{filename}:\n{s}") | ||
f.write(s) | ||
|
||
# Checks if constructor is available | ||
try: | ||
command = [ | ||
"constructor", | ||
"--help", | ||
] | ||
logged_command(context, command, timeout=10) | ||
except FileNotFoundError: | ||
warnings.warn( | ||
"Installer generation requires constructor: https://github.com/conda/constructor" | ||
) | ||
return | ||
|
||
# pip dependencies are not directly supported by constructor, they will be | ||
# installed via the post_install script: | ||
# https://github.com/conda/constructor/issues/515 | ||
# conda and pip need to be in dependencies for the post_install script | ||
dependencies = ["conda", "pip"] | ||
pip_dependencies = [] | ||
for d in specification.dependencies: | ||
if type(d) is schema.CondaSpecificationPip: | ||
pip_dependencies.extend(d.pip) | ||
else: | ||
dependencies.append(d) | ||
|
||
# Creates the construct.yaml file and post_install script | ||
ext = ".exe" if sys.platform == "win32" else ".sh" | ||
pi_ext = ".bat" if sys.platform == "win32" else ".sh" | ||
installer_filename = (installer_dir / specification.name).with_suffix(ext) | ||
|
||
os.makedirs(installer_dir, exist_ok=True) | ||
|
||
with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tmp_dir: | ||
tmp_dir = pathlib.Path(tmp_dir) | ||
cache_dir = tmp_dir / "pkgs" | ||
tmp_dir /= "build" | ||
os.makedirs(cache_dir, exist_ok=True) | ||
os.makedirs(tmp_dir, exist_ok=True) | ||
construct_file = tmp_dir / "construct.yaml" | ||
post_install_file = (tmp_dir / "post_install").with_suffix(pi_ext) | ||
|
||
construct = { | ||
"installer_filename": str(installer_filename), | ||
"post_install": str(post_install_file), | ||
"name": specification.name, | ||
"channels": specification.channels, | ||
"specs": dependencies, | ||
"version": version, | ||
} | ||
|
||
if sys.platform == "win32": | ||
post_install = """\ | ||
call "%PREFIX%\Scripts\\activate.bat" | ||
""" | ||
else: | ||
post_install = """\ | ||
#!/usr/bin/env bash | ||
set -euxo pipefail | ||
source "$PREFIX/etc/profile.d/conda.sh" | ||
conda activate "$PREFIX" | ||
""" | ||
if pip_dependencies: | ||
post_install += f""" | ||
python -m pip install {' '.join(pip_dependencies)} | ||
""" | ||
|
||
# Writes files to disk | ||
write_file(construct_file, yaml.dump(construct)) | ||
write_file(post_install_file, post_install) | ||
|
||
# Calls constructor | ||
# Note: `cache_dir` is the same as the conda `pkgs` directory. It needs | ||
# to be specified here because the default `pkgs` directory is not | ||
# available in Docker, which was causing conda's `create_cache_dir` to | ||
# fail. | ||
command = [ | ||
"constructor", | ||
"-v", | ||
"--cache-dir", | ||
str(cache_dir), | ||
"--platform", | ||
get_installer_platform(), | ||
str(tmp_dir), | ||
] | ||
logged_command(context, command) | ||
|
||
return installer_filename |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import subprocess | ||
|
||
|
||
def logged_command(context, command, **kwargs): | ||
context.log.info(f"Running command: {' '.join(command)}") | ||
context.log.info( | ||
subprocess.check_output( | ||
command, stderr=subprocess.STDOUT, encoding="utf-8", **kwargs | ||
) | ||
) |
46 changes: 46 additions & 0 deletions
46
conda-store-server/conda_store_server/alembic/versions/57cd11b949d5_add_installer.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
"""add installer | ||
Revision ID: 57cd11b949d5 | ||
Revises: 0f7e23ff24ee | ||
Create Date: 2024-01-28 14:31:35.723505 | ||
""" | ||
import sqlalchemy as sa | ||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "57cd11b949d5" | ||
down_revision = "0f7e23ff24ee" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
with op.batch_alter_table( | ||
"build_artifact", | ||
schema=None, | ||
) as batch_op: | ||
batch_op.alter_column( | ||
"artifact_type", | ||
existing_type=sa.VARCHAR(length=18), | ||
type_=sa.VARCHAR(length=21), | ||
existing_nullable=False, | ||
) | ||
if not str(op.get_bind().engine.url).startswith("sqlite"): | ||
op.execute("DROP TYPE IF EXISTS buildartifacttype") | ||
|
||
|
||
def downgrade(): | ||
op.execute( | ||
"DELETE FROM build_artifact WHERE artifact_type = 'CONSTRUCTOR_INSTALLER'" | ||
) | ||
with op.batch_alter_table( | ||
"build_artifact", | ||
schema=None, | ||
) as batch_op: | ||
batch_op.alter_column( | ||
"artifact_type", | ||
existing_type=sa.VARCHAR(length=21), | ||
type_=sa.VARCHAR(length=18), | ||
existing_nullable=False, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.