Skip to main content

crap4rust/invocation/
entry_point.rs

1// Copyright 2026 Umberto Gotti <umberto.gotti@umbertogotti.dev>
2// Licensed under the MIT License
3// SPDX-License-Identifier: MIT
4
5use crate::invocation::app::run_from_args;
6use std::process::ExitCode;
7
8// Everything `main` used to do, moved somewhere a test can reach it.
9//
10// A binary entry point is not reachable from an integration test, so logic
11// living in `main.rs` is logic nothing can check. What was sitting there is not
12// glue: it is the argv fixup every cargo subcommand needs, and it has two
13// properties that are easy to get wrong and impossible to notice.
14//
15// Cargo runs `cargo crap4rust ...` as `cargo-crap4rust crap4rust ...`, so the
16// name arrives twice. Running the binary directly does not repeat it, which is
17// why the strip is **conditional**. And it is **positional** -- only argv[1] is
18// dropped -- because removing every occurrence would swallow
19// `--package crap4rust`.
20pub struct EntryPoint;
21
22impl EntryPoint {
23    pub const SUBCOMMAND: &'static str = "crap4rust";
24
25    // Conditional and positional: only a repeated name in argv[1] goes.
26    pub fn without_cargo_subcommand(args: Vec<String>) -> Vec<String> {
27        if args.get(1).map(String::as_str) != Some(Self::SUBCOMMAND) {
28            return args;
29        }
30        let mut forwarded = Vec::with_capacity(args.len().saturating_sub(1));
31        let mut rest = args.into_iter();
32        if let Some(binary) = rest.next() {
33            forwarded.push(binary);
34        }
35        forwarded.extend(rest.skip(1));
36        forwarded
37    }
38
39    // An error is exit 2, the same code a broken rule uses, because a run that
40    // could not finish must never read as a clean project.
41    pub fn run(args: Vec<String>) -> ExitCode {
42        match run_from_args(Self::without_cargo_subcommand(args)) {
43            Ok(code) => code,
44            Err(error) => {
45                println!("error: {error:#}");
46                ExitCode::from(2)
47            }
48        }
49    }
50}