diff --git a/lib/galaxy/tool_util/deps/conda_util.py b/lib/galaxy/tool_util/deps/conda_util.py index 8bead7148a5d..ccc8cf2da06d 100644 --- a/lib/galaxy/tool_util/deps/conda_util.py +++ b/lib/galaxy/tool_util/deps/conda_util.py @@ -425,7 +425,7 @@ class CondaTarget: def __init__( self, package: str, version: Optional[str] = None, build: Optional[str] = None, channel: Optional[str] = None ) -> None: - if SHELL_UNSAFE_PATTERN.search(package) is not None: + if SHELL_UNSAFE_PATTERN.search(package) is not None or not package: raise ValueError(f"Invalid package [{package}] encountered.") self.capitalized_package = package self.package = package.lower() diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_build.py b/lib/galaxy/tool_util/deps/mulled/mulled_build.py index be956c84a8b9..422ac0a0b605 100644 --- a/lib/galaxy/tool_util/deps/mulled/mulled_build.py +++ b/lib/galaxy/tool_util/deps/mulled/mulled_build.py @@ -527,8 +527,8 @@ def add_single_image_arguments(parser): ) -def target_str_to_targets(targets_raw): - def parse_target(target_str): +def target_str_to_targets(targets_raw: str) -> List[CondaTarget]: + def parse_target(target_str: str) -> CondaTarget: if "=" in target_str: package_name, version = target_str.split("=", 1) build = None @@ -541,8 +541,10 @@ def parse_target(target_str): target = build_target(target_str) return target - targets = [parse_target(_) for _ in targets_raw.split(",")] - return targets + if targets_raw.strip() == "": + return [] + else: + return [parse_target(_) for _ in targets_raw.split(",")] def args_to_mull_targets_kwds(args): diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py b/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py index a469bcd5eac9..a9dfea4d66d7 100644 --- a/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py +++ b/lib/galaxy/tool_util/deps/mulled/mulled_build_tool.py @@ -20,13 +20,21 @@ add_single_image_arguments, args_to_mull_targets_kwds, mull_targets, + target_str_to_targets, ) -from .util import build_target if TYPE_CHECKING: from galaxy.tool_util.deps.conda_util import CondaTarget +def _mulled_build_tool(tool, args): + tool_source = get_tool_source(tool) + requirements, *_ = tool_source.parse_requirements_and_containers() + targets = requirements_to_mulled_targets(requirements) + kwds = args_to_mull_targets_kwds(args) + mull_targets(targets, **kwds) + + def main(argv=None) -> None: """Main entry-point for the CLI tool.""" parser = arg_parser(argv, globals()) @@ -35,11 +43,7 @@ def main(argv=None) -> None: parser.add_argument("command", metavar="COMMAND", help="Command (build-and-test, build, all)") parser.add_argument("tool", metavar="TOOL", default=None, help="Path to tool to build mulled image for.") args = parser.parse_args() - tool_source = get_tool_source(args.tool) - requirements, *_ = tool_source.parse_requirements_and_containers() - targets = requirements_to_mulled_targets(requirements) - kwds = args_to_mull_targets_kwds(args) - mull_targets(targets, **kwds) + _mulled_build_tool(args.tool, args) def requirements_to_mulled_targets(requirements) -> List["CondaTarget"]: @@ -48,7 +52,8 @@ def requirements_to_mulled_targets(requirements) -> List["CondaTarget"]: Only package requirements are retained. """ package_requirements = [r for r in requirements if r.type == "package"] - targets = [build_target(r.name, r.version) for r in package_requirements] + target_str = ",".join([f"{r.name}={r.version}" for r in package_requirements]) + targets = target_str_to_targets(target_str) return targets diff --git a/lib/galaxy/tool_util/deps/mulled/mulled_hash.py b/lib/galaxy/tool_util/deps/mulled/mulled_hash.py index 691e4ab7e749..3b4766c61648 100644 --- a/lib/galaxy/tool_util/deps/mulled/mulled_hash.py +++ b/lib/galaxy/tool_util/deps/mulled/mulled_hash.py @@ -16,6 +16,18 @@ ) +def _mulled_hash(hash, targets): + """ + >>> _mulled_hash(hash="v2", targets="samtools=1.3.1,bedtools=2.26.0") + 'mulled-v2-8186960447c5cb2faa697666dc1e6d919ad23f3e:a6419f25efff953fc505dbd5ee734856180bb619' + >>> _mulled_hash(hash="v2", targets="samtools=1.3.1=h9071d68_10,bedtools=2.26.0=0") + 'mulled-v2-8186960447c5cb2faa697666dc1e6d919ad23f3e:a6419f25efff953fc505dbd5ee734856180bb619' + """ + targets = target_str_to_targets(targets) + image_name = v2_image_name if hash == "v2" else v1_image_name + return image_name(targets) + + def main(argv=None): """Main entry-point for the CLI tool.""" parser = arg_parser(argv, globals()) @@ -25,8 +37,7 @@ def main(argv=None): parser.add_argument("--hash", dest="hash", choices=["v1", "v2"], default="v2") args = parser.parse_args() targets = target_str_to_targets(args.targets) - image_name = v2_image_name if args.hash == "v2" else v1_image_name - print(image_name(targets)) + print(_mulled_hash(args.hash, targets)) __all__ = ("main",) diff --git a/lib/galaxy/tool_util/deps/mulled/util.py b/lib/galaxy/tool_util/deps/mulled/util.py index a7eacb33806c..ddff7acd32b1 100644 --- a/lib/galaxy/tool_util/deps/mulled/util.py +++ b/lib/galaxy/tool_util/deps/mulled/util.py @@ -335,7 +335,11 @@ def v2_image_name( >>> multi_targets_versionless = [build_target("samtools"), build_target("bwa")] >>> v2_image_name(multi_targets_versionless) 'mulled-v2-fe8faa35dbf6dc65a0f7f5d4ea12e31a79f73e40' + >>> targets_version_with_build = [build_target("samtools", version="1.3.1", build="h9071d68_10"), build_target("bedtools", version="2.26.0", build="0")] + >>> v2_image_name(targets_version_with_build) + 'mulled-v2-8186960447c5cb2faa697666dc1e6d919ad23f3e:a6419f25efff953fc505dbd5ee734856180bb619' """ + if name_override is not None: print( "WARNING: Overriding mulled image name, auto-detection of 'mulled' package attributes will fail to detect result." diff --git a/test/integration/test_container_resolvers.py b/test/integration/test_container_resolvers.py index 2188cf3f9bb2..1d1fda4739ea 100644 --- a/test/integration/test_container_resolvers.py +++ b/test/integration/test_container_resolvers.py @@ -480,6 +480,11 @@ class MulledTestCase: mulled_hash = "mulled-v2-8186960447c5cb2faa697666dc1e6d919ad23f3e:a6419f25efff953fc505dbd5ee734856180bb619-0" +class MulledTestCaseWithBuildInfo: + tool_id = "mulled_example_multi_2" + mulled_hash = "mulled-v2-8186960447c5cb2faa697666dc1e6d919ad23f3e:a6419f25efff953fc505dbd5ee734856180bb619-0" + + class TestDefaultContainerResolvers(DockerContainerResolverTestCase, ContainerResolverTestCases, MulledTestCase): """ Test default container resolvers