diff --git a/docs/recipe_file.md b/docs/recipe_file.md index 8f17bb2c..44c04969 100644 --- a/docs/recipe_file.md +++ b/docs/recipe_file.md @@ -311,9 +311,10 @@ The following example creates a Python entry point named "bsdiff4" that calls ```yaml build: - entry_points: - - bsdiff4 = bsdiff4.cli:main_bsdiff4 - - bspatch4 = bsdiff4.cli:main_bspatch4 + python: + entry_points: + - bsdiff4 = bsdiff4.cli:main_bsdiff4 + - bspatch4 = bsdiff4.cli:main_bspatch4 ``` diff --git a/examples/mamba/recipe.yaml b/examples/mamba/recipe.yaml index cbb25cca..327d762c 100644 --- a/examples/mamba/recipe.yaml +++ b/examples/mamba/recipe.yaml @@ -59,17 +59,17 @@ outputs: commands: - if: unix then: - - test -d ${PREFIX}/include/mamba # [unix] - - test -f ${PREFIX}/include/mamba/version.hpp # [unix] - - test -f ${PREFIX}/lib/cmake/libmamba/libmambaConfig.cmake # [unix] - - test -f ${PREFIX}/lib/cmake/libmamba/libmambaConfigVersion.cmake # [unix] - - test -e ${PREFIX}/lib/libmamba${SHLIB_EXT} # [unix] + - test -d ${PREFIX}/include/mamba # [unix] + - test -f ${PREFIX}/include/mamba/version.hpp # [unix] + - test -f ${PREFIX}/lib/cmake/libmamba/libmambaConfig.cmake # [unix] + - test -f ${PREFIX}/lib/cmake/libmamba/libmambaConfigVersion.cmake # [unix] + - test -e ${PREFIX}/lib/libmamba${SHLIB_EXT} # [unix] else: - - if not exist %LIBRARY_PREFIX%\include\mamba\version.hpp (exit 1) # [win] - - if not exist %LIBRARY_PREFIX%\lib\cmake\libmamba\libmambaConfig.cmake (exit 1) # [win] - - if not exist %LIBRARY_PREFIX%\lib\cmake\libmamba\libmambaConfigVersion.cmake (exit 1) # [win] - - if not exist %LIBRARY_PREFIX%\bin\libmamba.dll (exit 1) # [win] - - if not exist %LIBRARY_PREFIX%\lib\libmamba.lib (exit 1) # [win] + - if not exist %LIBRARY_PREFIX%\include\mamba\version.hpp (exit 1) # [win] + - if not exist %LIBRARY_PREFIX%\lib\cmake\libmamba\libmambaConfig.cmake (exit 1) # [win] + - if not exist %LIBRARY_PREFIX%\lib\cmake\libmamba\libmambaConfigVersion.cmake (exit 1) # [win] + - if not exist %LIBRARY_PREFIX%\bin\libmamba.dll (exit 1) # [win] + - if not exist %LIBRARY_PREFIX%\lib\libmamba.lib (exit 1) # [win] # - cat $PREFIX/include/mamba/version.hpp | grep "LIBMAMBA_VERSION_MAJOR ${{ libmamba_version_split[0] }}" # [unix] # - cat $PREFIX/include/mamba/version.hpp | grep "LIBMAMBA_VERSION_MINOR ${{ libmamba_version_split[1] }}" # [unix] # - cat $PREFIX/include/mamba/version.hpp | grep "LIBMAMBA_VERSION_PATCH ${{ libmamba_version_split[2] }}" # [unix] @@ -129,8 +129,9 @@ outputs: - ${{ "build_mamba.sh" if unix }} - ${{ "build_mamba.bat" if win }} string: py${{ python | version_to_buildstring }}h${{ hash }}_${{ build_number }} - entry_points: - - mamba = mamba.mamba:main + python: + entry_points: + - mamba = mamba.mamba:main requirements: build: - if: build_platform != target_platform diff --git a/src/packaging.rs b/src/packaging.rs index 54937699..799c3381 100644 --- a/src/packaging.rs +++ b/src/packaging.rs @@ -546,7 +546,7 @@ fn write_to_dest( /// This function creates a link.json file for the given output. fn create_link_json(output: &Output) -> Result, PackagingError> { let noarch_links = PythonEntryPoints { - entry_points: output.recipe.build().entry_points().to_owned(), + entry_points: output.recipe.build().python().entry_points().to_owned(), }; let link_json = LinkJson { @@ -816,6 +816,7 @@ pub fn package_conda( if output .recipe .build() + .python() .entry_points() .iter() .any(|ep| ep.command == name.to_string_lossy()) @@ -827,10 +828,17 @@ pub fn package_conda( // Windows else if stripped.starts_with("Scripts") { if let Some(name) = stripped.file_name() { - if output.recipe.build().entry_points().iter().any(|ep| { - format!("{}.exe", ep.command) == name.to_string_lossy() - || format!("{}-script.py", ep.command) == name.to_string_lossy() - }) { + if output + .recipe + .build() + .python() + .entry_points() + .iter() + .any(|ep| { + format!("{}.exe", ep.command) == name.to_string_lossy() + || format!("{}-script.py", ep.command) == name.to_string_lossy() + }) + { continue; } } diff --git a/src/recipe/parser/build.rs b/src/recipe/parser/build.rs index a5c95fc8..ba834e56 100644 --- a/src/recipe/parser/build.rs +++ b/src/recipe/parser/build.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use rattler_conda_types::{package::EntryPoint, NoArchKind, NoArchType}; +use rattler_conda_types::{package::EntryPoint, NoArchType}; use serde::{Deserialize, Serialize}; use super::Dependency; @@ -31,9 +31,9 @@ pub struct Build { pub(super) script: Script, /// A noarch package runs on any platform. It can be either a python package or a generic package. pub(super) noarch: NoArchType, - /// For a Python noarch package to have executables it is necessary to specify the python entry points. - /// These contain the name of the executable and the module + function that should be executed. - pub(super) entry_points: Vec, + /// Python specific build configuration + #[serde(default, skip_serializing_if = "Python::is_default")] + pub(super) python: Python, // TODO: Add and parse the rest of the fields } @@ -63,9 +63,9 @@ impl Build { &self.noarch } - /// Get the entry points. - pub fn entry_points(&self) -> &[EntryPoint] { - self.entry_points.as_slice() + /// Python specific build configuration. + pub const fn python(&self) -> &Python { + &self.python } /// Check if the build should be skipped. @@ -104,16 +104,8 @@ impl TryConvertNode for RenderedMappingNode { "noarch" => { build.noarch = value.try_convert(key_str)?; } - "entry_points" => { - if let Some(NoArchKind::Generic) = build.noarch.kind() { - return Err(_partialerror!( - *key.span(), - ErrorKind::Other, - label = "`entry_points` are only allowed for `python` noarch packages" - )); - } - - build.entry_points = value.try_convert(key_str)?; + "python" => { + build.python = value.try_convert(key_str)?; } invalid => { return Err(_partialerror!( @@ -128,6 +120,58 @@ impl TryConvertNode for RenderedMappingNode { } } +/// Python specific build configuration +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct Python { + /// For a Python noarch package to have executables it is necessary to specify the python entry points. + /// These contain the name of the executable and the module + function that should be executed. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub(super) entry_points: Vec, +} + +impl Python { + /// Get the entry points. + pub fn entry_points(&self) -> &[EntryPoint] { + self.entry_points.as_slice() + } + + /// Returns true if this is the default python configuration. + pub fn is_default(&self) -> bool { + self.entry_points.is_empty() + } +} + +impl TryConvertNode for RenderedNode { + fn try_convert(&self, name: &str) -> Result { + self.as_mapping() + .ok_or_else(|| _partialerror!(*self.span(), ErrorKind::ExpectedMapping)) + .and_then(|m| m.try_convert(name)) + } +} + +impl TryConvertNode for RenderedMappingNode { + fn try_convert(&self, _name: &str) -> Result { + let mut python = Python::default(); + + for (key, value) in self.iter() { + let key_str = key.as_str(); + match key_str { + "entry_points" => { + python.entry_points = value.try_convert(key_str)?; + } + invalid => { + return Err(_partialerror!( + *key.span(), + ErrorKind::InvalidField(invalid.to_string().into()), + )); + } + } + } + + Ok(python) + } +} + /// Run exports are applied to downstream packages that depend on this package. #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct RunExports { diff --git a/src/recipe/snapshots/rattler_build__recipe__parser__tests__it_works.snap b/src/recipe/snapshots/rattler_build__recipe__parser__tests__it_works.snap index 7abe7921..76a59dc3 100644 --- a/src/recipe/snapshots/rattler_build__recipe__parser__tests__it_works.snap +++ b/src/recipe/snapshots/rattler_build__recipe__parser__tests__it_works.snap @@ -88,7 +88,9 @@ Recipe { noarch: NoArchType( None, ), - entry_points: [], + python: Python { + entry_points: [], + }, }, requirements: Requirements { build: [ diff --git a/src/recipe/snapshots/rattler_build__recipe__parser__tests__jinja_sequence.snap b/src/recipe/snapshots/rattler_build__recipe__parser__tests__jinja_sequence.snap index 368dff6a..2989afcf 100644 --- a/src/recipe/snapshots/rattler_build__recipe__parser__tests__jinja_sequence.snap +++ b/src/recipe/snapshots/rattler_build__recipe__parser__tests__jinja_sequence.snap @@ -13,7 +13,6 @@ build: script: - test succeeded noarch: false - entry_points: [] requirements: {} test: imports: [] diff --git a/src/recipe/snapshots/rattler_build__recipe__parser__tests__recipe_windows.snap b/src/recipe/snapshots/rattler_build__recipe__parser__tests__recipe_windows.snap index 13ae7233..d347805a 100644 --- a/src/recipe/snapshots/rattler_build__recipe__parser__tests__recipe_windows.snap +++ b/src/recipe/snapshots/rattler_build__recipe__parser__tests__recipe_windows.snap @@ -88,7 +88,9 @@ Recipe { noarch: NoArchType( None, ), - entry_points: [], + python: Python { + entry_points: [], + }, }, requirements: Requirements { build: [ diff --git a/src/render/snapshots/rattler_build__render__recipe__tests__render.snap b/src/render/snapshots/rattler_build__render__recipe__tests__render.snap index 04449871..4170e9b3 100644 --- a/src/render/snapshots/rattler_build__render__recipe__tests__render.snap +++ b/src/render/snapshots/rattler_build__render__recipe__tests__render.snap @@ -18,7 +18,6 @@ build: number: 0 string: h12341234_0 noarch: false - entry_points: [] requirements: build: [] host: [] diff --git a/src/snapshots/rattler_build__metadata__test__read_full_recipe-2.snap b/src/snapshots/rattler_build__metadata__test__read_full_recipe-2.snap index f9d5f5e8..7706f0b7 100644 --- a/src/snapshots/rattler_build__metadata__test__read_full_recipe-2.snap +++ b/src/snapshots/rattler_build__metadata__test__read_full_recipe-2.snap @@ -18,7 +18,6 @@ recipe: skip: false script: [] noarch: false - entry_points: [] requirements: build: - __COMPILER c diff --git a/src/snapshots/rattler_build__metadata__test__read_full_recipe.snap b/src/snapshots/rattler_build__metadata__test__read_full_recipe.snap index 7fe87fb6..40a3b2da 100644 --- a/src/snapshots/rattler_build__metadata__test__read_full_recipe.snap +++ b/src/snapshots/rattler_build__metadata__test__read_full_recipe.snap @@ -19,7 +19,6 @@ recipe: script: - python -m pip install . -vv --no-deps --no-build-isolation noarch: python - entry_points: [] requirements: host: - pip diff --git a/test-data/recipes/flask/recipe.yaml b/test-data/recipes/flask/recipe.yaml index a921608f..ecc7776e 100644 --- a/test-data/recipes/flask/recipe.yaml +++ b/test-data/recipes/flask/recipe.yaml @@ -16,8 +16,9 @@ source: build: number: 0 script: python -m pip install . -vv --no-deps --no-build-isolation - entry_points: - - flask = flask.cli:main + python: + entry_points: + - flask = flask.cli:main noarch: python requirements: diff --git a/test-data/rendered_recipes/curl_recipe.yaml b/test-data/rendered_recipes/curl_recipe.yaml index 7b56f9c0..ca074a9e 100644 --- a/test-data/rendered_recipes/curl_recipe.yaml +++ b/test-data/rendered_recipes/curl_recipe.yaml @@ -14,7 +14,6 @@ recipe: skip: false script: [] noarch: false - entry_points: [] requirements: build: - __COMPILER c diff --git a/test-data/rendered_recipes/rich_recipe.yaml b/test-data/rendered_recipes/rich_recipe.yaml index aef7cf5a..5ad6c679 100644 --- a/test-data/rendered_recipes/rich_recipe.yaml +++ b/test-data/rendered_recipes/rich_recipe.yaml @@ -15,7 +15,6 @@ recipe: script: - python -m pip install . -vv --no-deps --no-build-isolation noarch: python - entry_points: [] requirements: build: [] host: