Repository: conda-incubator/conda-recipe-manager

Issue:
Add `merge_build_host` transformation
We are missing a transformation of the `merge_build_host` field from CEP-14:
```
  # merge the build and host environments (used in many R packages on Windows)
  # was `merge_build_host`
  merge_build_and_host_envs: bool (defaults to false)
```

`rattler-build` error:
```
Error:   × Parsing: invalid field `merge_build_host`.
    ╭─[50:3]
 49 │   noarch: generic
 50 │   merge_build_host: $${{ true if win }}
    ·   ────────┬───────
    ·           ╰── here
 51 │   rpaths:
    ╰────
```

Discussion:
schuylermartin45: Although the integration testing passed, there was a slight dip in the success metrics. ~50 recipes in AnacondaRecipes (and more elsewhere) set `source` to a list of objects:

```
source:
  - path: ./
```
`rattler-build` supports this so I'll need to make a slight adjustment and add a regression test.
schuylermartin45: If this latest push passes, and the error rate is improved, we should be good to merge.
schuylermartin45: #50 was a quick win so I've added it to this PR as well.

Patch:
diff --git a/conda_recipe_manager/parser/_types.py b/conda_recipe_manager/parser/_types.py
index fc3f85c..5cf081b 100644
--- a/conda_recipe_manager/parser/_types.py
+++ b/conda_recipe_manager/parser/_types.py
@@ -42,6 +42,28 @@ TOP_LEVEL_KEY_SORT_ORDER: Final[dict[str, int]] = {
     "extra": 120,
 }
 
+# Canonical sort order for the new "v1" recipe format's `build` block
+V1_SOURCE_SECTION_KEY_SORT_ORDER: Final[dict[str, int]] = {
+    # URL source fields
+    "url": 0,
+    "sha256": 10,
+    "md5": 20,
+    # Local source fields (not including above)
+    "path": 30,
+    "use_gitignore": 40,
+    # Git source fields (not including above)
+    "git": 50,
+    "branch": 60,
+    "tag": 70,
+    "rev": 80,
+    "depth": 90,
+    "lfs": 100,
+    # Common fields
+    "target_directory": 120,
+    "file_name": 130,
+    "patches": 140,
+}
+
 # Canonical sort order for the new "v1" recipe format's `build` block
 V1_BUILD_SECTION_KEY_SORT_ORDER: Final[dict[str, int]] = {
     "number": 0,
diff --git a/conda_recipe_manager/parser/recipe_parser_convert.py b/conda_recipe_manager/parser/recipe_parser_convert.py
index 41c9932..0bf3551 100644
--- a/conda_recipe_manager/parser/recipe_parser_convert.py
+++ b/conda_recipe_manager/parser/recipe_parser_convert.py
@@ -15,6 +15,7 @@ from conda_recipe_manager.parser._types import (
     ROOT_NODE_VALUE,
     TOP_LEVEL_KEY_SORT_ORDER,
     V1_BUILD_SECTION_KEY_SORT_ORDER,
+    V1_SOURCE_SECTION_KEY_SORT_ORDER,
     Regex,
 )
 from conda_recipe_manager.parser._utils import stack_path_to_str, str_to_stack_path
@@ -196,6 +197,45 @@ class RecipeParserConvert(RecipeParser):
                 self._patch_and_log(patch)
                 self._new_recipe.remove_selector(selector_path)
 
+    def _upgrade_source_section(self, base_package_paths: list[str]) -> None:
+        """
+        Upgrades/converts the `source` section(s) of a recipe file.
+        :param base_package_paths: Set of base paths to process that could contain this section.
+        """
+        for base_path in base_package_paths:
+            source_path = RecipeParser.append_to_path(base_path, "/source")
+            if not self._new_recipe.contains_value(source_path):
+                continue
+
+            # The `source` field can contain a list of elements or a single element (not encapsulated in a list).
+            # This logic sets up a list to iterate through that will handle both cases.
+            source_data = self._new_recipe.get_value(source_path)
+            source_paths = []
+            if isinstance(source_data, list):
+                for x in range(len(source_data)):
+                    source_paths.append(RecipeParser.append_to_path(source_path, f"/{x}"))
+            else:
+                source_paths.append(source_path)
+
+            for src_path in source_paths:
+                # SVN and HG source options are no longer supported. This seems to have been deprecated a long
+                # time ago and there are unlikely any recipes that fall into this camp. Still, we should flag it.
+                if self._new_recipe.contains_value(RecipeParser.append_to_path(src_path, "svn_url")):
+                    self._msg_tbl.add_message(
+                        MessageCategory.WARNING, "SVN packages are no longer supported in the new format"
+                    )
+                if self._new_recipe.contains_value(RecipeParser.append_to_path(src_path, "hg_url")):
+                    self._msg_tbl.add_message(
+                        MessageCategory.WARNING, "HG (Mercury) packages are no longer supported in the new format"
+                    )
+
+                # Basic renaming transformations
+                self._patch_move_base_path(src_path, "/fn", "/file_name")
+                self._patch_move_base_path(src_path, "/folder", "/target_directory")
+
+                # Canonically sort this section
+                self._sort_subtree_keys(src_path, V1_SOURCE_SECTION_KEY_SORT_ORDER)
+
     def _upgrade_build_section(self, base_package_paths: list[str]) -> None:
         """
         Upgrades/converts the `about` section(s) of a recipe file.
@@ -226,6 +266,10 @@ class RecipeParserConvert(RecipeParser):
             if not self._new_recipe.contains_value(build_path):
                 continue
 
+            # Simple transformations
+            self._patch_move_base_path(build_path, "merge_build_host", "merge_build_and_host_envs")
+            self._patch_move_base_path(build_path, "no_link", "always_copy_files")
+
             # `build/entry_points` -> `build/python/entry_points`
             self._patch_move_new_path(build_path, "/entry_points", "/python")
 
@@ -238,35 +282,16 @@ class RecipeParserConvert(RecipeParser):
             # Canonically sort this section
             self._sort_subtree_keys(build_path, V1_BUILD_SECTION_KEY_SORT_ORDER)
 
-    def _upgrade_about_section(self) -> None:
+    def _upgrade_about_section(self, base_package_paths: list[str]) -> None:
         """
         Upgrades/converts the `about` section of a recipe file.
+        :param base_package_paths: Set of base paths to process that could contain this section.
         """
-        # Warn if "required" fields are missing
-        about_required: Final[list[str]] = [
-            "summary",
-            "description",
-            "license",
-            "license_file",
-            "license_url",
-        ]
-        for field in about_required:
-            path = f"/about/{field}"
-            if not self._new_recipe.contains_value(path):
-                self._msg_tbl.add_message(MessageCategory.WARNING, f"Required field missing: {path}")
-
-        # Transform renamed fields
-        about_rename: Final[list[tuple[str, str]]] = [
+        about_rename_mapping: Final[list[tuple[str, str]]] = [
             ("home", "homepage"),
             ("dev_url", "repository"),
             ("doc_url", "documentation"),
         ]
-        for old, new in about_rename:
-            self._patch_move_base_path("/about", old, new)
-
-        # TODO validate: /about/license must be SPDX recognized.
-
-        # Remove deprecated `about` fields
         about_deprecated: Final[list[str]] = [
             "prelink_message",
             "license_family",
@@ -275,10 +300,25 @@ class RecipeParserConvert(RecipeParser):
             "keywords",
             "doc_source_url",
         ]
-        for field in about_deprecated:
-            path = f"/about/{field}"
-            if self._new_recipe.contains_value(path):
-                self._patch_and_log({"op": "remove", "path": path})
+
+        for base_path in base_package_paths:
+            about_path = RecipeParser.append_to_path(base_path, "/about")
+
+            # Skip transformations if there is no `/about` section
+            if not self._new_recipe.contains_value(about_path):
+                continue
+
+            # Transform renamed fields
+            for old, new in about_rename_mapping:
+                self._patch_move_base_path(about_path, old, new)
+
+            # TODO validate: /about/license must be SPDX recognized.
+
+            # Remove deprecated `about` fields
+            for field in about_deprecated:
+                path = RecipeParser.append_to_path(about_path, field)
+                if self._new_recipe.contains_value(path):
+                    self._patch_and_log({"op": "remove", "path": path})
 
     def _upgrade_test_pip_check(self, base_path: str, test_path: str) -> None:
         """
@@ -472,8 +512,9 @@ class RecipeParserConvert(RecipeParser):
         # TODO Fix: comments are not preserved with patch operations (add a flag to `patch()`?)
 
         # Upgrade common sections found in a recipe
+        self._upgrade_source_section(base_package_paths)
         self._upgrade_build_section(base_package_paths)
-        self._upgrade_about_section()
+        self._upgrade_about_section(base_package_paths)
         self._upgrade_test_section(base_package_paths)
         self._upgrade_multi_output(base_package_paths)
 


Test patch:
diff --git a/tests/parser/test_recipe_parser_convert.py b/tests/parser/test_recipe_parser_convert.py
index 8282322..c10ac1d 100644
--- a/tests/parser/test_recipe_parser_convert.py
+++ b/tests/parser/test_recipe_parser_convert.py
@@ -40,43 +40,29 @@ def test_pre_process_recipe_text(input_file: str, expected_file: str) -> None:
             [
                 "A non-list item had a selector at: /package/name",
                 "A non-list item had a selector at: /requirements/empty_field2",
-                "Required field missing: /about/license_file",
-                "Required field missing: /about/license_url",
             ],
         ),
         (
             "multi-output.yaml",
             [],
-            [
-                "Required field missing: /about/summary",
-                "Required field missing: /about/description",
-                "Required field missing: /about/license",
-                "Required field missing: /about/license_file",
-                "Required field missing: /about/license_url",
-            ],
+            [],
         ),
         (
             "huggingface_hub.yaml",
             [],
-            [
-                "Required field missing: /about/license_url",
-            ],
+            [],
         ),
         (
             "types-toml.yaml",
             [],
-            [
-                "Required field missing: /about/license_url",
-            ],
+            [],
         ),
         # Regression test: Contains a `test` section that caused an empty dictionary to be inserted in the conversion
         # process, causing an index-out-of-range exception.
         (
             "pytest-pep8.yaml",
             [],
-            [
-                "Required field missing: /about/license_url",
-            ],
+            [],
         ),
         # Regression test: Contains selectors and test section data that caused previous conversion issues.
         (
@@ -87,24 +73,26 @@ def test_pre_process_recipe_text(input_file: str, expected_file: str) -> None:
                 "A non-list item had a selector at: /outputs/1/script",
                 "A non-list item had a selector at: /outputs/0/script",
                 "A non-list item had a selector at: /outputs/1/script",
-                "Required field missing: /about/description",
-                "Required field missing: /about/license_url",
             ],
         ),
         # Tests for transformations related to the new `build/dynamic_linking` section
         (
             "dynamic-linking.yaml",
             [],
-            ["Required field missing: /about/license_url"],
+            [],
         ),
         # Regression: Tests for proper indentation of a list item inside a collection node element
         (
             "boto.yaml",
             [],
-            [
-                "Required field missing: /about/license_file",
-                "Required field missing: /about/license_url",
-            ],
+            [],
+        ),
+        # Regression: Tests a recipe that has multiple `source`` objects in `/source` AND an `about` per `output`
+        # TODO Issue #50 tracks an edge case caused by this project that is not currently handled.
+        (
+            "cctools-ld64.yaml",
+            [],
+            [],
         ),
         # TODO complete: The `rust.yaml` test contains many edge cases and selectors that aren't directly supported in
         # the new recipe format
diff --git a/tests/test_aux_files/cctools-ld64.yaml b/tests/test_aux_files/cctools-ld64.yaml
new file mode 100644
index 0000000..3738dcf
--- /dev/null
+++ b/tests/test_aux_files/cctools-ld64.yaml
@@ -0,0 +1,131 @@
+# Extracted from
+
+{% set cctools_version = '921' %}
+{% set cctools_sha256 = '53449a7f2e316c7df5e6b94fd04e12b6d0356f2487d77aad3000134e4c010cc5' %}
+{% set ld64_version = '409.12' %}
+{% set ld64_sha256 = 'c34561b44210668c51e49efdb7d1e814a33056051ac7698571605ab968d31d5f' %}
+{% set dyld_version = '551.4' %}
+{% set dyld_sha256 = '15f86b62fb91c75fcdfedfee2ef8759585d4b9ef9ed1757cae8f4f13bd58e51c' %}
+{% set clang_version = '7.0.0' %}
+{% set clang_sha256 = 'b3ad93c3d69dfd528df9c5bb1a434367babb8f3baea47fbb99bf49f1b03c94ca' %}
+{% set native_compiler_subdir = 'linux-64' %}
+
+package:
+  name: cctools-and-ld64
+  version: {{ ld64_version }}
+
+source:
+  - url: https://opensource.apple.com/tarballs/cctools/cctools-{{ cctools_version }}.tar.gz
+    sha256: {{ cctools_sha256 }}
+    folder: cctools
+    patches:
+      - 001-cctools-remove_static_part.patch
+      - 100-cctools-add_sdkroot_headers.patch
+      - 110-cctools-import_to_include.patch
+      - 120-cctools-fix_time_bugs.patch
+      - 130-cctools-add_compileguards.patch
+      - 140-cctools-remove_sysctl_osversion_detection.patch
+      - 160-cctools-map_64bit_arches.patch
+      - 170-cctools-fix_printf_format_bugs.patch
+      - 180-cctools-add_CROSS_SYSROOT.patch
+      - 190-cctools-default_arch.patch
+      - 210-cctools-dont_typedef_NxConstantString.patch
+      - 220-cctools-cross-prefixes-EXEEXT-and-progname_fixes.patch
+      - 240-cctools-use_strerror.patch
+      - 250-cctools-dont_assume_getattrlist.patch
+      - 260-cctools-ppc64_reenable.patch
+      - 270-cctools-dont_assume_vm_sync.patch
+      - 280-cctools-missing_includes.patch
+      - 290-cctools-error_as_weak_symbol.patch
+      - 300-cctools-undef___unused_for_sysctl.patch
+      - 340-cctools-win_O_BINARY.patch
+      - 350-cctools-win_fileio_mode.patch
+      - 360-cctools-win_TMPDIR_to_TEMP.patch
+      - 370-cctools-win_execute.patch
+      - 380-cctools-win_avoid_mmap_ofile.patch
+      - 400-cctools-_WIN64-fixes.patch
+      - 410-cctools-remove_inc_arch_sparc_reg_h_PC.patch
+      - 420-cctools-autoconfiscate.patch
+  - url: https://opensource.apple.com/tarballs/ld64/ld64-{{ ld64_version }}.tar.gz
+    sha256: {{ ld64_sha256 }}
+    folder: cctools/ld64
+    patches:
+      - 100-ld64-add_sdkroot_headers.patch
+      - 150-ld64-allow_glibc_or_bsd_qsort_r.patch
+      - 180-ld64-add_CROSS_SYSROOT.patch
+      - 200-ld64-add_typename.patch
+      - 280-ld64-missing_includes.patch
+      - 320-ld64-extern_C_log2_only_if___APPLE__.patch
+      - 330-ld64-extern_C___assert_rtn.patch
+      - 340-ld64-win_O_BINARY.patch
+      - 350-ld64-win_fileio_mode.patch
+      - 390-ld64-_WIN64-fixes.patch
+      - 420-ld64-autoconfiscate.patch
+      - 500-ld64-add-fake-CrashReporterClient.h.patch
+      - 520-ld64-fix-usr-local-and-usr-ordering.patch
+      - 530-ld64-add-conda-specific-env-vars-to-modify-lib-search-paths.patch
+      - 540-ld64-add-LD64_LOG_HASH_TABLE.patch
+  # We copy headers necessary for building cctools/ld64 from dyld and MacOSX10.9.sdk (on all OSes).
+  # older versions of these files are added by 100-add_sdkroot_headers.patch, we overwrite those...
+  - url: https://opensource.apple.com/tarballs/dyld/dyld-{{ dyld_version }}.tar.gz
+    sha256: {{ dyld_sha256 }}
+    folder: bootstrap/dyld
+  - url: http://releases.llvm.org/{{ clang_version }}/clang+llvm-{{ clang_version }}-x86_64-apple-darwin.tar.xz
+    sha256: {{ clang_sha256 }}
+    folder: bootstrap/clang7
+
+requirements:
+  build:
+    # we use selectors rather than jinja2 here because we only want to use the native
+    #   compiler to build llvm and clang (which are natively cross-compilers.)
+    # We might want to split the runtime libs below into a separate recipe,
+    #    so that this recipe can use jinja2 instead.
+    - gcc_{{ native_compiler_subdir }}  # [linux]
+    - gxx_{{ native_compiler_subdir }}  # [linux]
+    # - {{ compiler('cxx') }}  # [osx]
+    - autoconf
+    - automake
+  host:
+    - xar-bootstrap
+    # We only use the static library from this and only get away with that as it depends on nothing.
+    - zlib
+    - llvm-lto-tapi
+
+outputs:
+  - name: cctools
+    version: {{ cctools_version }}
+    script: install-cctools.sh
+    requirements:
+      run:
+        - llvm-lto-tapi
+    build:
+      number: 1
+      ignore_run_exports:
+        - zlib
+    about:
+      home: https://opensource.apple.com/source
+      license: Apple Public Source License 2.0
+      license_family: Other
+      license_file: cctools/APPLE_LICENSE
+      summary: Assembler, archiver, ranlib, libtool, otool et al for Darwin Mach-O files
+
+  - name: ld64
+    version: {{ ld64_version }}
+    script: install-ld64.sh
+    requirements:
+      host:
+        - llvm-lto-tapi
+        - libcxx  # [osx]
+      run:
+        - llvm-lto-tapi
+        - libcxx  # [osx]
+    build:
+      number: 1
+      ignore_run_exports:
+        - zlib
+    about:
+      home: https://opensource.apple.com/source
+      license: Apple Public Source License 2.0
+      license_family: Other
+      license_file: cctools/ld64/APPLE_LICENSE
+      summary: Darwin Mach-O linker
diff --git a/tests/test_aux_files/new_format_boto.yaml b/tests/test_aux_files/new_format_boto.yaml
index 4903eb9..cd8b29e 100644
--- a/tests/test_aux_files/new_format_boto.yaml
+++ b/tests/test_aux_files/new_format_boto.yaml
@@ -9,9 +9,9 @@ package:
   version: ${{ version }}
 
 source:
-  fn: ${{ name }}-${{ version }}.tar.gz
   url: https://pypi.org/packages/source/${{ name[0] }}/${{ name }}/${{ name }}-${{ version }}.tar.gz
   sha256: ea0d3b40a2d852767be77ca343b58a9e3a4b00d9db440efb8da74b4e58025e5a
+  file_name: ${{ name }}-${{ version }}.tar.gz
 
 build:
   number: 0
diff --git a/tests/test_aux_files/new_format_cctools-ld64.yaml b/tests/test_aux_files/new_format_cctools-ld64.yaml
new file mode 100644
index 0000000..5126cc6
--- /dev/null
+++ b/tests/test_aux_files/new_format_cctools-ld64.yaml
@@ -0,0 +1,136 @@
+# Extracted from
+schema_version: 1
+
+context:
+  cctools_version: 921
+  cctools_sha256: 53449a7f2e316c7df5e6b94fd04e12b6d0356f2487d77aad3000134e4c010cc5
+  ld64_version: 409.12
+  ld64_sha256: c34561b44210668c51e49efdb7d1e814a33056051ac7698571605ab968d31d5f
+  dyld_version: 551.4
+  dyld_sha256: 15f86b62fb91c75fcdfedfee2ef8759585d4b9ef9ed1757cae8f4f13bd58e51c
+  clang_version: 7.0.0
+  clang_sha256: b3ad93c3d69dfd528df9c5bb1a434367babb8f3baea47fbb99bf49f1b03c94ca
+  native_compiler_subdir: linux-64
+
+recipe:
+  name: cctools-and-ld64
+  version: ${{ ld64_version }}
+
+source:
+  - url: https://opensource.apple.com/tarballs/cctools/cctools-${{ cctools_version }}.tar.gz
+    sha256: ${{ cctools_sha256 }}
+    target_directory: cctools
+    patches:
+      - 001-cctools-remove_static_part.patch
+      - 100-cctools-add_sdkroot_headers.patch
+      - 110-cctools-import_to_include.patch
+      - 120-cctools-fix_time_bugs.patch
+      - 130-cctools-add_compileguards.patch
+      - 140-cctools-remove_sysctl_osversion_detection.patch
+      - 160-cctools-map_64bit_arches.patch
+      - 170-cctools-fix_printf_format_bugs.patch
+      - 180-cctools-add_CROSS_SYSROOT.patch
+      - 190-cctools-default_arch.patch
+      - 210-cctools-dont_typedef_NxConstantString.patch
+      - 220-cctools-cross-prefixes-EXEEXT-and-progname_fixes.patch
+      - 240-cctools-use_strerror.patch
+      - 250-cctools-dont_assume_getattrlist.patch
+      - 260-cctools-ppc64_reenable.patch
+      - 270-cctools-dont_assume_vm_sync.patch
+      - 280-cctools-missing_includes.patch
+      - 290-cctools-error_as_weak_symbol.patch
+      - 300-cctools-undef___unused_for_sysctl.patch
+      - 340-cctools-win_O_BINARY.patch
+      - 350-cctools-win_fileio_mode.patch
+      - 360-cctools-win_TMPDIR_to_TEMP.patch
+      - 370-cctools-win_execute.patch
+      - 380-cctools-win_avoid_mmap_ofile.patch
+      - 400-cctools-_WIN64-fixes.patch
+      - 410-cctools-remove_inc_arch_sparc_reg_h_PC.patch
+      - 420-cctools-autoconfiscate.patch
+  - url: https://opensource.apple.com/tarballs/ld64/ld64-${{ ld64_version }}.tar.gz
+    sha256: ${{ ld64_sha256 }}
+    target_directory: cctools/ld64
+    patches:
+      - 100-ld64-add_sdkroot_headers.patch
+      - 150-ld64-allow_glibc_or_bsd_qsort_r.patch
+      - 180-ld64-add_CROSS_SYSROOT.patch
+      - 200-ld64-add_typename.patch
+      - 280-ld64-missing_includes.patch
+      - 320-ld64-extern_C_log2_only_if___APPLE__.patch
+      - 330-ld64-extern_C___assert_rtn.patch
+      - 340-ld64-win_O_BINARY.patch
+      - 350-ld64-win_fileio_mode.patch
+      - 390-ld64-_WIN64-fixes.patch
+      - 420-ld64-autoconfiscate.patch
+      - 500-ld64-add-fake-CrashReporterClient.h.patch
+      - 520-ld64-fix-usr-local-and-usr-ordering.patch
+      - 530-ld64-add-conda-specific-env-vars-to-modify-lib-search-paths.patch
+      - 540-ld64-add-LD64_LOG_HASH_TABLE.patch
+  # We copy headers necessary for building cctools/ld64 from dyld and MacOSX10.9.sdk (on all OSes).
+  # older versions of these files are added by 100-add_sdkroot_headers.patch, we overwrite those...
+  - url: https://opensource.apple.com/tarballs/dyld/dyld-${{ dyld_version }}.tar.gz
+    sha256: ${{ dyld_sha256 }}
+    target_directory: bootstrap/dyld
+  - url: http://releases.llvm.org/${{ clang_version }}/clang+llvm-${{ clang_version }}-x86_64-apple-darwin.tar.xz
+    sha256: ${{ clang_sha256 }}
+    target_directory: bootstrap/clang7
+
+requirements:
+  build:
+    # we use selectors rather than jinja2 here because we only want to use the native
+    #   compiler to build llvm and clang (which are natively cross-compilers.)
+    # We might want to split the runtime libs below into a separate recipe,
+    #    so that this recipe can use jinja2 instead.
+    - if: linux
+      then: gcc_${{ native_compiler_subdir }}
+    - if: linux
+      then: gxx_${{ native_compiler_subdir }}
+    # - {{ compiler('cxx') }}  # [osx]
+    - autoconf
+    - automake
+  host:
+    - xar-bootstrap
+    # We only use the static library from this and only get away with that as it depends on nothing.
+    - zlib
+    - llvm-lto-tapi
+
+outputs:
+  - package:
+      name: cctools
+      version: ${{ cctools_version }}
+    build:
+      number: 1
+      ignore_run_exports:
+        - zlib
+    requirements:
+      run:
+        - llvm-lto-tapi
+    about:
+      license: Apple Public Source License 2.0
+      license_file: cctools/APPLE_LICENSE
+      summary: Assembler, archiver, ranlib, libtool, otool et al for Darwin Mach-O files
+      homepage: https://opensource.apple.com/source
+    script: install-cctools.sh
+  - package:
+      name: ld64
+      version: ${{ ld64_version }}
+    build:
+      number: 1
+      ignore_run_exports:
+        - zlib
+    requirements:
+      host:
+        - llvm-lto-tapi
+        - if: osx
+          then: libcxx
+      run:
+        - llvm-lto-tapi
+        - if: osx
+          then: libcxx
+    about:
+      license: Apple Public Source License 2.0
+      license_file: cctools/ld64/APPLE_LICENSE
+      summary: Darwin Mach-O linker
+      homepage: https://opensource.apple.com/source
+    script: install-ld64.sh
diff --git a/tests/test_aux_files/new_format_pytest-pep8.yaml b/tests/test_aux_files/new_format_pytest-pep8.yaml
index 2e34a7e..feefba6 100644
--- a/tests/test_aux_files/new_format_pytest-pep8.yaml
+++ b/tests/test_aux_files/new_format_pytest-pep8.yaml
@@ -10,9 +10,9 @@ package:
   version: ${{ version }}
 
 source:
-  fn: ${{ name }}-${{ version }}.tar.gz
   url: https://pypi.io/packages/source/${{ name[0] }}/${{ name }}/${{ name }}-${{ version }}.tar.gz
   sha256: ${{ sha256 }}
+  file_name: ${{ name }}-${{ version }}.tar.gz
 
 build:
   number: 1