Skip to content

Commit 97e9d74

Browse files
committed
add an argument parser to linkchecker
1 parent 3a4c287 commit 97e9d74

File tree

1 file changed

+46
-5
lines changed

1 file changed

+46
-5
lines changed

src/tools/linkchecker/main.rs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
1919
use std::cell::{Cell, RefCell};
2020
use std::collections::{HashMap, HashSet};
21+
use std::fs;
2122
use std::io::ErrorKind;
2223
use std::path::{Component, Path, PathBuf};
2324
use std::rc::Rc;
2425
use std::time::Instant;
25-
use std::{env, fs};
2626

2727
use html5ever::tendril::ByteTendril;
2828
use html5ever::tokenizer::{
@@ -110,10 +110,20 @@ macro_rules! t {
110110
};
111111
}
112112

113+
struct Cli {
114+
docs: PathBuf,
115+
}
116+
113117
fn main() {
114-
let docs = env::args_os().nth(1).expect("doc path should be first argument");
115-
let docs = env::current_dir().unwrap().join(docs);
116-
let mut checker = Checker { root: docs.clone(), cache: HashMap::new() };
118+
let cli = match parse_cli() {
119+
Ok(cli) => cli,
120+
Err(err) => {
121+
eprintln!("error: {err}");
122+
usage_and_exit(1);
123+
}
124+
};
125+
126+
let mut checker = Checker { root: cli.docs.clone(), cache: HashMap::new() };
117127
let mut report = Report {
118128
errors: 0,
119129
start: Instant::now(),
@@ -125,14 +135,45 @@ fn main() {
125135
intra_doc_exceptions: 0,
126136
has_broken_urls: false,
127137
};
128-
checker.walk(&docs, &mut report);
138+
checker.walk(&cli.docs, &mut report);
129139
report.report();
130140
if report.errors != 0 {
131141
println!("found some broken links");
132142
std::process::exit(1);
133143
}
134144
}
135145

146+
fn parse_cli() -> Result<Cli, String> {
147+
fn to_canonical_path(arg: &str) -> Result<PathBuf, String> {
148+
PathBuf::from(arg).canonicalize().map_err(|e| format!("could not canonicalize {arg}: {e}"))
149+
}
150+
151+
let mut verbatim = false;
152+
let mut docs = None;
153+
154+
let mut args = std::env::args().skip(1);
155+
while let Some(arg) = args.next() {
156+
if !verbatim && arg == "--" {
157+
verbatim = true;
158+
} else if !verbatim && (arg == "-h" || arg == "--help") {
159+
usage_and_exit(0)
160+
} else if !verbatim && arg.starts_with('-') {
161+
return Err(format!("unknown flag: {arg}"));
162+
} else if docs.is_none() {
163+
docs = Some(arg);
164+
} else {
165+
return Err("too many positional arguments".into());
166+
}
167+
}
168+
169+
Ok(Cli { docs: to_canonical_path(&docs.ok_or("missing first positional argument")?)? })
170+
}
171+
172+
fn usage_and_exit(code: i32) -> ! {
173+
eprintln!("usage: linkchecker <path>");
174+
std::process::exit(code)
175+
}
176+
136177
struct Checker {
137178
root: PathBuf,
138179
cache: Cache,

0 commit comments

Comments
 (0)