diff --git a/.authors.yml b/.authors.yml index 92914dbfc..281b1ef95 100644 --- a/.authors.yml +++ b/.authors.yml @@ -27,7 +27,7 @@ aliases: - John Kirkham - jakirkham - num_commits: 24 + num_commits: 25 first_commit: 2016-03-17 21:05:53 github: jakirkham - name: Daniel Bast @@ -182,7 +182,7 @@ email: marcel.bargull@udo.edu alternate_emails: - mbargull@users.noreply.github.com - num_commits: 26 + num_commits: 30 first_commit: 2018-07-30 05:17:51 github: mbargull - name: xoviat @@ -393,7 +393,7 @@ github: shadowwalkersb - name: Matthew R. Becker email: becker.mr@gmail.com - num_commits: 156 + num_commits: 163 first_commit: 2020-01-07 17:44:33 github: beckermr alternate_emails: @@ -476,7 +476,7 @@ github: jwillemsen - name: Jaime Rodríguez-Guerra email: jaimergp@users.noreply.github.com - num_commits: 126 + num_commits: 132 first_commit: 2020-11-01 14:18:08 github: jaimergp - name: Bastian Zimmermann @@ -517,7 +517,7 @@ github: bkpoon - name: Matthias Diener email: mdiener@illinois.edu - num_commits: 6 + num_commits: 7 first_commit: 2021-09-27 17:26:18 github: matthiasdiener - name: Matthew W. Thompson @@ -537,7 +537,7 @@ github: nehaljwani - name: H. Vetinari email: h.vetinari@gmx.com - num_commits: 18 + num_commits: 19 first_commit: 2021-11-14 02:53:10 - name: Benjamin Tovar email: btovar@nd.edu @@ -575,7 +575,7 @@ github: mikemhenry - name: Bela Stoyan email: bela.stoyan@gmail.com - num_commits: 8 + num_commits: 11 first_commit: 2023-09-19 09:24:51 github: '0xbe7a' - name: Klaus Zimmermann @@ -585,7 +585,7 @@ github: zklaus - name: pre-commit-ci[bot] email: 66853113+pre-commit-ci[bot]@users.noreply.github.com - num_commits: 9 + num_commits: 11 first_commit: 2023-10-30 15:49:50 github: carterbox - name: Amit Kumar @@ -600,3 +600,8 @@ email: david.hirschfeld@stanwell.com num_commits: 4 first_commit: 2020-10-24 23:53:21 +- name: Antonio S. Cofiño + email: cofinoa@gmail.com + num_commits: 7 + first_commit: 2024-01-08 15:21:06 + github: cofinoa diff --git a/.mailmap b/.mailmap index 96d227c22..e503f41d2 100644 --- a/.mailmap +++ b/.mailmap @@ -26,18 +26,18 @@ shadow_walker Michael Sarahan Mike Sarahan Min RK Marcel Bargull Marcel Bargull +John Kirkham John Kirkham +John Kirkham jakirkham Mark Harfouche Leo Fang Leo Fang Leo Fang Leo Fang Hadrien Mary Hadrien Mary Ryan Volz Ryan Volz -John Kirkham John Kirkham -John Kirkham jakirkham Johnny Willemsen +H. Vetinari Chris Burr Chris Burr Julian Rüth Bastian Zimmermann <10774221+BastianZim@users.noreply.github.com> BastianZim <10774221+BastianZim@users.noreply.github.com> -H. Vetinari Daniel Bast <2790401+dbast@users.noreply.github.com> Billy K. Poon Tim Snyder @@ -49,23 +49,24 @@ Daniel Ching Maksim Rakitin Maksim Rakitin Jan Schulz Josh Reichardt +Bela Stoyan +pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Justin Calamari Jason Furmanek Patrick Sodré C.A.M. Gerlach refraction-ray -pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Nicholas Bollweg Leopold Talirz Tom Pollard -Bela Stoyan Gonzalo Pena-Castellanos +Matthias Diener +Antonio S. Cofiño Carlo Carlo Matthew Craig Matt Craig Peter Williams Joshua L. Adelman Wolf Vollprecht -Matthias Diener John Blischak Marius van Niekerk mariusvniekerk Marius van Niekerk mariusvniekerk diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f8fe71da9..4568d379c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 23.12.1 + rev: 24.1.1 hooks: - id: black diff --git a/AUTHORS.rst b/AUTHORS.rst index d759df4fe..f129d4c4b 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -15,16 +15,16 @@ Authors are sorted by number of commits. * Michael Sarahan * Min RK * Marcel Bargull +* John Kirkham * Mark Harfouche * Leo Fang * Hadrien Mary * Ryan Volz -* John Kirkham * Johnny Willemsen +* H. Vetinari * Chris Burr * Julian Rüth * Bastian Zimmermann -* H. Vetinari * Daniel Bast * Billy K. Poon * Tim Snyder @@ -35,23 +35,24 @@ Authors are sorted by number of commits. * Maksim Rakitin * Jan Schulz * Josh Reichardt +* Bela Stoyan +* pre-commit-ci[bot] * Justin Calamari * Jason Furmanek * Patrick Sodré * C.A.M. Gerlach * refraction-ray -* pre-commit-ci[bot] * Nicholas Bollweg * Leopold Talirz * Tom Pollard -* Bela Stoyan * Gonzalo Pena-Castellanos +* Matthias Diener +* Antonio S. Cofiño * Carlo * Matthew Craig * Peter Williams * Joshua L. Adelman * Wolf Vollprecht -* Matthias Diener * John Blischak * Marius van Niekerk * Johannes Köster diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b3fb14fb6..47e10e171 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,58 @@ conda-smithy Change Log .. current developments +v3.31.1 +==================== + +**Changed:** + +* Do not consider broken releases when checking if local version is up to date. (#1848 via #1849) +* Added rerendering support for additional mpi variants ``msmpi``, ``mpi_serial``, and ``impi``. + +**Fixed:** + +* Fixed regression where some variant keys were mismatched during rerendering. + +**Authors:** + +* Matthew R. Becker +* Jaime Rodríguez-Guerra + + + +v3.31.0 +==================== + +**Added:** + +* Smithy now understand the new stdlib jinja function. +* Complete conda-build load data functions stubs PR #1829 +* `noarch` packages can now include keys from their `conda_build_config.yaml` as selectors in their recipe. +This allows for building multiple variants of a `noarch` packages, e.g., to use different dependencies depending on the Python version as runtime. + +**Changed:** + +* Default build tool changed from conda-mambabuild to conda-build again. (#1844) +* Cleanup ``run_win_build.bat`` ( #1836 ) + +**Fixed:** + +* Resolve warnings in Github Actions workflows by updating to ``actions/checkout@v4``. (#1839) +* Fix randomly mismatched zipped variant keys. (#1459 and #1782 via #1815) + +**Authors:** + +* Jaime Rodríguez-Guerra +* Marcel Bargull +* John Kirkham +* H. Vetinari +* Bela Stoyan +* pre-commit-ci[bot] +* Matthias Diener +* Antonio S. Cofiño + + + v3.30.4 ==================== diff --git a/conda_smithy/anaconda_token_rotation.py b/conda_smithy/anaconda_token_rotation.py index 8955d1c2f..980425cdf 100644 --- a/conda_smithy/anaconda_token_rotation.py +++ b/conda_smithy/anaconda_token_rotation.py @@ -8,6 +8,7 @@ Note that if you are using appveyor, you will need to push the changes to the conda-forge.yml in your feedstock to GitHub. """ + import os import sys from contextlib import redirect_stderr, redirect_stdout diff --git a/conda_smithy/azure_ci_utils.py b/conda_smithy/azure_ci_utils.py index d67851fbc..a10a3d6f5 100644 --- a/conda_smithy/azure_ci_utils.py +++ b/conda_smithy/azure_ci_utils.py @@ -83,10 +83,10 @@ def get_service_endpoint(config: AzureConfig = default_config): service_endpoint_client = ServiceEndpointClient( base_url=config.instance_base_url, creds=config.credentials ) - endpoints: typing.List[ - ServiceEndpoint - ] = service_endpoint_client.get_service_endpoints( - project=config.project_name, type="GitHub" + endpoints: typing.List[ServiceEndpoint] = ( + service_endpoint_client.get_service_endpoints( + project=config.project_name, type="GitHub" + ) ) for service_endpoint in endpoints: if service_endpoint.name == config.org_or_user: @@ -224,9 +224,9 @@ def register_repo(github_org, repo_name, config: AzureConfig = default_config): ) # clean up existing builds for the same feedstock if present - existing_definitions: typing.List[ - BuildDefinitionReference - ] = bclient.get_definitions(project=config.project_name, name=repo_name) + existing_definitions: typing.List[BuildDefinitionReference] = ( + bclient.get_definitions(project=config.project_name, name=repo_name) + ) if existing_definitions: assert len(existing_definitions) == 1 ed = existing_definitions[0] diff --git a/conda_smithy/ci_skeleton.py b/conda_smithy/ci_skeleton.py index d2f34ab6d..e253a18a9 100644 --- a/conda_smithy/ci_skeleton.py +++ b/conda_smithy/ci_skeleton.py @@ -5,6 +5,7 @@ Note that your CI jobs will still execute under your organization, and not be added to conda-forge's queue. """ + import os import sys diff --git a/conda_smithy/cirun_utils.py b/conda_smithy/cirun_utils.py index 50d2f7007..8b5917a5c 100644 --- a/conda_smithy/cirun_utils.py +++ b/conda_smithy/cirun_utils.py @@ -1,6 +1,7 @@ """ See http://py.cirun.io/api.html for cirun client docs """ + import os from functools import lru_cache from typing import List, Dict, Any, Optional diff --git a/conda_smithy/configure_feedstock.py b/conda_smithy/configure_feedstock.py index 03da8e591..220a9ceab 100644 --- a/conda_smithy/configure_feedstock.py +++ b/conda_smithy/configure_feedstock.py @@ -6,6 +6,7 @@ import re import subprocess import sys +import pprint import textwrap import time import jsonschema @@ -314,6 +315,119 @@ def _trim_unused_pin_run_as_build(all_used_vars): del all_used_vars["pin_run_as_build"] +def _get_used_key_values_by_input_order( + squished_input_variants, + squished_used_variants, + all_used_vars, +): + used_key_values = { + key: squished_input_variants[key] + for key in all_used_vars + if key in squished_input_variants + } + logger.debug( + "initial used_key_values {}".format(pprint.pformat(used_key_values)) + ) + + # we want remove any used key values not in used variants and make sure they follow the + # input order + # zipped keys are a special case since they are ordered by the list of tuple of zipped + # key values + # so we do the zipped keys first and then do the rest + zipped_tuples = {} + zipped_keys = set() + for keyset in squished_input_variants["zip_keys"]: + zipped_tuples[tuple(keyset)] = list( + zip(*[squished_input_variants[k] for k in keyset]) + ) + zipped_keys |= set(keyset) + logger.debug("zipped_keys {}".format(pprint.pformat(zipped_keys))) + logger.debug("zipped_tuples {}".format(pprint.pformat(zipped_tuples))) + + for keyset, tuples in zipped_tuples.items(): + # for each set of zipped keys from squished_input_variants, + # we trim them down to what is in squished_used_variants + used_keyset = [] + used_keyset_inds = [] + for k in keyset: + if k in squished_used_variants: + used_keyset.append(k) + used_keyset_inds.append(keyset.index(k)) + used_keyset = tuple(used_keyset) + used_keyset_inds = tuple(used_keyset_inds) + + # if we find nothing, keep going + if not used_keyset: + continue + + # this trims the zipped tuples down to the used keys + used_tuples = tuple( + [ + tuple( + [ + tup[used_keyset_ind] + for used_keyset_ind in used_keyset_inds + ] + ) + for tup in tuples + ] + ) + logger.debug("used_keyset {}".format(pprint.pformat(used_keyset))) + logger.debug( + "used_keyset_inds {}".format(pprint.pformat(used_keyset_inds)) + ) + logger.debug("used_tuples {}".format(pprint.pformat(used_tuples))) + + # this is the set of tuples that we want to keep, but need to be reordered + used_tuples_to_be_reordered = set( + list(zip(*[squished_used_variants[k] for k in used_keyset])) + ) + logger.debug( + "used_tuples_to_be_reordered {}".format( + pprint.pformat(used_tuples_to_be_reordered) + ) + ) + + # we double check the logic above by looking to ensure everything in + # the squished_used_variants + # is in the squished_input_variants + used_tuples_set = set(used_tuples) + logger.debug( + "are all used tuples in input tuples? %s", + all( + used_tuple in used_tuples_set + for used_tuple in used_tuples_to_be_reordered + ), + ) + + # now we do the final rdering + final_used_tuples = tuple( + [tup for tup in used_tuples if tup in used_tuples_to_be_reordered] + ) + logger.debug( + "final_used_tuples {}".format(pprint.pformat(final_used_tuples)) + ) + + # now we reconstruct the list of values per key and replace in used_key_values + # we keep only keys in all_used_vars + for i, k in enumerate(used_keyset): + if k in all_used_vars: + used_key_values[k] = [tup[i] for tup in final_used_tuples] + + # finally, we handle the rest of the keys that are not zipped + for k, v in squished_used_variants.items(): + if k in all_used_vars and k not in zipped_keys: + used_key_values[k] = v + + logger.debug( + "post input reorder used_key_values {}".format( + pprint.pformat(used_key_values) + ) + ) + + return used_key_values + + def _collapse_subpackage_variants( list_of_metas, root_path, platform, arch, forge_config ): @@ -340,7 +454,9 @@ def _collapse_subpackage_variants( # smithy CI support scripts # future MPI variants have to be added here if "mpi" in all_used_vars: - all_used_vars.update(["mpich", "openmpi"]) + all_used_vars.update( + ["mpich", "openmpi", "msmpi", "mpi_serial", "impi"] + ) all_variants.update( conda_build.utils.HashableDict(v) for v in meta.config.variants ) @@ -357,6 +473,10 @@ def _collapse_subpackage_variants( if "target_platform" in all_used_vars: top_level_loop_vars.add("target_platform") + logger.debug( + "initial all_used_vars {}".format(pprint.pformat(all_used_vars)) + ) + # this is the initial collection of all variants before we discard any. "Squishing" # them is necessary because the input form is already broken out into one matrix # configuration per item, and we want a single dict, with each key representing many values @@ -368,10 +488,23 @@ def _collapse_subpackage_variants( squished_used_variants = ( conda_build.variants.list_of_dicts_to_dict_of_lists(list(all_variants)) ) + logger.debug( + "squished_input_variants {}".format( + pprint.pformat(squished_input_variants) + ) + ) + logger.debug( + "squished_used_variants {}".format( + pprint.pformat(squished_used_variants) + ) + ) # these are variables that only occur in the top level, and thus won't show up as loops in the # above collection of all variants. We need to transfer them from the input_variants. preserve_top_level_loops = set(top_level_loop_vars) - set(all_used_vars) + logger.debug( + "preserve_top_level_loops {}".format(preserve_top_level_loops) + ) # Add in some variables that should always be preserved always_keep_keys = { @@ -401,15 +534,19 @@ def _collapse_subpackage_variants( all_used_vars.update(always_keep_keys) all_used_vars.update(top_level_vars) - used_key_values = { - key: squished_input_variants[key] - for key in all_used_vars - if key in squished_input_variants - } + logger.debug( + "final all_used_vars {}".format(pprint.pformat(all_used_vars)) + ) + logger.debug("top_level_vars {}".format(pprint.pformat(top_level_vars))) + logger.debug( + "top_level_loop_vars {}".format(pprint.pformat(top_level_loop_vars)) + ) - for k, v in squished_used_variants.items(): - if k in all_used_vars: - used_key_values[k] = v + used_key_values = _get_used_key_values_by_input_order( + squished_input_variants, + squished_used_variants, + all_used_vars, + ) for k in preserve_top_level_loops: used_key_values[k] = squished_input_variants[k] @@ -433,8 +570,9 @@ def _collapse_subpackage_variants( _trim_unused_zip_keys(used_key_values) _trim_unused_pin_run_as_build(used_key_values) - logger.debug("top_level_loop_vars {}".format(top_level_loop_vars)) - logger.debug("used_key_values {}".format(used_key_values)) + logger.debug( + "final used_key_values {}".format(pprint.pformat(used_key_values)) + ) return ( break_up_top_level_values(top_level_loop_vars, used_key_values), @@ -501,6 +639,9 @@ def dump_subspace_config_files( arch, forge_config, ) + logger.debug( + "collapsed subspace config files: {}".format(pprint.pformat(configs)) + ) # get rid of the special object notation in the yaml file for objects that we dump yaml.add_representer(set, yaml.representer.SafeRepresenter.represent_list) @@ -531,6 +672,9 @@ def dump_subspace_config_files( os.makedirs(out_folder) config = finalize_config(config, platform, arch, forge_config) + logger.debug( + "finalized config file: {}".format(pprint.pformat(config)) + ) with write_file(out_path) as f: yaml.dump(config, f, default_flow_style=False) @@ -2062,17 +2206,17 @@ def _load_forge_config(forge_dir, exclusive_config_file, forge_yml=None): return config -def get_most_recent_version(name): +def get_most_recent_version(name, include_broken=False): from conda_build.conda_interface import VersionOrder request = requests.get( "https://api.anaconda.org/package/conda-forge/" + name ) request.raise_for_status() - - pkg = max( - request.json()["files"], key=lambda x: VersionOrder(x["version"]) - ) + files = request.json()["files"] + if not include_broken: + files = [f for f in files if "broken" not in f.get("labels", ())] + pkg = max(files, key=lambda x: VersionOrder(x["version"])) PackageRecord = namedtuple("PackageRecord", ["name", "version", "url"]) return PackageRecord(name, pkg["version"], "https:" + pkg["download_url"]) @@ -2249,6 +2393,7 @@ def clear_scripts(forge_dir): "run_docker_build.sh", "build_steps.sh", "run_osx_build.sh", + "run_win_build.bat", "create_conda_build_artifacts.bat", "create_conda_build_artifacts.sh", ]: diff --git a/conda_smithy/data/conda-forge.yml b/conda_smithy/data/conda-forge.yml index ee0e24553..76f33c673 100644 --- a/conda_smithy/data/conda-forge.yml +++ b/conda_smithy/data/conda-forge.yml @@ -66,7 +66,7 @@ conda_build: error_overlinking: false pkg_format: 2 zstd_compression_level: 16 -conda_build_tool: mambabuild +conda_build_tool: conda-build conda_forge_output_validation: false conda_install_tool: mamba conda_solver: libmamba @@ -133,6 +133,7 @@ provider: recipe_dir: recipe remote_ci_setup: - conda-forge-ci-setup=4 +- conda-build>=24.1 secrets: [] shellcheck: enabled: false diff --git a/conda_smithy/feedstock_content/build-locally.py b/conda_smithy/feedstock_content/build-locally.py index 3f4b7a794..e0d408d07 100755 --- a/conda_smithy/feedstock_content/build-locally.py +++ b/conda_smithy/feedstock_content/build-locally.py @@ -64,8 +64,9 @@ def verify_config(ns): elif ns.config.startswith("osx"): if "OSX_SDK_DIR" not in os.environ: raise RuntimeError( - "Need OSX_SDK_DIR env variable set. Run 'export OSX_SDK_DIR=SDKs' " - "to download the SDK automatically to 'SDKs/MacOSX.sdk'. " + "Need OSX_SDK_DIR env variable set. Run 'export OSX_SDK_DIR=$PWD/SDKs' " + "to download the SDK automatically to '$PWD/SDKs/MacOSX.sdk'. " + "Note: OSX_SDK_DIR must be set to an absolute path. " "Setting this variable implies agreement to the licensing terms of the SDK by Apple." ) diff --git a/conda_smithy/lint_recipe.py b/conda_smithy/lint_recipe.py index ea95ceb55..878af85e6 100644 --- a/conda_smithy/lint_recipe.py +++ b/conda_smithy/lint_recipe.py @@ -126,6 +126,24 @@ def lint_about_contents(about_section, lints): ) +def find_local_config_file(recipe_dir, filename): + # support + # 1. feedstocks + # 2. staged-recipes with custom conda-forge.yaml in recipe + # 3. staged-recipes + found_filesname = ( + glob(os.path.join(recipe_dir, filename)) + or glob( + os.path.join(recipe_dir, "..", filename), + ) + or glob( + os.path.join(recipe_dir, "..", "..", filename), + ) + ) + + return found_filesname[0] if found_filesname else None + + def lintify_forge_yaml(recipe_dir=None) -> (list, list): if recipe_dir: forge_yaml_filename = ( @@ -416,21 +434,27 @@ def lintify_meta_yaml( ) if recipe_dir: - forge_yaml_filename = ( - glob(os.path.join(recipe_dir, "..", "conda-forge.yml")) - or glob( - os.path.join(recipe_dir, "conda-forge.yml"), - ) - or glob( - os.path.join(recipe_dir, "..", "..", "conda-forge.yml"), - ) + conda_build_config_filename = find_local_config_file( + recipe_dir, "conda_build_config.yaml" ) + + if conda_build_config_filename: + with open(conda_build_config_filename, "r") as fh: + conda_build_config_keys = set(get_yaml().load(fh).keys()) + else: + conda_build_config_keys = set() + + forge_yaml_filename = find_local_config_file( + recipe_dir, "conda-forge.yml" + ) + if forge_yaml_filename: - with open(forge_yaml_filename[0], "r") as fh: + with open(forge_yaml_filename, "r") as fh: forge_yaml = get_yaml().load(fh) else: forge_yaml = {} else: + conda_build_config_keys = set() forge_yaml = {} # 18: noarch doesn't work with selectors for runtime dependencies @@ -456,7 +480,9 @@ def lintify_meta_yaml( in_runreqs = False continue if is_selector_line( - line, allow_platforms=noarch_platforms + line, + allow_platforms=noarch_platforms, + allow_keys=conda_build_config_keys, ): lints.append( "`noarch` packages can't have selectors. If " @@ -714,21 +740,9 @@ def check_pins_build_and_requirements(top_level): shell_scripts = [] if recipe_dir: shell_scripts = glob(os.path.join(recipe_dir, "*.sh")) - # support - # 1. feedstocks - # 2. staged-recipes with custom conda-forge.yaml in recipe - # 3. staged-recipes - forge_yaml = ( - glob(os.path.join(recipe_dir, "..", "conda-forge.yml")) - or glob( - os.path.join(recipe_dir, "conda-forge.yml"), - ) - or glob( - os.path.join(recipe_dir, "..", "..", "conda-forge.yml"), - ) - ) + forge_yaml = find_local_config_file(recipe_dir, "conda-forge.yml") if shell_scripts and forge_yaml: - with open(forge_yaml[0], "r") as fh: + with open(forge_yaml, "r") as fh: code = get_yaml().load(fh) shellcheck_enabled = code.get("shellcheck", {}).get( "enabled", shellcheck_enabled @@ -1006,7 +1020,7 @@ def run_conda_forge_specific(meta, recipe_dir, lints, hints): ) -def is_selector_line(line, allow_platforms=False): +def is_selector_line(line, allow_platforms=False, allow_keys=set()): # Using the same pattern defined in conda-build (metadata.py), # we identify selectors. line = line.rstrip() @@ -1015,13 +1029,17 @@ def is_selector_line(line, allow_platforms=False): return False m = sel_pat.match(line) if m: - if allow_platforms: - nouns = { - w for w in m.group(3).split() if w not in ("not", "and", "or") - } - if nouns.issubset({"win", "linux", "osx", "unix"}): - # the selector only contains (a boolean chain of) platform selectors - return False + nouns = { + w for w in m.group(3).split() if w not in ("not", "and", "or") + } + allowed_nouns = ( + {"win", "linux", "osx", "unix"} if allow_platforms else set() + ) | allow_keys + + if nouns.issubset(allowed_nouns): + # the selector only contains (a boolean chain of) platform selectors + # and/or keys from the conda_build_config.yaml + return False else: return True return False diff --git a/conda_smithy/templates/github-actions.yml.tmpl b/conda_smithy/templates/github-actions.yml.tmpl index 0bf0566a4..04a96e2e5 100644 --- a/conda_smithy/templates/github-actions.yml.tmpl +++ b/conda_smithy/templates/github-actions.yml.tmpl @@ -84,7 +84,7 @@ jobs: {%- endif %} - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 {%- if clone_depth is not none %} with: fetch-depth: {{ clone_depth }} diff --git a/conda_smithy/utils.py b/conda_smithy/utils.py index b0be1a656..c20b88886 100644 --- a/conda_smithy/utils.py +++ b/conda_smithy/utils.py @@ -93,10 +93,14 @@ def render_meta_yaml(text): env.globals.update( dict( compiler=lambda x: x + "_compiler_stub", + stdlib=lambda x: x + "_stdlib_stub", pin_subpackage=stub_subpackage_pin, pin_compatible=stub_compatible_pin, cdt=lambda *args, **kwargs: "cdt_stub", load_file_regex=lambda *args, **kwargs: defaultdict(lambda: ""), + load_file_data=lambda *args, **kwargs: defaultdict(lambda: ""), + load_setup_py_data=lambda *args, **kwargs: defaultdict(lambda: ""), + load_str_data=lambda *args, **kwargs: defaultdict(lambda: ""), datetime=datetime, time=time, target_platform="linux-64", diff --git a/tests/recipes/noarch_selector_variants/conda_build_config.yaml b/tests/recipes/noarch_selector_variants/conda_build_config.yaml new file mode 100644 index 000000000..23fd94475 --- /dev/null +++ b/tests/recipes/noarch_selector_variants/conda_build_config.yaml @@ -0,0 +1,3 @@ +python_geq_310: + - False + - True diff --git a/tests/recipes/noarch_selector_variants/meta.yaml b/tests/recipes/noarch_selector_variants/meta.yaml new file mode 100644 index 000000000..f5e25e59d --- /dev/null +++ b/tests/recipes/noarch_selector_variants/meta.yaml @@ -0,0 +1,64 @@ +{% set version = "1.34.41" %} +{% set hash = "3a6943c75a0d292ab6e008bce58ee6503776969479f991f5ad03a5d877af29ae" %} + +package: + name: botocore + version: {{ version }} + +source: + url: https://pypi.org/packages/source/b/botocore/botocore-{{ version }}.tar.gz + sha256: {{ hash }} + +build: + number: 1 + noarch: python + script: {{ PYTHON }} -m pip install . --no-deps --ignore-installed --no-cache-dir -vvv + string: pygeq38_{{ PKG_HASH }}_{{ PKG_BUILDNUM }} # [not python_geq_310] + string: pygeq310_{{ PKG_HASH }}_{{ PKG_BUILDNUM }} # [python_geq_310] + +requirements: + build: + - cross-python_{{ target_platform }} # [build_platform != target_platform] + - python # [build_platform != target_platform] + host: + - python + - pip + run: + - python >=3.8 # [not python_geq_310] + - python >=3.10 # [python_geq_310] + - jmespath >=0.7.1,<2.0.0 + - python-dateutil >=2.1,<3.0.0 + - urllib3 >=1.25.4,<1.27 # [not python_geq_310] + - urllib3 >=1.25.4,<2.1 # [python_geq_310] + +test: + imports: + - botocore + - botocore.docs + - botocore.vendored + - botocore.vendored.requests + - botocore.vendored.requests.packages + - botocore.vendored.requests.packages.urllib3 + commands: + - pip check + requires: + - pip + +about: + home: http://aws.amazon.com/sdk-for-python/ + license_file: LICENSE.txt + license: Apache-2.0 + license_url: http://aws.amazon.com/apache2.0/ + license_family: Apache + summary: Low-level, data-driven core of boto 3. + description: | + Provides the core functionality of Boto3, the AWS SDK for Python + dev_url: https://github.com/boto/botocore + doc_url: https://botocore.readthedocs.io/en/latest/ + +extra: + recipe-maintainers: + - hajapy + - tkelman + - ocefpaf + - '0xbe7a' diff --git a/tests/recipes/variant_mismatches/conda_build_config.yaml b/tests/recipes/variant_mismatches/conda_build_config.yaml new file mode 100644 index 000000000..bd31d1a9b --- /dev/null +++ b/tests/recipes/variant_mismatches/conda_build_config.yaml @@ -0,0 +1,13 @@ +a: + - 1 + - 2 + - 2 +b: + - 1 + - 2 + - 1 + +zip_keys: + - + - a + - b diff --git a/tests/recipes/variant_mismatches/meta.yaml b/tests/recipes/variant_mismatches/meta.yaml new file mode 100644 index 000000000..d84a64d2f --- /dev/null +++ b/tests/recipes/variant_mismatches/meta.yaml @@ -0,0 +1,8 @@ +package: + name: test-variant-mismatches + version: 1.0 + +build: + skip: true # [not linux64 or a != b] + +about: {} diff --git a/tests/test_cli.py b/tests/test_cli.py index 47b8d73c4..a4d09d3e0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -328,3 +328,45 @@ def test_regenerate(py_recipe, testing_workdir): # one py ver, no target_platform (tests that older configs don't stick around) assert len(os.listdir(matrix_folder)) == 4 + + +def test_render_variant_mismatches(testing_workdir): + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers() + init_obj = cli.Init(subparser) + regen_obj = cli.Regenerate(subparser) + _thisdir = os.path.abspath(os.path.dirname(__file__)) + recipe = os.path.join(_thisdir, "recipes", "variant_mismatches") + feedstock_dir = os.path.join( + testing_workdir, "test-variant-mismatches-feedstock" + ) + args = InitArgs( + recipe_directory=recipe, + feedstock_directory=feedstock_dir, + temporary_directory=os.path.join(recipe, "temp"), + ) + init_obj(args) + # Ignore conda-forge-pinning for this test, as the test relies on conda-forge-pinning + # not being present + args = RegenerateArgs( + feedstock_directory=feedstock_dir, + feedstock_config=None, + commit=False, + no_check_uptodate=True, + exclusive_config_file="recipe/conda_build_config.yaml", + check=False, + temporary_directory=os.path.join(recipe, "temp"), + ) + regen_obj(args) + + matrix_dir = os.path.join(feedstock_dir, ".ci_support") + cfgs = os.listdir(matrix_dir) + assert len(cfgs) == 3 # readme + 2 configs + + for _cfg in cfgs: + if _cfg == "README": + continue + cfg = os.path.join(matrix_dir, _cfg) + with open(cfg, "r") as f: + data = yaml.safe_load(f) + assert data["a"] == data["b"] diff --git a/tests/test_configure_feedstock.py b/tests/test_configure_feedstock.py index 497310dd5..04f4f538d 100644 --- a/tests/test_configure_feedstock.py +++ b/tests/test_configure_feedstock.py @@ -879,7 +879,7 @@ def test_conda_build_tools(config_yaml): assert ( "build_with_mambabuild" not in cfg ) # superseded by conda_build_tool=mambabuild - assert cfg["conda_build_tool"] == "mambabuild" # current default + assert cfg["conda_build_tool"] == "conda-build" # current default # legacy compatibility config with open(os.path.join(config_yaml, "conda-forge.yml")) as fp: @@ -948,3 +948,935 @@ def test_remote_ci_setup(config_yaml): '"py-lief<0.12"', ] ) + + +@pytest.mark.parametrize( + "squished_input_variants,squished_used_variants,all_used_vars,used_key_values", + [ + ( + dict( + [ + ( + "extend_keys", + { + "extend_keys", + "ignore_build_only_deps", + "ignore_version", + "pin_run_as_build", + }, + ), + ("ignore_build_only_deps", {"python", "numpy"}), + ( + "pin_run_as_build", + dict( + [ + ( + "python", + {"max_pin": "x.x", "min_pin": "x.x"}, + ), + ( + "r-base", + {"max_pin": "x.x", "min_pin": "x.x"}, + ), + ("flann", {"max_pin": "x.x.x"}), + ("graphviz", {"max_pin": "x"}), + ("libsvm", {"max_pin": "x"}), + ("netcdf-cxx4", {"max_pin": "x.x"}), + ("occt", {"max_pin": "x.x"}), + ("poppler", {"max_pin": "x.x"}), + ("vlfeat", {"max_pin": "x.x.x"}), + ] + ), + ), + ("glew", ["2.1"]), + ("pango", ["1.50"]), + ("libgoogle_cloud_compute_devel", ["2.21"]), + ("dav1d", ["1.2.1"]), + ("lzo", ["2"]), + ("pybind11_abi", ["4"]), + ("sqlite", ["3"]), + ("nlopt", ["2.7"]), + ("aws_checksums", ["0.1.18"]), + ("aws_c_mqtt", ["0.10.2"]), + ("aws_c_s3", ["0.5.1"]), + ("libaec", ["1"]), + ("pari", ["2.15.* *_pthread"]), + ("libgoogle_cloud_devel", ["2.21"]), + ("libjpeg_turbo", ["3"]), + ("libblitz", ["1.0.2"]), + ("ptscotch", ["7.0.4"]), + ("openslide", ["4"]), + ("libdeflate", ["1.19"]), + ("gf2x", ["1.3"]), + ("cuda_compiler_version_min", ["11.2"]), + ("aws_c_event_stream", ["0.4.2"]), + ("arb", ["2.23"]), + ("expat", ["2"]), + ("bzip2", ["1"]), + ("target_goexe", [""]), + ("VERBOSE_AT", ["V=1"]), + ("cran_mirror", ["https://cran.r-project.org"]), + ("aws_c_compression", ["0.2.18"]), + ("libsvm", ["332"]), + ("uhd", ["4.6.0"]), + ("libcrc32c", ["1.1"]), + ("libtensorflow_cc", ["2.15"]), + ("msgpack_cxx", ["6"]), + ("libunwind", ["1.6"]), + ("libv8", ["8.9.83"]), + ("libpq", ["16"]), + ("lmdb", ["0.9.29"]), + ("root_base", ["6.28.10", "6.30.2"]), + ("geotiff", ["1.7.1"]), + ("google_cloud_cpp", ["2.21"]), + ("mpfr", ["4"]), + ("gmp", ["6"]), + ("harfbuzz", ["8"]), + ("_libgcc_mutex", ["0.1 conda_forge"]), + ("wxwidgets", ["3.2"]), + ("svt_av1", ["1.8.0"]), + ("libcurl", ["8"]), + ("liblapack", ["3.9 *netlib"]), + ("libmatio_cpp", ["0.2.3"]), + ("libvips", ["8"]), + ("aws_sdk_cpp", ["1.11.267"]), + ("proj", ["9.3.1"]), + ("libgoogle_cloud_all_devel", ["2.21"]), + ("libgoogle_cloud_aiplatform_devel", ["2.21"]), + ("libpcap", ["1.10"]), + ("pulseaudio_client", ["16.1"]), + ("ffmpeg", ["6"]), + ("graphviz", ["9"]), + ("cudnn", ["8"]), + ("x264", ["1!164.*"]), + ("libcint", ["5.5"]), + ("s2n", ["1.4.4"]), + ("sdl2_ttf", ["2"]), + ("pugixml", ["1.14"]), + ("flatbuffers", ["23.5.26"]), + ("krb5", ["1.20"]), + ("ntl", ["11.4.3"]), + ("libev", ["4.33"]), + ("aws_c_io", ["0.14.4"]), + ("target_gobin", ["${PREFIX}/bin/"]), + ("cxx_compiler", ["gxx"]), + ("ccr", ["1.3"]), + ("postgresql", ["16"]), + ("antic", ["0.2"]), + ("gst_plugins_base", ["1.22"]), + ("rdma_core", ["49"]), + ("libssh2", ["1"]), + ("libtiff", ["4.6"]), + ("kealib", ["1.5"]), + ("mpich", ["4"]), + ("spdlog", ["1.12"]), + ("netcdf_fortran", ["4.6"]), + ("elfutils", ["0.190"]), + ("gsl", ["2.7"]), + ("eclib", ["20231211"]), + ("tiledb", ["2.20"]), + ("libhugetlbfs", ["2"]), + ("nss", ["3"]), + ("netcdf_cxx4", ["4.3"]), + ("pcl", ["1.13.1"]), + ("sox", ["14.4.2"]), + ("superlu_dist", ["8"]), + ("libgoogle_cloud_dialogflow_es_devel", ["2.21"]), + ("attr", ["2.5"]), + ("log4cxx", ["1.2.0"]), + ("aws_c_sdkutils", ["0.1.15"]), + ("libxml2", ["2"]), + ("libsentencepiece", ["0.1.99"]), + ("tbb_devel", ["2021"]), + ("jsoncpp", ["1.9.5"]), + ("msgpack_c", ["6"]), + ("libzip", ["1"]), + ("mkl", ["2023"]), + ("giflib", ["5.2"]), + ("fortran_compiler", ["gfortran"]), + ("libboost_python_devel", ["1.82"]), + ("dbus", ["1"]), + ("libwebp_base", ["1"]), + ("libflint", ["2.9"]), + ("libsoup", ["3"]), + ("libgoogle_cloud_bigtable_devel", ["2.21"]), + ("abseil_cpp", ["20220623.0"]), + ("librdkafka", ["2.2"]), + ("starlink_ast", ["9.2.7"]), + ("lerc", ["4"]), + ("davix", ["0.8"]), + ("libxsmm", ["1"]), + ("poppler", ["23.07"]), + ("dcap", ["2.47"]), + ("gnuradio_core", ["3.10.9"]), + ("gsoap", ["2.8.123"]), + ("fmt", ["10"]), + ("libopencv", ["4.9.0"]), + ("aws_c_http", ["0.8.1"]), + ("lua", ["5"]), + ("qt", ["5.15"]), + ("pcre", ["8"]), + ("ldas_tools_framecpp", ["2.9"]), + ("ruby", ["2.5", "2.6"]), + ("libgoogle_cloud_policytroubleshooter_devel", ["2.21"]), + ("libdap4", ["3.20.6"]), + ("mimalloc", ["2.1.2"]), + ("coin_or_osi", ["0.108"]), + ("gdk_pixbuf", ["2"]), + ("target_goarch", ["amd64"]), + ("assimp", ["5.3.1"]), + ("flann", ["1.9.2"]), + ("gct", ["6.2.1629922860"]), + ("aws_c_auth", ["0.7.16"]), + ("pyqtchart", ["5.15"]), + ("coin_or_clp", ["1.17"]), + ("grpc_cpp", ["1.52"]), + ("libgdal", ["3.8"]), + ("volk", ["3.1"]), + ("curl", ["8"]), + ("geos", ["3.12.1"]), + ("zstd", ["1.5"]), + ("libabseil", ["20240116"]), + ("blas_impl", ["openblas", "mkl", "blis"]), + ("openblas", ["0.3.*"]), + ("zlib_ng", ["2.0"]), + ("liblapacke", ["3.9 *netlib"]), + ("libframel", ["8.41"]), + ("postgresql_plpython", ["16"]), + ("libgoogle_cloud", ["2.21"]), + ("gstreamer", ["1.22"]), + ("lcms", ["2"]), + ("libuuid", ["2"]), + ("coin_or_cgl", ["0.60"]), + ("rust_compiler", ["rust"]), + ("bullet_cpp", ["3.25"]), + ("fftw", ["3"]), + ("tbb", ["2021"]), + ("libsecret", ["0.18"]), + ("libgoogle_cloud_spanner_devel", ["2.21"]), + ("channel_sources", ["conda-forge"]), + ("pcre2", ["10.42"]), + ("glib", ["2"]), + ("google_cloud_cpp_common", ["0.25.0"]), + ("openmpi", ["4"]), + ("ncurses", ["6"]), + ("openh264", ["2.4.1"]), + ("wcslib", ["8"]), + ("soapysdr", ["0.8"]), + ("tinyxml2", ["10"]), + ("libavif", ["1.0.1"]), + ("cairo", ["1"]), + ("icu", ["73"]), + ("libsndfile", ["1.2"]), + ("aom", ["3.7"]), + ("x265", ["3.5"]), + ("jasper", ["4"]), + ("pyqt", ["5.15"]), + ("xrootd", ["5"]), + ("gnutls", ["3.7"]), + ("rocksdb", ["8.0"]), + ("libgit2", ["1.7"]), + ("libgoogle_cloud_oauth2_devel", ["2.21"]), + ("zfp", ["1.0"]), + ("libtorch", ["2.1"]), + ("libarchive", ["3.7"]), + ("freetype", ["2"]), + ("poco", ["1.13.2"]), + ("libthrift", ["0.19.0"]), + ("qt_main", ["5.15"]), + ("libosqp", ["0.6.3"]), + ("ucx", ["1.15.0"]), + ("libgoogle_cloud_automl_devel", ["2.21"]), + ("slepc", ["3.20"]), + ("aws_c_cal", ["0.6.10"]), + ("p11_kit", ["0.24"]), + ("target_platform", ["linux-64"]), + ("libblas", ["3.9 *netlib"]), + ("libgoogle_cloud_bigquery_devel", ["2.21"]), + ("libmicrohttpd", ["1.0"]), + ("mpg123", ["1.32"]), + ("srm_ifce", ["1.24.6"]), + ("petsc", ["3.20"]), + ("libiconv", ["1"]), + ("aws_crt_cpp", ["0.26.2"]), + ("console_bridge", ["1.0"]), + ("libgoogle_cloud_storage_devel", ["2.21"]), + ("lz4_c", ["1.9.3"]), + ("mumps_mpi", ["5.6.2"]), + ("coincbc", ["2.10"]), + ("orc", ["1.9.2"]), + ("libcblas", ["3.9 *netlib"]), + ("readline", ["8"]), + ("nodejs", ["18", "20"]), + ("glpk", ["5.0"]), + ("imath", ["3.1.9"]), + ("gdal", ["3.8"]), + ("nettle", ["3.9"]), + ("qtkeychain", ["0.14"]), + ("c_ares", ["1"]), + ("libduckdb_devel", ["0.9.2"]), + ("occt", ["7.7.2"]), + ("qt6_main", ["6.6"]), + ("perl", ["5.32.1"]), + ("libidn2", ["2"]), + ("pyqtwebengine", ["5.15"]), + ("coin_or_utils", ["2.11"]), + ("libopenvino_dev", ["2023.3.0"]), + ("googleapis_cpp", ["0.10"]), + ("libwebp", ["1"]), + ("coin_or_cbc", ["2.10"]), + ("channel_targets", ["conda-forge main"]), + ("sdl2_image", ["2"]), + ("sdl2_mixer", ["2"]), + ("vtk", ["9.2.6"]), + ("librsvg", ["2"]), + ("jpeg", ["9"]), + ("hdf4", ["4.2.15"]), + ("pytorch", ["2.1"]), + ("libintervalxt", ["3"]), + ("thrift_cpp", ["0.19.0"]), + ("libgoogle_cloud_discoveryengine_devel", ["2.21"]), + ("arpack", ["3.8"]), + ("libtensorflow", ["2.15"]), + ("vlfeat", ["0.9.21"]), + ("snappy", ["1"]), + ("capnproto", ["0.10.2"]), + ("libmatio", ["1.5.26"]), + ("c_compiler", ["gcc"]), + ("cgo_compiler", ["go-cgo"]), + ("ipopt", ["3.14.14"]), + ("libiio", ["0"]), + ("singular", ["4.3.2.p8"]), + ("libhwy", ["1.0"]), + ("zeromq", ["4.3.5"]), + ("pixman", ["0"]), + ("libspatialindex", ["1.9.3"]), + ("libffi", ["3.4"]), + ("nspr", ["4"]), + ("petsc4py", ["3.20"]), + ("libsqlite", ["3"]), + ("pulseaudio", ["16.1"]), + ("libopentelemetry_cpp", ["1.14"]), + ("libptscotch", ["7.0.4"]), + ("libraw", ["0.21"]), + ("libgoogle_cloud_dlp_devel", ["2.21"]), + ("libgoogle_cloud_iam_devel", ["2.21"]), + ("openjpeg", ["2"]), + ("libhwloc", ["2.9.1"]), + ("r_base", ["4.2", "4.3"]), + ("gfal2", ["2.21"]), + ("libexactreal", ["4"]), + ("mkl_devel", ["2023"]), + ("zlib", ["1.2"]), + ("libmed", ["4.1"]), + ("fontconfig", ["2"]), + ("xz", ["5"]), + ("suitesparse", ["5"]), + ("libgoogle_cloud_speech_devel", ["2.21"]), + ("sdl2_net", ["2"]), + ("slepc4py", ["3.20"]), + ("tk", ["8.6"]), + ("libpng", ["1.6"]), + ("libssh", ["0.10"]), + ("urdfdom", ["3.1"]), + ("metis", ["5.1.0"]), + ("libnetcdf", ["4.9.2"]), + ("sdl2", ["2"]), + ("target_goos", ["linux"]), + ("cfitsio", ["4.3.0"]), + ("pulseaudio_daemon", ["16.1"]), + ("mumps_seq", ["5.6.2"]), + ("hdf5", ["1.14.3"]), + ("nccl", ["2"]), + ("libevent", ["2.1.12"]), + ("exiv2", ["0.27"]), + ("libeantic", ["2"]), + ("alsa_lib", ["1.2.10"]), + ("glog", ["0.7"]), + ("libscotch", ["7.0.4"]), + ("cutensor", ["2"]), + ("json_c", ["0.17"]), + ("aws_c_common", ["0.9.13"]), + ("isl", ["0.26"]), + ("openssl", ["3"]), + ("xerces_c", ["3.2"]), + ("cpu_optimization_target", ["nocona"]), + ("libflatsurf", ["3"]), + ("libkml", ["1.3"]), + ("gflags", ["2.2"]), + ("libboost_devel", ["1.82"]), + ("libgoogle_cloud_dialogflow_cx_devel", ["2.21"]), + ("VERBOSE_CM", ["VERBOSE=1"]), + ("openexr", ["3.2"]), + ("scotch", ["7.0.4"]), + ("libgoogle_cloud_pubsub_devel", ["2.21"]), + ("libabseil_static", ["20220623.0"]), + ("go_compiler", ["go-nocgo"]), + ("re2", ["2023.06.02"]), + ("tensorflow", ["2.15"]), + ("libarrow_all", ("12", "14", "13", "15")), + ("arrow_cpp", ("12", "14", "13", "15")), + ("libarrow", ("12", "14", "13", "15")), + ("c_compiler_version", ("12", "11", "10", "12")), + ("fortran_compiler_version", ("12", "11", "10", "12")), + ("cdt_name", ("cos7", "cos7", "cos7", "cos6")), + ( + "docker_image", + ( + "quay.io/condaforge/linux-anvil-cos7-x86_64", + "quay.io/condaforge/linux-anvil-cuda:11.8", + "quay.io/condaforge/linux-anvil-cuda:11.2", + "quay.io/condaforge/linux-anvil-cos7-x86_64", + ), + ), + ("cuda_compiler", ("cuda-nvcc", "nvcc", "nvcc", "None")), + ("cxx_compiler_version", ("12", "11", "10", "12")), + ( + "cuda_compiler_version", + ("12.0", "11.8", "11.2", "None"), + ), + ("libgrpc", ("1.61",)), + ("libprotobuf", ("4.25.2",)), + ("c_stdlib_version", ("2.12",)), + ("c_stdlib", ("sysroot",)), + ( + "python", + ( + "3.9.* *_cpython", + "3.10.* *_cpython", + "3.11.* *_cpython", + "3.8.* *_cpython", + "3.12.* *_cpython", + ), + ), + ("numpy", ("1.22", "1.22", "1.23", "1.22", "1.26")), + ( + "python_impl", + ( + "cpython", + "cpython", + "cpython", + "cpython", + "cpython", + ), + ), + ( + "zip_keys", + [ + ["python", "numpy", "python_impl"], + ["arrow_cpp", "libarrow", "libarrow_all"], + ["c_stdlib", "c_stdlib_version"], + [ + "c_compiler_version", + "cxx_compiler_version", + "fortran_compiler_version", + "cuda_compiler", + "cuda_compiler_version", + "cdt_name", + "docker_image", + ], + ["libgrpc", "libprotobuf"], + ], + ), + ] + ), + dict( + [ + ( + "extend_keys", + { + "extend_keys", + "ignore_build_only_deps", + "ignore_version", + "pin_run_as_build", + }, + ), + ("ignore_build_only_deps", {"python", "numpy"}), + ( + "pin_run_as_build", + dict( + [ + ( + "python", + {"max_pin": "x.x", "min_pin": "x.x"}, + ), + ( + "r-base", + {"max_pin": "x.x", "min_pin": "x.x"}, + ), + ("flann", {"max_pin": "x.x.x"}), + ("graphviz", {"max_pin": "x"}), + ("libsvm", {"max_pin": "x"}), + ("netcdf-cxx4", {"max_pin": "x.x"}), + ("occt", {"max_pin": "x.x"}), + ("poppler", {"max_pin": "x.x"}), + ("vlfeat", {"max_pin": "x.x.x"}), + ] + ), + ), + ("glew", ["2.1"]), + ("pango", ["1.50"]), + ("libgoogle_cloud_compute_devel", ["2.21"]), + ("dav1d", ["1.2.1"]), + ("lzo", ["2"]), + ("pybind11_abi", ["4"]), + ("sqlite", ["3"]), + ("nlopt", ["2.7"]), + ("aws_checksums", ["0.1.18"]), + ("aws_c_mqtt", ["0.10.2"]), + ("aws_c_s3", ["0.5.1"]), + ("libaec", ["1"]), + ("pari", ["2.15.* *_pthread"]), + ("libgoogle_cloud_devel", ["2.21"]), + ("libjpeg_turbo", ["3"]), + ("libblitz", ["1.0.2"]), + ("ptscotch", ["7.0.4"]), + ("openslide", ["4"]), + ("libdeflate", ["1.19"]), + ("gf2x", ["1.3"]), + ("cuda_compiler_version_min", ["11.2"]), + ("aws_c_event_stream", ["0.4.2"]), + ("arb", ["2.23"]), + ("expat", ["2"]), + ("bzip2", ["1"]), + ("target_goexe", [""]), + ("VERBOSE_AT", ["V=1"]), + ("cran_mirror", ["https://cran.r-project.org"]), + ("aws_c_compression", ["0.2.18"]), + ("libsvm", ["332"]), + ("uhd", ["4.6.0"]), + ("libcrc32c", ["1.1"]), + ("libtensorflow_cc", ["2.15"]), + ("msgpack_cxx", ["6"]), + ("libunwind", ["1.6"]), + ("libv8", ["8.9.83"]), + ("libpq", ["16"]), + ("lmdb", ["0.9.29"]), + ("root_base", ["6.28.10", "6.30.2"]), + ("geotiff", ["1.7.1"]), + ("google_cloud_cpp", ["2.21"]), + ("mpfr", ["4"]), + ("gmp", ["6"]), + ("harfbuzz", ["8"]), + ("_libgcc_mutex", ["0.1 conda_forge"]), + ("wxwidgets", ["3.2"]), + ("svt_av1", ["1.8.0"]), + ("libcurl", ["8"]), + ("liblapack", ["3.9 *netlib"]), + ("libmatio_cpp", ["0.2.3"]), + ("libvips", ["8"]), + ("aws_sdk_cpp", ["1.11.267"]), + ("proj", ["9.3.1"]), + ("libgoogle_cloud_all_devel", ["2.21"]), + ("libgoogle_cloud_aiplatform_devel", ["2.21"]), + ("libpcap", ["1.10"]), + ("pulseaudio_client", ["16.1"]), + ("ffmpeg", ["6"]), + ("graphviz", ["9"]), + ("cudnn", ["8"]), + ("x264", ["1!164.*"]), + ("libcint", ["5.5"]), + ("s2n", ["1.4.4"]), + ("sdl2_ttf", ["2"]), + ("pugixml", ["1.14"]), + ("flatbuffers", ["23.5.26"]), + ("krb5", ["1.20"]), + ("ntl", ["11.4.3"]), + ("libev", ["4.33"]), + ("aws_c_io", ["0.14.4"]), + ("target_gobin", ["${PREFIX}/bin/"]), + ("cxx_compiler", ["gxx"]), + ("ccr", ["1.3"]), + ("postgresql", ["16"]), + ("antic", ["0.2"]), + ("gst_plugins_base", ["1.22"]), + ("rdma_core", ["49"]), + ("libssh2", ["1"]), + ("libtiff", ["4.6"]), + ("kealib", ["1.5"]), + ("mpich", ["4"]), + ("spdlog", ["1.12"]), + ("netcdf_fortran", ["4.6"]), + ("elfutils", ["0.190"]), + ("gsl", ["2.7"]), + ("eclib", ["20231211"]), + ("tiledb", ["2.20"]), + ("libhugetlbfs", ["2"]), + ("nss", ["3"]), + ("netcdf_cxx4", ["4.3"]), + ("pcl", ["1.13.1"]), + ("sox", ["14.4.2"]), + ("superlu_dist", ["8"]), + ("libgoogle_cloud_dialogflow_es_devel", ["2.21"]), + ("attr", ["2.5"]), + ("log4cxx", ["1.2.0"]), + ("aws_c_sdkutils", ["0.1.15"]), + ("libxml2", ["2"]), + ("libsentencepiece", ["0.1.99"]), + ("tbb_devel", ["2021"]), + ("jsoncpp", ["1.9.5"]), + ("msgpack_c", ["6"]), + ("libzip", ["1"]), + ("mkl", ["2023"]), + ("giflib", ["5.2"]), + ("fortran_compiler", ["gfortran"]), + ("libboost_python_devel", ["1.82"]), + ("dbus", ["1"]), + ("libwebp_base", ["1"]), + ("libflint", ["2.9"]), + ("libsoup", ["3"]), + ("libgoogle_cloud_bigtable_devel", ["2.21"]), + ("abseil_cpp", ["20220623.0"]), + ("librdkafka", ["2.2"]), + ("starlink_ast", ["9.2.7"]), + ("lerc", ["4"]), + ("davix", ["0.8"]), + ("libxsmm", ["1"]), + ("poppler", ["23.07"]), + ("dcap", ["2.47"]), + ("gnuradio_core", ["3.10.9"]), + ("gsoap", ["2.8.123"]), + ("fmt", ["10"]), + ("libopencv", ["4.9.0"]), + ("aws_c_http", ["0.8.1"]), + ("lua", ["5"]), + ("qt", ["5.15"]), + ("pcre", ["8"]), + ("ldas_tools_framecpp", ["2.9"]), + ("ruby", ["2.6", "2.5"]), + ("libgoogle_cloud_policytroubleshooter_devel", ["2.21"]), + ("libdap4", ["3.20.6"]), + ("mimalloc", ["2.1.2"]), + ("coin_or_osi", ["0.108"]), + ("gdk_pixbuf", ["2"]), + ("target_goarch", ["amd64"]), + ("assimp", ["5.3.1"]), + ("flann", ["1.9.2"]), + ("gct", ["6.2.1629922860"]), + ("aws_c_auth", ["0.7.16"]), + ("pyqtchart", ["5.15"]), + ("coin_or_clp", ["1.17"]), + ("grpc_cpp", ["1.52"]), + ("libgdal", ["3.8"]), + ("volk", ["3.1"]), + ("curl", ["8"]), + ("geos", ["3.12.1"]), + ("zstd", ["1.5"]), + ("libabseil", ["20240116"]), + ("blas_impl", ["openblas", "mkl", "blis"]), + ("openblas", ["0.3.*"]), + ("zlib_ng", ["2.0"]), + ("liblapacke", ["3.9 *netlib"]), + ("libframel", ["8.41"]), + ("postgresql_plpython", ["16"]), + ("libgoogle_cloud", ["2.21"]), + ("gstreamer", ["1.22"]), + ("lcms", ["2"]), + ("libuuid", ["2"]), + ("coin_or_cgl", ["0.60"]), + ("rust_compiler", ["rust"]), + ("bullet_cpp", ["3.25"]), + ("fftw", ["3"]), + ("tbb", ["2021"]), + ("libsecret", ["0.18"]), + ("libgoogle_cloud_spanner_devel", ["2.21"]), + ("channel_sources", ["conda-forge"]), + ("pcre2", ["10.42"]), + ("glib", ["2"]), + ("google_cloud_cpp_common", ["0.25.0"]), + ("openmpi", ["4"]), + ("ncurses", ["6"]), + ("openh264", ["2.4.1"]), + ("wcslib", ["8"]), + ("soapysdr", ["0.8"]), + ("tinyxml2", ["10"]), + ("libavif", ["1.0.1"]), + ("cairo", ["1"]), + ("icu", ["73"]), + ("libsndfile", ["1.2"]), + ("aom", ["3.7"]), + ("x265", ["3.5"]), + ("jasper", ["4"]), + ("pyqt", ["5.15"]), + ("xrootd", ["5"]), + ("gnutls", ["3.7"]), + ("rocksdb", ["8.0"]), + ("libgit2", ["1.7"]), + ("libgoogle_cloud_oauth2_devel", ["2.21"]), + ("zfp", ["1.0"]), + ("libtorch", ["2.1"]), + ("libarchive", ["3.7"]), + ("freetype", ["2"]), + ("poco", ["1.13.2"]), + ("libthrift", ["0.19.0"]), + ("qt_main", ["5.15"]), + ("libosqp", ["0.6.3"]), + ("ucx", ["1.15.0"]), + ("libgoogle_cloud_automl_devel", ["2.21"]), + ("slepc", ["3.20"]), + ("aws_c_cal", ["0.6.10"]), + ("p11_kit", ["0.24"]), + ("target_platform", ["linux-64"]), + ("libblas", ["3.9 *netlib"]), + ("libgoogle_cloud_bigquery_devel", ["2.21"]), + ("libmicrohttpd", ["1.0"]), + ("mpg123", ["1.32"]), + ("srm_ifce", ["1.24.6"]), + ("petsc", ["3.20"]), + ("libiconv", ["1"]), + ("aws_crt_cpp", ["0.26.2"]), + ("console_bridge", ["1.0"]), + ("libgoogle_cloud_storage_devel", ["2.21"]), + ("lz4_c", ["1.9.3"]), + ("mumps_mpi", ["5.6.2"]), + ("coincbc", ["2.10"]), + ("orc", ["1.9.2"]), + ("libcblas", ["3.9 *netlib"]), + ("readline", ["8"]), + ("nodejs", ["18", "20"]), + ("glpk", ["5.0"]), + ("imath", ["3.1.9"]), + ("gdal", ["3.8"]), + ("nettle", ["3.9"]), + ("qtkeychain", ["0.14"]), + ("c_ares", ["1"]), + ("libduckdb_devel", ["0.9.2"]), + ("occt", ["7.7.2"]), + ("qt6_main", ["6.6"]), + ("perl", ["5.32.1"]), + ("libidn2", ["2"]), + ("pyqtwebengine", ["5.15"]), + ("coin_or_utils", ["2.11"]), + ("libopenvino_dev", ["2023.3.0"]), + ("googleapis_cpp", ["0.10"]), + ("libwebp", ["1"]), + ("coin_or_cbc", ["2.10"]), + ("channel_targets", ["conda-forge main"]), + ("sdl2_image", ["2"]), + ("sdl2_mixer", ["2"]), + ("vtk", ["9.2.6"]), + ("librsvg", ["2"]), + ("jpeg", ["9"]), + ("hdf4", ["4.2.15"]), + ("pytorch", ["2.1"]), + ("libintervalxt", ["3"]), + ("thrift_cpp", ["0.19.0"]), + ("libgoogle_cloud_discoveryengine_devel", ["2.21"]), + ("arpack", ["3.8"]), + ("libtensorflow", ["2.15"]), + ("vlfeat", ["0.9.21"]), + ("snappy", ["1"]), + ("capnproto", ["0.10.2"]), + ("libmatio", ["1.5.26"]), + ("c_compiler", ["gcc"]), + ("cgo_compiler", ["go-cgo"]), + ("ipopt", ["3.14.14"]), + ("libiio", ["0"]), + ("singular", ["4.3.2.p8"]), + ("libhwy", ["1.0"]), + ("zeromq", ["4.3.5"]), + ("pixman", ["0"]), + ("libspatialindex", ["1.9.3"]), + ("libffi", ["3.4"]), + ("nspr", ["4"]), + ("petsc4py", ["3.20"]), + ("libsqlite", ["3"]), + ("pulseaudio", ["16.1"]), + ("libopentelemetry_cpp", ["1.14"]), + ("libptscotch", ["7.0.4"]), + ("libraw", ["0.21"]), + ("libgoogle_cloud_dlp_devel", ["2.21"]), + ("libgoogle_cloud_iam_devel", ["2.21"]), + ("openjpeg", ["2"]), + ("libhwloc", ["2.9.1"]), + ("r_base", ["4.2", "4.3"]), + ("gfal2", ["2.21"]), + ("libexactreal", ["4"]), + ("mkl_devel", ["2023"]), + ("zlib", ["1.2"]), + ("libmed", ["4.1"]), + ("fontconfig", ["2"]), + ("xz", ["5"]), + ("suitesparse", ["5"]), + ("libgoogle_cloud_speech_devel", ["2.21"]), + ("sdl2_net", ["2"]), + ("slepc4py", ["3.20"]), + ("tk", ["8.6"]), + ("libpng", ["1.6"]), + ("libssh", ["0.10"]), + ("urdfdom", ["3.1"]), + ("metis", ["5.1.0"]), + ("libnetcdf", ["4.9.2"]), + ("sdl2", ["2"]), + ("target_goos", ["linux"]), + ("cfitsio", ["4.3.0"]), + ("pulseaudio_daemon", ["16.1"]), + ("mumps_seq", ["5.6.2"]), + ("hdf5", ["1.14.3"]), + ("nccl", ["2"]), + ("libevent", ["2.1.12"]), + ("exiv2", ["0.27"]), + ("libeantic", ["2"]), + ("alsa_lib", ["1.2.10"]), + ("glog", ["0.7"]), + ("libscotch", ["7.0.4"]), + ("cutensor", ["2"]), + ("json_c", ["0.17"]), + ("aws_c_common", ["0.9.13"]), + ("isl", ["0.26"]), + ("openssl", ["3"]), + ("xerces_c", ["3.2"]), + ("cpu_optimization_target", ["nocona"]), + ("libflatsurf", ["3"]), + ("libkml", ["1.3"]), + ("gflags", ["2.2"]), + ("libboost_devel", ["1.82"]), + ("libgoogle_cloud_dialogflow_cx_devel", ["2.21"]), + ("VERBOSE_CM", ["VERBOSE=1"]), + ("openexr", ["3.2"]), + ("scotch", ["7.0.4"]), + ("libgoogle_cloud_pubsub_devel", ["2.21"]), + ("libabseil_static", ["20220623.0"]), + ("go_compiler", ["go-nocgo"]), + ("re2", ["2023.06.02"]), + ("tensorflow", ["2.15"]), + ("libarrow_all", ("12", "14", "13", "15")), + ("arrow_cpp", ("12", "14", "13", "15")), + ("libarrow", ("12", "14", "13", "15")), + ("c_compiler_version", ("10", "12")), + ("fortran_compiler_version", ("10", "12")), + ("cdt_name", ("cos7", "cos6")), + ( + "docker_image", + ( + "quay.io/condaforge/linux-anvil-cuda:11.2", + "quay.io/condaforge/linux-anvil-cos7-x86_64", + ), + ), + ("cuda_compiler", ("nvcc", "None")), + ("cxx_compiler_version", ("10", "12")), + ("cuda_compiler_version", ("11.2", "None")), + ("libgrpc", ("1.61",)), + ("libprotobuf", ("4.25.2",)), + ("c_stdlib_version", ("2.12",)), + ("c_stdlib", ("sysroot",)), + ( + "python", + ( + "3.9.* *_cpython", + "3.10.* *_cpython", + "3.11.* *_cpython", + "3.8.* *_cpython", + "3.12.* *_cpython", + ), + ), + ("numpy", ("1.22", "1.22", "1.23", "1.22", "1.26")), + ( + "python_impl", + ( + "cpython", + "cpython", + "cpython", + "cpython", + "cpython", + ), + ), + ( + "zip_keys", + [ + ("arrow_cpp", "libarrow", "libarrow_all"), + ( + "c_compiler_version", + "cxx_compiler_version", + "fortran_compiler_version", + "cuda_compiler", + "cuda_compiler_version", + "cdt_name", + "docker_image", + ), + ("c_stdlib", "c_stdlib_version"), + ("libgrpc", "libprotobuf"), + ("python", "numpy", "python_impl"), + ], + ), + ] + ), + { + "BUILD", + "MACOSX_DEPLOYMENT_TARGET", + "MACOSX_SDK_VERSION", + "build_number_decrement", + "c_compiler", + "c_compiler_version", + "cdt_arch", + "cdt_name", + "channel_sources", + "channel_targets", + "cuda_compiler", + "cuda_compiler_version", + "docker_image", + "macos_machine", + "macos_min_version", + "pin_run_as_build", + "target_platform", + "zip_keys", + }, + { + "c_compiler": ["gcc"], + "c_compiler_version": ["10", "12"], + "cdt_name": ["cos7", "cos6"], + "channel_sources": ["conda-forge"], + "channel_targets": ["conda-forge main"], + "cuda_compiler": ["nvcc", "None"], + "cuda_compiler_version": ["11.2", "None"], + "docker_image": [ + "quay.io/condaforge/linux-anvil-cuda:11.2", + "quay.io/condaforge/linux-anvil-cos7-x86_64", + ], + "pin_run_as_build": dict( + [ + ("python", {"max_pin": "x.x", "min_pin": "x.x"}), + ("r-base", {"max_pin": "x.x", "min_pin": "x.x"}), + ("flann", {"max_pin": "x.x.x"}), + ("graphviz", {"max_pin": "x"}), + ("libsvm", {"max_pin": "x"}), + ("netcdf-cxx4", {"max_pin": "x.x"}), + ("occt", {"max_pin": "x.x"}), + ("poppler", {"max_pin": "x.x"}), + ("vlfeat", {"max_pin": "x.x.x"}), + ] + ), + "target_platform": ["linux-64"], + "zip_keys": [ + ("arrow_cpp", "libarrow", "libarrow_all"), + ( + "c_compiler_version", + "cxx_compiler_version", + "fortran_compiler_version", + "cuda_compiler", + "cuda_compiler_version", + "cdt_name", + "docker_image", + ), + ("c_stdlib", "c_stdlib_version"), + ("libgrpc", "libprotobuf"), + ("python", "numpy", "python_impl"), + ], + }, + ) + ], +) +def test_get_used_key_values_by_input_order( + squished_input_variants, + squished_used_variants, + all_used_vars, + used_key_values, +): + assert ( + cnfgr_fdstk._get_used_key_values_by_input_order( + squished_input_variants, + squished_used_variants, + all_used_vars, + ) + == used_key_values + ) diff --git a/tests/test_lint_recipe.py b/tests/test_lint_recipe.py index b49673b5b..60798757b 100644 --- a/tests/test_lint_recipe.py +++ b/tests/test_lint_recipe.py @@ -680,6 +680,57 @@ def test_jinja_load_file_regex(self): ) lints = linter.main(recipe_dir) + def test_jinja_load_file_data(self): + # Test that we can use load_file_data in a recipe. We don't care about + # the results here and/or the actual file data because the recipe linter + # renders conda-build functions to just function stubs to pass the linting. + # TODO: add *args and **kwargs for functions used to parse the file. + with tmp_directory() as recipe_dir: + with io.open(os.path.join(recipe_dir, "meta.yaml"), "w") as fh: + fh.write( + """ + {% set data = load_file_data("IDONTNEED", from_recipe_dir=True, recipe_dir=".") %} + package: + name: foo + version: {{ version }} + """ + ) + lints = linter.main(recipe_dir) + + def test_jinja_load_setup_py_data(self): + # Test that we can use load_setup_py_data in a recipe. We don't care about + # the results here and/or the actual file data because the recipe linter + # renders conda-build functions to just function stubs to pass the linting. + # TODO: add *args and **kwargs for functions used to parse the file. + with tmp_directory() as recipe_dir: + with io.open(os.path.join(recipe_dir, "meta.yaml"), "w") as fh: + fh.write( + """ + {% set data = load_setup_py_data("IDONTNEED", from_recipe_dir=True, recipe_dir=".") %} + package: + name: foo + version: {{ version }} + """ + ) + lints = linter.main(recipe_dir) + + def test_jinja_load_str_data(self): + # Test that we can use load_str_data in a recipe. We don't care about + # the results here and/or the actual file data because the recipe linter + # renders conda-build functions to just function stubs to pass the linting. + # TODO: add *args and **kwargs for functions used to parse the data. + with tmp_directory() as recipe_dir: + with io.open(os.path.join(recipe_dir, "meta.yaml"), "w") as fh: + fh.write( + """ + {% set data = load_str_data("IDONTNEED", "json") %} + package: + name: foo + version: {{ version }} + """ + ) + lints = linter.main(recipe_dir) + def test_jinja_os_sep(self): # Test that we can use os.sep in a recipe. with tmp_directory() as recipe_dir: @@ -1226,6 +1277,12 @@ def test_noarch_platforms(self): ) assert not lints + def test_noarch_selector_variants(self): + lints = linter.main( + os.path.join(_thisdir, "recipes", "noarch_selector_variants") + ) + assert not lints + def test_string_source(self): url = "http://mistake.com/v1.0.tar.gz" lints, hints = linter.lintify_meta_yaml({"source": url})