From bf82c42ac1c8db0ca7432cd15a8009e84188d20e Mon Sep 17 00:00:00 2001 From: Ken Odegard Date: Mon, 9 Oct 2023 18:24:55 -0500 Subject: [PATCH] Update `conda inspect channels` --- conda_build/cli/main_inspect.py | 16 +++--- conda_build/inspect_pkg.py | 95 +++++++++++++-------------------- 2 files changed, 45 insertions(+), 66 deletions(-) diff --git a/conda_build/cli/main_inspect.py b/conda_build/cli/main_inspect.py index 79e0594a4f..05f76c0fbc 100644 --- a/conda_build/cli/main_inspect.py +++ b/conda_build/cli/main_inspect.py @@ -134,8 +134,10 @@ def parse_args(args): "--test-installable", "-t", action="store_true", - help="""Test every package in the channel to see if it is installable - by conda.""", + help=( + "DEPRECATED. This is the default (and only) behavior. " + "Test every package in the channel to see if it is installable by conda." + ), ) channels.add_argument( "channel", @@ -184,13 +186,9 @@ def execute(args): if not args.subcommand: parser.print_help() - exit() - + sys.exit(0) elif args.subcommand == "channels": - if not args.test_installable: - parser.error("At least one option (--test-installable) is required.") - else: - print(api.test_installable(args.channel)) + print(api.test_installable(args.channel)) elif args.subcommand == "linkages": print( api.inspect_linkages( @@ -219,7 +217,7 @@ def execute(args): elif args.subcommand == "hash-inputs": pprint(api.inspect_hash_inputs(args.packages)) else: - raise ValueError(f"Unrecognized subcommand: {args.subcommand}.") + parser.error(f"Unrecognized subcommand: {args.subcommand}.") @deprecated("3.26.0", "4.0.0", addendum="Use `conda inspect` instead.") diff --git a/conda_build/inspect_pkg.py b/conda_build/inspect_pkg.py index e38c5aa9e7..e4aad7ed27 100644 --- a/conda_build/inspect_pkg.py +++ b/conda_build/inspect_pkg.py @@ -1,20 +1,23 @@ # Copyright (C) 2014 Anaconda, Inc # SPDX-License-Identifier: BSD-3-Clause +from __future__ import annotations + import json import os import re import sys -import tempfile from collections import defaultdict from functools import lru_cache from itertools import groupby from operator import itemgetter from os.path import abspath, basename, dirname, exists, join, normcase +from tempfile import TemporaryDirectory +from typing import Iterable + +from conda.api import Solver +from conda.core.index import get_index from conda_build.conda_interface import ( - display_actions, - get_index, - install_actions, is_linked, linked_data, specs_from_args, @@ -31,9 +34,10 @@ ensure_list, get_logger, package_has_file, - rm_rf, ) +log = get_logger(__name__) + @lru_cache(maxsize=None) def dist_files(prefix, dist): @@ -88,22 +92,19 @@ def __str__(self): def check_install( - packages, platform=None, channel_urls=(), prepend=True, minimal_hint=False -): - prefix = tempfile.mkdtemp("conda") - try: - specs = specs_from_args(packages) - index = get_index( - channel_urls=channel_urls, prepend=prepend, platform=platform, prefix=prefix - ) - actions = install_actions( - prefix, index, specs, pinned=False, minimal_hint=minimal_hint - ) - display_actions(actions, index) - return actions - finally: - rm_rf(prefix) - return None + packages: Iterable[str], + subdir: str | None = None, + channel_urls: Iterable[str] = (), + prepend: bool = True, + minimal_hint: bool = False, +) -> None: + with TemporaryDirectory() as prefix: + Solver( + prefix, + channel_urls, + [subdir], + specs_from_args(packages), + ).solve_for_transaction().print_transaction_summary() def print_linkages(depmap, show_files=False): @@ -155,61 +156,41 @@ def replace_path(binary, path, prefix): return "not found" -def test_installable(channel="defaults"): +def test_installable(channel: str = "defaults") -> bool: success = True - log = get_logger(__name__) - has_py = re.compile(r"py(\d)(\d)") - for platform in ["osx-64", "linux-32", "linux-64", "win-32", "win-64"]: - log.info("######## Testing platform %s ########", platform) - channels = [channel] - index = get_index(channel_urls=channels, prepend=False, platform=platform) - for _, rec in index.items(): - # If we give channels at the command line, only look at - # packages from those channels (not defaults). - if channel != "defaults" and rec.get("schannel", "defaults") == "defaults": - continue - name = rec["name"] + for subdir in ["osx-64", "linux-32", "linux-64", "win-32", "win-64"]: + log.info("######## Testing subdir %s ########", subdir) + for prec in get_index(channel_urls=[channel], prepend=False, platform=subdir): + name = prec["name"] if name in {"conda", "conda-build"}: # conda can only be installed in the root environment continue - if name.endswith("@"): + elif name.endswith("@"): # this is a 'virtual' feature record that conda adds to the index for the solver # and should be ignored here continue - # Don't fail just because the package is a different version of Python - # than the default. We should probably check depends rather than the - # build string. - build = rec["build"] - match = has_py.search(build) - assert match if "py" in build else True, build - if match: - additional_packages = [f"python={match.group(1)}.{match.group(2)}"] - else: - additional_packages = [] - version = rec["version"] + version = prec["version"] log.info("Testing %s=%s", name, version) try: - install_steps = check_install( - [name + "=" + version] + additional_packages, - channel_urls=channels, + check_install( + [f"{name}={version}"], + channel_urls=[channel], prepend=False, - platform=platform, + subdir=subdir, ) - success &= bool(install_steps) except KeyboardInterrupt: raise - # sys.exit raises an exception that doesn't subclass from Exception - except BaseException as e: + except BaseException as err: + # sys.exit raises an exception that doesn't subclass from Exception success = False log.error( - "FAIL: %s %s on %s with %s (%s)", + "%s=%s on %s: %s", name, version, - platform, - additional_packages, - e, + subdir, + repr(err), ) return success