diff --git a/backends/pixi-build-ros/src/pixi_build_ros/config.py b/backends/pixi-build-ros/src/pixi_build_ros/config.py index 87791cd4..8bf5d45b 100644 --- a/backends/pixi-build-ros/src/pixi_build_ros/config.py +++ b/backends/pixi-build-ros/src/pixi_build_ros/config.py @@ -71,7 +71,9 @@ class ROSBackendConfig(pydantic.BaseModel, extra="forbid", arbitrary_types_allow # Environment variables to set during the build env: dict[str, str] | None = None # Directory for debug files of this script - debug_dir: Path | None = pydantic.Field(default=None, alias="debug-dir") + debug_dir: Path | None = pydantic.Field( + default=None, validation_alias=pydantic.AliasChoices("debug-dir", "debug_dir") + ) # Extra input globs to include in the build hash extra_input_globs: list[str] | None = pydantic.Field(default=None, alias="extra-input-globs") diff --git a/backends/pixi-build-ros/src/pixi_build_ros/metadata_provider.py b/backends/pixi-build-ros/src/pixi_build_ros/metadata_provider.py index e3b95d3b..73ffca1b 100644 --- a/backends/pixi-build-ros/src/pixi_build_ros/metadata_provider.py +++ b/backends/pixi-build-ros/src/pixi_build_ros/metadata_provider.py @@ -47,6 +47,7 @@ class PackageXmlMetadataProvider(MetadataProvider): # type: ignore[misc] # Met def __init__( # type: ignore[no-untyped-def] # no typing for args and kwargs self, package_xml_path: str, + manifest_root: str, *args, extra_input_globs: list[str] | None = None, package_mapping_files: list[str] | None = None, @@ -57,11 +58,13 @@ def __init__( # type: ignore[no-untyped-def] # no typing for args and kwargs Args: package_xml_path: Path to the package.xml file + manifest_root: Path to the manifest root directory extra_input_globs: Additional glob patterns to include package_mapping_files: Package mapping file paths to track as inputs """ super().__init__(*args, **kwargs) self.package_xml_path = package_xml_path + self.manifest_root = manifest_root self._package_data: PackageData | None = None self._extra_input_globs = list(extra_input_globs or []) self._package_mapping_files = list(package_mapping_files or []) @@ -148,8 +151,9 @@ def license(self) -> str | None: return None def license_file(self) -> str | None: - """Return package.xml as the license files.""" - return "package.xml" + """Return package.xml as the license files, relative to manifest_root.""" + # TODO: This does not work currently, so return None + return None def summary(self) -> str | None: """Return the description as summary from package.xml.""" @@ -189,6 +193,7 @@ class ROSPackageXmlMetadataProvider(PackageXmlMetadataProvider): def __init__( self, package_xml_path: str, + manifest_root: str, distro_name: str | None = None, *, extra_input_globs: list[str] | None = None, @@ -199,12 +204,14 @@ def __init__( Args: package_xml_path: Path to the package.xml file + manifest_root: Path to the manifest root directory distro_name: ROS distro. If None, will use the base package name without distro prefix. extra_input_globs: Additional glob patterns to include package_mapping_files: Package mapping file paths to track as inputs """ super().__init__( package_xml_path, + manifest_root=manifest_root, extra_input_globs=extra_input_globs, package_mapping_files=package_mapping_files, ) diff --git a/backends/pixi-build-ros/src/pixi_build_ros/ros_generator.py b/backends/pixi-build-ros/src/pixi_build_ros/ros_generator.py index 422746a3..22f983a6 100644 --- a/backends/pixi-build-ros/src/pixi_build_ros/ros_generator.py +++ b/backends/pixi-build-ros/src/pixi_build_ros/ros_generator.py @@ -54,6 +54,7 @@ def generate_recipe( package_mapping_files = [str(path) for path in backend_config.get_package_mapping_file_paths()] metadata_provider = ROSPackageXmlMetadataProvider( str(package_xml_path), + str(manifest_root), backend_config.distro.name, extra_input_globs=list(backend_config.extra_input_globs or []), package_mapping_files=package_mapping_files, diff --git a/backends/pixi-build-ros/templates/build_catkin.sh b/backends/pixi-build-ros/templates/build_catkin.sh index e0968210..4f6044f0 100644 --- a/backends/pixi-build-ros/templates/build_catkin.sh +++ b/backends/pixi-build-ros/templates/build_catkin.sh @@ -14,8 +14,7 @@ if [ "${PKG_NAME}" == "ros-noetic-catkin" ]; then CATKIN_BUILD_BINARY_PACKAGE="OFF" fi -rm -rf build -mkdir build +mkdir -p build cd build # necessary for correctly linking SIP files (from python_qt_bindings) diff --git a/backends/pixi-build-ros/tests/__snapshots__/test_package_xml.ambr b/backends/pixi-build-ros/tests/__snapshots__/test_package_xml.ambr index aca58249..4133fae1 100644 --- a/backends/pixi-build-ros/tests/__snapshots__/test_package_xml.ambr +++ b/backends/pixi-build-ros/tests/__snapshots__/test_package_xml.ambr @@ -124,7 +124,7 @@ about: homepage: https://test.io/custom_ros license: LicenseRef-Apache License 2.0 - license_file: package.xml + license_file: null summary: Demo description: Demo documentation: null diff --git a/backends/pixi-build-ros/tests/__snapshots__/test_version_constraints.ambr b/backends/pixi-build-ros/tests/__snapshots__/test_version_constraints.ambr index 1f182c1b..820fc309 100644 --- a/backends/pixi-build-ros/tests/__snapshots__/test_version_constraints.ambr +++ b/backends/pixi-build-ros/tests/__snapshots__/test_version_constraints.ambr @@ -68,7 +68,7 @@ about: homepage: null license: LicenseRef-Apache License 2.0 - license_file: package.xml + license_file: null summary: Demo description: Demo documentation: null @@ -145,7 +145,7 @@ about: homepage: null license: LicenseRef-Apache License 2.0 - license_file: package.xml + license_file: null summary: Demo description: Demo documentation: null @@ -222,7 +222,7 @@ about: homepage: null license: LicenseRef-Apache License 2.0 - license_file: package.xml + license_file: null summary: Demo description: Demo documentation: null diff --git a/backends/pixi-build-ros/tests/test_meta_data_provider.py b/backends/pixi-build-ros/tests/test_meta_data_provider.py index 2499fcb5..735397e3 100644 --- a/backends/pixi-build-ros/tests/test_meta_data_provider.py +++ b/backends/pixi-build-ros/tests/test_meta_data_provider.py @@ -10,25 +10,27 @@ def test_metadata_provider(package_xmls: Path): """Test the MetaDataProvider class.""" package_xml_path = package_xmls / "custom_ros.xml" - metadata_provider = PackageXmlMetadataProvider(str(package_xml_path)) + metadata_provider = PackageXmlMetadataProvider(str(package_xml_path), str(package_xmls)) assert metadata_provider.name() == "custom_ros" assert metadata_provider.version() == "0.0.1" assert metadata_provider.license() == "LicenseRef-Apache License 2.0" assert metadata_provider.description() == "Demo" assert metadata_provider.homepage() == "https://test.io/custom_ros" assert metadata_provider.repository() == "https://github.com/test/custom_ros" + assert metadata_provider.license_file() is None def test_ros_metadata_provider(package_xmls: Path): """Test the RosMetaDataProvider class.""" package_xml_path = package_xmls / "custom_ros.xml" - metadata_provider = ROSPackageXmlMetadataProvider(str(package_xml_path), distro_name="noetic") + metadata_provider = ROSPackageXmlMetadataProvider(str(package_xml_path), str(package_xmls), distro_name="noetic") assert metadata_provider.name() == "ros-noetic-custom-ros" assert metadata_provider.version() == "0.0.1" assert metadata_provider.license() == "LicenseRef-Apache License 2.0" assert metadata_provider.description() == "Demo" assert metadata_provider.homepage() == "https://test.io/custom_ros" assert metadata_provider.repository() == "https://github.com/test/custom_ros" + assert metadata_provider.license_file() is None def test_metadata_provider_raises_on_broken_xml(package_xmls: Path): @@ -36,7 +38,7 @@ def test_metadata_provider_raises_on_broken_xml(package_xmls: Path): broken_xml_path = package_xmls / "broken.xml" with pytest.raises(RuntimeError) as exc_info: - ROSPackageXmlMetadataProvider(str(broken_xml_path), distro_name="noetic") + ROSPackageXmlMetadataProvider(str(broken_xml_path), str(package_xmls), distro_name="noetic") # Verify the exception contains location information error = exc_info.value @@ -85,6 +87,7 @@ def test_metadata_provider_includes_package_mapping_files_in_input_globs(): # Create metadata provider metadata_provider = ROSPackageXmlMetadataProvider( str(package_xml_path), + str(temp_path), distro_name="noetic", package_mapping_files=package_mapping_files, ) diff --git a/crates/pixi-build-backend/src/intermediate_backend.rs b/crates/pixi-build-backend/src/intermediate_backend.rs index 313fd1d1..e9b2afeb 100644 --- a/crates/pixi-build-backend/src/intermediate_backend.rs +++ b/crates/pixi-build-backend/src/intermediate_backend.rs @@ -113,9 +113,13 @@ impl IntermediateBackend { (source_dir, manifest_rel_path) } Some(source_dir) => { - let manifest_rel_path = pathdiff::diff_paths(manifest_path, &source_dir) + let manifest_rel_path = pathdiff::diff_paths(&manifest_path, &source_dir) .ok_or_else(|| { - miette::miette!("the manifest is not relative to the source directory") + miette::miette!( + "the manifest: {} is not relative to the source directory: {}", + manifest_path.display(), + source_dir.display() + ) })?; (source_dir, manifest_rel_path) } diff --git a/crates/pixi-build-backend/tests/integration/protocol.rs b/crates/pixi-build-backend/tests/integration/protocol.rs index 248c5975..86c6f9ae 100644 --- a/crates/pixi-build-backend/tests/integration/protocol.rs +++ b/crates/pixi-build-backend/tests/integration/protocol.rs @@ -26,6 +26,7 @@ mod imp { #[serde(rename_all = "kebab-case")] pub struct TestBackendConfig { /// If set, internal state will be logged as files in that directory + #[serde(alias = "debug_dir")] pub debug_dir: Option, } diff --git a/crates/pixi-build-cmake/src/config.rs b/crates/pixi-build-cmake/src/config.rs index 75eefc53..476bfe10 100644 --- a/crates/pixi-build-cmake/src/config.rs +++ b/crates/pixi-build-cmake/src/config.rs @@ -14,6 +14,7 @@ pub struct CMakeBackendConfig { #[serde(default)] pub env: IndexMap, /// If set, internal state will be logged as files in that directory + #[serde(alias = "debug_dir")] pub debug_dir: Option, /// Extra input globs to include in addition to the default ones #[serde(default)] diff --git a/crates/pixi-build-mojo/src/config.rs b/crates/pixi-build-mojo/src/config.rs index eaca8963..458c0aec 100644 --- a/crates/pixi-build-mojo/src/config.rs +++ b/crates/pixi-build-mojo/src/config.rs @@ -17,6 +17,7 @@ pub struct MojoBackendConfig { pub env: IndexMap, /// Dir that can be specified for outputting pixi debug state. + #[serde(alias = "debug_dir")] pub debug_dir: Option, /// Extra input globs to include in addition to the default ones. diff --git a/crates/pixi-build-python/src/config.rs b/crates/pixi-build-python/src/config.rs index bf6d9263..84b1a11b 100644 --- a/crates/pixi-build-python/src/config.rs +++ b/crates/pixi-build-python/src/config.rs @@ -17,6 +17,7 @@ pub struct PythonBackendConfig { #[serde(default)] pub env: IndexMap, /// If set, internal state will be logged as files in that directory + #[serde(alias = "debug_dir")] pub debug_dir: Option, /// Extra input globs to include in addition to the default ones #[serde(default)] diff --git a/crates/pixi-build-rattler-build/src/config.rs b/crates/pixi-build-rattler-build/src/config.rs index e61f2e7e..ffde090a 100644 --- a/crates/pixi-build-rattler-build/src/config.rs +++ b/crates/pixi-build-rattler-build/src/config.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; #[serde(rename_all = "kebab-case", deny_unknown_fields)] pub struct RattlerBuildBackendConfig { /// If set, internal state will be logged as files in that directory + #[serde(alias = "debug_dir")] pub debug_dir: Option, /// Extra input globs to include in addition to the default ones #[serde(default)] diff --git a/crates/pixi-build-rust/src/config.rs b/crates/pixi-build-rust/src/config.rs index 157cda01..ef370fb2 100644 --- a/crates/pixi-build-rust/src/config.rs +++ b/crates/pixi-build-rust/src/config.rs @@ -14,6 +14,7 @@ pub struct RustBackendConfig { #[serde(default)] pub env: IndexMap, /// If set, internal state will be logged as files in that directory + #[serde(alias = "debug_dir")] pub debug_dir: Option, /// Extra input globs to include in addition to the default ones #[serde(default)] @@ -95,6 +96,23 @@ mod tests { serde_json::from_value::(json_data).unwrap(); } + #[test] + fn test_debug_dir_accepts_both_formats() { + // Test with debug-dir (kebab-case) - the canonical format + let json_with_hyphen = json!({ + "debug-dir": "/path/to/debug" + }); + let config = serde_json::from_value::(json_with_hyphen).unwrap(); + assert_eq!(config.debug_dir, Some(PathBuf::from("/path/to/debug"))); + + // Test with debug_dir (underscore) - should also work due to alias + let json_with_underscore = json!({ + "debug_dir": "/path/to/debug" + }); + let config = serde_json::from_value::(json_with_underscore).unwrap(); + assert_eq!(config.debug_dir, Some(PathBuf::from("/path/to/debug"))); + } + #[test] fn test_merge_with_target_config() { let mut base_env = indexmap::IndexMap::new(); diff --git a/py-pixi-build-backend/src/types/config.rs b/py-pixi-build-backend/src/types/config.rs index 63195d89..2cc0d956 100644 --- a/py-pixi-build-backend/src/types/config.rs +++ b/py-pixi-build-backend/src/types/config.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use pixi_build_backend::generated_recipe::BackendConfig; -use pyo3::{Py, PyAny, Python, pyclass, pymethods}; +use pyo3::{pyclass, pymethods, Py, PyAny, Python}; use pythonize::pythonize; use serde::Deserialize; use serde::Deserializer; @@ -26,9 +26,10 @@ impl<'de> Deserialize<'de> for PyBackendConfig { Python::attach(|py| { let model = pythonize(py, &data).map_err(serde::de::Error::custom)?; + // Support both debug_dir and debug-dir let debug_dir: Option = data .as_object_mut() - .and_then(|obj| obj.get("debug_dir")) + .and_then(|obj| obj.get("debug-dir").or_else(|| obj.get("debug_dir"))) .and_then(|v| v.as_str().map(PathBuf::from)); Ok(PyBackendConfig {