Skip to content

Commit

Permalink
vendor: prioritize file mappings over directories
Browse files Browse the repository at this point in the history
File mappings are more specific and
should be preferred over directory mappings.

As an example we have two mappings:
a/ -> c/
b/file -> c/file

Any change in c/ should be then result in a patch.
If the change is in c/file we must make sure it is linked back
to b/file, not erroneously to a/, the sorting does this.

Similarly when initializing we first need to copy the a/ dir to c/
and only then copy b/file to c/file.
  • Loading branch information
phsauter authored and micprog committed Aug 21, 2024
1 parent 779d524 commit 5a8ba6c
Showing 1 changed file with 35 additions and 15 deletions.
50 changes: 35 additions & 15 deletions src/cmd/vendor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,40 @@ pub fn run(sess: &Session, matches: &ArgMatches) -> Result<()> {
}
};

// sort patch_links so more specific links have priority
// 1. file links over directory links eg 'a/file -> c/file' before 'b/ -> c/'
// 2. deeper paths first eg 'a/aa/ -> c/aa' before 'a/ab -> c/'
let mut sorted_links: Vec<_> = patch_links.clone();
sorted_links.sort_by(|a, b| {
let a_is_file = a.to_prefix.is_file();
let b_is_file = b.to_prefix.is_file();

if a_is_file != b_is_file {
return b_is_file.cmp(&a_is_file);
}

let a_depth = a.to_prefix.iter().count();
let b_depth = b.to_prefix.iter().count();

b_depth.cmp(&a_depth)
});
let git = Git::new(tmp_path, &sess.config.git);

match matches.subcommand() {
Some(("diff", matches)) => {
// Apply patches
patch_links.clone().into_iter().try_for_each(|patch_link| {
apply_patches(&rt, git, vendor_package.name.clone(), patch_link).map(|_| ())
})?;
sorted_links
.clone()
.into_iter()
.try_for_each(|patch_link| {
apply_patches(&rt, git, vendor_package.name.clone(), patch_link).map(|_| ())
})?;

// Stage applied patches to clean working tree
rt.block_on(git.add_all())?;

// Print diff for each link
patch_links.into_iter().try_for_each(|patch_link| {
sorted_links.into_iter().try_for_each(|patch_link| {
let get_diff = diff(&rt, git, vendor_package, patch_link, dep_path.clone())
.map_err(|cause| Error::chain("Failed to get diff.", cause))?;
if !get_diff.is_empty() {
Expand All @@ -176,7 +196,7 @@ pub fn run(sess: &Session, matches: &ArgMatches) -> Result<()> {
}

Some(("init", matches)) => {
patch_links.clone().into_iter().try_for_each(|patch_link| {
sorted_links.into_iter().rev().try_for_each(|patch_link| {
stageln!("Copying", "{} files from upstream", vendor_package.name);
// Remove existing directories before importing them again
let target_path = patch_link
Expand Down Expand Up @@ -209,7 +229,7 @@ pub fn run(sess: &Session, matches: &ArgMatches) -> Result<()> {
Some(("patch", matches)) => {
// Apply patches
let mut num_patches = 0;
patch_links
sorted_links
.clone()
.into_iter()
.try_for_each(|patch_link| {
Expand All @@ -225,7 +245,7 @@ pub fn run(sess: &Session, matches: &ArgMatches) -> Result<()> {
}

// Generate patch
patch_links.clone().into_iter().try_for_each( |patch_link| {
sorted_links.into_iter().try_for_each( |patch_link| {
match patch_link.patch_dir.clone() {
Some(patch_dir) => {
if matches.get_flag("plain") {
Expand Down Expand Up @@ -364,19 +384,19 @@ pub fn apply_patches(
})
.and_then(|_| {
git.spawn_with(|c| {
let current_patch_target = if !patch_link
let is_file = patch_link
.from_prefix
.clone()
.prefix_paths(git.path)
.unwrap()
.is_file()
{
patch_link.from_prefix.as_path()
.is_file();

let current_patch_target = if is_file {
patch_link.from_prefix.parent().unwrap().to_str().unwrap()
} else {
patch_link.from_prefix.parent().unwrap()
}
.to_str()
.unwrap();
patch_link.from_prefix.as_path().to_str().unwrap()
};

c.arg("apply")
.arg("--directory")
.arg(current_patch_target)
Expand Down

0 comments on commit 5a8ba6c

Please sign in to comment.