Skip to content

Commit 3e52771

Browse files
committed
Added capability to process local folder.
1 parent 992ff60 commit 3e52771

File tree

6 files changed

+118
-32
lines changed

6 files changed

+118
-32
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "git2prompt"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
authors = ["Fabio Thomaz Molinar <[email protected]>"]
55
description = "git2prompt is a command-line tool that takes a GitHub repository URL, downloads its contents, and generates a single text file optimized for use as input to AI tools."
66
readme = "README.md"

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ For example:
3030

3131
`git2prompt rust-lang/rust-by-example`
3232

33+
Or in case you have the repository on your local machine, then just run it with the `--local` flag. For example:
34+
35+
`git2prompt --local .`
36+
3337
### **Advanced Usage**
3438

3539
Process multiple repositories and merge their contents into a single file:

src/lib.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub mod repository;
55

66
use futures::future::join_all;
77
use io_utils::{ensure_directories, read_ignore_patterns};
8-
use processing::process_single_repository;
8+
use processing::{process_repository_files, process_single_repository}; // Import process_repository_files
99
use repository::Repository;
1010
use std::path::PathBuf;
1111
use std::sync::Arc;
@@ -75,3 +75,44 @@ pub async fn process_github_urls(
7575

7676
Ok(output_paths)
7777
}
78+
79+
/// Processes a single local directory path, prepares content, and writes to output.
80+
pub async fn process_local_path(
81+
path: PathBuf,
82+
no_headers: bool,
83+
ignore_file: Option<PathBuf>,
84+
folder: Option<String>,
85+
) -> Result<Vec<PathBuf>, String> {
86+
if !path.is_dir() {
87+
return Err(format!("Local path {:?} is not a directory.", path));
88+
}
89+
90+
// Prepare output directory
91+
let output_dir = PathBuf::from("./output");
92+
ensure_directories(&PathBuf::new(), &output_dir).await?; // No download dir needed
93+
94+
// Read ignore patterns
95+
let ignore_patterns = read_ignore_patterns(ignore_file).await?;
96+
97+
// Create a repository object from the local path
98+
let mut repository = Repository::from_local_path(&path);
99+
// Print full path for debugging
100+
println!("Processing local repository at path: {:?}", repository.path);
101+
102+
// Process the files in the local directory
103+
let content = process_repository_files(
104+
&repository.path,
105+
no_headers,
106+
false, // merge_files is false since there is only one repo
107+
&ignore_patterns,
108+
folder.as_deref(),
109+
)
110+
.await?;
111+
repository.content = Some(content);
112+
113+
// Use handle_results to generate the output file
114+
let repositories = vec![repository];
115+
let output_paths = processing::handle_results(repositories, false, &output_dir).await?;
116+
117+
Ok(output_paths)
118+
}

src/main.rs

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
use clap::Parser;
2-
use git2prompt::process_github_urls;
2+
use git2prompt::{process_github_urls, process_local_path};
33
use std::path::PathBuf;
44

5-
/// A command-line tool to download GitHub repository contents and format them for AI tools.
5+
/// A command-line tool to process repository contents and format them for AI tools.
66
#[derive(Parser, Debug)]
77
#[clap(author, version, about, long_about = None)]
88
struct Args {
9-
/// GitHub repository URLs (e.g., "owner/repo"). Supports multiple URLs.
9+
/// GitHub repository URLs (e.g., "owner/repo") or a single local path with --local.
1010
#[clap(required = true)]
11-
urls: Vec<String>,
11+
sources: Vec<String>,
12+
13+
/// Process the source as a local directory path instead of a GitHub URL.
14+
#[clap(short, long, action)]
15+
local: bool,
1216

1317
/// Do not add file paths as headers above code blocks in the output file(s).
1418
#[clap(short, long, action)]
1519
no_headers: bool,
1620

1721
/// Merge contents of all repositories into a single output file.
18-
/// If not set, a separate file will be created for each repository.
19-
#[clap(short, long, action)]
22+
/// Incompatible with --local.
23+
#[clap(short, long, action, conflicts_with = "local")]
2024
merge_files: bool,
2125

2226
/// Path to a file containing a list of files/folders to ignore.
@@ -28,12 +32,13 @@ struct Args {
2832
)]
2933
ignore_file: PathBuf,
3034

31-
/// Download and process only a specific folder within the repository
35+
/// Download and process only a specific folder within the repository.
3236
#[clap(short, long, value_name = "FOLDER PATH", conflicts_with = "pr")]
3337
folder: Option<String>,
3438

35-
/// Process only the files changed in a specific pull request
36-
#[clap(long, value_name = "PULL REQUEST NUMBER", conflicts_with = "folder")]
39+
/// Process only the files changed in a specific pull request.
40+
/// Incompatible with --local.
41+
#[clap(long, value_name = "PULL REQUEST NUMBER", conflicts_with_all = ["folder", "local"])]
3742
pr: Option<u32>,
3843
}
3944

@@ -42,25 +47,48 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
4247
let args = Args::parse();
4348

4449
println!("Starting git2prompt...");
45-
println!("Repositories to process: {:?}", args.urls);
46-
println!("No file headers: {}", args.no_headers);
47-
println!("Merge into a single output file: {}", args.merge_files);
48-
println!("Ignore file path: {:?}", args.ignore_file);
49-
println!("Folder to process: {:?}", args.folder);
50-
println!("Pull request number: {:?}", args.pr);
51-
println!("----------------------------------------");
5250

53-
// Call the library function to process the URLs, wrapping the ignore file path in Some
54-
match process_github_urls(
55-
args.urls,
56-
args.no_headers,
57-
args.merge_files,
58-
Some(args.ignore_file),
59-
args.folder,
60-
args.pr,
61-
)
62-
.await
63-
{
51+
let result = if args.local {
52+
// --- LOCAL PATH MODE ---
53+
if args.sources.len() != 1 {
54+
// Using Box::from to create a valid error type
55+
return Err(Box::from(
56+
"Error: When using --local, exactly one directory path must be provided.",
57+
));
58+
}
59+
let local_path = PathBuf::from(&args.sources[0]);
60+
println!("Processing local repository at: {:?}", local_path);
61+
println!("No file headers: {}", args.no_headers);
62+
println!("Ignore file path: {:?}", args.ignore_file);
63+
println!("----------------------------------------");
64+
process_local_path(
65+
local_path,
66+
args.no_headers,
67+
Some(args.ignore_file),
68+
args.folder,
69+
)
70+
.await
71+
} else {
72+
// --- GITHUB URL MODE (default) ---
73+
println!("Repositories to process: {:?}", args.sources);
74+
println!("No file headers: {}", args.no_headers);
75+
println!("Merge into a single output file: {}", args.merge_files);
76+
println!("Ignore file path: {:?}", args.ignore_file);
77+
println!("Folder to process: {:?}", args.folder);
78+
println!("Pull request number: {:?}", args.pr);
79+
println!("----------------------------------------");
80+
process_github_urls(
81+
args.sources,
82+
args.no_headers,
83+
args.merge_files,
84+
Some(args.ignore_file),
85+
args.folder,
86+
args.pr,
87+
)
88+
.await
89+
};
90+
91+
match result {
6492
Ok(output_paths) => {
6593
println!("Processing complete. Output files created:");
6694
for path in output_paths {
@@ -73,4 +101,4 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
73101
Err(e.into())
74102
}
75103
}
76-
}
104+
}

src/repository.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub struct Repository {
1212
}
1313

1414
impl Repository {
15+
/// Creates a new Repository instance from a remote GitHub URL.
1516
pub fn new(base_download_dir: &Path, repo_url: &str) -> Self {
1617
let url = format!("https://github.com/{}.git", repo_url);
1718
let name = repo_url.replace("/", "-");
@@ -24,6 +25,18 @@ impl Repository {
2425
content: None,
2526
}
2627
}
28+
29+
/// Creates a new Repository instance from a local file system path.
30+
pub fn from_local_path(local_path: &Path) -> Self {
31+
32+
Self {
33+
url: "local".to_string(), // URL is not applicable
34+
name: "local-repo".to_string(), // A generic name for local repos
35+
path: local_path.to_path_buf(), // The path is the provided local path
36+
content: None,
37+
}
38+
}
39+
2740
pub fn has_content(&self) -> bool {
2841
self.content.is_some()
2942
}
@@ -40,4 +53,4 @@ impl fmt::Display for Repository {
4053
self.has_content()
4154
)
4255
}
43-
}
56+
}

0 commit comments

Comments
 (0)