From 3cd3fc64ba9c4c48f689ae5e435649d230a79b8f Mon Sep 17 00:00:00 2001 From: nichmor Date: Wed, 31 Jul 2024 15:47:46 +0300 Subject: [PATCH 01/13] fix: omit also jinja functions --- src/rattler_build_conda_compat/jinja.py | 10 ++++++++++ tests/__snapshots__/test_jinja.ambr | 1 + tests/data/context.yaml | 1 + 3 files changed, 12 insertions(+) diff --git a/src/rattler_build_conda_compat/jinja.py b/src/rattler_build_conda_compat/jinja.py index 456849c..03bec6f 100644 --- a/src/rattler_build_conda_compat/jinja.py +++ b/src/rattler_build_conda_compat/jinja.py @@ -22,6 +22,16 @@ def __str__(self) -> str: """ return f"${super().__str__()}" + def _fail_with_undefined_error(self, *args, **kwargs) -> None: # noqa: ARG002, ANN003, ANN002 + """ + Override the default behavior of raising an exception when an undefined variable is found or called. + Instead, we want to keep the undefined variable as-is and just return it. + """ + return self.__str__() + + def __call__(self, *args, **kwargs): # noqa: ARG002, ANN003, ANN002, ANN204 + return self._fail_with_undefined_error() + def jinja_env() -> jinja2.Environment: """ diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index f3e6259..388653d 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -8,6 +8,7 @@ name_version: foo-bla version: bla package: + func_result: ${{ compiler }} name: foo version: bla diff --git a/tests/data/context.yaml b/tests/data/context.yaml index af611ce..406cfae 100644 --- a/tests/data/context.yaml +++ b/tests/data/context.yaml @@ -6,6 +6,7 @@ context: package: name: ${{ name }} version: ${{ version }} + func_result: ${{ compiler('c') }} build: string: ${{ blas_variant }}${{ hash }}_${{ name_version }} From 73b16fafe4aa431c2c658239f290e3d19cc422f8 Mon Sep 17 00:00:00 2001 From: nichmor Date: Wed, 31 Jul 2024 16:42:01 +0300 Subject: [PATCH 02/13] misc: inject necessary functions instead of just returing --- src/rattler_build_conda_compat/jinja.py | 53 ++++++++++++++++++++----- tests/__snapshots__/test_jinja.ambr | 12 +++--- tests/data/context.yaml | 4 +- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/rattler_build_conda_compat/jinja.py b/src/rattler_build_conda_compat/jinja.py index 03bec6f..7276dce 100644 --- a/src/rattler_build_conda_compat/jinja.py +++ b/src/rattler_build_conda_compat/jinja.py @@ -22,22 +22,33 @@ def __str__(self) -> str: """ return f"${super().__str__()}" - def _fail_with_undefined_error(self, *args, **kwargs) -> None: # noqa: ARG002, ANN003, ANN002 - """ - Override the default behavior of raising an exception when an undefined variable is found or called. - Instead, we want to keep the undefined variable as-is and just return it. - """ - return self.__str__() - - def __call__(self, *args, **kwargs): # noqa: ARG002, ANN003, ANN002, ANN204 - return self._fail_with_undefined_error() - def jinja_env() -> jinja2.Environment: """ Create a `rattler-build` specific Jinja2 environment with modified syntax. """ - return jinja2.Environment( + + def stub_compatible_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 + return f"compatible_pin {args[0]}" + + def stub_subpackage_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 + return f"subpackage_pin {args[0]}" + + def version_to_build_string(some_string: str) -> str: + """Converts some version by removing the . character and returning only the first two elements of the version)""" + # We first split the string by whitespace and take the first part + split = some_string.split()[0] if some_string.split() else some_string + # We then split the string by . and take the first two parts + parts = split.split(".") + major = parts[0] if len(parts) > 0 else "" + minor = parts[1] if len(parts) > 1 else "" + return f"{major}{minor}" + + def split_filter(s: str, sep: str = " ") -> list[str]: + """Filter that split a string by a separator""" + return s.split(sep) + + env = jinja2.Environment( variable_start_string="${{", variable_end_string="}}", trim_blocks=True, @@ -46,6 +57,26 @@ def jinja_env() -> jinja2.Environment: undefined=_MissingUndefined, ) + # inject rattler-build recipe functions in jinja environment + env.globals.update( + { + "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", # noqa: ARG005 + } + ) + + # inject rattler-build recipe filters in jinja environment + env.filters.update( + { + "version_to_buildstring": version_to_build_string, + "split": split_filter, + } + ) + return env + def load_recipe_context(context: dict[str, str], jinja_env: jinja2.Environment) -> dict[str, str]: """ diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 388653d..705f484 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -2,15 +2,17 @@ # name: test_render_recipe_with_context ''' build: - string: ${{ blas_variant }}${{ hash }}_foo-bla + string: ${{ blas_variant }}${{ hash }}_foo-1.2.3 context: + cuda_version: ${{ hash }}_cuda_12 name: foo - name_version: foo-bla - version: bla + name_version: foo-1.2.3 + splitted_version: 1;2;3 + version: 1.2.3 package: - func_result: ${{ compiler }} + func_result: c_compiler_stub name: foo - version: bla + version: 1.2.3 ''' # --- diff --git a/tests/data/context.yaml b/tests/data/context.yaml index 406cfae..6e980d0 100644 --- a/tests/data/context.yaml +++ b/tests/data/context.yaml @@ -1,7 +1,9 @@ context: name: "foo" - version: "bla" + version: "1.2.3" name_version: ${{ name }}-${{ version }} + cuda_version: ${{ hash }}_cuda_${{ version | version_to_buildstring }} + split_version: ${{ version | split('.') | join(';') }} package: name: ${{ name }} From 05639ce697847e7389e7c4091c8e212ea3247495 Mon Sep 17 00:00:00 2001 From: nichmor Date: Wed, 31 Jul 2024 16:44:17 +0300 Subject: [PATCH 03/13] misc: update snapshot --- tests/__snapshots__/test_jinja.ambr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 705f484..033e509 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -7,7 +7,7 @@ cuda_version: ${{ hash }}_cuda_12 name: foo name_version: foo-1.2.3 - splitted_version: 1;2;3 + split_version: 1;2;3 version: 1.2.3 package: func_result: c_compiler_stub From a47231a090e923947514f6f019cbfef72dbe5f32 Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 10:49:08 +0300 Subject: [PATCH 04/13] feat: move modules around by refactoring --- src/rattler_build_conda_compat/jinja.py | 121 -------------- .../jinja/__init__.py | 0 src/rattler_build_conda_compat/jinja/jinja.py | 58 +++++++ .../jinja/objects.py | 99 ++++++++++++ tests/__snapshots__/test_jinja.ambr | 144 +++++++++++++++-- tests/data/context.yaml | 14 -- tests/data/mamba_recipe.yaml | 149 ++++++++++++++++++ tests/test_jinja.py | 2 +- 8 files changed, 441 insertions(+), 146 deletions(-) delete mode 100644 src/rattler_build_conda_compat/jinja.py create mode 100644 src/rattler_build_conda_compat/jinja/__init__.py create mode 100644 src/rattler_build_conda_compat/jinja/jinja.py create mode 100644 src/rattler_build_conda_compat/jinja/objects.py delete mode 100644 tests/data/context.yaml create mode 100644 tests/data/mamba_recipe.yaml diff --git a/src/rattler_build_conda_compat/jinja.py b/src/rattler_build_conda_compat/jinja.py deleted file mode 100644 index 7276dce..0000000 --- a/src/rattler_build_conda_compat/jinja.py +++ /dev/null @@ -1,121 +0,0 @@ -from __future__ import annotations - -from typing import Any, TypedDict - -import jinja2 -import yaml -from jinja2 import DebugUndefined - -from rattler_build_conda_compat.loader import load_yaml - - -class RecipeWithContext(TypedDict, total=False): - context: dict[str, str] - - -class _MissingUndefined(DebugUndefined): - def __str__(self) -> str: - """ - By default, `DebugUndefined` return values in the form `{{ value }}`. - `rattler-build` has a different syntax, so we need to override this method, - and return the value in the form `${{ value }}`. - """ - return f"${super().__str__()}" - - -def jinja_env() -> jinja2.Environment: - """ - Create a `rattler-build` specific Jinja2 environment with modified syntax. - """ - - def stub_compatible_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 - return f"compatible_pin {args[0]}" - - def stub_subpackage_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 - return f"subpackage_pin {args[0]}" - - def version_to_build_string(some_string: str) -> str: - """Converts some version by removing the . character and returning only the first two elements of the version)""" - # We first split the string by whitespace and take the first part - split = some_string.split()[0] if some_string.split() else some_string - # We then split the string by . and take the first two parts - parts = split.split(".") - major = parts[0] if len(parts) > 0 else "" - minor = parts[1] if len(parts) > 1 else "" - return f"{major}{minor}" - - def split_filter(s: str, sep: str = " ") -> list[str]: - """Filter that split a string by a separator""" - return s.split(sep) - - env = jinja2.Environment( - variable_start_string="${{", - variable_end_string="}}", - trim_blocks=True, - lstrip_blocks=True, - autoescape=True, - undefined=_MissingUndefined, - ) - - # inject rattler-build recipe functions in jinja environment - env.globals.update( - { - "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", # noqa: ARG005 - } - ) - - # inject rattler-build recipe filters in jinja environment - env.filters.update( - { - "version_to_buildstring": version_to_build_string, - "split": split_filter, - } - ) - return env - - -def load_recipe_context(context: dict[str, str], jinja_env: jinja2.Environment) -> dict[str, str]: - """ - Load all string values from the context dictionary as Jinja2 templates. - """ - # Process each key-value pair in the dictionary - for key, value in context.items(): - # If the value is a string, render it as a template - if isinstance(value, str): - template = jinja_env.from_string(value) - rendered_value = template.render(context) - context[key] = rendered_value - - return context - - -def render_recipe_with_context(recipe_content: RecipeWithContext) -> dict[str, Any]: - """ - Render the recipe using known values from context section. - Unknown values are not evaluated and are kept as it is. - - Examples: - --- - ```python - >>> from pathlib import Path - >>> from rattler_build_conda_compat.loader import load_yaml - >>> recipe_content = load_yaml((Path().resolve() / "tests" / "data" / "eval_recipe_using_context.yaml").read_text()) - >>> evaluated_context = render_recipe_with_context(recipe_content) - >>> assert "my_value-${{ not_present_value }}" == evaluated_context["build"]["string"] - >>> - ``` - """ - env = jinja_env() - context = recipe_content.get("context", {}) - # load all context templates - context_templates = load_recipe_context(context, env) - - # render the rest of the document with the values from the context - # and keep undefined expressions _as is_. - template = env.from_string(yaml.dump(recipe_content)) - rendered_content = template.render(context_templates) - return load_yaml(rendered_content) diff --git a/src/rattler_build_conda_compat/jinja/__init__.py b/src/rattler_build_conda_compat/jinja/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/rattler_build_conda_compat/jinja/jinja.py b/src/rattler_build_conda_compat/jinja/jinja.py new file mode 100644 index 0000000..b7fb052 --- /dev/null +++ b/src/rattler_build_conda_compat/jinja/jinja.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, TypedDict + +if TYPE_CHECKING: + import jinja2 + +import yaml + +from rattler_build_conda_compat.jinja.objects import jinja_env +from rattler_build_conda_compat.loader import load_yaml + + +class RecipeWithContext(TypedDict, total=False): + context: dict[str, str] + + +def load_recipe_context(context: dict[str, str], jinja_env: jinja2.Environment) -> dict[str, str]: + """ + Load all string values from the context dictionary as Jinja2 templates. + """ + # Process each key-value pair in the dictionary + for key, value in context.items(): + # If the value is a string, render it as a template + if isinstance(value, str): + template = jinja_env.from_string(value) + rendered_value = template.render(context) + context[key] = rendered_value + + return context + + +def render_recipe_with_context(recipe_content: RecipeWithContext) -> dict[str, Any]: + """ + Render the recipe using known values from context section. + Unknown values are not evaluated and are kept as it is. + + Examples: + --- + ```python + >>> from pathlib import Path + >>> from rattler_build_conda_compat.loader import load_yaml + >>> recipe_content = load_yaml((Path().resolve() / "tests" / "data" / "eval_recipe_using_context.yaml").read_text()) + >>> evaluated_context = render_recipe_with_context(recipe_content) + >>> assert "my_value-${{ not_present_value }}" == evaluated_context["build"]["string"] + >>> + ``` + """ + env = jinja_env() + context = recipe_content.get("context", {}) + # load all context templates + context_templates = load_recipe_context(context, env) + + # render the rest of the document with the values from the context + # and keep undefined expressions _as is_. + template = env.from_string(yaml.dump(recipe_content)) + rendered_content = template.render(context_templates) + return load_yaml(rendered_content) diff --git a/src/rattler_build_conda_compat/jinja/objects.py b/src/rattler_build_conda_compat/jinja/objects.py new file mode 100644 index 0000000..36d826b --- /dev/null +++ b/src/rattler_build_conda_compat/jinja/objects.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +import os + +import jinja2 +from jinja2 import DebugUndefined + + +class _MissingUndefined(DebugUndefined): + def __str__(self) -> str: + """ + By default, `DebugUndefined` return values in the form `{{ value }}`. + `rattler-build` has a different syntax, so we need to override this method, + and return the value in the form `${{ value }}`. + """ + return f"${super().__str__()}" + + +class _Env: + """A class to represent the env object used in rattler-build recipe.""" + + def get(self, env_var: str, default: str | None) -> str: + try: + return str(os.environ[env_var]) + except KeyError: + if default: + return default + return env_var + + def exists(self, env_var: str) -> bool: + return env_var in os.environ + + +def _stub_compatible_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 + return f"compatible_pin {args[0]}" + + +def _stub_subpackage_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 + return f"subpackage_pin {args[0]}" + + +def _version_to_build_string(some_string: str | _MissingUndefined) -> str: + """ + Converts some version by removing the . character and returning only the first two elements of the version. + If piped value is undefined, it returns the undefined value as is. + """ + if isinstance(some_string, _MissingUndefined): + inner_value = f"{some_string._undefined_name} | version_to_build_string" # noqa: SLF001 + return f"${{{{ {inner_value} }}}}" + # We first split the string by whitespace and take the first part + split = some_string.split()[0] if some_string.split() else some_string + # We then split the string by . and take the first two parts + parts = split.split(".") + major = parts[0] if len(parts) > 0 else "" + minor = parts[1] if len(parts) > 1 else "" + return f"{major}{minor}" + + +def _split_filter(s: str, sep: str = " ") -> list[str]: + """Filter that split a string by a separator""" + return s.split(sep) + + +def jinja_env() -> jinja2.Environment: + """ + Create a `rattler-build` specific Jinja2 environment with modified syntax. + """ + + env = jinja2.Environment( + variable_start_string="${{", + variable_end_string="}}", + trim_blocks=True, + lstrip_blocks=True, + autoescape=True, + undefined=_MissingUndefined, + ) + + env_obj = _Env() + + # inject rattler-build recipe functions in jinja environment + env.globals.update( + { + "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", # noqa: ARG005 + "env": env_obj, + } + ) + + # inject rattler-build recipe filters in jinja environment + env.filters.update( + { + "version_to_buildstring": _version_to_build_string, + "split": _split_filter, + } + ) + return env diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 033e509..7833ef9 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -1,18 +1,142 @@ # serializer version: 1 # name: test_render_recipe_with_context ''' + about: + description: '# Mamba, the Fast Cross-Platform Package Manager + + MY_ENV_VAR + + default_value + + ' + homepage: https://github.com/mamba-org/mamba + license: BSD-3-Clause + license_family: BSD + license_file: LICENSE + repository: https://github.com/mamba-org/mamba + summary: A fast drop-in alternative to conda, using libsolv for dependency resolution build: - string: ${{ blas_variant }}${{ hash }}_foo-1.2.3 + number: '2' context: - cuda_version: ${{ hash }}_cuda_12 - name: foo - name_version: foo-1.2.3 - split_version: 1;2;3 - version: 1.2.3 - package: - func_result: c_compiler_stub - name: foo - version: 1.2.3 + build_number: '2' + libmamba_version: 1.5.8 + libmambapy_version: 1.5.8 + mamba_version: 1.5.8 + name: mamba + release: 2024.03.25 + outputs: + - build: + script: + - '' + - '' + package: + name: libmamba + version: 1.5.8 + requirements: + build: + - cxx_compiler_stub + - cmake + - ninja + - '' + host: + - libsolv >=0.7.23 + - libcurl >=8.4.0 + - fmt + - '' + ignore_run_exports: + by_name: + - spdlog + - python + run: + - libsolv >=0.7.23 + run_exports: + - subpackage_pin libmamba + tests: + - script: + - else: + - if not exist %LIBRARY_PREFIX%\include\mamba\version.hpp (exit 1) + if: unix + then: + - test -d ${PREFIX}/include/mamba + - build: + script: + - '' + - '' + package: + name: libmambapy + version: 1.5.8 + requirements: + build: + - cxx_compiler_stub + - cmake + - ninja + - if: build_platform != target_platform + then: + - python + - cross-python_${{ target_platform }} + - pybind11 + - pybind11-abi + host: + - python + - nlohmann_json + - subpackage_pin libmamba + ignore_run_exports: + by_name: + - spdlog + run: + - python + - subpackage_pin libmamba + run_exports: + - subpackage_pin libmambapy + tests: + - python: + imports: + - libmambapy + - libmambapy.bindings + - script: + - python -c "import libmambapy._version; assert libmambapy._version.__version__ + == '1.5.8'" + - build: + python: + entry_points: + - mamba = mamba.mamba:main + script: + - '' + - '' + string: ${{ python | version_to_build_string }} + package: + name: mamba + version: 1.5.8 + requirements: + build: + - if: build_platform != target_platform + then: + - python + - cross-python_${{ target_platform }} + run: + - python + - conda >=23.9,<24 + - subpackage_pin libmambapy + tests: + - python: + imports: + - mamba + - script: + - mamba --help + - python -c "import mamba._version; assert mamba._version.__version__ == '1.5.8'" + - if: linux + then: + - test -f ${PREFIX}/etc/profile.d/mamba.sh + - mamba create -n test_py2 python=2.7 --dry-run + - mamba install xtensor xsimd -c conda-forge --dry-run + - if: unix + then: + - test -f ${PREFIX}/condabin/mamba + recipe: + name: mamba-split + source: + sha256: 6ddaf4b0758eb7ca1250f427bc40c2c3ede43257a60bac54e4320a4de66759a6 + url: https://github.com/mamba-org/mamba/archive/refs/tags/2024.03.25.tar.gz ''' # --- diff --git a/tests/data/context.yaml b/tests/data/context.yaml deleted file mode 100644 index 6e980d0..0000000 --- a/tests/data/context.yaml +++ /dev/null @@ -1,14 +0,0 @@ -context: - name: "foo" - version: "1.2.3" - name_version: ${{ name }}-${{ version }} - cuda_version: ${{ hash }}_cuda_${{ version | version_to_buildstring }} - split_version: ${{ version | split('.') | join(';') }} - -package: - name: ${{ name }} - version: ${{ version }} - func_result: ${{ compiler('c') }} - -build: - string: ${{ blas_variant }}${{ hash }}_${{ name_version }} diff --git a/tests/data/mamba_recipe.yaml b/tests/data/mamba_recipe.yaml new file mode 100644 index 0000000..d0eb4a2 --- /dev/null +++ b/tests/data/mamba_recipe.yaml @@ -0,0 +1,149 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/prefix-dev/recipe-format/main/schema.json + +context: + name: mamba + libmamba_version: "1.5.8" + libmambapy_version: "1.5.8" + mamba_version: "1.5.8" + release: "2024.03.25" + build_number: 2 + +recipe: + name: mamba-split + +source: + url: https://github.com/mamba-org/mamba/archive/refs/tags/${{ release }}.tar.gz + sha256: 6ddaf4b0758eb7ca1250f427bc40c2c3ede43257a60bac54e4320a4de66759a6 + +build: + number: ${{ build_number }} + +outputs: + - package: + name: libmamba + version: ${{ libmamba_version }} + build: + script: + - ${{ "build_mamba.sh" if unix }} + - ${{ "build_mamba.bat" if win }} + requirements: + build: + - ${{ compiler('cxx') }} + - cmake + - ninja + - ${{ "python" if win }} + host: + - libsolv >=0.7.23 + - libcurl >=8.4.0 + - fmt + - ${{ "winreg" if win }} + run: + - libsolv >=0.7.23 + run_exports: + - ${{ pin_subpackage('libmamba', max_pin='x.x') }} + ignore_run_exports: + by_name: + - spdlog + - python + tests: + - script: + - if: unix + then: + - test -d ${PREFIX}/include/mamba # [unix] + else: + - if not exist %LIBRARY_PREFIX%\include\mamba\version.hpp (exit 1) # [win] + + - package: + name: libmambapy + version: ${{ libmambapy_version }} + build: + script: + - ${{ "build_mamba.sh" if unix }} + - ${{ "build_mamba.bat" if win }} + # string: py_sup${{ python | version_to_buildstring }}h${{ hash }}_${{ build_number }} + requirements: + build: + - ${{ compiler('cxx') }} + - cmake + - ninja + - if: build_platform != target_platform + then: + - python + - cross-python_${{ target_platform }} + - pybind11 + - pybind11-abi + host: + - python + - nlohmann_json + - ${{ pin_subpackage('libmamba', exact=True) }} + run: + - python + - ${{ pin_subpackage('libmamba', exact=True) }} + run_exports: + - ${{ pin_subpackage('libmambapy', max_pin='x.x') }} + ignore_run_exports: + by_name: + - spdlog + tests: + - python: + imports: + - libmambapy + - libmambapy.bindings + - script: + - python -c "import libmambapy._version; assert libmambapy._version.__version__ == '${{ libmambapy_version }}'" + + - package: + name: mamba + version: ${{ mamba_version }} + build: + script: + - ${{ "build_mamba.sh" if unix }} + - ${{ "build_mamba.bat" if win }} + # string: py${{ python | version_to_buildstring }}h${{ hash }}_${{ build_number }} + string: ${{ python | version_to_buildstring }} + python: + entry_points: + - mamba = mamba.mamba:main + requirements: + build: + - if: build_platform != target_platform + then: + - python + - cross-python_${{ target_platform }} + run: + - python + - conda >=23.9,<24 + - ${{ pin_subpackage('libmambapy', exact=True) }} + + tests: + - python: + imports: + - mamba + - script: + - mamba --help + # for some reason tqdm doesn't have a proper colorama dependency so pip check fails + # but that's completely unrelated to mamba + - python -c "import mamba._version; assert mamba._version.__version__ == '${{ mamba_version }}'" + + - if: linux + then: + - test -f ${PREFIX}/etc/profile.d/mamba.sh + # these tests work when run on win, but for some reason not during conda build + - mamba create -n test_py2 python=2.7 --dry-run + - mamba install xtensor xsimd -c conda-forge --dry-run + - if: unix + then: + - test -f ${PREFIX}/condabin/mamba + +about: + homepage: https://github.com/mamba-org/mamba + license: BSD-3-Clause + license_file: LICENSE + license_family: BSD + summary: A fast drop-in alternative to conda, using libsolv for dependency resolution + description: | + # Mamba, the Fast Cross-Platform Package Manager + ${{ env.get("MY_ENV_VAR") }} + ${{ env.get("MY_ENV_VAR", default="default_value") }} + + repository: https://github.com/mamba-org/mamba diff --git a/tests/test_jinja.py b/tests/test_jinja.py index 3feb3a0..2b60dd8 100644 --- a/tests/test_jinja.py +++ b/tests/test_jinja.py @@ -5,7 +5,7 @@ def test_render_recipe_with_context(snapshot) -> None: - recipe = Path("tests/data/context.yaml") + recipe = Path("tests/data/mamba_recipe.yaml") with recipe.open() as f: recipe_yaml = load_yaml(f) From af23b011004d124d516ccfeba66c55e5a87f876f Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 11:22:15 +0300 Subject: [PATCH 05/13] feat: add tests and do a little refactoring --- src/rattler_build_conda_compat/jinja/jinja.py | 61 ++++++++++- .../jinja/objects.py | 101 ++++-------------- tests/__snapshots__/test_jinja.ambr | 4 +- tests/test_jinja.py | 13 ++- 4 files changed, 90 insertions(+), 89 deletions(-) diff --git a/src/rattler_build_conda_compat/jinja/jinja.py b/src/rattler_build_conda_compat/jinja/jinja.py index b7fb052..bfdb68e 100644 --- a/src/rattler_build_conda_compat/jinja/jinja.py +++ b/src/rattler_build_conda_compat/jinja/jinja.py @@ -1,13 +1,21 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, TypedDict - -if TYPE_CHECKING: - import jinja2 +from typing import Any, TypedDict +import jinja2 import yaml -from rattler_build_conda_compat.jinja.objects import jinja_env +from rattler_build_conda_compat.jinja.filters import _bool, _split, _version_to_build_string +from rattler_build_conda_compat.jinja.objects import ( + _Env, + _is_linux, + _is_unix, + _is_win, + _stub_compatible_pin, + _stub_match, + _stub_subpackage_pin, +) +from rattler_build_conda_compat.jinja.utils import _MissingUndefined from rattler_build_conda_compat.loader import load_yaml @@ -15,6 +23,49 @@ class RecipeWithContext(TypedDict, total=False): context: dict[str, str] +def jinja_env() -> jinja2.Environment: + """ + Create a `rattler-build` specific Jinja2 environment with modified syntax. + """ + + env = jinja2.Environment( + variable_start_string="${{", + variable_end_string="}}", + trim_blocks=True, + lstrip_blocks=True, + autoescape=True, + undefined=_MissingUndefined, + ) + + env_obj = _Env() + + # inject rattler-build recipe functions in jinja environment + env.globals.update( + { + "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", # noqa: ARG005 + "env": env_obj, + "match": _stub_match, + "is_unix": _is_unix, + "is_win": _is_win, + "is_linux": _is_linux, + } + ) + + # inject rattler-build recipe filters in jinja environment + env.filters.update( + { + "version_to_buildstring": _version_to_build_string, + "split": _split, + "bool": _bool, + } + ) + return env + + def load_recipe_context(context: dict[str, str], jinja_env: jinja2.Environment) -> dict[str, str]: """ Load all string values from the context dictionary as Jinja2 templates. diff --git a/src/rattler_build_conda_compat/jinja/objects.py b/src/rattler_build_conda_compat/jinja/objects.py index 36d826b..24d94a0 100644 --- a/src/rattler_build_conda_compat/jinja/objects.py +++ b/src/rattler_build_conda_compat/jinja/objects.py @@ -1,34 +1,17 @@ from __future__ import annotations -import os - -import jinja2 -from jinja2 import DebugUndefined - - -class _MissingUndefined(DebugUndefined): - def __str__(self) -> str: - """ - By default, `DebugUndefined` return values in the form `{{ value }}`. - `rattler-build` has a different syntax, so we need to override this method, - and return the value in the form `${{ value }}`. - """ - return f"${super().__str__()}" - class _Env: """A class to represent the env object used in rattler-build recipe.""" - def get(self, env_var: str, default: str | None) -> str: - try: - return str(os.environ[env_var]) - except KeyError: - if default: - return default - return env_var + def get(self, env_var: str, default: str | None = None) -> str: + if default: + return f"""${{{{ env.get('{env_var}', default='{default}') }}}}""" + + return f"""${{{{ env.get("{env_var}")}}}}""" def exists(self, env_var: str) -> bool: - return env_var in os.environ + return f"${{{{ env.exists('{env_var}') }}}}" def _stub_compatible_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 @@ -39,61 +22,17 @@ def _stub_subpackage_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN00 return f"subpackage_pin {args[0]}" -def _version_to_build_string(some_string: str | _MissingUndefined) -> str: - """ - Converts some version by removing the . character and returning only the first two elements of the version. - If piped value is undefined, it returns the undefined value as is. - """ - if isinstance(some_string, _MissingUndefined): - inner_value = f"{some_string._undefined_name} | version_to_build_string" # noqa: SLF001 - return f"${{{{ {inner_value} }}}}" - # We first split the string by whitespace and take the first part - split = some_string.split()[0] if some_string.split() else some_string - # We then split the string by . and take the first two parts - parts = split.split(".") - major = parts[0] if len(parts) > 0 else "" - minor = parts[1] if len(parts) > 1 else "" - return f"{major}{minor}" - - -def _split_filter(s: str, sep: str = " ") -> list[str]: - """Filter that split a string by a separator""" - return s.split(sep) - - -def jinja_env() -> jinja2.Environment: - """ - Create a `rattler-build` specific Jinja2 environment with modified syntax. - """ - - env = jinja2.Environment( - variable_start_string="${{", - variable_end_string="}}", - trim_blocks=True, - lstrip_blocks=True, - autoescape=True, - undefined=_MissingUndefined, - ) - - env_obj = _Env() - - # inject rattler-build recipe functions in jinja environment - env.globals.update( - { - "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", # noqa: ARG005 - "env": env_obj, - } - ) - - # inject rattler-build recipe filters in jinja environment - env.filters.update( - { - "version_to_buildstring": _version_to_build_string, - "split": _split_filter, - } - ) - return env +def _stub_match(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 + return f"match {args[0]}" + + +def _is_unix(platform: str) -> str: + return f"is_unix {platform}" + + +def _is_win(platform: str) -> str: + return f"is_win {platform}" + + +def _is_linux(platform: str) -> str: + return f"is_linux {platform}" diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 7833ef9..00e15e2 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -4,9 +4,9 @@ about: description: '# Mamba, the Fast Cross-Platform Package Manager - MY_ENV_VAR + ${{ env.get("MY_ENV_VAR")}} - default_value + ${{ env.get('MY_ENV_VAR', default='default_value') }} ' homepage: https://github.com/mamba-org/mamba diff --git a/tests/test_jinja.py b/tests/test_jinja.py index 2b60dd8..b963fd6 100644 --- a/tests/test_jinja.py +++ b/tests/test_jinja.py @@ -1,7 +1,10 @@ from pathlib import Path import yaml -from rattler_build_conda_compat.jinja import load_yaml, render_recipe_with_context +from rattler_build_conda_compat.jinja.filters import _version_to_build_string +from rattler_build_conda_compat.jinja.jinja import render_recipe_with_context +from rattler_build_conda_compat.jinja.utils import _MissingUndefined +from rattler_build_conda_compat.loader import load_yaml def test_render_recipe_with_context(snapshot) -> None: @@ -13,3 +16,11 @@ def test_render_recipe_with_context(snapshot) -> None: into_yaml = yaml.dump(rendered) assert into_yaml == snapshot + + +def test_version_to_build_string() -> None: + assert _version_to_build_string("1.2.3") == "12" + assert _version_to_build_string("1.2") == "12" + assert _version_to_build_string("nothing") == "nothing" + some_undefined = _MissingUndefined(name="python") + assert _version_to_build_string(some_undefined) == "${{ python | version_to_build_string }}" From 0def0e1263fd4e2f88e03d6dc2b288db19f95083 Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 11:23:17 +0300 Subject: [PATCH 06/13] feat: add env objects and missing filters --- .../jinja/filters.py | 29 +++++++++++++++++++ .../jinja/objects.py | 2 +- src/rattler_build_conda_compat/jinja/utils.py | 11 +++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/rattler_build_conda_compat/jinja/filters.py create mode 100644 src/rattler_build_conda_compat/jinja/utils.py diff --git a/src/rattler_build_conda_compat/jinja/filters.py b/src/rattler_build_conda_compat/jinja/filters.py new file mode 100644 index 0000000..bde4075 --- /dev/null +++ b/src/rattler_build_conda_compat/jinja/filters.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from rattler_build_conda_compat.jinja.utils import _MissingUndefined + + +def _version_to_build_string(some_string: str | _MissingUndefined) -> str: + """ + Converts some version by removing the . character and returning only the first two elements of the version. + If piped value is undefined, it returns the undefined value as is. + """ + if isinstance(some_string, _MissingUndefined): + inner_value = f"{some_string._undefined_name} | version_to_build_string" # noqa: SLF001 + return f"${{{{ {inner_value} }}}}" + # We first split the string by whitespace and take the first part + split = some_string.split()[0] if some_string.split() else some_string + # We then split the string by . and take the first two parts + parts = split.split(".") + major = parts[0] if len(parts) > 0 else "" + minor = parts[1] if len(parts) > 1 else "" + return f"{major}{minor}" + + +def _bool(value: str) -> bool: + return bool(value) + + +def _split(s: str, sep: str = " ") -> list[str]: + """Filter that split a string by a separator""" + return s.split(sep) diff --git a/src/rattler_build_conda_compat/jinja/objects.py b/src/rattler_build_conda_compat/jinja/objects.py index 24d94a0..b80a0d8 100644 --- a/src/rattler_build_conda_compat/jinja/objects.py +++ b/src/rattler_build_conda_compat/jinja/objects.py @@ -10,7 +10,7 @@ def get(self, env_var: str, default: str | None = None) -> str: return f"""${{{{ env.get("{env_var}")}}}}""" - def exists(self, env_var: str) -> bool: + def exists(self, env_var: str) -> str: return f"${{{{ env.exists('{env_var}') }}}}" diff --git a/src/rattler_build_conda_compat/jinja/utils.py b/src/rattler_build_conda_compat/jinja/utils.py new file mode 100644 index 0000000..dc688e9 --- /dev/null +++ b/src/rattler_build_conda_compat/jinja/utils.py @@ -0,0 +1,11 @@ +from jinja2 import DebugUndefined + + +class _MissingUndefined(DebugUndefined): + def __str__(self) -> str: + """ + By default, `DebugUndefined` return values in the form `{{ value }}`. + `rattler-build` has a different syntax, so we need to override this method, + and return the value in the form `${{ value }}`. + """ + return f"${super().__str__()}" From 91085d130dd2070861ca309b515af8e4a6d972fc Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 11:36:05 +0300 Subject: [PATCH 07/13] misc: update tests --- tests/__snapshots__/test_jinja.ambr | 2 +- tests/data/mamba_recipe.yaml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 00e15e2..646f2de 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -103,7 +103,7 @@ script: - '' - '' - string: ${{ python | version_to_build_string }} + string: py${{ python | version_to_build_string }}h${{ hash }}_2 package: name: mamba version: 1.5.8 diff --git a/tests/data/mamba_recipe.yaml b/tests/data/mamba_recipe.yaml index d0eb4a2..62e9db0 100644 --- a/tests/data/mamba_recipe.yaml +++ b/tests/data/mamba_recipe.yaml @@ -99,8 +99,7 @@ outputs: script: - ${{ "build_mamba.sh" if unix }} - ${{ "build_mamba.bat" if win }} - # string: py${{ python | version_to_buildstring }}h${{ hash }}_${{ build_number }} - string: ${{ python | version_to_buildstring }} + string: py${{ python | version_to_buildstring }}h${{ hash }}_${{ build_number }} python: entry_points: - mamba = mamba.mamba:main From bff5681775ff4fba4d521abbb9172ceb434a6e1d Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 12:32:17 +0300 Subject: [PATCH 08/13] fix: escaping of quotes --- src/rattler_build_conda_compat/jinja/jinja.py | 24 ++++++++++++------- .../jinja/objects.py | 20 ++++++++-------- tests/__snapshots__/test_jinja.ambr | 15 +++++++----- tests/data/mamba_recipe.yaml | 2 ++ 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/rattler_build_conda_compat/jinja/jinja.py b/src/rattler_build_conda_compat/jinja/jinja.py index bfdb68e..c999082 100644 --- a/src/rattler_build_conda_compat/jinja/jinja.py +++ b/src/rattler_build_conda_compat/jinja/jinja.py @@ -7,11 +7,11 @@ from rattler_build_conda_compat.jinja.filters import _bool, _split, _version_to_build_string from rattler_build_conda_compat.jinja.objects import ( - _Env, - _is_linux, - _is_unix, - _is_win, _stub_compatible_pin, + _Stub_Env, + _stub_is_linux, + _stub_is_unix, + _stub_is_win, _stub_match, _stub_subpackage_pin, ) @@ -33,11 +33,11 @@ def jinja_env() -> jinja2.Environment: variable_end_string="}}", trim_blocks=True, lstrip_blocks=True, - autoescape=True, + autoescape=jinja2.select_autoescape(default_for_string=False), undefined=_MissingUndefined, ) - env_obj = _Env() + env_obj = _Stub_Env() # inject rattler-build recipe functions in jinja environment env.globals.update( @@ -49,9 +49,14 @@ def jinja_env() -> jinja2.Environment: "cdt": lambda *args, **kwargs: "cdt_stub", # noqa: ARG005 "env": env_obj, "match": _stub_match, - "is_unix": _is_unix, - "is_win": _is_win, - "is_linux": _is_linux, + "is_unix": _stub_is_unix, + "is_win": _stub_is_win, + "is_linux": _stub_is_linux, + "unix": True, + "linux": True, + "target_platform": "linux-64", + "build_platform": "linux-64", + "mpi": "mpi", } ) @@ -69,6 +74,7 @@ def jinja_env() -> jinja2.Environment: def load_recipe_context(context: dict[str, str], jinja_env: jinja2.Environment) -> dict[str, str]: """ Load all string values from the context dictionary as Jinja2 templates. + Use linux-64 as default target_platform, build_platform, and mpi. """ # Process each key-value pair in the dictionary for key, value in context.items(): diff --git a/src/rattler_build_conda_compat/jinja/objects.py b/src/rattler_build_conda_compat/jinja/objects.py index b80a0d8..e168b85 100644 --- a/src/rattler_build_conda_compat/jinja/objects.py +++ b/src/rattler_build_conda_compat/jinja/objects.py @@ -1,21 +1,21 @@ from __future__ import annotations -class _Env: +class _StubEnv: """A class to represent the env object used in rattler-build recipe.""" def get(self, env_var: str, default: str | None = None) -> str: if default: - return f"""${{{{ env.get('{env_var}', default='{default}') }}}}""" + return f"""${{{{ env.get("{env_var}", default="{default}") }}}}""" return f"""${{{{ env.get("{env_var}")}}}}""" def exists(self, env_var: str) -> str: - return f"${{{{ env.exists('{env_var}') }}}}" + return f"""${{{{ env.exists("{env_var}") }}}}""" def _stub_compatible_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 - return f"compatible_pin {args[0]}" + return f"${{{{ compatible_pin {args[0]} }}}}" def _stub_subpackage_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 @@ -26,13 +26,13 @@ def _stub_match(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 return f"match {args[0]}" -def _is_unix(platform: str) -> str: - return f"is_unix {platform}" +def _stub_is_unix(platform: str) -> str: + return f"${{{{ is_unix {platform} }}}}" -def _is_win(platform: str) -> str: - return f"is_win {platform}" +def _stub_is_win(platform: str) -> str: + return f"${{{{ is_win {platform} }}}}" -def _is_linux(platform: str) -> str: - return f"is_linux {platform}" +def _stub_is_linux(platform: str) -> str: + return f"${{{{ is_linux {platform} }}}}" diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 646f2de..9c0c3ef 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -4,9 +4,11 @@ about: description: '# Mamba, the Fast Cross-Platform Package Manager - ${{ env.get("MY_ENV_VAR")}} + ${{ env.get("MY_ENV_VAR")}} - ${{ env.get('MY_ENV_VAR', default='default_value') }} + ${{ env.get("MY_ENV_VAR", default="default_value") }} + + ${{ env.exists("MY_ENV_VAR") }} ' homepage: https://github.com/mamba-org/mamba @@ -27,7 +29,7 @@ outputs: - build: script: - - '' + - build_mamba.sh - '' package: name: libmamba @@ -60,7 +62,7 @@ - test -d ${PREFIX}/include/mamba - build: script: - - '' + - build_mamba.sh - '' package: name: libmambapy @@ -73,7 +75,7 @@ - if: build_platform != target_platform then: - python - - cross-python_${{ target_platform }} + - cross-python_linux-64 - pybind11 - pybind11-abi host: @@ -101,6 +103,7 @@ entry_points: - mamba = mamba.mamba:main script: + - build_mamba.sh - '' - '' string: py${{ python | version_to_build_string }}h${{ hash }}_2 @@ -112,7 +115,7 @@ - if: build_platform != target_platform then: - python - - cross-python_${{ target_platform }} + - cross-python_linux-64 run: - python - conda >=23.9,<24 diff --git a/tests/data/mamba_recipe.yaml b/tests/data/mamba_recipe.yaml index 62e9db0..0478704 100644 --- a/tests/data/mamba_recipe.yaml +++ b/tests/data/mamba_recipe.yaml @@ -99,6 +99,7 @@ outputs: script: - ${{ "build_mamba.sh" if unix }} - ${{ "build_mamba.bat" if win }} + - ${{ "test_mamba.bat" if target_platform == win }} string: py${{ python | version_to_buildstring }}h${{ hash }}_${{ build_number }} python: entry_points: @@ -144,5 +145,6 @@ about: # Mamba, the Fast Cross-Platform Package Manager ${{ env.get("MY_ENV_VAR") }} ${{ env.get("MY_ENV_VAR", default="default_value") }} + ${{ env.exists("MY_ENV_VAR")}} repository: https://github.com/mamba-org/mamba From c4532f90da65904537f5e4ed04c1f221739db8f8 Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 12:32:47 +0300 Subject: [PATCH 09/13] fix: escaping of quotes --- src/rattler_build_conda_compat/jinja/jinja.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rattler_build_conda_compat/jinja/jinja.py b/src/rattler_build_conda_compat/jinja/jinja.py index c999082..86f6a70 100644 --- a/src/rattler_build_conda_compat/jinja/jinja.py +++ b/src/rattler_build_conda_compat/jinja/jinja.py @@ -8,12 +8,12 @@ from rattler_build_conda_compat.jinja.filters import _bool, _split, _version_to_build_string from rattler_build_conda_compat.jinja.objects import ( _stub_compatible_pin, - _Stub_Env, _stub_is_linux, _stub_is_unix, _stub_is_win, _stub_match, _stub_subpackage_pin, + _StubEnv, ) from rattler_build_conda_compat.jinja.utils import _MissingUndefined from rattler_build_conda_compat.loader import load_yaml @@ -37,7 +37,7 @@ def jinja_env() -> jinja2.Environment: undefined=_MissingUndefined, ) - env_obj = _Stub_Env() + env_obj = _StubEnv() # inject rattler-build recipe functions in jinja environment env.globals.update( From 6cb46fe4ee8d4f972a6768d466f0e8dee777eeaa Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 12:35:24 +0300 Subject: [PATCH 10/13] fix: escaping of quotes --- src/rattler_build_conda_compat/jinja/jinja.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rattler_build_conda_compat/jinja/jinja.py b/src/rattler_build_conda_compat/jinja/jinja.py index 86f6a70..fc2db37 100644 --- a/src/rattler_build_conda_compat/jinja/jinja.py +++ b/src/rattler_build_conda_compat/jinja/jinja.py @@ -26,6 +26,7 @@ class RecipeWithContext(TypedDict, total=False): def jinja_env() -> jinja2.Environment: """ Create a `rattler-build` specific Jinja2 environment with modified syntax. + Target platform, build platform, and mpi are set to linux-64 by default. """ env = jinja2.Environment( @@ -91,6 +92,7 @@ def render_recipe_with_context(recipe_content: RecipeWithContext) -> dict[str, A """ Render the recipe using known values from context section. Unknown values are not evaluated and are kept as it is. + Target platform, build platform, and mpi are set to linux-64 by default. Examples: --- From e5d46fdc713f13ca345032f11546bef27aa0e254 Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 12:55:16 +0300 Subject: [PATCH 11/13] misc: make stub behave the same --- src/rattler_build_conda_compat/jinja/filters.py | 3 +-- src/rattler_build_conda_compat/jinja/objects.py | 17 +++++++---------- tests/__snapshots__/test_jinja.ambr | 8 ++++---- tests/test_jinja.py | 2 +- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/rattler_build_conda_compat/jinja/filters.py b/src/rattler_build_conda_compat/jinja/filters.py index bde4075..b28e455 100644 --- a/src/rattler_build_conda_compat/jinja/filters.py +++ b/src/rattler_build_conda_compat/jinja/filters.py @@ -9,8 +9,7 @@ def _version_to_build_string(some_string: str | _MissingUndefined) -> str: If piped value is undefined, it returns the undefined value as is. """ if isinstance(some_string, _MissingUndefined): - inner_value = f"{some_string._undefined_name} | version_to_build_string" # noqa: SLF001 - return f"${{{{ {inner_value} }}}}" + return f"{some_string._undefined_name}_version_to_build_string" # noqa: SLF001 # We first split the string by whitespace and take the first part split = some_string.split()[0] if some_string.split() else some_string # We then split the string by . and take the first two parts diff --git a/src/rattler_build_conda_compat/jinja/objects.py b/src/rattler_build_conda_compat/jinja/objects.py index e168b85..2387fc5 100644 --- a/src/rattler_build_conda_compat/jinja/objects.py +++ b/src/rattler_build_conda_compat/jinja/objects.py @@ -4,18 +4,15 @@ class _StubEnv: """A class to represent the env object used in rattler-build recipe.""" - def get(self, env_var: str, default: str | None = None) -> str: - if default: - return f"""${{{{ env.get("{env_var}", default="{default}") }}}}""" - - return f"""${{{{ env.get("{env_var}")}}}}""" + def get(self, env_var: str, _default: str | None = None) -> str: + return f"""env_"{env_var}" """ def exists(self, env_var: str) -> str: - return f"""${{{{ env.exists("{env_var}") }}}}""" + return f"""env_exists_"{env_var}" """ def _stub_compatible_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 - return f"${{{{ compatible_pin {args[0]} }}}}" + return f"compatible_pin {args[0]}" def _stub_subpackage_pin(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 @@ -27,12 +24,12 @@ def _stub_match(*args, **kwargs) -> str: # noqa: ARG001, ANN003, ANN002 def _stub_is_unix(platform: str) -> str: - return f"${{{{ is_unix {platform} }}}}" + return f"is_unix {platform}" def _stub_is_win(platform: str) -> str: - return f"${{{{ is_win {platform} }}}}" + return f"is_win {platform}" def _stub_is_linux(platform: str) -> str: - return f"${{{{ is_linux {platform} }}}}" + return f"is_linux {platform}" diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr index 9c0c3ef..42fbc5f 100644 --- a/tests/__snapshots__/test_jinja.ambr +++ b/tests/__snapshots__/test_jinja.ambr @@ -4,11 +4,11 @@ about: description: '# Mamba, the Fast Cross-Platform Package Manager - ${{ env.get("MY_ENV_VAR")}} + env_"MY_ENV_VAR - ${{ env.get("MY_ENV_VAR", default="default_value") }} + env_"MY_ENV_VAR - ${{ env.exists("MY_ENV_VAR") }} + env_exists_"MY_ENV_VAR ' homepage: https://github.com/mamba-org/mamba @@ -106,7 +106,7 @@ - build_mamba.sh - '' - '' - string: py${{ python | version_to_build_string }}h${{ hash }}_2 + string: pypython_version_to_build_stringh${{ hash }}_2 package: name: mamba version: 1.5.8 diff --git a/tests/test_jinja.py b/tests/test_jinja.py index b963fd6..62e58a0 100644 --- a/tests/test_jinja.py +++ b/tests/test_jinja.py @@ -23,4 +23,4 @@ def test_version_to_build_string() -> None: assert _version_to_build_string("1.2") == "12" assert _version_to_build_string("nothing") == "nothing" some_undefined = _MissingUndefined(name="python") - assert _version_to_build_string(some_undefined) == "${{ python | version_to_build_string }}" + assert _version_to_build_string(some_undefined) == "python_version_to_build_string" From e95ef4ad27531fd8f998b60d6502947afbb0cf2f Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 12:58:53 +0300 Subject: [PATCH 12/13] misc: make stub behave the same --- .../jinja/objects.py | 2 +- tests/__snapshots__/test_jinja.ambr | 145 ------------------ 2 files changed, 1 insertion(+), 146 deletions(-) delete mode 100644 tests/__snapshots__/test_jinja.ambr diff --git a/src/rattler_build_conda_compat/jinja/objects.py b/src/rattler_build_conda_compat/jinja/objects.py index 2387fc5..32e64ba 100644 --- a/src/rattler_build_conda_compat/jinja/objects.py +++ b/src/rattler_build_conda_compat/jinja/objects.py @@ -4,7 +4,7 @@ class _StubEnv: """A class to represent the env object used in rattler-build recipe.""" - def get(self, env_var: str, _default: str | None = None) -> str: + def get(self, env_var: str, default: str | None = None) -> str: # noqa: ARG002 return f"""env_"{env_var}" """ def exists(self, env_var: str) -> str: diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr deleted file mode 100644 index 42fbc5f..0000000 --- a/tests/__snapshots__/test_jinja.ambr +++ /dev/null @@ -1,145 +0,0 @@ -# serializer version: 1 -# name: test_render_recipe_with_context - ''' - about: - description: '# Mamba, the Fast Cross-Platform Package Manager - - env_"MY_ENV_VAR - - env_"MY_ENV_VAR - - env_exists_"MY_ENV_VAR - - ' - homepage: https://github.com/mamba-org/mamba - license: BSD-3-Clause - license_family: BSD - license_file: LICENSE - repository: https://github.com/mamba-org/mamba - summary: A fast drop-in alternative to conda, using libsolv for dependency resolution - build: - number: '2' - context: - build_number: '2' - libmamba_version: 1.5.8 - libmambapy_version: 1.5.8 - mamba_version: 1.5.8 - name: mamba - release: 2024.03.25 - outputs: - - build: - script: - - build_mamba.sh - - '' - package: - name: libmamba - version: 1.5.8 - requirements: - build: - - cxx_compiler_stub - - cmake - - ninja - - '' - host: - - libsolv >=0.7.23 - - libcurl >=8.4.0 - - fmt - - '' - ignore_run_exports: - by_name: - - spdlog - - python - run: - - libsolv >=0.7.23 - run_exports: - - subpackage_pin libmamba - tests: - - script: - - else: - - if not exist %LIBRARY_PREFIX%\include\mamba\version.hpp (exit 1) - if: unix - then: - - test -d ${PREFIX}/include/mamba - - build: - script: - - build_mamba.sh - - '' - package: - name: libmambapy - version: 1.5.8 - requirements: - build: - - cxx_compiler_stub - - cmake - - ninja - - if: build_platform != target_platform - then: - - python - - cross-python_linux-64 - - pybind11 - - pybind11-abi - host: - - python - - nlohmann_json - - subpackage_pin libmamba - ignore_run_exports: - by_name: - - spdlog - run: - - python - - subpackage_pin libmamba - run_exports: - - subpackage_pin libmambapy - tests: - - python: - imports: - - libmambapy - - libmambapy.bindings - - script: - - python -c "import libmambapy._version; assert libmambapy._version.__version__ - == '1.5.8'" - - build: - python: - entry_points: - - mamba = mamba.mamba:main - script: - - build_mamba.sh - - '' - - '' - string: pypython_version_to_build_stringh${{ hash }}_2 - package: - name: mamba - version: 1.5.8 - requirements: - build: - - if: build_platform != target_platform - then: - - python - - cross-python_linux-64 - run: - - python - - conda >=23.9,<24 - - subpackage_pin libmambapy - tests: - - python: - imports: - - mamba - - script: - - mamba --help - - python -c "import mamba._version; assert mamba._version.__version__ == '1.5.8'" - - if: linux - then: - - test -f ${PREFIX}/etc/profile.d/mamba.sh - - mamba create -n test_py2 python=2.7 --dry-run - - mamba install xtensor xsimd -c conda-forge --dry-run - - if: unix - then: - - test -f ${PREFIX}/condabin/mamba - recipe: - name: mamba-split - source: - sha256: 6ddaf4b0758eb7ca1250f427bc40c2c3ede43257a60bac54e4320a4de66759a6 - url: https://github.com/mamba-org/mamba/archive/refs/tags/2024.03.25.tar.gz - - ''' -# --- From 479fc6c5c62912b450a4c8ef8c54b003ca09b5a8 Mon Sep 17 00:00:00 2001 From: nichmor Date: Thu, 1 Aug 2024 12:59:13 +0300 Subject: [PATCH 13/13] misc: make stub behave the same --- tests/__snapshots__/test_jinja.ambr | 145 ++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 tests/__snapshots__/test_jinja.ambr diff --git a/tests/__snapshots__/test_jinja.ambr b/tests/__snapshots__/test_jinja.ambr new file mode 100644 index 0000000..18d5008 --- /dev/null +++ b/tests/__snapshots__/test_jinja.ambr @@ -0,0 +1,145 @@ +# serializer version: 1 +# name: test_render_recipe_with_context + ''' + about: + description: '# Mamba, the Fast Cross-Platform Package Manager + + env_"MY_ENV_VAR" + + env_"MY_ENV_VAR" + + env_exists_"MY_ENV_VAR" + + ' + homepage: https://github.com/mamba-org/mamba + license: BSD-3-Clause + license_family: BSD + license_file: LICENSE + repository: https://github.com/mamba-org/mamba + summary: A fast drop-in alternative to conda, using libsolv for dependency resolution + build: + number: '2' + context: + build_number: '2' + libmamba_version: 1.5.8 + libmambapy_version: 1.5.8 + mamba_version: 1.5.8 + name: mamba + release: 2024.03.25 + outputs: + - build: + script: + - build_mamba.sh + - '' + package: + name: libmamba + version: 1.5.8 + requirements: + build: + - cxx_compiler_stub + - cmake + - ninja + - '' + host: + - libsolv >=0.7.23 + - libcurl >=8.4.0 + - fmt + - '' + ignore_run_exports: + by_name: + - spdlog + - python + run: + - libsolv >=0.7.23 + run_exports: + - subpackage_pin libmamba + tests: + - script: + - else: + - if not exist %LIBRARY_PREFIX%\include\mamba\version.hpp (exit 1) + if: unix + then: + - test -d ${PREFIX}/include/mamba + - build: + script: + - build_mamba.sh + - '' + package: + name: libmambapy + version: 1.5.8 + requirements: + build: + - cxx_compiler_stub + - cmake + - ninja + - if: build_platform != target_platform + then: + - python + - cross-python_linux-64 + - pybind11 + - pybind11-abi + host: + - python + - nlohmann_json + - subpackage_pin libmamba + ignore_run_exports: + by_name: + - spdlog + run: + - python + - subpackage_pin libmamba + run_exports: + - subpackage_pin libmambapy + tests: + - python: + imports: + - libmambapy + - libmambapy.bindings + - script: + - python -c "import libmambapy._version; assert libmambapy._version.__version__ + == '1.5.8'" + - build: + python: + entry_points: + - mamba = mamba.mamba:main + script: + - build_mamba.sh + - '' + - '' + string: pypython_version_to_build_stringh${{ hash }}_2 + package: + name: mamba + version: 1.5.8 + requirements: + build: + - if: build_platform != target_platform + then: + - python + - cross-python_linux-64 + run: + - python + - conda >=23.9,<24 + - subpackage_pin libmambapy + tests: + - python: + imports: + - mamba + - script: + - mamba --help + - python -c "import mamba._version; assert mamba._version.__version__ == '1.5.8'" + - if: linux + then: + - test -f ${PREFIX}/etc/profile.d/mamba.sh + - mamba create -n test_py2 python=2.7 --dry-run + - mamba install xtensor xsimd -c conda-forge --dry-run + - if: unix + then: + - test -f ${PREFIX}/condabin/mamba + recipe: + name: mamba-split + source: + sha256: 6ddaf4b0758eb7ca1250f427bc40c2c3ede43257a60bac54e4320a4de66759a6 + url: https://github.com/mamba-org/mamba/archive/refs/tags/2024.03.25.tar.gz + + ''' +# ---