Hi. Trying to create cli tool to count lines in project with some extension.
I'm using clap for it.
Also it is just a draft, so most of errors are unwraps for now
use std::{fs, path::{Path, PathBuf}};
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(version, about, long_about = None)]
pub struct Cli {
path: PathBuf,
extension: String,
}
fn get_gitignore(dir: &Path) -> Result<Vec<String>, String> {
let mut gitignore: Vec<String> = vec![];
if dir.is_dir() {
'outer: for entry in fs::read_dir(dir).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_dir() {
let mut temp = get_gitignore(&path).unwrap();
if !temp.is_empty() {
gitignore.append(temp.as_mut());
}
}
if path.file_name().unwrap_or_default().to_str().unwrap_or("") == ".gitignore" {
let lines = fs::read_to_string(&path).unwrap();
let lines = lines.lines();
for line in lines {
gitignore.push(line.to_string())
}
break 'outer;
}
}
}
return Ok(gitignore);
}
fn visit_dir(dir: &Path, ext: &String, gitignore: &Vec<String>) -> std::io::Result<usize> {
let mut lines = 0usize;
println!("{:?}", gitignore);
if dir.is_dir() {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.file_name().unwrap_or_default().to_str().unwrap_or("").starts_with('.') {
continue;
}
let contains = gitignore.iter().any(|s| s == path.file_name().unwrap().to_str().unwrap());
if contains {
continue;
}
if path.is_dir() {
visit_dir(&path, ext, &gitignore)?;
} else {
if !path.file_name().unwrap().to_str().unwrap().ends_with(ext) {
continue;
} else {
println!("Good file with good ext");
println!("File name {:?}", path.file_name().unwrap());
let temp = count_lines(&path);
println!("{}", temp);
lines += temp;
println!("{}", lines);
}
}
}
}
println!("{}", lines);
Ok(lines)
}
fn count_lines(file: &Path) -> usize {
let file_str = fs::read_to_string(file).unwrap();
let lines = file_str.lines();
println!("{}", lines.clone().count());
lines.count()
}
fn main() {
let cli = Cli::parse();
match fs::metadata(&cli.path) {
Ok(metadata) => {
if metadata.is_dir() {
let gitignore = get_gitignore(&cli.path).unwrap();
let lines = visit_dir(&cli.path, &cli.extension, &gitignore);
println!("{}", lines.unwrap());
}
},
Err(_) => ()
}
println!("{:?}, {:?}",cli.path, cli.extension)
}
This is what i have.
For this code to work you must provide valid path and extension of files you want to scan.
Also .gitignore file is must, because i didn't implement fallback for this yet
I didn't test it in multi file directory, but even now i'm encoutering some issues.
My filter with gitignore and hidden files works perfectly. Count function works as well. But when im trying to return lines i'm getting 0 there despite the fact that in if else block i have some number. For main.rs its 108
Why does this issue happen? How can i fix it?
Upd i found out that there is some logical errors. But cant figure out where. If i proved /src path it works fine, but if im doing it from project root dir it works, but when recursion from src dir ends, remaining files make it 0 again
["target"]
Some(".git")
0
Some("src")
0
["target"]
Some("some_file.rs")
0
Good file with good ext
File name "some_file.rs"
6
6
6
Some("main.rs")
6
Good file with good ext
File name "main.rs"
107
107
113
113
Some("Cargo.lock")
0
Some("Cargo.toml")
0
Some("target")
0
Some(".gitignore")
0
0
0
This is my output