-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(broken_symlinks) basic walk done but need to handle (collect?) permi…
…ssion errors
- Loading branch information
Showing
1 changed file
with
63 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,81 @@ | ||
use clap::Parser; | ||
use color_eyre::eyre::Result; | ||
use color_eyre::eyre::{eyre, Result}; | ||
use std::env; | ||
use std::fs::read_dir; | ||
use std::path::PathBuf; | ||
use std::time::Instant; | ||
|
||
extern crate utils_rs; | ||
use utils_rs::common::parsers; | ||
|
||
/// A simple utility to find broken symlinks | ||
#[derive(Parser, Debug)] | ||
#[clap(author, version, about)] | ||
struct Args { | ||
// TODO: add description of the program | ||
#[arg(value_parser=parsers::parse_dir)] | ||
root: Option<PathBuf>, | ||
|
||
#[arg(default_value_t = false, short, long)] | ||
verbose: bool, | ||
} | ||
|
||
/// Config for the application | ||
struct Opts { | ||
verbose: bool, | ||
} | ||
|
||
impl Opts { | ||
pub(crate) fn new(args: &Args) -> Self { | ||
Self { | ||
verbose: args.verbose, | ||
} | ||
} | ||
} | ||
|
||
fn main() -> Result<()> { | ||
// setup color_eyre panic and error report handlers | ||
color_eyre::install()?; | ||
|
||
// parse args | ||
let args = Args::parse(); | ||
let root_dir = args.root.unwrap_or(env::current_dir()?); | ||
dbg!(&root_dir); | ||
// TODO: keep only a reference to root (later) | ||
let root_dir = args.root.clone().unwrap_or(env::current_dir()?); | ||
|
||
// construct options from the args | ||
let opts = Opts::new(&args); | ||
|
||
// fire off! | ||
let start = Instant::now(); | ||
process_dir(&root_dir, &opts)?; | ||
println!("Completed in: {:.2?}", start.elapsed()); | ||
|
||
Ok(()) | ||
} | ||
|
||
fn process_dir(dir: &PathBuf, opts: &Opts) -> Result<()> { | ||
if opts.verbose { | ||
println!("Processing: {}", dir.display()); | ||
} | ||
|
||
for entry in read_dir(dir)? { | ||
let entry = entry?; | ||
let file_type = entry.file_type()?; | ||
|
||
if file_type.is_dir() { | ||
// process directory | ||
process_dir(&entry.path(), opts)?; | ||
} else if file_type.is_symlink() { | ||
// process symlink | ||
let target = entry.path(); | ||
match target.try_exists() { | ||
Ok(_) => println!("Broken Symlink: {}", target.display()), | ||
Err(_) => Err(eyre!( | ||
"Failed to check if symlink exists: {}", | ||
target.display() | ||
))?, | ||
} | ||
} | ||
} | ||
|
||
Ok(()) | ||
} |