Skip to content

Commit

Permalink
Merge pull request #88 from mufeedvh/fb-relative-path-fix
Browse files Browse the repository at this point in the history
Fb relative path fix
  • Loading branch information
ODAncona authored Feb 24, 2025
2 parents e89af5c + ac51247 commit d5a5165
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 35 deletions.
17 changes: 11 additions & 6 deletions src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,23 @@ fn build_globset(patterns: &[String]) -> GlobSet {
builder.build().expect("❌ Impossible to build GlobSet")
}

/// Determines whether a file should be included based on include and exclude patterns.
/// Determines whether a file should be included based on the provided glob patterns.
///
/// Note: The `path` argument must be a relative path (i.e. relative to the base directory)
/// for the patterns to match as expected. Absolute paths will not yield correct matching.
///
/// # Arguments
///
/// * `path` - The path to the file to be checked.
/// * `include_patterns` - A slice of strings representing the include patterns.
/// * `exclude_patterns` - A slice of strings representing the exclude patterns.
/// * `include_priority` - A boolean indicating whether to give priority to include patterns if both include and exclude patterns match.
/// * `path` - A relative path to the file that will be checked against the patterns.
/// * `include_patterns` - A slice of glob pattern strings specifying which files to include.
/// If empty, all files are considered included unless excluded.
/// * `exclude_patterns` - A slice of glob pattern strings specifying which files to exclude.
/// * `include_priority` - A boolean flag that, when set to `true`, gives include patterns
/// precedence over exclude patterns in cases where both match.
///
/// # Returns
///
/// * `bool` - `true` if the file should be included, `false` otherwise.
/// * `bool` - Returns `true` if the file should be included; otherwise, returns `false`.
pub fn should_include_file(
path: &Path,
include_patterns: &[String],
Expand Down
16 changes: 12 additions & 4 deletions src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,19 @@ pub fn traverse_directory(
.follow_links(follow_symlinks)
.build()
.filter_map(|entry| match entry {
Ok(entry)
Ok(entry) => {
// Convert to a relative path using the canonical root as the base.
let relative_path = entry
.path()
.strip_prefix(&canonical_root_path)
.unwrap_or(entry.path());
if full_directory_tree
|| should_include_file(entry.path(), include, exclude, include_priority) =>
{
Some(entry)
|| should_include_file(relative_path, include, exclude, include_priority)
{
Some(entry)
} else {
None
}
}
_ => None,
})
Expand Down
140 changes: 115 additions & 25 deletions tests/filter_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// This file tests the filter logic
/// Code2prompt uses the file globbing and globpattern to match files
/// Therefore you can match files:
/// Therefore you can match files:
use code2prompt::filter::should_include_file;
use colored::*;
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -115,7 +115,7 @@ mod tests {
));
}
}

// ¬Include && Exclude
#[test]
fn test_no_include_exclude_path() {
Expand Down Expand Up @@ -150,6 +150,56 @@ mod tests {
));
}

#[test]
fn test_no_include_exclude_path_patterns() {
let base_path = TEST_DIR.path();

let include_patterns = vec![];
let exclude_patterns = vec!["lowercase/{*.txt,*.py}".to_string()];
let include_priority = false;

// ~~~ Must be excluded ~~~
for file in [
"lowercase/qux.txt",
"lowercase/corge.txt",
"lowercase/grault.txt",
"lowercase/foo.py",
"lowercase/bar.py",
"lowercase/baz.py",
] {
let path = base_path.join(file);
let relative_path = path.strip_prefix(base_path).unwrap();

assert!(!should_include_file(
&relative_path,
&include_patterns,
&exclude_patterns,
include_priority
));
}

// ~~~ Must be included ~~~
for file in [
"uppercase/QUX.txt",
"uppercase/CORGE.txt",
"uppercase/GRAULT.txt",
".secret/secret.txt",
"uppercase/FOO.py",
"uppercase/BAR.py",
"uppercase/BAZ.py",
] {
let path = base_path.join(file);
let relative_path = path.strip_prefix(base_path).unwrap();

assert!(should_include_file(
&relative_path,
&include_patterns,
&exclude_patterns,
include_priority
));
}
}

#[test]
fn test_no_include_exclude_patterns() {
let base_path = TEST_DIR.path();
Expand Down Expand Up @@ -248,11 +298,7 @@ mod tests {
let include_priority = false;

// ~~~ Must be excluded ~~~
for file in [
"lowercase/foo.py",
"lowercase/bar.py",
"lowercase/qux.txt",
] {
for file in ["lowercase/foo.py", "lowercase/bar.py", "lowercase/qux.txt"] {
let path = base_path.join(file);
assert!(!should_include_file(
&path,
Expand Down Expand Up @@ -335,12 +381,7 @@ mod tests {
let include_priority = false;

// ~~~ Must be excluded ~~~
for file in [
"src/filter.rs",
"src/git.rs",
"src/lib.rs",
"src/token.rs",
] {
for file in ["src/filter.rs", "src/git.rs", "src/lib.rs", "src/token.rs"] {
let path = base_path.join(file);
assert!(!should_include_file(
&path,
Expand All @@ -358,23 +399,69 @@ mod tests {
&exclude_patterns,
include_priority
));

}

#[test]
fn test_include_no_exclude_folders() {
fn test_include_no_exclude_by_path_pattern() {
let base_path = TEST_DIR.path();

let include_patterns = vec!["**/lowercase/**".to_string()];
// let include_patterns = vec!["lowercase/*.txt".to_string(), "lowercase/*.py".to_string()];
let include_patterns = vec!["lowercase/{*.txt,*.py}".to_string()];
let exclude_patterns = vec![];
let include_priority = true;
let include_priority = false;

// ~~~ Must be included ~~~
for file in [
"lowercase/qux.txt",
"lowercase/corge.txt",
"lowercase/grault.txt",
"lowercase/foo.py",
"lowercase/bar.py",
"lowercase/qux.txt",
"lowercase/baz.py",
] {
let path = base_path.join(file);
let relative_path = path.strip_prefix(base_path).unwrap();

assert!(should_include_file(
&relative_path,
&include_patterns,
&exclude_patterns,
include_priority
));
}

// ~~~ Must be excluded ~~~
for file in [
"uppercase/QUX.txt",
"uppercase/CORGE.txt",
"uppercase/GRAULT.txt",
".secret/secret.txt",
"uppercase/FOO.py",
"uppercase/BAR.py",
"uppercase/BAZ.py",
] {
let path = base_path.join(file);
let relative_path = path.strip_prefix(base_path).unwrap();

assert!(!should_include_file(
&relative_path,
&include_patterns,
&exclude_patterns,
include_priority
));
}
}

#[test]
fn test_include_no_exclude_folders() {
let base_path = TEST_DIR.path();

let include_patterns = vec!["**/lowercase/**".to_string()];
let exclude_patterns = vec![];
let include_priority = true;

// ~~~ Must be included ~~~
for file in ["lowercase/foo.py", "lowercase/bar.py", "lowercase/qux.txt"] {
let path = base_path.join(file);
assert!(should_include_file(
&path,
Expand Down Expand Up @@ -579,15 +666,15 @@ mod tests {
));
}
}

#[test]
fn test_include_exclude_priority_include() {
let base_path = TEST_DIR.path();

let include_patterns = vec!["**/*.py".to_string()];
let exclude_patterns = vec!["**/uppercase/*".to_string()];
let include_priority = true;

// ~~~ Must be included ~~~ priority
for file in ["lowercase/foo.py", "uppercase/FOO.py"] {
let path = base_path.join(file);
Expand All @@ -598,9 +685,13 @@ mod tests {
include_priority
));
}

// ~~~ Must be excluded ~~~
for file in ["lowercase/qux.txt", "uppercase/QUX.txt", ".secret/secret.txt"] {
for file in [
"lowercase/qux.txt",
"uppercase/QUX.txt",
".secret/secret.txt",
] {
let path = base_path.join(file);
assert!(!should_include_file(
&path,
Expand Down Expand Up @@ -632,7 +723,7 @@ mod tests {
}

// ~~~ Must be excluded ~~~ priority
for file in ["uppercase/FOO.py", "uppercase/BAR.py",".secret/secret.txt"] {
for file in ["uppercase/FOO.py", "uppercase/BAR.py", ".secret/secret.txt"] {
let path = base_path.join(file);
assert!(!should_include_file(
&path,
Expand All @@ -642,5 +733,4 @@ mod tests {
));
}
}

}

0 comments on commit d5a5165

Please sign in to comment.