Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/pixi_build_discovery/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pixi_consts = { workspace = true }
pixi_manifest = { workspace = true }
pixi_spec = { workspace = true }
pixi_spec_containers = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
insta = { workspace = true, features = [
Expand Down
43 changes: 33 additions & 10 deletions crates/pixi_build_discovery/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use ordermap::OrderMap;
use pixi_build_type_conversions::{to_project_model_v1, to_target_selector_v1};
use pixi_build_types::{ProjectModelV1, TargetSelectorV1};
use pixi_config::Config;
use pixi_consts::consts::{RATTLER_BUILD_DIRS, RATTLER_BUILD_FILE_NAMES, ROS_BACKEND_FILE_NAMES};
use pixi_consts::consts::{
KNOWN_MANIFEST_FILES, RATTLER_BUILD_DIRS, RATTLER_BUILD_FILE_NAMES, ROS_BACKEND_FILE_NAMES,
};
use pixi_manifest::{
DiscoveryStart, ExplicitManifestError, PackageManifest, PrioritizedChannel, WithProvenance,
WorkspaceDiscoverer, WorkspaceDiscoveryError, WorkspaceManifest,
Expand Down Expand Up @@ -113,11 +115,9 @@ pub enum DiscoveryError {
#[diagnostic(help("This is often caused by an internal error. Please report this issue."))]
SpecConversionError(pixi_spec::SpecConversionError),

#[error("the source directory '{0}', does not contain a supported manifest")]
#[diagnostic(help(
"Ensure that the source directory contains a valid pixi.toml, pyproject.toml, recipe.yaml, package.xml or mojoproject.toml file."
))]
FailedToDiscover(String),
#[error("the source directory '{path}', does not contain a supported manifest")]
#[diagnostic(help("{help}"))]
FailedToDiscover { path: String, help: String },

#[error("the manifest path '{0}', does not have a parent directory")]
NoParentDir(PathBuf),
Expand Down Expand Up @@ -159,7 +159,7 @@ impl DiscoveredBackend {
}
let source_dir = source_path
.parent()
.expect("the recipe must live somewhere");
.expect("the package.xml must live somewhere");
return Self::from_ros_package(
source_dir.to_path_buf(),
source_path,
Expand All @@ -182,9 +182,27 @@ impl DiscoveredBackend {
return Ok(pixi);
}

Err(DiscoveryError::FailedToDiscover(
source_path.to_string_lossy().to_string(),
))
// Test whether we can discover as a ROS package.
let help_msg = if enabled_protocols.enable_pixi
&& ROS_BACKEND_FILE_NAMES
.iter()
.any(|&f| source_path.join(f).is_file())
{
format!(
"ROS packages require you to specify the 'package.xml' file path directly, due to supporting more backends in the future. Or ensure that the source directory contains a valid manifest file: {}.",
KNOWN_MANIFEST_FILES.join(", ")
)
} else {
format!(
"Ensure that the source directory contains a valid manifest file: {}.",
KNOWN_MANIFEST_FILES.join(", ")
)
};

Err(DiscoveryError::FailedToDiscover {
path: source_path.to_string_lossy().to_string(),
help: help_msg,
})
}

/// Construct a new instance based on a specific `recipe.yaml` file in the
Expand Down Expand Up @@ -350,6 +368,11 @@ impl DiscoveredBackend {
)?));
}
}
tracing::trace!(
"No rattler-build manifests ({}) found in '{}'",
RATTLER_BUILD_FILE_NAMES.join(", "),
source_dir.display()
);
Ok(None)
}

Expand Down
36 changes: 36 additions & 0 deletions crates/pixi_build_discovery/tests/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,39 @@ fn test_direct_package_xml() {
assert_discover_snapshot ! ( & path);
});
}

#[test]
fn test_ros_discovery_priority() {
// Test that ROS packages are discovered after rattler-build recipes
// Create a test case with both package.xml and recipe.yaml
let path = dunce::canonicalize(discovery_directory().join("ros-priority")).unwrap();
let file_path = Path::new(file!()).parent().unwrap();
let channel_config = ChannelConfig::default_with_root_dir(file_path.to_owned());

match DiscoveredBackend::discover(&path, &channel_config, &EnabledProtocols::default()) {
Ok(backend) => {
// Should discover rattler-build backend, not ROS
insta::with_settings!({
filters => vec![
(path.to_string_lossy().replace(r"\", r"\\").as_str(), "file://<ROOT>"),
(r"\\", r"/"),
],
}, {
assert_yaml_snapshot!(backend, {
"[\"init-params\"][\"manifest-path\"]" => insta::dynamic_redaction(|value, _path| {
redact_path(value.as_str().unwrap())
}),
"[\"init-params\"][\"workspace-root\"]" => insta::dynamic_redaction(|value, _path| {
redact_path(value.as_str().unwrap())
}),
"[\"init-params\"][\"source-anchor\"]" => insta::dynamic_redaction(|value, _path| {
redact_path(value.as_str().unwrap())
}),
});
});
}
Err(err) => {
assert_snapshot!(pixi_test_utils::format_diagnostic(&err));
}
}
}
35 changes: 4 additions & 31 deletions crates/pixi_build_discovery/tests/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -1,35 +1,8 @@
---
source: crates/pixi_build_discovery/tests/discovery.rs
expression: backend
expression: "pixi_test_utils :: format_diagnostic(& err)"
input_file: tests/data/discovery/ros-package/TEST-CASE
---
backend-spec:
type: json-rpc
name: pixi-build-ros
command:
type: environment-spec
requirement:
- pixi-build-ros
- "*"
channels:
- "https://conda.anaconda.org/conda-forge"
- "https://prefix.dev/pixi-build-backends"
init-params:
workspace-root: "file://<ROOT>/ros-package"
source: ~
source-anchor: "file://<ROOT>/ros-package"
manifest-path: "file://<ROOT>/ros-package/package.xml"
project-model:
name: ~
version: ~
description: ~
authors: ~
license: ~
licenseFile: ~
readme: ~
homepage: ~
repository: ~
documentation: ~
targets: ~
configuration: ~
target-configuration: ~
× the source directory '<CARGO_ROOT>/tests/data/discovery/ros-package', does not contain a supported manifest
help: ROS packages require you to specify the 'package.xml' file path directly, due to supporting more backends in the future. Or ensure that the source directory contains a valid manifest file:
pixi.toml, pyproject.toml, mojoproject.toml, recipe.yaml, recipe.yml.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: crates/pixi_build_discovery/tests/discovery.rs
expression: backend
---
backend-spec:
type: json-rpc
name: pixi-build-rattler-build
command:
type: environment-spec
requirement:
- pixi-build-rattler-build
- "*"
channels:
- "https://prefix.dev/conda-forge"
init-params:
workspace-root: "file://<ROOT>/ros-priority"
build-source: ~
source-anchor: "file://<ROOT>/ros-priority"
manifest-path: "file://<ROOT>/ros-priority/recipe.yaml"
project-model: ~
configuration: ~
target-configuration: ~
12 changes: 8 additions & 4 deletions crates/pixi_consts/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,14 @@ pub const RATTLER_BUILD_FILE_NAMES: [&str; 2] = ["recipe.yaml", "recipe.yml"];
pub const RATTLER_BUILD_DIRS: [&str; 2] = ["", "recipe"];
pub const ROS_BACKEND_FILE_NAMES: [&str; 1] = ["package.xml"];

/// Known manifest file names that indicate the path points to a file rather than a directory.
pub const KNOWN_MANIFEST_FILES: &[&str] =
&[WORKSPACE_MANIFEST, PYPROJECT_MANIFEST, MOJOPROJECT_MANIFEST];

pub static KNOWN_MANIFEST_FILES: LazyLock<Vec<&'static str>> = LazyLock::new(|| {
let mut v = Vec::new();
v.push(WORKSPACE_MANIFEST);
v.push(PYPROJECT_MANIFEST);
v.push(MOJOPROJECT_MANIFEST);
v.extend(RATTLER_BUILD_FILE_NAMES);
v
});
pub static TASK_STYLE: LazyLock<Style> = LazyLock::new(|| Style::new().blue());
pub static TASK_ERROR_STYLE: LazyLock<Style> = LazyLock::new(|| Style::new().red());
pub static PLATFORM_STYLE: LazyLock<Style> = LazyLock::new(|| Style::new().yellow());
Expand Down
8 changes: 2 additions & 6 deletions crates/pixi_spec/src/source_anchor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use pixi_consts::consts::{KNOWN_MANIFEST_FILES, RATTLER_BUILD_FILE_NAMES, ROS_BACKEND_FILE_NAMES};
use pixi_consts::consts::KNOWN_MANIFEST_FILES;
use typed_path::{
Utf8Component, Utf8Encoding, Utf8Path, Utf8PathBuf, Utf8TypedPath, Utf8TypedPathBuf,
};
Expand Down Expand Up @@ -108,11 +108,7 @@ impl SourceAnchor {
/// to the workspace root.
fn is_known_manifest_file(path: Utf8TypedPath<'_>) -> bool {
path.file_name()
.map(|name| {
KNOWN_MANIFEST_FILES.contains(&name)
|| RATTLER_BUILD_FILE_NAMES.contains(&name)
|| ROS_BACKEND_FILE_NAMES.contains(&name)
})
.map(|name| KNOWN_MANIFEST_FILES.contains(&name))
.unwrap_or(false)
}

Expand Down
1 change: 1 addition & 0 deletions tests/data/discovery/ros-package/TEST-CASE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Marks this directory as a test-case for discovery tests.
5 changes: 5 additions & 0 deletions tests/data/discovery/ros-priority/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0"?>
<package format="3">
<name>priority_test_package</name>
<version>0.2.0</version>
</package>
6 changes: 6 additions & 0 deletions tests/data/discovery/ros-priority/recipe.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package:
name: priority-test
version: 0.1.0

build:
script: echo "This should be discovered"
5 changes: 5 additions & 0 deletions tests/data/discovery/ros-with-workspace/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0"?>
<package format="3">
<name>workspace_test_package</name>
<version>1.0.0</version>
</package>
4 changes: 4 additions & 0 deletions tests/data/discovery/ros-with-workspace/pixi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[workspace]
channels = ["robostack-staging", "conda-forge"]
name = "ros-workspace"
platforms = ["linux-64"]
Loading