1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use std::path::PathBuf;
use clap::Args;
#[derive(Debug, Args)]
#[command(arg_required_else_help = true)]
pub struct PrecompileArgs {
/// File or directory to precompile. Directories are walked recursively
/// for `.harn` files.
#[arg(required_unless_present = "artifact_contract")]
pub target: Option<PathBuf>,
/// Print the machine-readable adjacent-artifact compatibility contract.
#[arg(
long,
conflicts_with_all = ["target", "relocatable", "out", "keep_going", "quiet", "jobs"]
)]
pub artifact_contract: bool,
/// Use a path-independent import-graph key for an artifact that moves
/// with its complete source tree. Used by the directory-walk child.
#[arg(long, hide = true)]
pub relocatable: bool,
/// Output directory for compiled `.harnbc` artifacts. When omitted,
/// each artifact is written next to its source. The directory tree
/// under `target` is mirrored under `--out` so per-source pathing is
/// preserved.
#[arg(long, value_name = "DIR")]
pub out: Option<PathBuf>,
/// Continue processing the remaining sources even if one fails to
/// compile. The exit code still reflects the failure.
#[arg(long)]
pub keep_going: bool,
/// Compile up to N sources concurrently when walking a directory.
/// Defaults to the machine's available parallelism. Output order,
/// artifacts, and the summary are the same for every value.
#[arg(
long = "jobs",
short = 'j',
value_name = "N",
value_parser = clap::value_parser!(u32).range(1..)
)]
pub jobs: Option<u32>,
/// Suppress per-file progress output.
#[arg(short = 'q', long)]
pub quiet: bool,
}
/// Env var carrying the resolved `--jobs` bound to the embedded driver script.
pub const PRECOMPILE_JOBS_ENV: &str = "HARN_PRECOMPILE_JOBS";
impl PrecompileArgs {
/// The concurrency bound the directory walk runs with. Resolved in Rust so
/// the driver always receives a concrete bound: the script has no portable
/// way to ask for the core count.
pub fn resolved_jobs(&self) -> usize {
self.jobs.map_or_else(
|| {
std::thread::available_parallelism()
.map(std::num::NonZeroUsize::get)
.unwrap_or(1)
},
|jobs| jobs as usize,
)
}
}