Skip to content

Commit bcea6f6

Browse files
authored
fix: rattler-build backend globs (#151)
1 parent 229d980 commit bcea6f6

File tree

3 files changed

+154
-26
lines changed

3 files changed

+154
-26
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pixi-build-rattler-build/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ serde_json = { workspace = true }
1515
tempfile = { workspace = true }
1616
tokio = { workspace = true, features = ["macros"] }
1717
url = { workspace = true }
18+
pathdiff = { workspace = true }
1819

1920
pixi-build-backend = { workspace = true }
2021

crates/pixi-build-rattler-build/src/protocol.rs

Lines changed: 152 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use fs_err::tokio as tokio_fs;
88
use miette::{Context, IntoDiagnostic};
99
use pixi_build_backend::{
1010
protocol::{Protocol, ProtocolInstantiator},
11-
source::Source,
1211
tools::RattlerBuild,
1312
utils::TemporaryRenderedRecipe,
1413
};
@@ -196,9 +195,11 @@ impl Protocol for RattlerBuildBackend {
196195
solved_packages.push(conda);
197196
}
198197

198+
let input_globs = Some(Vec::from(["recipe.yaml".to_string()]));
199+
199200
Ok(CondaMetadataResult {
200201
packages: solved_packages,
201-
input_globs: Some(input_globs(&self.recipe_source, None)),
202+
input_globs,
202203
})
203204
}
204205

@@ -318,9 +319,22 @@ impl Protocol for RattlerBuildBackend {
318319
})
319320
.await?;
320321

322+
let package_sources = output.finalized_sources.as_ref().map(|package_sources| {
323+
package_sources
324+
.iter()
325+
.filter_map(|source| {
326+
if let rattler_build::recipe::parser::Source::Path(path_source) = source {
327+
Some(path_source.path.clone())
328+
} else {
329+
None
330+
}
331+
})
332+
.collect()
333+
});
334+
321335
built.push(CondaBuiltPackage {
322336
output_file: build_path,
323-
input_globs: input_globs(&self.recipe_source, output.finalized_sources.as_ref()),
337+
input_globs: build_input_globs(&self.recipe_source.path, package_sources)?,
324338
name: output.name().as_normalized().to_string(),
325339
version: output.version().to_string(),
326340
build: build_string.to_string(),
@@ -331,40 +345,55 @@ impl Protocol for RattlerBuildBackend {
331345
}
332346
}
333347

334-
fn input_globs(
335-
source: &Source,
336-
package_sources: Option<&Vec<rattler_build::recipe::parser::Source>>,
337-
) -> Vec<String> {
338-
let mut input_globs = vec![];
339-
let parent = if source.path.is_file() {
348+
/// Returns the relative path from `base` to `input`, joined by "/".
349+
pub fn relative_path_joined(
350+
base: &std::path::Path,
351+
input: &std::path::Path,
352+
) -> miette::Result<String> {
353+
let rel = pathdiff::diff_paths(input, base).ok_or_else(|| {
354+
miette::miette!(
355+
"could not compute relative path from '{:?}' to '{:?}'",
356+
input,
357+
base
358+
)
359+
})?;
360+
let joined = rel
361+
.components()
362+
.map(|c| c.as_os_str().to_string_lossy())
363+
.collect::<Vec<_>>()
364+
.join("/");
365+
Ok(joined)
366+
}
367+
368+
fn build_input_globs(
369+
source: &Path,
370+
package_sources: Option<Vec<PathBuf>>,
371+
) -> miette::Result<Vec<String>> {
372+
// Always add the current directory of the package to the globs
373+
let mut input_globs = vec!["*/**".to_string()];
374+
375+
// Get parent directory path
376+
let parent = if source.is_file() {
340377
// use the parent path as glob
341-
if let Some(parent) = source.path.parent() {
342-
parent.to_path_buf()
343-
} else {
344-
source.path.clone()
345-
}
378+
source.parent().unwrap_or(source).to_path_buf()
346379
} else {
347380
// use the source path as glob
348-
source.path.clone()
381+
source.to_path_buf()
349382
};
350383

351-
// add the source path as glob
352-
input_globs.push(format!("{}/**", parent.display()));
353-
384+
// If there are sources add them to the globs as well
354385
if let Some(package_sources) = package_sources {
355386
for source in package_sources {
356-
if let rattler_build::recipe::parser::Source::Path(path_source) = source {
357-
// add the package source path as glob
358-
if path_source.path.is_dir() {
359-
input_globs.push(format!("{}/**", path_source.path.display()));
360-
} else {
361-
input_globs.push(path_source.path.display().to_string());
362-
}
387+
let source_glob = relative_path_joined(&parent, &source)?;
388+
if source.is_dir() {
389+
input_globs.push(format!("{}/**", source_glob));
390+
} else {
391+
input_globs.push(source_glob);
363392
}
364393
}
365394
}
366395

367-
input_globs
396+
Ok(input_globs)
368397
}
369398

370399
#[async_trait::async_trait]
@@ -590,4 +619,101 @@ mod tests {
590619
recipe
591620
);
592621
}
622+
623+
#[test]
624+
fn test_relative_path_joined() {
625+
use std::path::Path;
626+
// Simple case
627+
let base = Path::new("/foo/bar");
628+
let input = Path::new("/foo/bar/baz/qux.txt");
629+
assert_eq!(
630+
super::relative_path_joined(base, input).unwrap(),
631+
"baz/qux.txt"
632+
);
633+
// Same path
634+
let base = Path::new("/foo/bar");
635+
let input = Path::new("/foo/bar");
636+
assert_eq!(super::relative_path_joined(base, input).unwrap(), "");
637+
// Input not under base
638+
let base = Path::new("/foo/bar");
639+
let input = Path::new("/foo/other");
640+
assert_eq!(
641+
super::relative_path_joined(base, input).unwrap(),
642+
"../other"
643+
);
644+
// Relative paths
645+
let base = Path::new("foo/bar");
646+
let input = Path::new("foo/bar/baz");
647+
assert_eq!(super::relative_path_joined(base, input).unwrap(), "baz");
648+
}
649+
650+
#[test]
651+
#[cfg(windows)]
652+
fn test_relative_path_joined_windows() {
653+
use std::path::Path;
654+
let base = Path::new(r"C:\foo\bar");
655+
let input = Path::new(r"C:\foo\bar\baz\qux.txt");
656+
assert_eq!(
657+
super::relative_path_joined(base, input).unwrap(),
658+
"baz/qux.txt"
659+
);
660+
let base = Path::new(r"C:\foo\bar");
661+
let input = Path::new(r"C:\foo\bar");
662+
assert_eq!(super::relative_path_joined(base, input).unwrap(), "");
663+
let base = Path::new(r"C:\foo\bar");
664+
let input = Path::new(r"C:\foo\other");
665+
assert_eq!(
666+
super::relative_path_joined(base, input).unwrap(),
667+
"../other"
668+
);
669+
}
670+
671+
#[test]
672+
fn test_build_input_globs_with_tempdirs() {
673+
use std::fs;
674+
use tempfile::tempdir;
675+
676+
// Create a temp directory to act as the base
677+
let base_dir = tempdir().unwrap();
678+
let base_path = base_dir.path();
679+
680+
// Case 1: source is a file in the base dir
681+
let recipe_path = base_path.join("recipe.yaml");
682+
fs::write(&recipe_path, "fake").unwrap();
683+
let globs = super::build_input_globs(&recipe_path, None).unwrap();
684+
assert_eq!(globs, vec!["*/**"]);
685+
686+
// Case 2: source is a directory, with a file and a dir as package sources
687+
let pkg_dir = base_path.join("pkg");
688+
let pkg_file = pkg_dir.join("file.txt");
689+
let pkg_subdir = pkg_dir.join("dir");
690+
fs::create_dir_all(&pkg_subdir).unwrap();
691+
fs::write(&pkg_file, "fake").unwrap();
692+
let globs =
693+
super::build_input_globs(base_path, Some(vec![pkg_file.clone(), pkg_subdir.clone()]))
694+
.unwrap();
695+
assert_eq!(globs, vec!["*/**", "pkg/file.txt", "pkg/dir/**"]);
696+
}
697+
698+
#[test]
699+
fn test_build_input_globs_two_folders_in_tempdir() {
700+
use std::fs;
701+
use tempfile::tempdir;
702+
703+
// Create a temp directory
704+
let temp = tempdir().unwrap();
705+
let temp_path = temp.path();
706+
707+
// Create two folders: source_dir and package_source_dir
708+
let source_dir = temp_path.join("source");
709+
let package_source_dir = temp_path.join("pkgsrc");
710+
fs::create_dir_all(&source_dir).unwrap();
711+
fs::create_dir_all(&package_source_dir).unwrap();
712+
713+
// Call build_input_globs with source_dir as source, and package_source_dir as package source
714+
let globs =
715+
super::build_input_globs(&source_dir, Some(vec![package_source_dir.clone()])).unwrap();
716+
// The relative path from source_dir to package_source_dir should be "../pkgsrc/**"
717+
assert_eq!(globs, vec!["*/**", "../pkgsrc/**"]);
718+
}
593719
}

0 commit comments

Comments
 (0)