Skip to content

Commit 872e01c

Browse files
christian-schillingLMG
authored andcommitted
Don't change order of filters that share a prefix
This fixed an issue where pushing through workspace does not work correctly: The workspace root was sorted to the back and then reversed first, resulting in all mapped files being moved to the workspace dir.
1 parent 6b02ffe commit 872e01c

File tree

5 files changed

+89
-9
lines changed

5 files changed

+89
-9
lines changed

.github/workflows/rust.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ jobs:
3030
- uses: actions/checkout@v2
3131
- name: Check format
3232
run: cargo fmt -- --check
33+
- name: Run Rust tests
34+
run: cargo test
3335
- name: Configure environment
3436
run: |
3537
export CARGO_TARGET_DIR=`pwd`/target

src/cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::*;
22
use std::collections::HashMap;
33

4-
const VERSION: u64 = 4;
4+
const VERSION: u64 = 5;
55

66
lazy_static! {
77
static ref DB: std::sync::Mutex<Option<sled::Db>> =

src/filter/mod.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,34 @@ fn spec2(op: &Op) -> String {
175175
}
176176
}
177177

178+
pub fn src_path(filter: Filter) -> std::path::PathBuf {
179+
src_path2(&to_op(filter))
180+
}
181+
182+
fn src_path2(op: &Op) -> std::path::PathBuf {
183+
normalize_path(&match op {
184+
Op::Subdir(path) => path.to_owned(),
185+
Op::File(path) => path.to_owned(),
186+
Op::Chain(a, b) => src_path(*a).join(src_path(*b)),
187+
_ => std::path::PathBuf::new(),
188+
})
189+
.to_owned()
190+
}
191+
192+
pub fn dst_path(filter: Filter) -> std::path::PathBuf {
193+
dst_path2(&to_op(filter))
194+
}
195+
196+
fn dst_path2(op: &Op) -> std::path::PathBuf {
197+
normalize_path(&match op {
198+
Op::Prefix(path) => path.to_owned(),
199+
Op::File(path) => path.to_owned(),
200+
Op::Chain(a, b) => dst_path(*b).join(dst_path(*a)),
201+
_ => std::path::PathBuf::new(),
202+
})
203+
.to_owned()
204+
}
205+
178206
/// Calculate the filtered commit for `commit`. This can take some time if done
179207
/// for the first time and thus should generally be done asynchronously.
180208
pub fn apply_to_commit(
@@ -670,3 +698,32 @@ pub fn chain(first: Filter, second: Filter) -> Filter {
670698
pub fn compose(first: Filter, second: Filter) -> Filter {
671699
opt::optimize(to_filter(Op::Compose(vec![first, second])))
672700
}
701+
702+
#[cfg(test)]
703+
mod tests {
704+
use super::*;
705+
use std::path::PathBuf;
706+
707+
#[test]
708+
fn src_path_test() {
709+
assert_eq!(PathBuf::from("x"), src_path(parse(":/x").unwrap()));
710+
assert_eq!(PathBuf::from("x/y"), src_path(parse(":/x/y").unwrap()));
711+
assert_eq!(PathBuf::from("x/y"), src_path(parse(":/x::y").unwrap()));
712+
}
713+
714+
#[test]
715+
fn dst_path_test() {
716+
assert_eq!(PathBuf::from(""), dst_path(parse(":/x").unwrap()));
717+
assert_eq!(PathBuf::from(""), dst_path(parse(":/x/y").unwrap()));
718+
assert_eq!(PathBuf::from("y"), dst_path(parse(":/x::y").unwrap()));
719+
assert_eq!(
720+
PathBuf::from("a/y"),
721+
dst_path(parse(":[a=:/x::y/]").unwrap())
722+
);
723+
724+
assert_eq!(
725+
PathBuf::from("c/a"),
726+
dst_path(parse(":[a=:/x::y/,a/b=:/i]:prefix=c").unwrap())
727+
);
728+
}
729+
}

src/filter/opt.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,17 +201,19 @@ fn last_chain(rest: Filter, filter: Filter) -> (Filter, Filter) {
201201

202202
fn prefix_sort(filters: &Vec<Filter>) -> Vec<Filter> {
203203
let mut sorted = filters.clone();
204-
let mut ok = true;
205204
sorted.sort_by(|a, b| {
206-
if let (Op::Chain(a, _), Op::Chain(b, _)) = (to_op(*a), to_op(*b)) {
207-
if let (Op::Subdir(a), Op::Subdir(b)) = (to_op(a), to_op(b)) {
208-
return a.partial_cmp(&b).unwrap();
209-
}
205+
let (src_a, src_b) = (src_path(*a), src_path(*b));
206+
if src_a.starts_with(&src_b) || src_b.starts_with(&src_a) {
207+
return std::cmp::Ordering::Equal;
208+
}
209+
let (dst_a, dst_b) = (dst_path(*a), dst_path(*b));
210+
if dst_a.starts_with(&dst_b) || dst_b.starts_with(&dst_a) {
211+
return std::cmp::Ordering::Equal;
210212
}
211-
ok = false;
212-
std::cmp::Ordering::Equal
213+
214+
return (&src_a, &dst_a).partial_cmp(&(&src_b, &dst_b)).unwrap();
213215
});
214-
return if ok { sorted } else { filters.clone() };
216+
return sorted;
215217
}
216218

217219
fn common_pre(filters: &Vec<Filter>) -> Option<(Filter, Vec<Filter>)> {

tests/filter/pretty_print.t

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,22 @@
182182
::subsub1/
183183
::subsub2/
184184
]
185+
186+
Subdir only filters should not reorder filters that share a prefix
187+
$ cat > f <<EOF
188+
> a/subsub1 = :/sub1/subsub1
189+
> :/x/subsub2
190+
> EOF
191+
192+
$ josh-filter -p --file f
193+
a/subsub1 = :/sub1/subsub1
194+
:/x/subsub2
195+
196+
$ cat > f <<EOF
197+
> :/x/subsub2
198+
> a/subsub1 = :/sub1/subsub1
199+
> EOF
200+
201+
$ josh-filter -p --file f
202+
:/x/subsub2
203+
a/subsub1 = :/sub1/subsub1

0 commit comments

Comments
 (0)