Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
24 changes: 13 additions & 11 deletions crates/pixi_command_dispatcher/src/build_backend_metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,11 +584,10 @@ pub enum BuildBackendMetadataError {
#[error("the build backend {0} does not support the `conda/outputs` procedure")]
BackendMissingCapabilities(String),

#[error("the build backend returned outputs with duplicate variants for package '{package}': {duplicates}")]
DuplicateVariants {
package: String,
duplicates: String,
},
#[error(
"the build backend returned outputs with duplicate variants for package '{package}': {duplicates}"
)]
DuplicateVariants { package: String, duplicates: String },

#[error("could not compute hash of input files")]
GlobHash(#[from] pixi_glob::GlobHashError),
Expand Down Expand Up @@ -624,10 +623,7 @@ mod tests {
use rattler_conda_types::{NoArchType, PackageName, Platform, Version};
use std::collections::BTreeMap;

fn create_test_output(
name: &str,
variant: BTreeMap<String, String>,
) -> CondaOutput {
fn create_test_output(name: &str, variant: BTreeMap<String, String>) -> CondaOutput {
CondaOutput {
metadata: CondaOutputMetadata {
name: PackageName::try_from(name).unwrap(),
Expand Down Expand Up @@ -669,7 +665,10 @@ mod tests {
];

let result = BuildBackendMetadataSpec::validate_unique_variants(&outputs);
assert!(result.is_ok(), "Expected validation to pass for unique variants");
assert!(
result.is_ok(),
"Expected validation to pass for unique variants"
);
}

#[test]
Expand Down Expand Up @@ -749,7 +748,10 @@ mod tests {
)];

let result = BuildBackendMetadataSpec::validate_unique_variants(&outputs);
assert!(result.is_ok(), "Expected validation to pass for single output");
assert!(
result.is_ok(),
"Expected validation to pass for single output"
);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/pixi_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ repository.workspace = true
version = "0.1.0"

[features]
slow_integration_tests = []
self_update = []
slow_integration_tests = []

[dependencies]
async-once-cell = { workspace = true }
Expand Down
77 changes: 76 additions & 1 deletion crates/pixi_manifest/src/manifests/provenance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,16 @@ impl ManifestProvenance {
}

/// Returns the absolute path to the manifest file.
///
/// This method canonicalizes the parent directory but preserves the original
/// filename, which allows symlinked manifest files to be treated correctly.
pub fn absolute_path(&self) -> PathBuf {
dunce::canonicalize(self.path.clone()).unwrap_or(self.path.to_path_buf())
match (self.path.parent(), self.path.file_name()) {
(Some(parent), Some(file_name)) => dunce::canonicalize(parent)
.map(|canonical_parent| canonical_parent.join(file_name))
.unwrap_or_else(|_| self.path.to_path_buf()),
_ => self.path.to_path_buf(),
}
}
}

Expand Down Expand Up @@ -142,3 +150,70 @@ impl<T> AssociateProvenance for T {
WithProvenance::new(self, provenance)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn absolute_path_canonicalizes_parent_only() {
let temp_dir = tempfile::tempdir().unwrap();
let dotfiles_dir = temp_dir.path().join("dotfiles");
let home_dir = temp_dir.path().join("home");
fs_err::create_dir_all(&dotfiles_dir).unwrap();
fs_err::create_dir_all(&home_dir).unwrap();

// Real manifest lives inside the dotfiles directory.
let real_manifest = dotfiles_dir.join("pixi.toml");
fs_err::write(&real_manifest, "[workspace]\nname = \"test\"\n").unwrap();

// Home directory contains a symlink that points at the real manifest.
let symlink_manifest = home_dir.join("pixi.toml");
#[cfg(unix)]
std::os::unix::fs::symlink(&real_manifest, &symlink_manifest).unwrap();

let canonical_real_path = dunce::canonicalize(&real_manifest).unwrap();
let cases = [
(
"real file",
real_manifest.clone(),
dotfiles_dir.clone(),
true,
),
(
"symlinked file",
symlink_manifest.clone(),
home_dir.clone(),
false,
),
];

for (label, manifest_path, expected_parent, should_match_real) in cases {
let provenance = ManifestProvenance::new(manifest_path.clone(), ManifestKind::Pixi);
let absolute = provenance.absolute_path();

assert_eq!(
absolute.file_name(),
manifest_path.file_name(),
"filename changed for {label}"
);
assert_eq!(
absolute.parent().unwrap(),
dunce::canonicalize(&expected_parent).unwrap(),
"parent directory mismatch for {label}"
);

if should_match_real {
assert_eq!(
absolute, canonical_real_path,
"real file should resolve exactly"
);
} else {
assert_ne!(
absolute, canonical_real_path,
"symlink should not resolve to the real file path"
);
}
}
}
}
Loading