Skip to content

Commit 986f89b

Browse files
committed
Implements #3.
1 parent 898776c commit 986f89b

File tree

5 files changed

+34
-8
lines changed

5 files changed

+34
-8
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ Use the `--no-headers` flag to remove the file path headers above each code bloc
4040

4141
`git2prompt --no-headers rust-lang/rust-by-example`
4242

43+
Sometimes you only need a single folder from a repository (instead of downloading the entire repo and ignoring most files). Use the `--folder` flag to restrict processing to a single directory:
44+
45+
`git2prompt rust-lang/rust-by-example -f src`
46+
4347
## **Filtering**
4448

4549
**git2prompt** automatically ignores certain common file types and directories to keep the output clean.

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub async fn process_github_urls(
1818
no_headers: bool,
1919
merge_files: bool,
2020
ignore_file: Option<PathBuf>,
21+
folder: Option<String>,
2122
) -> Result<Vec<PathBuf>, String> {
2223
println!(
2324
"Library received URLs: {:?}, no_headers: {}, merge_files: {}",
@@ -38,8 +39,9 @@ pub async fn process_github_urls(
3839
.map(|url| {
3940
let repository = Repository::new(&download_dir, url);
4041
let ignore_patterns = Arc::clone(&ignore_patterns);
42+
let folder = folder.clone();
4143
tokio::spawn(async move {
42-
process_single_repository(repository, no_headers, merge_files, ignore_patterns)
44+
process_single_repository(repository, no_headers, merge_files, ignore_patterns, folder)
4345
.await
4446
})
4547
})

src/main.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ struct Args {
2727
default_value = ".git2promptignore"
2828
)]
2929
ignore_file: PathBuf,
30+
31+
/// Download and process only a specific folder within the repository
32+
#[clap(short, long, value_name = "FOLDER PATH")]
33+
folder: Option<String>,
3034
}
3135

3236
#[tokio::main]
@@ -37,13 +41,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3741
println!("Repositories to process: {:?}", args.urls);
3842
println!("No file headers: {}", args.no_headers);
3943
println!("Merge into a single output file: {}", args.merge_files);
44+
println!("Ignore file path: {:?}", args.ignore_file);
45+
println!("Folder to process: {:?}", args.folder);
46+
println!("----------------------------------------");
4047

4148
// Call the library function to process the URLs, wrapping the ignore file path in Some
4249
match process_github_urls(
4350
args.urls,
4451
args.no_headers,
4552
args.merge_files,
4653
Some(args.ignore_file),
54+
args.folder,
4755
)
4856
.await
4957
{

src/processing.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub async fn process_single_repository(
1212
no_headers: bool,
1313
merge_files: bool,
1414
ignore_patterns: Arc<Vec<String>>,
15+
folder: Option<String>,
1516
) -> Result<Repository, String> {
1617
println!(
1718
"Preparing to clone {} to {:?}",
@@ -24,7 +25,7 @@ pub async fn process_single_repository(
2425
);
2526

2627
let content =
27-
process_repository_files(&repository.path, no_headers, merge_files, &ignore_patterns)
28+
process_repository_files(&repository.path, no_headers, merge_files, &ignore_patterns, folder.as_deref())
2829
.await?;
2930
repository.content = Some(content);
3031

@@ -37,10 +38,21 @@ pub async fn process_repository_files(
3738
no_headers: bool,
3839
merge_files: bool,
3940
ignore_patterns: &[String],
41+
folder: Option<&str>,
4042
) -> Result<String, String> {
4143
let mut combined_content = String::new();
4244

43-
for entry in WalkDir::new(repo_path).into_iter().filter_map(|e| e.ok()) {
45+
let base_path = if let Some(folder) = folder {
46+
repo_path.join(folder)
47+
} else {
48+
repo_path.to_path_buf()
49+
};
50+
51+
if !base_path.exists() {
52+
return Err(format!("Specified folder {:?} not found in repo", base_path));
53+
}
54+
55+
for entry in WalkDir::new(&base_path).into_iter().filter_map(|e| e.ok()) {
4456
let path = entry.path();
4557

4658
if is_valid_file(path, repo_path, ignore_patterns) {

tests/integration_tests.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ async fn test_process_repository_files() -> Result<(), Box<dyn std::error::Error
5353
let src_main_path = PathBuf::from("src").join("main.rs");
5454
let readme_path = PathBuf::from("README.md");
5555

56-
let content_with_headers = process_repository_files(&test_repo_path, false, false, &Vec::new())
56+
let content_with_headers = process_repository_files(&test_repo_path, false, false, &Vec::new(), None)
5757
.await
5858
.unwrap();
5959
assert!(content_with_headers.contains(&format!("## File: {}", src_main_path.display())));
6060
assert!(content_with_headers.contains("fn main() { println!(\"Hello\"); }"));
6161
assert!(content_with_headers.contains(&format!("## File: {}", readme_path.display())));
6262
assert!(content_with_headers.contains("# Test Repo"));
6363

64-
let content_no_headers = process_repository_files(&test_repo_path, true, false, &Vec::new())
64+
let content_no_headers = process_repository_files(&test_repo_path, true, false, &Vec::new(), None)
6565
.await
6666
.unwrap();
6767
assert!(!content_no_headers.contains(&format!("## File: {}", src_main_path.display())));
@@ -70,7 +70,7 @@ async fn test_process_repository_files() -> Result<(), Box<dyn std::error::Error
7070
assert!(content_no_headers.contains("# Test Repo"));
7171

7272
let content_with_headers_merged =
73-
process_repository_files(&test_repo_path, false, true, &Vec::new())
73+
process_repository_files(&test_repo_path, false, true, &Vec::new(), None)
7474
.await
7575
.unwrap();
7676
assert!(
@@ -81,7 +81,7 @@ async fn test_process_repository_files() -> Result<(), Box<dyn std::error::Error
8181
assert!(content_with_headers_merged.contains("# Test Repo"));
8282

8383
let content_no_headers_merged =
84-
process_repository_files(&test_repo_path, true, true, &Vec::new())
84+
process_repository_files(&test_repo_path, true, true, &Vec::new(), None)
8585
.await
8686
.unwrap();
8787
assert!(!content_no_headers_merged.contains(&format!("### File: {}", src_main_path.display())));
@@ -126,7 +126,7 @@ async fn test_ignore_patterns_cross_platform() -> Result<(), Box<dyn std::error:
126126
];
127127

128128
let content =
129-
processing::process_repository_files(&test_repo_path, true, true, &ignore_patterns).await?;
129+
processing::process_repository_files(&test_repo_path, true, true, &ignore_patterns, None).await?;
130130

131131
// Ignored files should not be in the output
132132
assert!(!content.contains("secret.txt"));

0 commit comments

Comments
 (0)