Repository: bitcoin/bitcoin
File: contrib/devtools/deterministic-fuzz-coverage/src/main.rs (Rust)

Code before:
// file COPYING or https://opensource.org/license/mit/.

use std::collections::VecDeque;
use std::env;
use std::fs::{read_dir, DirEntry, File};
use std::path::{Path, PathBuf};
use std::process::{Command, ExitCode};
use std::str;
use std::thread::{self, ScopedJoinHandle};

/// A type for a complete and readable error message.
type AppError = String;
type AppResult = Result<(), AppError>;

const LLVM_PROFDATA: &str = "llvm-profdata";
const LLVM_COV: &str = "llvm-cov";
const GIT: &str = "git";

const DEFAULT_PAR: usize = 1;

fn exit_help(err: &str) -> AppError {
    format!(
        r#"
Error: {err}

Usage: program ./build_dir ./qa-assets/fuzz_corpora fuzz_target_name (parallelism={DEFAULT_PAR})

Refer to the devtools/README.md for more details."#
    )
}

fn sanity_check(corpora_dir: &Path, fuzz_exe: &Path) -> AppResult {
    for tool in [LLVM_PROFDATA, LLVM_COV, GIT] {
        let output = Command::new(tool).arg("--help").output();
        match output {
            Ok(output) if output.status.success() => {}
            _ => Err(exit_help(&format!("The tool {} is not installed", tool)))?,
        }
    }
    if !corpora_dir.is_dir() {
        Err(exit_help(&format!(
            "Fuzz corpora path ({}) must be a directory",
            corpora_dir.display()
        )))?;
    }
    if !fuzz_exe.exists() {
        Err(exit_help(&format!(
            "Fuzz executable ({}) not found",
            fuzz_exe.display()
        )))?;
    }

Review comment (suggestion):
nit: `[]`-brackets are commonly used for optional arguments.
```suggestion
Usage: program ./build_dir ./qa-assets/fuzz_corpora fuzz_target_name [parallelism={DEFAULT_PAR}]
```

Might be nice to standardize on `-jN`, but keeping the logic simple is also good.

Code after:
// file COPYING or https://opensource.org/license/mit/.

use std::collections::VecDeque;
use std::env;
use std::fs::{read_dir, DirEntry, File};
use std::path::{Path, PathBuf};
use std::process::{Command, ExitCode};
use std::str;
use std::thread;

/// A type for a complete and readable error message.
type AppError = String;
type AppResult = Result<(), AppError>;

const LLVM_PROFDATA: &str = "llvm-profdata";
const LLVM_COV: &str = "llvm-cov";
const GIT: &str = "git";

const DEFAULT_PAR: usize = 1;

fn exit_help(err: &str) -> AppError {
    format!(
        r#"
Error: {err}

Usage: program ./build_dir ./qa-assets/fuzz_corpora fuzz_target_name [parallelism={DEFAULT_PAR}]

Refer to the devtools/README.md for more details."#
    )
}

fn sanity_check(corpora_dir: &Path, fuzz_exe: &Path) -> AppResult {
    for tool in [LLVM_PROFDATA, LLVM_COV, GIT] {
        let output = Command::new(tool).arg("--help").output();
        match output {
            Ok(output) if output.status.success() => {}
            _ => Err(exit_help(&format!("The tool {} is not installed", tool)))?,
        }
    }
    if !corpora_dir.is_dir() {
        Err(exit_help(&format!(
            "Fuzz corpora path ({}) must be a directory",
            corpora_dir.display()
        )))?;
    }
    if !fuzz_exe.exists() {
        Err(exit_help(&format!(
            "Fuzz executable ({}) not found",
            fuzz_exe.display()
        )))?;
    }