Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ The following arguments are available:
| `--version` | `-V` | Print current version of mlc |
| `--ignore-path` | `-p` | Comma separated list of directories or files which shall be ignored. For example |
| `--gitignore` | `-g` | Ignore all files currently ignored by git (requires `git` binary to be available on $PATH). |
| `--gituntracked` | `-u` | Ignore all files currently untracked by git (requires `git` binary to be available on $PATH). |
| `--ignore-links` | `-i` | Comma separated list of links which shall be ignored. Use simple `?` and `*` wildcards. For example `--ignore-links "http*://crates.io*"` will skip all links to the crates.io website. See the [used lib](https://github.com/becheran/wildmatch) for more information. |
| `--markup-types` | `-t` | Comma separated list list of markup types which shall be checked [possible values: md, html] |
| `--root-dir` | `-r` | All links to the file system starting with a slash on linux or backslash on windows will use another virtual root dir. For example the link in a file `[link](/dir/other/file.md)` checked with the cli arg `--root-dir /env/another/dir` will let *mlc* check the existence of `/env/another/dir/dir/other/file.md`. |
Expand Down
13 changes: 13 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ pub fn parse_args() -> Config {
.action(ArgAction::SetTrue)
.required(false),
)
.arg(
Arg::new("gituntracked")
.long("gituntracked")
.short('u')
.value_name("GITUNTRACKED")
.help("Ignore all files untracked by git")
.action(ArgAction::SetTrue)
.required(false),
)
.get_matches();

let default_dir = format!(".{}", &MAIN_SEPARATOR);
Expand Down Expand Up @@ -175,6 +184,10 @@ pub fn parse_args() -> Config {
opt.gitignore = Some(true);
}

if matches.get_flag("gituntracked") {
opt.gituntracked = Some(true);
}

if let Some(root_dir) = matches.get_one::<String>("root-dir") {
let root_path = Path::new(
&root_dir
Expand Down
52 changes: 52 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ pub struct OptionalConfig {
pub root_dir: Option<PathBuf>,
#[serde(rename(deserialize = "gitignore"))]
pub gitignore: Option<bool>,
#[serde(rename(deserialize = "gituntracked"))]
pub gituntracked: Option<bool>,
pub throttle: Option<u32>,
}

Expand Down Expand Up @@ -92,6 +94,7 @@ Offline: {}
MatchExt: {}
RootDir: {}
Gitignore: {}
Gituntracked: {}
IgnoreLinks: {}
IgnorePath: {:?}
Throttle: {} ms",
Expand All @@ -103,6 +106,7 @@ Throttle: {} ms",
self.optional.match_file_extension.unwrap_or_default(),
root_dir_str,
self.optional.gitignore.unwrap_or_default(),
self.optional.gituntracked.unwrap_or_default(),
ignore_str.join(","),
ignore_path_str,
self.optional.throttle.unwrap_or(0)
Expand Down Expand Up @@ -157,7 +161,30 @@ fn find_git_ignored_files() -> Option<Vec<PathBuf>> {
None
}
}
fn find_git_untracked_files() -> Option<Vec<PathBuf>> {
let output = Command::new("git")
.arg("ls-files")
.arg("--others")
.arg("--exclude-standard")
.output()
.expect("Failed to execute 'git' command");

if output.status.success() {
let ignored_files = String::from_utf8(output.stdout)
.expect("Invalid UTF-8 sequence")
.lines()
.filter(|line| line.ends_with(".md") || line.ends_with(".html"))
.filter_map(|line| fs::canonicalize(Path::new(line.trim())).ok())
.collect::<Vec<_>>();
Some(ignored_files)
} else {
eprintln!(
"git ls-files command failed: {}",
String::from_utf8_lossy(&output.stderr)
);
None
}
}

fn print_helper(
link: &MarkupLink,
Expand Down Expand Up @@ -213,6 +240,16 @@ pub async fn run(config: &Config) -> Result<(), ()> {

let is_gitignore_enabled = gitignored_files.is_some();

let gituntracked_files: Option<Vec<PathBuf>> = if config.optional.gituntracked.is_some() {
let files = find_git_untracked_files();
debug!("Found gituntracked files: {:?}", files);
files
} else {
None
};

let is_gituntracked_enabled = gituntracked_files.is_some();

for link in &links {
let canonical_link_source = match fs::canonicalize(&link.source) {
Ok(path) => path,
Expand All @@ -237,6 +274,21 @@ pub async fn run(config: &Config) -> Result<(), ()> {
}
}

if is_gituntracked_enabled {
if let Some(ref gif) = gituntracked_files {
if gif.iter().any(|path| path == &canonical_link_source) {
print_helper(
link,
&"Skip".green(),
"Ignore link because it is untracked by git.",
false,
);
skipped += 1;
continue;
}
}
}

if ignore_links.iter().any(|m| m.matches(&link.target)) {
print_helper(
link,
Expand Down
2 changes: 2 additions & 0 deletions tests/end_to_end.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ async fn end_to_end() {
]),
root_dir: None,
gitignore: None,
gituntracked: None,
},
};
if let Err(e) = mlc::run(&config).await {
Expand All @@ -48,6 +49,7 @@ async fn end_to_end_different_root() {
throttle: None,
root_dir: Some(test_files),
gitignore: None,
gituntracked: None,
},
};
if let Err(e) = mlc::run(&config).await {
Expand Down