barexp/lib.rs
1//! # Barexp
2//!
3//! `barexp` is a library that automatically generates `mod.rs` files for your Rust project's subdirectories.
4//!
5//! ## Quick Start
6//!
7//! Add this to your `Cargo.toml`:
8//!
9//! ```toml
10//! [build-dependencies]
11//! barexp = "1.1.0"
12//! ```
13//!
14//! Then create a `build.rs` in your project root:
15//!
16//! ```rust
17//! fn main() {
18//! barexp::build();
19//! }
20//! ```
21//!
22//! ## Examples
23//!
24//! Basic usage:
25//!
26//! ```rust
27//! // Your project's build.rs
28//! fn main() {
29//! barexp::build();
30//! }
31//! ```
32//!
33//! ## Features
34//!
35//! - Recursively scans project subdirectories
36//! - Automatically generates `mod.rs` files
37//! - Re-exports all modules
38//! - Ignores hidden files and `target` directory
39
40
41use std::fs;
42use std::path::{Path, PathBuf};
43use walkdir::WalkDir;
44
45/// Represents a Rust module in the file system
46#[derive(Debug)]
47struct Module {
48 name: String,
49 path: PathBuf,
50 is_file: bool,
51}
52/// Optional function to generate mod.rs files for a given directory
53///
54/// This function is useful if you want to generate mod.rs files for a directory
55/// other than the default "src" directory.
56///
57/// # Arguments
58///
59/// * `src_dir` - The source directory to scan
60///
61/// # Examples
62///
63/// ```rust
64/// fn main() {
65/// barexp::generate_mod_files("src/services");
66/// }
67/// ```
68pub fn generate_mod_files(src_dir: &str) {
69 println!("cargo:rerun-if-changed={}", src_dir);
70
71 let src_path = Path::new(src_dir);
72
73 // Tüm Rust dosyalarını ve dizinlerini bul
74 for entry in WalkDir::new(src_dir)
75 .into_iter()
76 .filter_entry(|e| !is_hidden(e.path()))
77 .filter_map(|e| e.ok()) {
78
79 let path = entry.path();
80
81 // Root src dizini hariç, dizin içindeki mod.rs'i oluştur
82 if path.is_dir() && path != src_path && should_create_mod_rs(path) {
83 generate_mod_rs(path);
84 }
85 }
86}
87
88/// Internal function to check if a path is hidden
89///
90/// # Arguments
91///
92/// * `path` - The path to check
93///
94/// # Returns
95///
96/// * `true` if the path is hidden or is "target" directory
97/// * `false` otherwise
98fn is_hidden(path: &Path) -> bool {
99 path.file_name()
100 .and_then(|s| s.to_str())
101 .map(|s| s.starts_with('.') || s == "target")
102 .unwrap_or(false)
103}
104
105fn should_create_mod_rs(dir: &Path) -> bool {
106 // Dizinde en az bir .rs dosyası veya alt dizin varsa
107 fs::read_dir(dir).map_or(false, |entries| {
108 entries
109 .filter_map(Result::ok)
110 .any(|e| {
111 let p = e.path();
112 (p.is_file() && p.extension().map_or(false, |ext| ext == "rs") &&
113 p.file_name().map_or(false, |name| name != "mod.rs")) ||
114 (p.is_dir() && !is_hidden(&p))
115 })
116 })
117}
118
119fn collect_modules(dir: &Path) -> Vec<Module> {
120 let mut modules = Vec::new();
121
122 if let Ok(entries) = fs::read_dir(dir) {
123 for entry in entries.filter_map(Result::ok) {
124 let path = entry.path();
125
126 // Gizli dosyaları ve mod.rs'i atla
127 if is_hidden(&path) || path.file_name().map_or(false, |n| n == "mod.rs") {
128 continue;
129 }
130
131 if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") {
132 // foo.rs -> mod foo
133 if let Some(name) = path.file_stem().and_then(|n| n.to_str()) {
134 modules.push(Module {
135 name: name.to_string(),
136 path,
137 is_file: true,
138 });
139 }
140 } else if path.is_dir() {
141 // foo/mod.rs veya foo/lib.rs varsa -> mod foo
142 if path.join("mod.rs").exists() || path.join("lib.rs").exists() {
143 if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
144 modules.push(Module {
145 name: name.to_string(),
146 path,
147 is_file: false,
148 });
149 }
150 }
151 }
152 }
153 }
154
155 modules
156}
157
158fn generate_mod_rs(dir: &Path) {
159 let modules = collect_modules(dir);
160
161 if modules.is_empty() {
162 return;
163 }
164
165 let mut content = String::new();
166
167 // Önce mod declarations
168 for module in &modules {
169 content.push_str(&format!("pub mod {};\n", module.name));
170 }
171
172 content.push('\n');
173
174 // Sonra re-exports
175 content.push_str("pub use self::{\n");
176 for module in &modules {
177 content.push_str(&format!(" {}::*,\n", module.name));
178 }
179 content.push_str("};\n");
180
181 // mod.rs dosyasını oluştur veya güncelle
182 let mod_path = dir.join("mod.rs");
183 fs::write(mod_path, content).unwrap();
184}
185
186/// Main function to generate mod.rs files
187///
188/// This function scans the given directory and its subdirectories
189/// to automatically generate mod.rs files.
190///
191/// # Arguments
192///
193/// * `src_dir` - The source directory to scan, typically "src"
194///
195/// # Examples
196///
197/// ```rust
198/// fn main() {
199/// barexp::build();
200/// }
201/// ```
202///
203/// # Panics
204///
205/// Will panic if:
206/// * The source directory doesn't exist
207/// * File system operations fail
208/// * Permission errors occur
209pub fn build() {
210 generate_mod_files("src");
211}