├── .gitignore ├── .aggconfig ├── Cargo.toml ├── LICENSE ├── src ├── config.rs ├── cli.rs └── main.rs ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.aggconfig: -------------------------------------------------------------------------------- 1 | allowed_extensions = ["rs", "toml"] 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "agg" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | base64 = "0.22.1" 8 | clap = { version = "4.5", features = ["derive"] } 9 | ignore = "0.4.22" 10 | serde = { version = "1.0.217", features = ["derive"] } 11 | toml = "0.8.19" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2025 Felipe Coury 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::fs; 3 | use std::path::PathBuf; 4 | 5 | #[derive(Debug, Serialize, Deserialize)] 6 | pub struct AggConfig { 7 | #[serde(default)] 8 | pub include_binary: bool, 9 | pub path: Option, 10 | pub output: Option, 11 | #[serde(default)] 12 | pub exclude_dirs: Vec, 13 | #[serde(default)] 14 | pub allowed_extensions: Vec, 15 | } 16 | 17 | impl AggConfig { 18 | pub fn load() -> Option { 19 | let config_path = PathBuf::from(".aggconfig"); 20 | if config_path.exists() { 21 | match fs::read_to_string(config_path) { 22 | Ok(contents) => match toml::from_str(&contents) { 23 | Ok(config) => Some(config), 24 | Err(e) => { 25 | eprintln!("Error parsing .aggconfig: {}", e); 26 | None 27 | } 28 | }, 29 | Err(e) => { 30 | eprintln!("Error reading .aggconfig: {}", e); 31 | None 32 | } 33 | } 34 | } else { 35 | None 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use clap::Parser; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | use crate::config::AggConfig; 7 | 8 | #[derive(Parser, Debug, Serialize, Deserialize)] 9 | pub struct Args { 10 | /// Includes binary files as base64 encoded strings in the output 11 | #[arg(short = 'b', long)] 12 | pub include_binary: bool, 13 | 14 | /// Initial path to start searching for files, defaults to the current directory 15 | #[arg(short, long)] 16 | pub path: Option, 17 | 18 | /// Output file to write the generated prompt contents to, defaults to stdout 19 | #[arg(short, long)] 20 | pub output: Option, 21 | 22 | /// List of subdirectories to exclude from the output 23 | #[arg(short, long)] 24 | pub exclude_dirs: Vec, 25 | 26 | /// List of file extensions to include in the output 27 | #[clap(last = true)] 28 | pub allowed_extensions: Vec, 29 | } 30 | 31 | impl From for Args { 32 | fn from(config: AggConfig) -> Self { 33 | Args { 34 | include_binary: config.include_binary, 35 | path: config.path, 36 | output: config.output, 37 | exclude_dirs: config.exclude_dirs, 38 | allowed_extensions: config.allowed_extensions, 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # agg 2 | 3 | A command-line utility for preparing code snippets for AI tools by aggregating source code files from a project into a single text file. 4 | 5 | ## Features 6 | 7 | - Recursively traverses directories to collect source files 8 | - Supports filtering by file extensions 9 | - Handles binary files (optional base64 encoding) 10 | - Respects `.gitignore` and `.aggignore` patterns 11 | - Configurable through command line arguments or `.aggconfig` file 12 | - Excludes specified directories 13 | - Outputs to file or stdout 14 | 15 | ## Installation 16 | 17 | Make sure you have Rust installed, then: 18 | 19 | ```bash 20 | git clone [repository-url] 21 | cd agg 22 | cargo install --path . 23 | ``` 24 | 25 | ## Usage 26 | 27 | ### Command Line 28 | 29 | Basic usage: 30 | 31 | ```bash 32 | # Output all files in current directory to stdout 33 | agg 34 | 35 | # Specify source directory and output file 36 | agg -p /path/to/source -o output.txt 37 | 38 | # Only include specific file extensions 39 | agg rs toml md 40 | 41 | # Include binary files (base64 encoded) 42 | agg -b 43 | 44 | # Exclude specific directories 45 | agg -e node_modules -e target 46 | ``` 47 | 48 | ### Configuration File 49 | 50 | Instead of command line arguments, you can create a `.aggconfig` file in TOML format: 51 | 52 | ```toml 53 | include_binary = true 54 | path = "./src" 55 | output = "output.txt" 56 | exclude_dirs = ["target", "node_modules"] 57 | allowed_extensions = ["rs", "toml"] 58 | ``` 59 | 60 | The program will automatically detect and use the `.aggconfig` file if present. Command line arguments take precedence if both are provided. 61 | 62 | ## Command Line Options 63 | 64 | ``` 65 | Options: 66 | -b, --include-binary Include binary files as base64 encoded strings 67 | -p, --path Initial path to start searching [default: current directory] 68 | -o, --output Output file [default: stdout] 69 | -e, --exclude-dirs Directories to exclude 70 | [EXTENSIONS] File extensions to include (space-separated) 71 | ``` 72 | 73 | ## Ignore Files 74 | 75 | ### .gitignore 76 | 77 | The tool respects existing `.gitignore` files in your project directory. 78 | 79 | ### .aggignore 80 | 81 | Sometimes you want to ignore files when generating text for AI but you don't want to prevent the file from being added to git. 82 | 83 | You can create an `.aggignore` file specifically for this case. It follows the same pattern syntax as `.gitignore`. 84 | 85 | ## Example Output 86 | 87 | The tool generates output in the following format: 88 | 89 | ``` 90 | <<> 91 | // File contents here 92 | <<> 93 | <<> 94 | // File contents here 95 | <<> 96 | ``` 97 | 98 | ## Error Handling 99 | 100 | - Non-UTF8 files are skipped unless `-b` flag is used 101 | - Binary files are base64 encoded when included 102 | - Invalid configuration files or command line arguments produce error messages 103 | - File access errors are reported but don't stop the entire process 104 | 105 | ## Contributing 106 | 107 | Contributions are welcome! Please feel free to submit a Pull Request. 108 | 109 | ## License 110 | 111 | This project is licensed under the MIT License - see the LICENSE file for details. 112 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use cli::Args; 3 | use config::AggConfig; 4 | use ignore::gitignore::{Gitignore, GitignoreBuilder}; 5 | use std::fs::{self, File}; 6 | use std::io::{self, BufWriter, Read, Write}; 7 | use std::path::{Path, PathBuf}; 8 | 9 | mod cli; 10 | mod config; 11 | 12 | fn main() -> io::Result<()> { 13 | let args = AggConfig::load() 14 | .map(Args::from) 15 | .unwrap_or_else(Args::parse); 16 | 17 | let mut writer: Box = match args.output { 18 | Some(ref path) => Box::new(BufWriter::new(File::create(path).unwrap())), 19 | None => Box::new(BufWriter::new(io::stdout())), 20 | }; 21 | 22 | let root = args.path.unwrap_or_else(|| PathBuf::from(".")); 23 | let gitignore = load_ignore_file(&root, ".gitignore"); 24 | let aggignore = load_ignore_file(&root, ".aggignore"); 25 | 26 | visit_dirs( 27 | &root, 28 | &mut writer, 29 | &args.allowed_extensions, 30 | args.include_binary, 31 | &args.exclude_dirs, 32 | &gitignore, 33 | &aggignore, 34 | )?; 35 | 36 | Ok(()) 37 | } 38 | 39 | fn load_ignore_file(root: &Path, filename: &str) -> Gitignore { 40 | let mut builder = GitignoreBuilder::new(root); 41 | let ignore_path = root.join(filename); 42 | eprintln!("Reading {} from {:?}", filename, ignore_path); 43 | if ignore_path.exists() { 44 | match builder.add(ignore_path) { 45 | None => (), 46 | Some(err) => eprintln!("Error adding {}: {}", filename, err), 47 | } 48 | } 49 | builder.build().unwrap_or_else(|err| { 50 | eprintln!("Error building {}: {}", filename, err); 51 | Gitignore::empty() 52 | }) 53 | } 54 | 55 | fn visit_dirs( 56 | dir: &PathBuf, 57 | writer: &mut Box, 58 | allowed_extensions: &[String], 59 | include_binary: bool, 60 | exclude_dirs: &[String], 61 | gitignore: &Gitignore, 62 | aggignore: &Gitignore, 63 | ) -> io::Result<()> { 64 | if dir.is_dir() { 65 | for entry in fs::read_dir(dir)? { 66 | let entry = entry?; 67 | let path = entry.path(); 68 | 69 | // Check if the directory should be excluded 70 | let current_dir = path.file_name().unwrap().to_str().unwrap(); 71 | if exclude_dirs.contains(¤t_dir.to_string()) { 72 | continue; 73 | } 74 | 75 | // Check both gitignore and aggignore patterns 76 | if gitignore.matched(&path, path.is_dir()).is_ignore() 77 | || aggignore.matched(&path, path.is_dir()).is_ignore() 78 | { 79 | continue; // Skip ignored files/directories 80 | } 81 | 82 | if path.is_dir() { 83 | visit_dirs( 84 | &path, 85 | writer, 86 | allowed_extensions, 87 | include_binary, 88 | exclude_dirs, 89 | gitignore, 90 | aggignore, 91 | )?; 92 | } else if should_process_file(&path, allowed_extensions) { 93 | match process_file(&path, writer, include_binary) { 94 | Ok(_) => (), 95 | Err(e) => eprintln!("Error processing file {:?}: {}", path, e), 96 | } 97 | } 98 | } 99 | } 100 | Ok(()) 101 | } 102 | 103 | fn should_process_file(file_path: &Path, allowed_extensions: &[String]) -> bool { 104 | if allowed_extensions.is_empty() { 105 | return true; // Process all files if no extensions are specified 106 | } 107 | if let Some(extension) = file_path.extension() { 108 | let ext = extension.to_str().unwrap_or("").to_lowercase(); 109 | allowed_extensions.contains(&ext) 110 | } else { 111 | false 112 | } 113 | } 114 | 115 | fn process_file( 116 | file_path: &PathBuf, 117 | writer: &mut Box, 118 | include_binary: bool, 119 | ) -> io::Result<()> { 120 | let mut file = File::open(file_path)?; 121 | let mut buffer = Vec::new(); 122 | file.read_to_end(&mut buffer)?; 123 | // Check if the file is UTF-8 encoded 124 | if let Ok(contents) = String::from_utf8(buffer.clone()) { 125 | write_file_contents(file_path, writer, &contents) 126 | } else if include_binary { 127 | // If not UTF-8 and binary files are allowed, encode as base64 128 | #[allow(deprecated)] 129 | let base64 = base64::encode(&buffer); 130 | write_file_contents( 131 | file_path, 132 | writer, 133 | &format!("[Binary data encoded as base64]:\n{}", base64), 134 | ) 135 | } else { 136 | // eprintln!("Skipping non-UTF8 file: {:?}", file_path); 137 | Ok(()) 138 | } 139 | } 140 | 141 | fn write_file_contents( 142 | file_path: &Path, 143 | writer: &mut Box, 144 | contents: &str, 145 | ) -> io::Result<()> { 146 | let start_marker = format!("<<>\n", file_path.display()); 147 | let end_marker = format!("<<>\n", file_path.display()); 148 | writer.write_all(start_marker.as_bytes())?; 149 | writer.write_all(contents.as_bytes())?; 150 | writer.write_all(b"\n")?; 151 | writer.write_all(end_marker.as_bytes())?; 152 | Ok(()) 153 | } 154 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "agg" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "base64", 10 | "clap", 11 | "ignore", 12 | "serde", 13 | "toml", 14 | ] 15 | 16 | [[package]] 17 | name = "aho-corasick" 18 | version = "1.1.3" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 21 | dependencies = [ 22 | "memchr", 23 | ] 24 | 25 | [[package]] 26 | name = "anstream" 27 | version = "0.6.15" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" 30 | dependencies = [ 31 | "anstyle", 32 | "anstyle-parse", 33 | "anstyle-query", 34 | "anstyle-wincon", 35 | "colorchoice", 36 | "is_terminal_polyfill", 37 | "utf8parse", 38 | ] 39 | 40 | [[package]] 41 | name = "anstyle" 42 | version = "1.0.8" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" 45 | 46 | [[package]] 47 | name = "anstyle-parse" 48 | version = "0.2.5" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" 51 | dependencies = [ 52 | "utf8parse", 53 | ] 54 | 55 | [[package]] 56 | name = "anstyle-query" 57 | version = "1.1.1" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" 60 | dependencies = [ 61 | "windows-sys", 62 | ] 63 | 64 | [[package]] 65 | name = "anstyle-wincon" 66 | version = "3.0.4" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" 69 | dependencies = [ 70 | "anstyle", 71 | "windows-sys", 72 | ] 73 | 74 | [[package]] 75 | name = "base64" 76 | version = "0.22.1" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 79 | 80 | [[package]] 81 | name = "bstr" 82 | version = "1.10.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" 85 | dependencies = [ 86 | "memchr", 87 | "serde", 88 | ] 89 | 90 | [[package]] 91 | name = "clap" 92 | version = "4.5.13" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" 95 | dependencies = [ 96 | "clap_builder", 97 | "clap_derive", 98 | ] 99 | 100 | [[package]] 101 | name = "clap_builder" 102 | version = "4.5.13" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" 105 | dependencies = [ 106 | "anstream", 107 | "anstyle", 108 | "clap_lex", 109 | "strsim", 110 | ] 111 | 112 | [[package]] 113 | name = "clap_derive" 114 | version = "4.5.13" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" 117 | dependencies = [ 118 | "heck", 119 | "proc-macro2", 120 | "quote", 121 | "syn", 122 | ] 123 | 124 | [[package]] 125 | name = "clap_lex" 126 | version = "0.7.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 129 | 130 | [[package]] 131 | name = "colorchoice" 132 | version = "1.0.2" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" 135 | 136 | [[package]] 137 | name = "crossbeam-deque" 138 | version = "0.8.5" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 141 | dependencies = [ 142 | "crossbeam-epoch", 143 | "crossbeam-utils", 144 | ] 145 | 146 | [[package]] 147 | name = "crossbeam-epoch" 148 | version = "0.9.18" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 151 | dependencies = [ 152 | "crossbeam-utils", 153 | ] 154 | 155 | [[package]] 156 | name = "crossbeam-utils" 157 | version = "0.8.20" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 160 | 161 | [[package]] 162 | name = "equivalent" 163 | version = "1.0.1" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 166 | 167 | [[package]] 168 | name = "globset" 169 | version = "0.4.14" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" 172 | dependencies = [ 173 | "aho-corasick", 174 | "bstr", 175 | "log", 176 | "regex-automata", 177 | "regex-syntax", 178 | ] 179 | 180 | [[package]] 181 | name = "hashbrown" 182 | version = "0.15.2" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 185 | 186 | [[package]] 187 | name = "heck" 188 | version = "0.5.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 191 | 192 | [[package]] 193 | name = "ignore" 194 | version = "0.4.22" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" 197 | dependencies = [ 198 | "crossbeam-deque", 199 | "globset", 200 | "log", 201 | "memchr", 202 | "regex-automata", 203 | "same-file", 204 | "walkdir", 205 | "winapi-util", 206 | ] 207 | 208 | [[package]] 209 | name = "indexmap" 210 | version = "2.7.0" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 213 | dependencies = [ 214 | "equivalent", 215 | "hashbrown", 216 | ] 217 | 218 | [[package]] 219 | name = "is_terminal_polyfill" 220 | version = "1.70.1" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 223 | 224 | [[package]] 225 | name = "log" 226 | version = "0.4.22" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 229 | 230 | [[package]] 231 | name = "memchr" 232 | version = "2.7.4" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 235 | 236 | [[package]] 237 | name = "proc-macro2" 238 | version = "1.0.92" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 241 | dependencies = [ 242 | "unicode-ident", 243 | ] 244 | 245 | [[package]] 246 | name = "quote" 247 | version = "1.0.36" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 250 | dependencies = [ 251 | "proc-macro2", 252 | ] 253 | 254 | [[package]] 255 | name = "regex-automata" 256 | version = "0.4.7" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 259 | dependencies = [ 260 | "aho-corasick", 261 | "memchr", 262 | "regex-syntax", 263 | ] 264 | 265 | [[package]] 266 | name = "regex-syntax" 267 | version = "0.8.4" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 270 | 271 | [[package]] 272 | name = "same-file" 273 | version = "1.0.6" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 276 | dependencies = [ 277 | "winapi-util", 278 | ] 279 | 280 | [[package]] 281 | name = "serde" 282 | version = "1.0.217" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 285 | dependencies = [ 286 | "serde_derive", 287 | ] 288 | 289 | [[package]] 290 | name = "serde_derive" 291 | version = "1.0.217" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 294 | dependencies = [ 295 | "proc-macro2", 296 | "quote", 297 | "syn", 298 | ] 299 | 300 | [[package]] 301 | name = "serde_spanned" 302 | version = "0.6.8" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 305 | dependencies = [ 306 | "serde", 307 | ] 308 | 309 | [[package]] 310 | name = "strsim" 311 | version = "0.11.1" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 314 | 315 | [[package]] 316 | name = "syn" 317 | version = "2.0.95" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" 320 | dependencies = [ 321 | "proc-macro2", 322 | "quote", 323 | "unicode-ident", 324 | ] 325 | 326 | [[package]] 327 | name = "toml" 328 | version = "0.8.19" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 331 | dependencies = [ 332 | "serde", 333 | "serde_spanned", 334 | "toml_datetime", 335 | "toml_edit", 336 | ] 337 | 338 | [[package]] 339 | name = "toml_datetime" 340 | version = "0.6.8" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 343 | dependencies = [ 344 | "serde", 345 | ] 346 | 347 | [[package]] 348 | name = "toml_edit" 349 | version = "0.22.22" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 352 | dependencies = [ 353 | "indexmap", 354 | "serde", 355 | "serde_spanned", 356 | "toml_datetime", 357 | "winnow", 358 | ] 359 | 360 | [[package]] 361 | name = "unicode-ident" 362 | version = "1.0.12" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 365 | 366 | [[package]] 367 | name = "utf8parse" 368 | version = "0.2.2" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 371 | 372 | [[package]] 373 | name = "walkdir" 374 | version = "2.5.0" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 377 | dependencies = [ 378 | "same-file", 379 | "winapi-util", 380 | ] 381 | 382 | [[package]] 383 | name = "winapi-util" 384 | version = "0.1.9" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 387 | dependencies = [ 388 | "windows-sys", 389 | ] 390 | 391 | [[package]] 392 | name = "windows-sys" 393 | version = "0.52.0" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 396 | dependencies = [ 397 | "windows-targets", 398 | ] 399 | 400 | [[package]] 401 | name = "windows-targets" 402 | version = "0.52.6" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 405 | dependencies = [ 406 | "windows_aarch64_gnullvm", 407 | "windows_aarch64_msvc", 408 | "windows_i686_gnu", 409 | "windows_i686_gnullvm", 410 | "windows_i686_msvc", 411 | "windows_x86_64_gnu", 412 | "windows_x86_64_gnullvm", 413 | "windows_x86_64_msvc", 414 | ] 415 | 416 | [[package]] 417 | name = "windows_aarch64_gnullvm" 418 | version = "0.52.6" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 421 | 422 | [[package]] 423 | name = "windows_aarch64_msvc" 424 | version = "0.52.6" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 427 | 428 | [[package]] 429 | name = "windows_i686_gnu" 430 | version = "0.52.6" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 433 | 434 | [[package]] 435 | name = "windows_i686_gnullvm" 436 | version = "0.52.6" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 439 | 440 | [[package]] 441 | name = "windows_i686_msvc" 442 | version = "0.52.6" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 445 | 446 | [[package]] 447 | name = "windows_x86_64_gnu" 448 | version = "0.52.6" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 451 | 452 | [[package]] 453 | name = "windows_x86_64_gnullvm" 454 | version = "0.52.6" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 457 | 458 | [[package]] 459 | name = "windows_x86_64_msvc" 460 | version = "0.52.6" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 463 | 464 | [[package]] 465 | name = "winnow" 466 | version = "0.6.22" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" 469 | dependencies = [ 470 | "memchr", 471 | ] 472 | --------------------------------------------------------------------------------