Compare commits
14 Commits
cc222e52c0
...
master
Author | SHA1 | Date | |
---|---|---|---|
d01d2ef3e4 | |||
e06752f625 | |||
935f700e7e | |||
7c8d2e20c4 | |||
57f9c4bc67 | |||
13791a445a | |||
725891d1b6 | |||
8745c2627e | |||
73f6f74a71 | |||
c9d67c8cd9 | |||
3c9f288715 | |||
70524b4b34 | |||
dc61958151 | |||
6d36f4b3aa |
34
.github/workflows/ci.yml
vendored
Normal file
34
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Continuous Integration
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_test:
|
||||||
|
name: Build and Test on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
run: cargo fmt -- --check
|
||||||
|
|
||||||
|
- name: Run Clippy
|
||||||
|
run: cargo clippy -- -D warnings
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test
|
89
.github/workflows/release.yml
vendored
89
.github/workflows/release.yml
vendored
@@ -14,65 +14,54 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
target: x86_64-unknown-linux-gnu
|
target: x86_64-unknown-linux-gnu
|
||||||
- os: macos-latest
|
asset_name: codebase-to-prompt-linux-amd64
|
||||||
target: x86_64-apple-darwin
|
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
target: x86_64-pc-windows-msvc
|
target: x86_64-pc-windows-msvc
|
||||||
|
asset_name: codebase-to-prompt-windows-amd64.exe
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout code
|
||||||
- name: Build
|
uses: actions/checkout@v4
|
||||||
run: cargo build --release --target ${{ matrix.target }}
|
|
||||||
- name: Upload Artifact
|
- name: Install Rust toolchain
|
||||||
uses: actions/upload-artifact@v2
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
name: codebase-to-prompt-${{ matrix.target }}
|
targets: ${{ matrix.target }}
|
||||||
path: target/${{ matrix.target }}/release/codebase-to-prompt*
|
|
||||||
|
- name: Build binary
|
||||||
|
run: cargo build --release --target ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Prepare artifact path
|
||||||
|
id: artifact_path
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||||
|
echo "path=target/${{ matrix.target }}/release/codebase-to-prompt.exe" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "path=target/${{ matrix.target }}/release/codebase-to-prompt" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.asset_name }}
|
||||||
|
path: ${{ steps.artifact_path.outputs.path }}
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Create Release
|
name: Create GitHub Release
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # This is required to create a release and upload assets
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Download all artifacts
|
||||||
- name: Download Artifacts
|
uses: actions/download-artifact@v4
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts/
|
||||||
- name: Create Release
|
|
||||||
id: create_release
|
- name: Create Release and Upload Assets
|
||||||
uses: actions/create-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
files: |
|
||||||
release_name: Release ${{ github.ref }}
|
artifacts/codebase-to-prompt-linux-amd64/*
|
||||||
draft: false
|
artifacts/codebase-to-prompt-windows-amd64.exe/*
|
||||||
prerelease: false
|
|
||||||
- name: Upload Release Asset (Linux)
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: ./artifacts/codebase-to-prompt-x86_64-unknown-linux-gnu/codebase-to-prompt
|
|
||||||
asset_name: codebase-to-prompt-x86_64-unknown-linux-gnu
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload Release Asset (macOS)
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: ./artifacts/codebase-to-prompt-x86_64-apple-darwin/codebase-to-prompt
|
|
||||||
asset_name: codebase-to-prompt-x86_64-apple-darwin
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
- name: Upload Release Asset (Windows)
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: ./artifacts/codebase-to-prompt-x86_64-pc-windows-msvc/codebase-to-prompt.exe
|
|
||||||
asset_name: codebase-to-prompt-x86_64-pc-windows-msvc.exe
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -183,7 +183,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codebase-to-prompt"
|
name = "codebase-to-prompt"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "codebase-to-prompt"
|
name = "codebase-to-prompt"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Gabriel Kaszewski <gabrielkaszewski@gmail.com>"]
|
authors = ["Gabriel Kaszewski <gabrielkaszewski@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
89
README.md
89
README.md
@@ -1,5 +1,8 @@
|
|||||||
# Codebase to Prompt
|
# Codebase to Prompt
|
||||||
|
|
||||||
|
[](https://github.com/GKaszewski/codebase-to-prompt/actions/workflows/ci.yml)
|
||||||
|
[](https://github.com/GKaszewski/codebase-to-prompt/actions/workflows/release.yml)
|
||||||
|
|
||||||
`codebase-to-prompt` is a Rust-based CLI tool designed to bundle files from a directory into a single output file. It supports filtering files by extensions, respecting `.gitignore` rules, and formatting the output in Markdown, plain text, or console-friendly formats.
|
`codebase-to-prompt` is a Rust-based CLI tool designed to bundle files from a directory into a single output file. It supports filtering files by extensions, respecting `.gitignore` rules, and formatting the output in Markdown, plain text, or console-friendly formats.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@@ -14,17 +17,41 @@
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Ensure you have [Rust](https://www.rust-lang.org/) installed.
|
There are multiple ways to install `codebase-to-prompt`.
|
||||||
2. Clone this repository:
|
|
||||||
```bash
|
### Option 1: Using `cargo install` (Recommended for Rust developers)
|
||||||
git clone <repository-url>
|
|
||||||
cd codebase-to-prompt
|
If you have the Rust toolchain installed, you can easily install the latest version from [crates.io](https://crates.io/):
|
||||||
```
|
|
||||||
3. Build the project:
|
```bash
|
||||||
```bash
|
cargo install codebase-to-prompt
|
||||||
cargo build --release
|
```
|
||||||
```
|
|
||||||
4. The binary will be available at `target/release/codebase-to-prompt`.
|
### Option 2: Using the Install Script (for Linux & macOS)
|
||||||
|
|
||||||
|
You can download and run the installation script, which will install the latest release binary for your system:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/GKaszewski/codebase-to-prompt/master/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 3: From GitHub Releases
|
||||||
|
|
||||||
|
You can download the pre-compiled binary for your operating system directly from the [Releases page](https://github.com/GKaszewski/codebase-to-prompt/releases).
|
||||||
|
|
||||||
|
### Option 4: Building from Source
|
||||||
|
|
||||||
|
1. Ensure you have [Rust](https://www.rust-lang.org/) installed.
|
||||||
|
2. Clone this repository:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/GKaszewski/codebase-to-prompt
|
||||||
|
cd codebase-to-prompt
|
||||||
|
```
|
||||||
|
3. Build the project:
|
||||||
|
```bash
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
4. The binary will be available at `target/release/codebase-to-prompt`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -48,22 +75,23 @@ codebase-to-prompt [OPTIONS] [DIRECTORY]
|
|||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
1. Bundle all `.rs` files in the current directory into `output.md` in Markdown format:
|
1. Bundle all `.rs` files in the current directory into `output.md` in Markdown format:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codebase-to-prompt -o output.md -i rs --format markdown
|
codebase-to-prompt -o output.md -i rs
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Bundle all files except `.log` files, appending the current date and Git hash to the output file name:
|
2. Bundle all files except `.log` files, appending the current date and Git hash to the output file name:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codebase-to-prompt -o output.txt -e log -d -g
|
codebase-to-prompt -o output.txt -e log -d -g
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Output all files to the console, including line numbers:
|
3. Output all files to the console, including line numbers:
|
||||||
```bash
|
|
||||||
codebase-to-prompt -l
|
```bash
|
||||||
```
|
codebase-to-prompt -l
|
||||||
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -87,19 +115,6 @@ To run tests:
|
|||||||
cargo test
|
cargo test
|
||||||
```
|
```
|
||||||
|
|
||||||
### Code Structure
|
|
||||||
|
|
||||||
- `src/lib.rs`: Core logic for file processing and bundling.
|
|
||||||
- `src/main.rs`: CLI entry point.
|
|
||||||
|
|
||||||
### Adding Dependencies
|
|
||||||
|
|
||||||
To add a new dependency, update `Cargo.toml` and run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Linting and Formatting
|
### Linting and Formatting
|
||||||
|
|
||||||
To lint the code:
|
To lint the code:
|
||||||
@@ -120,4 +135,4 @@ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are welcome! Feel free to open issues or submit pull requests.
|
Contributions are welcome\! Feel free to open issues or submit pull requests.
|
||||||
|
88
src/lib.rs
88
src/lib.rs
@@ -7,7 +7,7 @@ use chrono::Local;
|
|||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
use git2::Repository;
|
use git2::Repository;
|
||||||
use ignore::gitignore::Gitignore;
|
use ignore::gitignore::Gitignore;
|
||||||
use tracing::{error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
/// Represents the output format for the bundled files.
|
/// Represents the output format for the bundled files.
|
||||||
@@ -26,8 +26,8 @@ pub enum Format {
|
|||||||
/// Configuration options for the file bundling process.
|
/// Configuration options for the file bundling process.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// The directory to process.
|
/// The directories to process.
|
||||||
pub directory: PathBuf,
|
pub directory: Vec<PathBuf>,
|
||||||
/// The optional output file path. If not provided, output is written to stdout.
|
/// The optional output file path. If not provided, output is written to stdout.
|
||||||
pub output: Option<PathBuf>,
|
pub output: Option<PathBuf>,
|
||||||
/// File extensions to include in the output.
|
/// File extensions to include in the output.
|
||||||
@@ -46,6 +46,8 @@ pub struct Config {
|
|||||||
pub ignore_hidden: bool,
|
pub ignore_hidden: bool,
|
||||||
/// Whether to respect `.gitignore` rules.
|
/// Whether to respect `.gitignore` rules.
|
||||||
pub respect_gitignore: bool,
|
pub respect_gitignore: bool,
|
||||||
|
/// Whether to use relative paths in the output.
|
||||||
|
pub relative_path: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the file bundling process based on the provided configuration.
|
/// Runs the file bundling process based on the provided configuration.
|
||||||
@@ -62,9 +64,20 @@ pub fn run(config: Config) -> Result<()> {
|
|||||||
append_date_and_git_hash(&mut output_path, &config)?;
|
append_date_and_git_hash(&mut output_path, &config)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let writer = determine_output_writer(&output_path)?;
|
let mut writer = determine_output_writer(&output_path)?;
|
||||||
|
|
||||||
process_directory(&config, writer)
|
for dir in &config.directory {
|
||||||
|
if !dir.is_dir() {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"The specified path is not a directory: {}",
|
||||||
|
dir.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
process_directory(&config, &mut writer, dir)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends the current date and/or Git hash to the output file name if required.
|
/// Appends the current date and/or Git hash to the output file name if required.
|
||||||
@@ -90,16 +103,18 @@ fn append_date_and_git_hash(output_path: &mut Option<PathBuf>, config: &Config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.append_git_hash {
|
if config.append_git_hash {
|
||||||
match Repository::open(&config.directory) {
|
for dir in &config.directory {
|
||||||
Ok(repo) => {
|
match Repository::open(dir) {
|
||||||
let head = repo.head().context("Failed to get repository HEAD")?;
|
Ok(repo) => {
|
||||||
if let Some(oid) = head.target() {
|
let head = repo.head().context("Failed to get repository HEAD")?;
|
||||||
new_filename.push('_');
|
if let Some(oid) = head.target() {
|
||||||
new_filename.push_str(&oid.to_string()[..7]);
|
new_filename.push('_');
|
||||||
info!("Appending git hash to filename.");
|
new_filename.push_str(&oid.to_string()[..7]);
|
||||||
|
info!("Appending git hash to filename.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Err(_) => warn!("Not a git repository, cannot append git hash."),
|
||||||
}
|
}
|
||||||
Err(_) => warn!("Not a git repository, cannot append git hash."),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,23 +154,26 @@ fn determine_output_writer(output_path: &Option<PathBuf>) -> Result<Box<dyn Writ
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// * `Result<()>` - Returns `Ok(())` if successful, or an error if the process fails.
|
/// * `Result<()>` - Returns `Ok(())` if successful, or an error if the process fails.
|
||||||
fn process_directory(config: &Config, mut writer: Box<dyn Write>) -> Result<()> {
|
fn process_directory(config: &Config, writer: &mut dyn Write, dir: &PathBuf) -> Result<()> {
|
||||||
let (gitignore, _) = Gitignore::new(config.directory.join(".gitignore"));
|
let (gitignore, _) = Gitignore::new(dir.join(".gitignore"));
|
||||||
|
|
||||||
let walker = WalkDir::new(&config.directory)
|
let walker = WalkDir::new(dir)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_entry(|e| should_include_entry(e, &gitignore, config));
|
.filter_entry(|e| should_include_entry(e, &gitignore, config));
|
||||||
|
|
||||||
for result in walker {
|
for result in walker {
|
||||||
let entry = match result {
|
let entry = match result {
|
||||||
Ok(entry) => entry,
|
Ok(entry) => {
|
||||||
|
debug!("Processing entry: {:?}", entry);
|
||||||
|
entry
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Failed to access entry: {}", err);
|
error!("Failed to access entry: {}", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = process_file_entry(&entry, &mut writer, config) {
|
if let Err(err) = process_file_entry(&entry, writer, config, dir) {
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,26 +204,37 @@ fn should_include_entry(entry: &DirEntry, gitignore: &Gitignore, config: &Config
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// * `Result<()>` - Returns `Ok(())` if successful, or an error if the process fails.
|
/// * `Result<()>` - Returns `Ok(())` if successful, or an error if the process fails.
|
||||||
fn process_file_entry(entry: &DirEntry, writer: &mut dyn Write, config: &Config) -> Result<()> {
|
fn process_file_entry(
|
||||||
|
entry: &DirEntry,
|
||||||
|
writer: &mut dyn Write,
|
||||||
|
config: &Config,
|
||||||
|
dir: &PathBuf,
|
||||||
|
) -> Result<()> {
|
||||||
|
debug!("File process entry process for {:?}", entry.path());
|
||||||
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if !path.is_file() {
|
if !path.is_file() {
|
||||||
|
debug!("{:?} is not a file.", path);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let extension = path.extension().and_then(|s| s.to_str()).unwrap_or("");
|
let extension = path.extension().and_then(|s| s.to_str()).unwrap_or("");
|
||||||
|
|
||||||
let apply_include_filter =
|
debug!("Extension {:?} for {:?}", extension, path);
|
||||||
!(config.include.is_empty() || config.include.len() == 1 && config.include[0].is_empty());
|
|
||||||
|
let apply_include_filter = !(config.include.is_empty());
|
||||||
|
|
||||||
if apply_include_filter && !config.include.contains(&extension.to_string()) {
|
if apply_include_filter && !config.include.contains(&extension.to_string()) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.exclude.contains(&extension.to_string()) {
|
let apply_exclude_filter = !(config.exclude.is_empty());
|
||||||
|
|
||||||
|
if apply_exclude_filter && config.exclude.contains(&extension.to_string()) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let relative_path = path.strip_prefix(&config.directory).unwrap_or(path);
|
let relative_path = path.strip_prefix(dir).unwrap_or(path);
|
||||||
let content = match fs::read_to_string(path) {
|
let content = match fs::read_to_string(path) {
|
||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -214,8 +243,17 @@ fn process_file_entry(entry: &DirEntry, writer: &mut dyn Write, config: &Config)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
write_file_content(writer, relative_path, &content, extension, config)
|
match &config.relative_path {
|
||||||
.with_context(|| format!("Failed to write file content for {}", path.display()))
|
true => write_file_content(writer, relative_path, &content, extension, config)
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to write file content for {}",
|
||||||
|
relative_path.display()
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
false => write_file_content(writer, path, &content, extension, config)
|
||||||
|
.with_context(|| format!("Failed to write file content for {}", path.display())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the content of a single file to the writer based on the specified format.
|
/// Writes the content of a single file to the writer based on the specified format.
|
||||||
|
31
src/main.rs
31
src/main.rs
@@ -8,16 +8,16 @@ use tracing_subscriber::FmtSubscriber;
|
|||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
#[arg(default_value = ".")]
|
#[arg(default_value = ".", value_delimiter = ' ', num_args=1..)]
|
||||||
directory: PathBuf,
|
directory: Vec<PathBuf>,
|
||||||
|
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
output: Option<PathBuf>,
|
output: Option<PathBuf>,
|
||||||
|
|
||||||
#[arg(short, long, use_value_delimiter = true, default_value = "")]
|
#[arg(short, long, value_delimiter = ',', num_args = 0..)]
|
||||||
include: Vec<String>,
|
include: Vec<String>,
|
||||||
|
|
||||||
#[arg(short, long, use_value_delimiter = true, default_value = "")]
|
#[arg(short, long, value_delimiter = ',', num_args = 0..)]
|
||||||
exclude: Vec<String>,
|
exclude: Vec<String>,
|
||||||
|
|
||||||
#[arg(long, value_enum, default_value_t = Format::Console)]
|
#[arg(long, value_enum, default_value_t = Format::Console)]
|
||||||
@@ -32,30 +32,32 @@ struct Args {
|
|||||||
#[arg(short = 'l', long)]
|
#[arg(short = 'l', long)]
|
||||||
line_numbers: bool,
|
line_numbers: bool,
|
||||||
|
|
||||||
#[arg(short = 'H', long)]
|
#[arg(short = 'H', long, default_value_t = true)]
|
||||||
ignore_hidden: bool,
|
ignore_hidden: bool,
|
||||||
|
|
||||||
#[arg(short = 'R', long, default_value_t = true)]
|
#[arg(short = 'R', long, default_value_t = true)]
|
||||||
respect_gitignore: bool,
|
respect_gitignore: bool,
|
||||||
|
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
relative_path: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let subscriber = FmtSubscriber::builder()
|
let subscriber = FmtSubscriber::builder()
|
||||||
.with_max_level(LevelFilter::INFO)
|
.with_max_level(LevelFilter::DEBUG)
|
||||||
.finish();
|
.finish();
|
||||||
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let mut format = args.format;
|
let mut format = args.format;
|
||||||
if matches!(format, Format::Console) {
|
if matches!(format, Format::Console)
|
||||||
if let Some(output_path) = &args.output {
|
&& let Some(output_path) = &args.output
|
||||||
if output_path.extension().and_then(|s| s.to_str()) == Some("md") {
|
{
|
||||||
format = Format::Markdown;
|
match output_path.extension().and_then(|s| s.to_str()) {
|
||||||
}
|
Some("md") => format = Format::Markdown,
|
||||||
if output_path.extension().and_then(|s| s.to_str()) == Some("txt") {
|
Some("txt") => format = Format::Text,
|
||||||
format = Format::Text;
|
_ => {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +72,7 @@ fn main() -> Result<()> {
|
|||||||
line_numbers: args.line_numbers,
|
line_numbers: args.line_numbers,
|
||||||
ignore_hidden: args.ignore_hidden,
|
ignore_hidden: args.ignore_hidden,
|
||||||
respect_gitignore: args.respect_gitignore,
|
respect_gitignore: args.respect_gitignore,
|
||||||
|
relative_path: args.relative_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("Starting codebase to prompt with config: {:?}", config);
|
debug!("Starting codebase to prompt with config: {:?}", config);
|
||||||
|
@@ -8,7 +8,7 @@ fn test_run_with_markdown_format() {
|
|||||||
let output_file = temp_dir.path().join("output.md");
|
let output_file = temp_dir.path().join("output.md");
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
directory: PathBuf::from("tests/fixtures"),
|
directory: vec![PathBuf::from("tests/fixtures")],
|
||||||
output: Some(output_file.clone()),
|
output: Some(output_file.clone()),
|
||||||
include: vec!["rs".to_string()],
|
include: vec!["rs".to_string()],
|
||||||
exclude: vec![],
|
exclude: vec![],
|
||||||
@@ -18,6 +18,7 @@ fn test_run_with_markdown_format() {
|
|||||||
line_numbers: false,
|
line_numbers: false,
|
||||||
ignore_hidden: true,
|
ignore_hidden: true,
|
||||||
respect_gitignore: true,
|
respect_gitignore: true,
|
||||||
|
relative_path: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = run(config);
|
let result = run(config);
|
||||||
@@ -33,7 +34,7 @@ fn test_run_with_text_format() {
|
|||||||
let output_file = temp_dir.path().join("output.txt");
|
let output_file = temp_dir.path().join("output.txt");
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
directory: PathBuf::from("tests/fixtures"),
|
directory: vec![PathBuf::from("tests/fixtures")],
|
||||||
output: Some(output_file.clone()),
|
output: Some(output_file.clone()),
|
||||||
include: vec!["txt".to_string()],
|
include: vec!["txt".to_string()],
|
||||||
exclude: vec![],
|
exclude: vec![],
|
||||||
@@ -43,6 +44,7 @@ fn test_run_with_text_format() {
|
|||||||
line_numbers: true,
|
line_numbers: true,
|
||||||
ignore_hidden: true,
|
ignore_hidden: true,
|
||||||
respect_gitignore: true,
|
respect_gitignore: true,
|
||||||
|
relative_path: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = run(config);
|
let result = run(config);
|
||||||
@@ -58,7 +60,7 @@ fn test_run_with_git_hash_append() {
|
|||||||
let output_file = temp_dir.path().join("output.txt");
|
let output_file = temp_dir.path().join("output.txt");
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
directory: PathBuf::from("tests/fixtures"),
|
directory: vec![PathBuf::from("tests/fixtures")],
|
||||||
output: Some(output_file.clone()),
|
output: Some(output_file.clone()),
|
||||||
include: vec!["txt".to_string()],
|
include: vec!["txt".to_string()],
|
||||||
exclude: vec![],
|
exclude: vec![],
|
||||||
@@ -68,6 +70,7 @@ fn test_run_with_git_hash_append() {
|
|||||||
line_numbers: false,
|
line_numbers: false,
|
||||||
ignore_hidden: true,
|
ignore_hidden: true,
|
||||||
respect_gitignore: true,
|
respect_gitignore: true,
|
||||||
|
relative_path: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = run(config);
|
let result = run(config);
|
||||||
|
Reference in New Issue
Block a user