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

Apply %DEPx% processing more uniformly #1144

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions bin/lib/ce_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ def get_installables(self, args_filter: List[str]) -> List[Installable]:
yaml_doc = yaml.load(yaml_file, Loader=ConfigSafeLoader)
for installer in installers_for(self.installation_context, yaml_doc, self.enabled):
installables.append(installer)
installables_by_name = {installable.name: installable for installable in installables}
for installable in installables:
installable.link(installables_by_name)
Installable.resolve(installables)
installables = sorted(
filter(lambda installable: filter_aggregate(args_filter, installable, self.filter_match_all), installables),
key=lambda x: x.sort_key,
Expand Down
13 changes: 0 additions & 13 deletions bin/lib/installable/archives.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
else:
raise RuntimeError(f"Unknown compression {compression}")
self.strip = self.config_get("strip", False)
self._setup_check_exe(self.install_path)

def fetch_and_pipe_to(self, staging: StagingDir, s3_path: str, command: list[str]) -> None:
# Extension point for subclasses
Expand Down Expand Up @@ -113,8 +112,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
self.compiler_pattern = os.path.join(self.subdir, f"{path_name_prefix}-*")
self.path_name_symlink = self.config_get("symlink", os.path.join(self.subdir, f"{path_name_prefix}"))
self.num_to_keep = self.config_get("num_to_keep", 5)
self._setup_check_exe(self.install_path)
self._setup_check_link(self.install_path, self.path_name_symlink)

@property
def nightly_like(self) -> bool:
Expand Down Expand Up @@ -203,9 +200,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
if extract_only:
self.tar_cmd += [extract_only]
self.strip = self.config_get("strip", False)
self._setup_check_exe(self.install_path)
if self.install_path_symlink:
self._setup_check_link(self.install_path, self.install_path_symlink)
self.remove_older_pattern = self.config_get("remove_older_pattern", "")
self.num_to_keep = self.config_get("num_to_keep", 5)

Expand Down Expand Up @@ -259,10 +253,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
today = datetime.today().strftime("%Y%m%d")
self.install_path = f"{self.install_path}-{today}"

# redo exe checks
self._setup_check_exe(self.install_path)
self._setup_check_link(self.install_path, self.install_path_symlink)

def should_install(self) -> bool:
return True

Expand All @@ -283,9 +273,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
self.folder_to_rename = self.config_get("folder", None if not self.extract_into_folder else "tmp")
self.configure_command = command_config(self.config_get("configure_command", []))
self.strip = self.config_get("strip", False)
self._setup_check_exe(self.install_path)
if self.install_path_symlink:
self._setup_check_link(self.install_path, self.install_path_symlink)

def stage(self, staging: StagingDir) -> None:
# Unzip does not support stdin piping so we need to create a file
Expand Down
1 change: 0 additions & 1 deletion bin/lib/installable/edg.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
self._compiler_type = self.config_get("compiler_type")
self._shim_shell_func = _SHIM_SHELL_FUNCS[self._compiler_type]
self.install_path = self.config_get("path_name")
self._setup_check_exe(self.install_path)

def stage(self, staging: StagingDir) -> None:
super().stage(staging)
Expand Down
55 changes: 34 additions & 21 deletions bin/lib/installable/installable.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from lib.staging import StagingDir

_LOGGER = logging.getLogger(__name__)
_DEP_RE = re.compile("%DEP([0-9]+)%")

running_on_admin_node = socket.gethostname() == "admin-node"

Expand All @@ -26,7 +27,7 @@
class Installable:
_check_link: Optional[Callable[[], bool]]
check_env: Dict
check_file: Optional[str]
check_file: str
check_call: List[str]

def __init__(self, install_context: InstallationContext, config: Dict[str, Any]):
Expand All @@ -39,47 +40,60 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
self.language = False
if len(self.context) > 0:
self.is_library = self.context[0] == "libraries"
if len(self.context) > 1:
self.language = self.context[1]
self.depends_by_name = self.config.get("depends", [])
self.depends: List[Installable] = []
self.install_always = self.config.get("install_always", False)
self._check_link = None
self.build_config = LibraryBuildConfig(config)
self.check_env = {}
self.check_file = None
self.check_file = self.config_get("check_file", "")
self.check_call = []
check_exe = self.config_get("check_exe", "")
if check_exe:
self.check_call = command_config(check_exe)
self.check_stderr_on_stdout = self.config.get("check_stderr_on_stdout", False)
self.install_path = ""
self.after_stage_script = self.config_get("after_stage_script", [])
self._logger = logging.getLogger(self.name)
self.install_path_symlink = self.config_get("symlink", False)

def _setup_check_exe(self, path_name: str) -> None:
self.check_env = dict([x.replace("%PATH%", path_name).split("=", 1) for x in self.config_get("check_env", [])])

check_file = self.config_get("check_file", "")
if check_file:
self.check_file = os.path.join(path_name, check_file)
else:
self.check_call = command_config(self.config_get("check_exe"))
self.check_call[0] = os.path.join(path_name, self.check_call[0])

def _setup_check_link(self, source: str, link: str) -> None:
self._check_link = partial(self.install_context.check_link, source, link)

def link(self, all_installables: Dict[str, Installable]):
def _resolve(self, all_installables: Dict[str, Installable]):
try:
self.depends = [all_installables[dep] for dep in self.depends_by_name]
except KeyError as ke:
self._logger.error("Unable to find dependency %s in %s", ke, all_installables)
raise
dep_re = re.compile("%DEP([0-9]+)%")

def dep_n(match):
return str(self.install_context.destination / self.depends[int(match.group(1))].install_path)

for k in self.check_env.keys():
self.check_env[k] = dep_re.sub(dep_n, self.check_env[k])
def resolve_deps(s: str) -> str:
return _DEP_RE.sub(dep_n, s)

self.check_env = dict(
[x.replace("%PATH%", self.install_path).split("=", 1) for x in self.config_get("check_env", [])]
)
self.check_env = {key: resolve_deps(value) for key, value in self.check_env.items()}

self.after_stage_script = [resolve_deps(line) for line in self.after_stage_script]
self.check_file = resolve_deps(self.check_file)
if self.check_file:
self.check_file = os.path.join(self.install_path, self.check_file)

self.check_call = [resolve_deps(arg) for arg in self.check_call]
if self.check_call:
self.check_call[0] = os.path.join(self.install_path, self.check_call[0])

if self.install_path_symlink:
self._check_link = partial(self.install_context.check_link, self.install_path, self.install_path_symlink)

@staticmethod
def resolve(installables: list[Installable]) -> None:
installables_by_name = {installable.name: installable for installable in installables}
for installable in installables:
installable._resolve(installables_by_name) # pylint: disable=protected-access

def find_dependee(self, name: str) -> Installable:
for i in self.depends:
Expand Down Expand Up @@ -134,7 +148,7 @@ def save_version(self, exe: str, res_call: str):
nightlies.update_version(fullpath.as_posix(), str(modified), res_call.split("\n", 1)[0], res_call)

def is_installed(self) -> bool:
if self.check_file is None and not self.check_call:
if not self.check_file and not self.check_call:
return True

if self._check_link and not self._check_link():
Expand Down Expand Up @@ -244,7 +258,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
self.install_path = self.config_get("dir")
self.url = self.config_get("url")
self.filename = self.config_get("filename")
self._setup_check_exe(self.install_path)

def stage(self, staging: StagingDir) -> None:
out_path = staging.path / self.install_path
Expand Down
1 change: 0 additions & 1 deletion bin/lib/installable/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class PipInstallable(Installable):
def __init__(self, install_context: InstallationContext, config: Dict[str, Any]):
super().__init__(install_context, config)
self.install_path = self.config_get("dir")
self._setup_check_exe(self.install_path)
self.package = self.config_get("package")
self.python = self.config_get("python")

Expand Down
1 change: 0 additions & 1 deletion bin/lib/installable/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class RustInstallable(Installable):
def __init__(self, install_context: InstallationContext, config: Dict[str, Any]):
super().__init__(install_context, config)
self.install_path = self.config_get("dir")
self._setup_check_exe(self.install_path)
self.base_package = self.config_get("base_package")
self.nightly_install_days = self.config_get("nightly_install_days", 0)
self.patchelf = self.config_get("patchelf")
Expand Down
3 changes: 0 additions & 3 deletions bin/lib/installable/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
self.fetch = self.config_get("fetch")
self.script = self.config_get("script")
self.strip = self.config_get("strip", False)
self._setup_check_exe(self.install_path)
if self.install_path_symlink:
self._setup_check_link(self.install_path, self.install_path_symlink)

def stage(self, staging: StagingDir) -> None:
for url in self.fetch:
Expand Down
1 change: 0 additions & 1 deletion bin/lib/installable/solidity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def __init__(self, install_context: InstallationContext, config: Dict[str, Any])
raise RuntimeError(f"Unable to find solidity {self.target_name}")
self.url = f"{self.url}/{release_path}"
self.filename = self.config_get("filename")
self._setup_check_exe(self.install_path)

def __repr__(self) -> str:
return f"SolidityInstallable({self.name}, {self.install_path})"
41 changes: 41 additions & 0 deletions bin/test/installation_test.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from pathlib import Path

import pytest
import yaml

from lib.config_safe_loader import ConfigSafeLoader
from lib.installable.installable import Installable
from lib.installation import targets_from
from lib.installation_context import InstallationContext
from unittest import mock


def parse_targets(string_config, enabled=None):
Expand Down Expand Up @@ -167,3 +172,39 @@ def test_jinja_expansion_with_filters_refering_forward():
"""
)
assert target["url"] == "https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2"


def test_after_stage_script_dep():
ic = mock.Mock(spec_set=InstallationContext)
ic.destination = Path("/some/install/dir")
installation_a = Installable(
ic,
{
"context": ["compilers"],
"name": "a",
"after_stage_script": ["echo hello", "echo %DEP0%", "moo"],
"depends": ["compilers b"],
},
)
installation_b = Installable(ic, {"context": ["compilers"], "name": "b"})
installation_b.install_path = "pathy"
Installable.resolve([installation_a, installation_b])
assert installation_a.after_stage_script == ["echo hello", "echo /some/install/dir/pathy", "moo"]


def test_check_exe_dep():
ic = mock.Mock(spec_set=InstallationContext)
ic.destination = Path("/some/install/dir")
installation_a = Installable(
ic,
{
"context": ["compilers"],
"name": "a",
"check_exe": "%DEP0%/bin/java --jar path/to/jar",
"depends": ["compilers b"],
},
)
installation_b = Installable(ic, {"context": ["compilers"], "name": "b"})
installation_b.install_path = "pathy"
Installable.resolve([installation_a, installation_b])
assert installation_a.check_call == ["/some/install/dir/pathy/bin/java", "--jar", "path/to/jar"]