Bump clap from 3.2.23 to 4.0.22 (#813)

* Bump clap from 3.2.23 to 4.0.22

Bumps [clap](https://github.com/clap-rs/clap) from 3.2.23 to 4.0.22.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v3.2.23...v4.0.22)

* The `headers` option got renamed to `header` to align with the rest
   of the options, which are singular.
* The short option for `header` (`-h`) was removed to avoid a conflict with
  help (`lychee -h`).
* Update and simplify readme check

Co-authored-by: Matthias <matthias-endler@gmx.net>
This commit is contained in:
dependabot[bot] 2022-11-13 21:10:32 +01:00 committed by GitHub
parent fbf0e9faea
commit 2ce1a9ae06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 254 additions and 200 deletions

75
Cargo.lock generated
View file

@ -595,22 +595,32 @@ version = "3.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"clap_lex 0.2.4",
"indexmap",
"once_cell",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.2.18"
name = "clap"
version = "4.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
checksum = "91b9970d7505127a162fdaa9b96428d28a479ba78c9ec7550a63a5d9863db682"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex 0.3.0",
"once_cell",
"strsim",
"termcolor",
]
[[package]]
name = "clap_derive"
version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck",
"proc-macro-error",
@ -628,6 +638,15 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "clap_lex"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "client_pool"
version = "0.1.0"
@ -747,7 +766,7 @@ dependencies = [
"atty",
"cast",
"ciborium",
"clap",
"clap 3.2.23",
"criterion-plot",
"itertools",
"lazy_static",
@ -1011,6 +1030,12 @@ dependencies = [
"syn",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "difflib"
version = "0.4.0"
@ -1873,7 +1898,7 @@ version = "0.10.3"
dependencies = [
"anyhow",
"assert_cmd",
"clap",
"clap 4.0.22",
"console",
"const_format",
"csv",
@ -1890,6 +1915,7 @@ dependencies = [
"openssl-sys",
"pad",
"predicates",
"pretty_assertions",
"regex",
"reqwest",
"ring",
@ -2256,6 +2282,15 @@ version = "6.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
[[package]]
name = "output_vt100"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
dependencies = [
"winapi",
]
[[package]]
name = "pad"
version = "0.1.6"
@ -2511,6 +2546,18 @@ dependencies = [
"termtree",
]
[[package]]
name = "pretty_assertions"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
dependencies = [
"ctor",
"diff",
"output_vt100",
"yansi",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@ -3918,6 +3965,12 @@ dependencies = [
"tokio",
]
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zeroize"
version = "1.5.7"

207
README.md
View file

@ -207,138 +207,161 @@ There is an extensive list of commandline parameters to customize the behavior.
See below for a full list.
```text
USAGE:
lychee [OPTIONS] <inputs>...
A fast, async link checker
ARGS:
<inputs>... The inputs (where to get links to check from). These can be: files (e.g.
`README.md`), file globs (e.g. `"~/git/*/README.md"`), remote URLs (e.g.
`https://example.com/README.md`) or standard input (`-`). NOTE: Use `--` to
separate inputs from options that allow multiple arguments
Finds broken URLs and mail addresses inside Markdown, HTML, `reStructuredText`, websites and more!
OPTIONS:
-a, --accept <ACCEPT>
Comma-separated list of accepted status codes for valid links
Usage: lychee [OPTIONS] <inputs>...
-b, --base <BASE>
Base URL or website root directory to check relative URLs e.g. https://example.com or
`/path/to/public`
Arguments:
<inputs>...
The inputs (where to get links to check from). These can be: files (e.g. `README.md`), file globs (e.g. `"~/git/*/README.md"`), remote URLs (e.g. `https://example.com/README.md`) or standard input (`-`). NOTE: Use `--` to separate inputs from options that allow multiple arguments
--basic-auth <BASIC_AUTH>
Basic authentication support. E.g. `username:password`
Options:
-c, --config <CONFIG_FILE>
Configuration file to use
[default: ./lychee.toml]
-c, --config <CONFIG_FILE>
Configuration file to use [default: ./lychee.toml]
-v, --verbose
Verbose program output
--cache
Use request cache stored on disk at `.lycheecache`
-n, --no-progress
Do not show progress bar.
This is recommended for non-interactive shells (e.g. for continuous integration)
--dump
Don't perform any link checking. Instead, dump all the links extracted from inputs that
would be checked
--cache
Use request cache stored on disk at `.lycheecache`
-E, --exclude-all-private
Exclude all private IPs from checking.
Equivalent to `--exclude-private --exclude-link-local --exclude-loopback`
--max-cache-age <MAX_CACHE_AGE>
Discard all cached requests older than this duration
[default: 1d]
--exclude <EXCLUDE>
Exclude URLs and mail addresses from checking (supports regex)
--dump
Don't perform any link checking. Instead, dump all the links extracted from inputs that would be checked
--exclude-file <EXCLUDE_FILE>
Deprecated; use `--exclude-path` instead
-m, --max-redirects <MAX_REDIRECTS>
Maximum number of allowed redirects
[default: 5]
--exclude-link-local
Exclude link-local IP address range from checking
--max-retries <MAX_RETRIES>
Maximum number of retries per request
[default: 3]
--exclude-loopback
Exclude loopback IP address range and localhost from checking
--max-concurrency <MAX_CONCURRENCY>
Maximum number of concurrent network requests
[default: 128]
--exclude-mail
Exclude all mail addresses from checking
-T, --threads <THREADS>
Number of threads to utilize. Defaults to number of cores available to the system
--exclude-path <EXCLUDE_PATH>
Exclude file path from getting checked
-u, --user-agent <USER_AGENT>
User agent
[default: lychee/0.10.3]
--exclude-private
Exclude private IP address ranges from checking
-i, --insecure
Proceed for server connections considered insecure (invalid TLS)
-f, --format <FORMAT>
Output format of final status report (compact, detailed, json, markdown) [default:
compact]
-s, --scheme <SCHEME>
Only test links with the given schemes (e.g. http and https)
--github-token <GITHUB_TOKEN>
GitHub API token to use when checking github.com links, to avoid rate limiting [env:
GITHUB_TOKEN]
--offline
Only check local files and block network requests
--glob-ignore-case
Ignore case when expanding filesystem path glob inputs
--include <INCLUDE>
URLs to check (supports regex). Has preference over all excludes
-h, --headers <HEADERS>
Custom request headers
--exclude <EXCLUDE>
Exclude URLs and mail addresses from checking (supports regex)
--help
Print help information
--exclude-file <EXCLUDE_FILE>
Deprecated; use `--exclude-path` instead
-i, --insecure
Proceed for server connections considered insecure (invalid TLS)
--exclude-path <EXCLUDE_PATH>
Exclude file path from getting checked
--include <INCLUDE>
URLs to check (supports regex). Has preference over all excludes
-E, --exclude-all-private
Exclude all private IPs from checking.
Equivalent to `--exclude-private --exclude-link-local --exclude-loopback`
--include-verbatim
Find links in verbatim sections like `pre`- and `code` blocks
--exclude-private
Exclude private IP address ranges from checking
-m, --max-redirects <MAX_REDIRECTS>
Maximum number of allowed redirects [default: 5]
--exclude-link-local
Exclude link-local IP address range from checking
--max-cache-age <MAX_CACHE_AGE>
Discard all cached requests older than this duration [default: 1d]
--exclude-loopback
Exclude loopback IP address range and localhost from checking
--max-concurrency <MAX_CONCURRENCY>
Maximum number of concurrent network requests [default: 128]
--exclude-mail
Exclude all mail addresses from checking
--max-retries <MAX_RETRIES>
Maximum number of retries per request [default: 3]
--remap <REMAP>
Remap URI matching pattern to different URI
-n, --no-progress
Do not show progress bar.
This is recommended for non-interactive shells (e.g. for continuous integration)
--header <HEADER>
Custom request header
-o, --output <OUTPUT>
Output file of status report
-a, --accept <ACCEPT>
Comma-separated list of accepted status codes for valid links
--offline
Only check local files and block network requests
-t, --timeout <TIMEOUT>
Website timeout in seconds from connect to response finished
[default: 20]
-r, --retry-wait-time <RETRY_WAIT_TIME>
Minimum wait time in seconds between retries of failed requests [default: 1]
-r, --retry-wait-time <RETRY_WAIT_TIME>
Minimum wait time in seconds between retries of failed requests
[default: 1]
--remap <REMAP>
Remap URI matching pattern to different URI
-X, --method <METHOD>
Request method
[default: get]
--require-https
When HTTPS is available, treat HTTP links as errors
-b, --base <BASE>
Base URL or website root directory to check relative URLs e.g. https://example.com or `/path/to/public`
-s, --scheme <SCHEME>
Only test links with the given schemes (e.g. http and https)
--basic-auth <BASIC_AUTH>
Basic authentication support. E.g. `username:password`
--skip-missing
Skip missing input files (default is to error if they don't exist)
--github-token <GITHUB_TOKEN>
GitHub API token to use when checking github.com links, to avoid rate limiting
[env: GITHUB_TOKEN]
-t, --timeout <TIMEOUT>
Website timeout in seconds from connect to response finished [default: 20]
--skip-missing
Skip missing input files (default is to error if they don't exist)
-T, --threads <THREADS>
Number of threads to utilize. Defaults to number of cores available to the system
--include-verbatim
Find links in verbatim sections like `pre`- and `code` blocks
-u, --user-agent <USER_AGENT>
User agent [default: lychee/0.10.3]
--glob-ignore-case
Ignore case when expanding filesystem path glob inputs
-v, --verbose
Verbose program output
-o, --output <OUTPUT>
Output file of status report
-f, --format <FORMAT>
Output format of final status report (compact, detailed, json, markdown)
[default: compact]
--require-https
When HTTPS is available, treat HTTP links as errors
-h, --help
Print help information (use `-h` for a summary)
-V, --version
Print version information
-X, --method <METHOD>
Request method [default: get]
```
### Exit codes

View file

@ -1,7 +1,7 @@
[package]
name = "lychee"
authors = ["Matthias Endler <matthias@endler.dev>"]
description = "A glorious link checker"
description = "A fast, async link checker"
documentation = "https://docs.rs/lychee"
homepage = "https://github.com/lycheeverse/lychee"
edition = "2021"
@ -50,11 +50,12 @@ supports-color = "1.3.0"
log = "0.4.17"
[dependencies.clap]
version = "3.2.23"
version = "4.0.22"
features = ["env", "derive"]
[dev-dependencies]
assert_cmd = "2.0.5"
pretty_assertions = "1.3.0"
predicates = "2.1.1"
tempfile = "3.3.0"
uuid = { version = "1.2.1", features = ["v4"] }

View file

@ -9,7 +9,7 @@ use std::{collections::HashSet, str::FromStr};
/// Creates a client according to the command-line config
pub(crate) fn create(cfg: &Config) -> Result<Client> {
let mut headers = parse_headers(&cfg.headers)?;
let mut headers = parse_headers(&cfg.header)?;
if let Some(auth) = &cfg.basic_auth {
let auth_header = parse_basic_auth(auth)?;
headers.typed_insert(auth_header);

View file

@ -1,6 +1,6 @@
use crate::parse::{parse_base, parse_statuscodes};
use anyhow::{anyhow, Context, Error, Result};
use clap::StructOpt;
use clap::{arg, Parser};
use const_format::{concatcp, formatcp};
use lychee_lib::{
Base, Input, DEFAULT_MAX_REDIRECTS, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_WAIT_TIME_SECS,
@ -95,24 +95,25 @@ macro_rules! fold_in {
};
}
#[derive(Debug, StructOpt)]
#[clap(
name = "lychee",
about = "A glorious link checker.\n\nProject home page: https://github.com/lycheeverse/lychee"
)]
#[derive(Parser, Debug)]
#[command(version, about)]
/// A fast, async link checker
///
/// Finds broken URLs and mail addresses inside Markdown, HTML,
/// `reStructuredText`, websites and more!
pub(crate) struct LycheeOptions {
/// The inputs (where to get links to check from).
/// These can be: files (e.g. `README.md`), file globs (e.g. `"~/git/*/README.md"`),
/// remote URLs (e.g. `https://example.com/README.md`) or standard input (`-`).
/// NOTE: Use `--` to separate inputs from options that allow multiple arguments.
#[clap(name = "inputs", required = true)]
#[arg(name = "inputs", required = true)]
raw_inputs: Vec<String>,
/// Configuration file to use
#[clap(short, long = "config", default_value = "./lychee.toml")]
#[arg(short, long = "config", default_value = "./lychee.toml")]
pub(crate) config_file: String,
#[clap(flatten)]
#[command(flatten)]
pub(crate) config: Config,
}
@ -136,28 +137,28 @@ impl LycheeOptions {
}
#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Deserialize, StructOpt, Clone)]
#[derive(Parser, Debug, Deserialize, Clone)]
pub(crate) struct Config {
/// Verbose program output
#[clap(short, long)]
#[arg(short, long)]
#[serde(default)]
pub(crate) verbose: bool,
/// Do not show progress bar.
/// This is recommended for non-interactive shells (e.g. for continuous integration)
#[clap(short, long, verbatim_doc_comment)]
#[arg(short, long, verbatim_doc_comment)]
#[serde(default)]
pub(crate) no_progress: bool,
#[clap(help = HELP_MSG_CACHE)]
#[clap(long)]
#[arg(help = HELP_MSG_CACHE)]
#[arg(long)]
#[serde(default)]
pub(crate) cache: bool,
/// Discard all cached requests older than this duration
#[clap(
#[arg(
long,
parse(try_from_str = humantime::parse_duration),
value_parser = humantime::parse_duration,
default_value = &MAX_CACHE_AGE_STR
)]
#[serde(default = "max_cache_age")]
@ -166,171 +167,171 @@ pub(crate) struct Config {
/// Don't perform any link checking.
/// Instead, dump all the links extracted from inputs that would be checked
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) dump: bool,
/// Maximum number of allowed redirects
#[clap(short, long, default_value = &MAX_REDIRECTS_STR)]
#[arg(short, long, default_value = &MAX_REDIRECTS_STR)]
#[serde(default = "max_redirects")]
pub(crate) max_redirects: usize,
/// Maximum number of retries per request
#[clap(long, default_value = &MAX_RETRIES_STR)]
#[arg(long, default_value = &MAX_RETRIES_STR)]
#[serde(default = "max_retries")]
pub(crate) max_retries: u64,
/// Maximum number of concurrent network requests
#[clap(long, default_value = &MAX_CONCURRENCY_STR)]
#[arg(long, default_value = &MAX_CONCURRENCY_STR)]
#[serde(default = "max_concurrency")]
pub(crate) max_concurrency: usize,
/// Number of threads to utilize.
/// Defaults to number of cores available to the system
#[clap(short = 'T', long)]
#[arg(short = 'T', long)]
#[serde(default)]
pub(crate) threads: Option<usize>,
/// User agent
#[clap(short, long, default_value = DEFAULT_USER_AGENT)]
#[arg(short, long, default_value = DEFAULT_USER_AGENT)]
#[serde(default = "user_agent")]
pub(crate) user_agent: String,
/// Proceed for server connections considered insecure (invalid TLS)
#[clap(short, long)]
#[arg(short, long)]
#[serde(default)]
pub(crate) insecure: bool,
/// Only test links with the given schemes (e.g. http and https)
#[clap(short, long)]
#[arg(short, long)]
#[serde(default)]
pub(crate) scheme: Vec<String>,
/// Only check local files and block network requests.
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) offline: bool,
/// URLs to check (supports regex). Has preference over all excludes.
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) include: Vec<String>,
/// Exclude URLs and mail addresses from checking (supports regex)
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude: Vec<String>,
/// Deprecated; use `--exclude-path` instead
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude_file: Vec<String>,
/// Exclude file path from getting checked.
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude_path: Vec<PathBuf>,
/// Exclude all private IPs from checking.
/// Equivalent to `--exclude-private --exclude-link-local --exclude-loopback`
#[clap(short = 'E', long, verbatim_doc_comment)]
#[arg(short = 'E', long, verbatim_doc_comment)]
#[serde(default)]
pub(crate) exclude_all_private: bool,
/// Exclude private IP address ranges from checking
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude_private: bool,
/// Exclude link-local IP address range from checking
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude_link_local: bool,
/// Exclude loopback IP address range and localhost from checking
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude_loopback: bool,
/// Exclude all mail addresses from checking
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) exclude_mail: bool,
/// Remap URI matching pattern to different URI
#[serde(default)]
#[clap(long)]
#[arg(long)]
pub(crate) remap: Vec<String>,
/// Custom request headers
#[clap(short, long)]
/// Custom request header
#[arg(long)]
#[serde(default)]
pub(crate) headers: Vec<String>,
pub(crate) header: Vec<String>,
/// Comma-separated list of accepted status codes for valid links
#[clap(short, long, parse(try_from_str = parse_statuscodes))]
#[arg(short, long, value_parser = parse_statuscodes)]
#[serde(default)]
pub(crate) accept: Option<HashSet<u16>>,
/// Website timeout in seconds from connect to response finished
#[clap(short, long, default_value = &TIMEOUT_STR)]
#[arg(short, long, default_value = &TIMEOUT_STR)]
#[serde(default = "timeout")]
pub(crate) timeout: usize,
/// Minimum wait time in seconds between retries of failed requests
#[clap(short, long, default_value = &RETRY_WAIT_TIME_STR)]
#[arg(short, long, default_value = &RETRY_WAIT_TIME_STR)]
#[serde(default = "retry_wait_time")]
pub(crate) retry_wait_time: usize,
/// Request method
// Using `-X` as a short param similar to curl
#[clap(short = 'X', long, default_value = DEFAULT_METHOD)]
#[arg(short = 'X', long, default_value = DEFAULT_METHOD)]
#[serde(default = "method")]
pub(crate) method: String,
/// Base URL or website root directory to check relative URLs
/// e.g. https://example.com or `/path/to/public`
#[clap(short, long, parse(try_from_str = parse_base))]
#[arg(short, long, value_parser= parse_base)]
#[serde(default)]
pub(crate) base: Option<Base>,
/// Basic authentication support. E.g. `username:password`
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) basic_auth: Option<String>,
/// GitHub API token to use when checking github.com links, to avoid rate limiting
#[clap(long, env = "GITHUB_TOKEN", hide_env_values = true)]
#[arg(long, env = "GITHUB_TOKEN", hide_env_values = true)]
#[serde(default)]
pub(crate) github_token: Option<SecretString>,
/// Skip missing input files (default is to error if they don't exist)
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) skip_missing: bool,
/// Find links in verbatim sections like `pre`- and `code` blocks
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) include_verbatim: bool,
/// Ignore case when expanding filesystem path glob inputs
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) glob_ignore_case: bool,
/// Output file of status report
#[clap(short, long, parse(from_os_str))]
#[arg(short, long, value_parser)]
#[serde(default)]
pub(crate) output: Option<PathBuf>,
/// Output format of final status report (compact, detailed, json, markdown)
#[clap(short, long, default_value = "compact")]
#[arg(short, long, default_value = "compact")]
#[serde(default)]
pub(crate) format: Format,
/// When HTTPS is available, treat HTTP links as errors
#[clap(long)]
#[arg(long)]
#[serde(default)]
pub(crate) require_https: bool,
}
@ -383,7 +384,7 @@ impl Config {
exclude_loopback: false;
exclude_mail: false;
remap: Vec::<String>::new();
headers: Vec::<String>::new();
header: Vec::<String>::new();
accept: None;
timeout: DEFAULT_TIMEOUT_SECS;
retry_wait_time: DEFAULT_RETRY_WAIT_TIME_SECS;

View file

@ -53,9 +53,9 @@ pub(crate) fn parse_base(src: &str) -> Result<Base, lychee_lib::ErrorKind> {
}
/// Parse HTTP status codes into a set of `StatusCode`
pub(crate) fn parse_statuscodes<T: AsRef<str>>(accept: T) -> Result<HashSet<u16>> {
pub(crate) fn parse_statuscodes(accept: &str) -> Result<HashSet<u16>> {
let mut statuscodes = HashSet::new();
for code in accept.as_ref().split(',') {
for code in accept.split(',') {
let code: u16 = code.parse::<u16>()?;
statuscodes.insert(code);
}

View file

@ -1,12 +1,11 @@
#[cfg(test)]
mod readme {
use std::{
fs::File,
io::{BufReader, Read},
path::Path,
};
use std::{fs, path::Path};
use assert_cmd::Command;
use pretty_assertions::assert_eq;
const USAGE_STRING: &str = "Usage: lychee [OPTIONS] <inputs>...\n";
fn main_command() -> Command {
// this gets the "main" binary name (e.g. `lychee`)
@ -18,15 +17,7 @@ mod readme {
.parent()
.unwrap()
.join("README.md");
let file = File::open(readme_path).expect("Couldn't open README.md");
let mut buf_reader = BufReader::new(file);
let mut text = String::new();
buf_reader
.read_to_string(&mut text)
.expect("Unable to read README.md file contents");
text
fs::read_to_string(readme_path).unwrap()
}
/// Test that the USAGE section in `README.md` is up to date with
@ -36,35 +27,20 @@ mod readme {
/// involved parsing).
#[test]
#[cfg(unix)]
fn test_readme_usage_up_to_date() {
fn test_readme_usage_up_to_date() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = main_command();
let result = cmd.env_clear().arg("--help").assert().success();
let help_output = std::str::from_utf8(&result.get_output().stdout)
.expect("Invalid utf8 output for `--help`");
let readme = load_readme_text();
const BACKTICKS_OFFSET: usize = 7; // marker: ```text
const NEWLINE_OFFSET: usize = 1;
let usage_start = BACKTICKS_OFFSET
+ NEWLINE_OFFSET
+ readme
.find("```text\nUSAGE:\n")
.expect("Couldn't find USAGE section in README.md");
let usage_end = readme[usage_start..]
.find("\n```")
.expect("Couldn't find USAGE section end in README.md");
// include final newline in usage text
let usage_in_readme = &readme[usage_start..usage_start + usage_end + NEWLINE_OFFSET];
let usage_in_help_start = help_output
.find("USAGE:\n")
.expect("Couldn't find USAGE section in `--help` output");
let help_cmd = cmd.env_clear().arg("--help").assert().success();
let help_output = std::str::from_utf8(&help_cmd.get_output().stdout).unwrap();
let usage_in_help_start = help_output.find(USAGE_STRING).unwrap();
let usage_in_help = &help_output[usage_in_help_start..];
let readme = load_readme_text();
let usage_start = readme.find(USAGE_STRING).unwrap();
let usage_end = readme[usage_start..].find("\n```").unwrap();
let usage_in_readme = &readme[usage_start..usage_start + usage_end];
assert_eq!(usage_in_readme, usage_in_help);
Ok(())
}
}

View file

@ -1,7 +1,7 @@
[package]
name = "lychee-lib"
authors = ["Matthias Endler <matthias@endler.dev>"]
description = "A glorious link checker"
description = "A fast, async link checker"
documentation = "https://docs.rs/lychee_lib"
edition = "2021"
homepage = "https://github.com/lycheeverse/lychee"