mitts 0.3.28

Rust-first build and package tooling with a shared artifact cache
Documentation
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/*
 * Mitts Build — Rust-first build and package tooling with shared artifact cache
 * Copyright (c) 2026 Alexander Panasenko
 *
 * Contact: alex@prod.codes
 * Author: https://prod.codes/about/
 * Project: https://github.com/alex09x/mitts
 * SPDX-License-Identifier: MIT OR Apache-2.0
 */

use clap::{Args, Parser, Subcommand};
use std::path::PathBuf;

const MITTS_VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", env!("MITTS_GIT_SHA"), ")");

#[derive(Parser, Debug)]
#[command(name = "mitts")]
#[command(author = "Alexander Panasenko <alex@prod.codes>")]
#[command(version = MITTS_VERSION)]
#[command(
    about = "Rust-first build and package tooling with a shared artifact cache",
    after_help = "Environment Variables:\n  MITTS_JOBS=N          Limit concurrent native build units to a positive integer (-j/--jobs N overrides it)\n  MITTS_TIMINGS=1       Enable sub-millisecond phase timings and I/O metrics on stderr\n  MITTS_NO_REFLINK=1    Disable CoW reflink (FICLONE/clonefile) to force byte copying\n  MITTS_NO_HARDLINK=1   Disable intra-workspace zero-copy hardlinks\n  MITTS_VERIFY_RESTORE=1 Re-hash every cache object before restoring it\n  MITTS_CACHE_IO_BUDGET=N Cache readers allowed at once (0 = unbounded; default 1 on macOS)\n  MITTS_STORE_HARDLINKS=0|1 Store objects reach target/ by reflink, else read-only hardlink (default); 0 = copy instead, 1 = always link\n  MITTS_GIT=<path>      git binary used to clone git dependencies (default: git on PATH)\n  MITTS_INDEX_TTL_SECS=N  How long cached sparse-index entries are trusted when online (default 900)\n  MITTS_FAST_LOCK=0|1   Fast build lock with an explicit --cache-dir (default: on only for the default cache root)"
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
}

#[derive(Subcommand, Debug)]
pub enum Commands {
    /// Compile the local package and its dependencies into the isolated Mitts target
    #[command(
        after_help = "Use -j N, or set MITTS_JOBS=N, to limit concurrent native build units. N must be a positive integer; the flag wins over the variable."
    )]
    Build(BuildArgs),

    /// Run native rustc queries for the selected package target
    Rustc(BuildArgs),

    /// Check a package to catch errors without producing binary artifacts
    #[command(
        after_help = "Use -j N, or set MITTS_JOBS=N, to limit concurrent native build units. N must be a positive integer; the flag wins over the variable."
    )]
    Check(CheckArgs),

    /// Run Clippy lints over local packages in the workspace
    #[command(
        after_help = "Use -j N, or set MITTS_JOBS=N, to limit concurrent native build units. N must be a positive integer; the flag wins over the variable."
    )]
    Clippy(ClippyArgs),

    /// Format Rust source files in the workspace using rustfmt
    Fmt(FmtArgs),

    /// Compile and run the benchmark targets of a package in the bench profile
    #[command(
        after_help = "Builds [[bench]] and benches/ targets with the release profile plus [profile.bench] and runs each with `--bench` (a libtest or harness = false benchmark such as Criterion measures instead of testing). Select targets with --bench NAME; BENCHNAME and arguments after `--` go to the benchmark binaries. Library and binary unit tests and documentation tests are not run. Use -j N, or set MITTS_JOBS=N, to limit concurrent native build units."
    )]
    Bench(BenchArgs),

    /// Execute unit and integration tests of a package
    #[command(
        after_help = "Use -j N, or set MITTS_JOBS=N, to limit concurrent native build units. N must be a positive integer; the flag wins over the variable."
    )]
    Test(TestArgs),

    /// Generate code coverage using LLVM source-based coverage tools
    Coverage(CoverageArgs),

    /// Cargo-compatible llvm-cov wrapper command
    LlvmCov(CoverageArgs),

    /// Run a binary of the local package
    Run(RunArgs),

    /// Explain the effective build plan, compilation units, and cache eligibility
    Explain(ExplainArgs),

    /// Print a target-filtered package and dependency graph as JSON
    #[command(
        after_help = "Format 1 includes packages, workspace members, resolve.root, resolve.nodes, dependency kinds, and selected features. The graph describes active native build units for the requested platform and features."
    )]
    Metadata(MetadataArgs),

    /// Fetch dependencies into the global source store
    Fetch(FetchArgs),

    /// Create a source package archive
    #[command(
        after_help = "Git packages currently require a clean repository with the package at its root. Include/exclude patterns are supported; include can select ignored files. Nested workspace packages and symlinked directories are not yet supported.\n\nExamples:\n  mitts package --locked\n  mitts package --offline --cache-dir /path/to/cache\n  mitts package --no-verify"
    )]
    Package(PackageArgs),

    /// Publish a source package to crates.io
    #[command(
        after_help = "Publishes to crates.io using CARGO_REGISTRY_TOKEN. The default operation creates and verifies a package; --archive accepts a previously prepared archive.\n\nExamples:\n  mitts publish --dry-run\n  mitts publish --locked\n  mitts publish --archive target/package/name-version.crate"
    )]
    Publish(PublishArgs),

    /// Prune old or unreferenced CAS objects according to storage quotas
    Gc(GcArgs),

    /// Remove generated artifacts and fast build lock for the workspace
    Clean(CleanArgs),
}

#[derive(Args, Debug, Clone, Default)]
pub struct CleanArgs {
    /// Path to Cargo.toml
    #[arg(long)]
    pub manifest_path: Option<PathBuf>,

    /// Directory for all generated artifacts
    #[arg(long)]
    pub target_dir: Option<PathBuf>,

    /// Clean release artifacts only
    #[arg(short, long)]
    pub release: bool,

    /// Clean the shared global artifact and action cache as well
    #[arg(long)]
    pub cache: bool,

    /// Directory for the shared artifact and action cache
    #[arg(long)]
    pub cache_dir: Option<PathBuf>,
}

impl Commands {
    /// The `-j/--jobs` value, for the commands that take one and when it was given.
    pub fn jobs(&self) -> Option<usize> {
        let jobs = match self {
            Commands::Build(args) | Commands::Rustc(args) => args.jobs,
            Commands::Check(args) => args.jobs,
            Commands::Clippy(args) => args.jobs,
            Commands::Test(args) => args.jobs,
            Commands::Bench(args) => args.jobs,
            Commands::Coverage(args) | Commands::LlvmCov(args) => args.jobs,
            Commands::Run(args) => args.build_args.jobs,
            _ => None,
        };
        jobs.and_then(|n| usize::try_from(n).ok())
    }

    /// For the commands that build with the shared cache: their `--cache-dir` (`Some(None)`
    /// when the default cache is used). `None` for the others.
    pub fn cache_use(&self) -> Option<Option<PathBuf>> {
        match self {
            Commands::Build(args) | Commands::Rustc(args) => Some(args.cache_dir.clone()),
            Commands::Check(args) => Some(args.cache_dir.clone()),
            Commands::Clippy(args) => Some(args.cache_dir.clone()),
            Commands::Test(args) => Some(args.cache_dir.clone()),
            Commands::Bench(args) => Some(args.cache_dir.clone()),
            Commands::Coverage(args) | Commands::LlvmCov(args) => Some(args.cache_dir.clone()),
            Commands::Run(args) => Some(args.build_args.cache_dir.clone()),
            _ => None,
        }
    }
}

#[derive(Args, Debug, Clone, Default)]
pub struct BuildArgs {
    /// Path to Cargo.toml
    #[arg(long)]
    pub manifest_path: Option<PathBuf>,

    /// Limit concurrent native build units (same as MITTS_JOBS; the flag wins)
    #[arg(short = 'j', long, value_name = "N", value_parser = clap::value_parser!(u64).range(1..))]
    pub jobs: Option<u64>,

    /// Package to build
    #[arg(skip)]
    pub package: Option<String>,

    /// Packages to build (repeat for multiple packages)
    #[arg(short = 'p', long = "package", action = clap::ArgAction::Append)]
    pub packages: Vec<String>,

    /// Build artifacts in release mode, with optimizations
    #[arg(short, long)]
    pub release: bool,

    /// Directory for all generated artifacts
    #[arg(long)]
    pub target_dir: Option<PathBuf>,

    /// Space or comma separated list of features to activate
    #[arg(short = 'F', long, value_delimiter = ',', num_args = 1..)]
    pub features: Vec<String>,

    /// Do not activate the `default` feature
    #[arg(long)]
    pub no_default_features: bool,

    /// Activate all available features
    #[arg(long)]
    pub all_features: bool,

    /// Do not read from or write to the shared action cache
    #[arg(long)]
    pub no_cache: bool,

    /// Directory for the shared artifact and action cache
    #[arg(long)]
    pub cache_dir: Option<PathBuf>,

    /// Require an existing compatible Cargo.lock; do not resolve or write one.
    #[arg(long)]
    pub locked: bool,

    /// Do not use the network to resolve dependencies; use only local sources.
    #[arg(long)]
    pub offline: bool,

    /// Require a compatible Cargo.lock and use only locally available sources.
    #[arg(long)]
    pub frozen: bool,

    /// Select target triple; outputs go under target/<triple>
    #[arg(long)]
    pub target: Option<String>,

    /// Build a named example target (repeatable; output under target/<profile>/examples)
    #[arg(long = "example", action = clap::ArgAction::Append)]
    pub example: Vec<String>,

    /// Suppress Mitts progress and success summaries; keep errors and program output
    #[arg(short, long)]
    pub quiet: bool,

    /// Override library crate types (for example, staticlib; use with --lib)
    #[arg(long = "crate-type", action = clap::ArgAction::Append)]
    pub crate_types: Vec<String>,

    /// Keep the fast build lock active with an explicit cache directory (API only)
    #[arg(skip)]
    pub fast_lock: Option<bool>,

    /// Force native rustc DAG compilation (zero intermediate target bloat)
    #[arg(long)]
    pub native: bool,

    /// Force fallback to Cargo execution engine
    #[arg(long)]
    pub cargo: bool,

    /// Use verbose output (-v, -vv for very verbose)
    #[arg(short, long, action = clap::ArgAction::Count)]
    pub verbose: u8,

    /// Override a configuration value (not yet supported)
    #[arg(long, action = clap::ArgAction::Append)]
    pub config: Vec<String>,

    /// Exclude packages from being built
    #[arg(long, value_name = "SPEC", action = clap::ArgAction::Append)]
    pub exclude: Vec<String>,

    /// Build the named binary target (repeatable; combines with other target selectors)
    #[arg(long = "bin", action = clap::ArgAction::Append)]
    pub bin: Vec<String>,

    /// Build all binary targets
    #[arg(long)]
    pub bins: bool,

    /// Build only this package's library
    #[arg(long)]
    pub lib: bool,

    /// Additional arguments passed to the underlying builder
    #[arg(last = true)]
    pub extra_args: Vec<String>,
}

#[derive(Args, Debug, Clone, Default)]
pub struct RunArgs {
    #[command(flatten)]
    pub build_args: BuildArgs,

    /// Arguments for the binary
    #[arg(skip)]
    pub trailing_args: Vec<String>,
}

#[derive(Args, Debug, Clone, Default)]
pub struct ExplainArgs {
    /// Path to Cargo.toml
    #[arg(long)]
    pub manifest_path: Option<PathBuf>,

    /// Package to explain
    #[arg(skip)]
    pub package: Option<String>,
    /// Packages to explain (repeat for multiple packages)
    #[arg(short = 'p', long = "package", action = clap::ArgAction::Append)]
    pub packages: Vec<String>,

    /// Check release mode profile
    #[arg(short, long)]
    pub release: bool,

    /// Space or comma separated list of features to activate
    #[arg(short = 'F', long, value_delimiter = ',', num_args = 1..)]
    pub features: Vec<String>,

    /// Do not activate the `default` feature
    #[arg(long)]
    pub no_default_features: bool,

    /// Activate all available features
    #[arg(long)]
    pub all_features: bool,

    /// Directory for the shared artifact and action cache
    #[arg(long)]
    pub cache_dir: Option<PathBuf>,

    /// Output explanation in JSON format
    #[arg(long)]
    pub json: bool,

    /// Write derived compilation unit ActionKeys (JSON) to a file
    #[arg(long, value_name = "FILE")]
    pub keys: Option<PathBuf>,
}

#[derive(Args, Debug, Clone, Default)]
pub struct MetadataArgs {
    /// Path to Cargo.toml
    #[arg(long)]
    pub manifest_path: Option<PathBuf>,

    /// Package whose dependency graph should be selected
    #[arg(short, long)]
    pub package: Option<String>,

    /// Space or comma separated list of features to activate
    #[arg(short = 'F', long, value_delimiter = ',', num_args = 1..)]
    pub features: Vec<String>,

    /// Do not activate the `default` feature
    #[arg(long)]
    pub no_default_features: bool,

    /// Activate all available features
    #[arg(long)]
    pub all_features: bool,

    /// Filter dependencies for a target triple
    #[arg(long)]
    pub filter_platform: Option<String>,

    /// Require an existing compatible Cargo.lock
    #[arg(long)]
    pub locked: bool,

    /// Resolve using local index and source data only
    #[arg(long)]
    pub offline: bool,

    /// Combine locked and offline resolution
    #[arg(long)]
    pub frozen: bool,

    /// Metadata JSON format version
    #[arg(long, default_value_t = 1)]
    pub format_version: u32,

    /// Directory for the shared artifact and source cache
    #[arg(long)]
    pub cache_dir: Option<PathBuf>,
}

#[derive(Args, Debug, Clone, Default)]
pub struct FetchArgs {
    /// Path to Cargo.toml
    #[arg(long)]
    pub manifest_path: Option<PathBuf>,

    /// Directory for the global source store
    #[arg(long)]
    pub cache_dir: Option<PathBuf>,

    /// Run in offline mode without network access
    #[arg(long)]
    pub offline: bool,

    /// Require Cargo.lock and cache to be up to date
    #[arg(long)]
    pub locked: bool,

    /// Require Cargo.lock to be unchanged
    #[arg(long)]
    pub frozen: bool,
}

#[derive(Args, Debug, Clone, Default)]
pub struct GcArgs {
    /// Directory for the shared artifact and action cache
    #[arg(long)]
    pub cache_dir: Option<PathBuf>,

    /// Maximum cache size in bytes (pruning oldest until under quota)
    #[arg(long)]
    pub max_bytes: Option<u64>,

    /// Prune CAS objects older than specified seconds
    #[arg(long)]
    pub max_age_secs: Option<u64>,
}

pub mod bench;
pub mod build;
pub mod check;
pub mod clippy;
pub mod coverage;
pub mod coverage_tools;
pub mod coverage_types;
pub mod diagnostic;
pub mod fmt;
pub mod handlers;
pub mod message_format;
pub mod metadata;
mod package;
mod package_archive;
mod package_directory;
mod package_lock;
mod package_patterns;
mod registry_metadata;
mod registry_protocol;
mod registry_upload;
pub mod run;
pub mod rustc;
pub mod terminal;
pub mod test;
pub mod test_doctest;
pub mod test_parallel;
mod test_progress;
pub mod test_runner;
pub mod ui;

pub use bench::{handle_bench, BenchArgs};
pub use build::handle_build;
pub use check::{handle_check, CheckArgs};
pub use clippy::{handle_clippy, ClippyArgs};
pub use coverage::{handle_coverage, CoverageArgs};
pub use diagnostic::render_compiler_diagnostics;
pub use fmt::{handle_fmt, FmtArgs};
pub use handlers::{handle_clean, handle_explain, handle_fetch, handle_gc};
pub use metadata::handle_metadata;
pub use package::{handle_package, handle_publish, PackageArgs, PublishArgs};
pub use run::handle_run;
pub use rustc::handle_rustc;
pub use terminal::TerminalGuard;
pub use test::{handle_test, TestArgs};
pub use ui::Ui;