#[path = "cargo_ktstr/affected/mod.rs"]
mod affected;
#[path = "cargo_ktstr/cli.rs"]
mod cli;
#[path = "cargo_ktstr/interrupt.rs"]
mod interrupt;
#[path = "cargo_ktstr/kernel/mod.rs"]
mod kernel;
#[path = "cargo_ktstr/misc/mod.rs"]
mod misc;
#[path = "cargo_ktstr/perf_delta.rs"]
mod perf_delta;
#[path = "cargo_ktstr/replay.rs"]
mod replay;
#[path = "cargo_ktstr/run_cargo.rs"]
mod run_cargo;
#[path = "cargo_ktstr/stats.rs"]
mod stats;
#[path = "cargo_ktstr/verifier.rs"]
mod verifier;
#[path = "cargo_ktstr/btf_catalog.rs"]
mod btf_catalog;
#[path = "cargo_ktstr/blobs.rs"]
mod blobs;
#[path = "cargo_ktstr/argsplit.rs"]
mod argsplit;
#[cfg(test)]
#[path = "cargo_ktstr/parse_tests.rs"]
mod parse_tests;
use clap::{CommandFactory, Parser};
use ktstr::cli::KernelCommand;
use crate::cli::{Cargo, CargoSub, KtstrCommand};
fn main() {
ktstr::cli::restore_sigpipe_default();
if let Err(e) = blobs::install_env() {
eprintln!("error: extract embedded blobs: {e}");
std::process::exit(1);
}
run_cargo::install_runs_root_env();
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")),
)
.with_writer(std::io::stderr)
.init();
let raw: Vec<std::ffi::OsString> = std::env::args_os().collect();
let rewritten = argsplit::rewrite(&Cargo::command(), &raw);
let Cargo {
command: CargoSub::Ktstr(ktstr),
} = match Cargo::try_parse_from(&rewritten) {
Ok(c) => c,
Err(e) => e.exit(),
};
let result = dispatch_command(ktstr.command);
if let Err(e) = result {
eprintln!("error: {e:#}");
std::process::exit(1);
}
}
fn dispatch_command(command: KtstrCommand) -> Result<(), String> {
dispatch_run_command(command)
}
fn dispatch_run_command(command: KtstrCommand) -> Result<(), String> {
match command {
KtstrCommand::Test {
kernel,
no_perf_mode,
no_skip_mode,
release,
profile,
nextest_profile,
include_eol,
relevant,
base,
base_ref,
default_branch,
args,
} => run_cargo::run_test(
kernel,
no_perf_mode,
no_skip_mode,
release,
profile,
nextest_profile,
include_eol,
relevant,
base,
base_ref,
default_branch,
args,
),
KtstrCommand::Coverage {
kernel,
no_perf_mode,
no_skip_mode,
release,
profile,
nextest_profile,
include_eol,
relevant,
base,
base_ref,
default_branch,
args,
} => run_cargo::run_coverage(
kernel,
no_perf_mode,
no_skip_mode,
release,
profile,
nextest_profile,
include_eol,
relevant,
base,
base_ref,
default_branch,
args,
),
KtstrCommand::LlvmCov {
kernel,
no_perf_mode,
no_skip_mode,
include_eol,
args,
} => run_cargo::run_llvm_cov(kernel, no_perf_mode, no_skip_mode, include_eol, args),
KtstrCommand::Stats { ref command } => stats::run_stats(command),
KtstrCommand::Replay {
dir,
filter,
exec,
profile,
nextest_profile,
args,
} => match replay::run_replay(
dir.as_deref(),
filter.as_deref(),
exec,
profile.as_deref(),
nextest_profile.as_deref(),
&args,
) {
Ok(0) => Ok(()),
Ok(code) => std::process::exit(code),
Err(e) => Err(format!("{e:#}")),
},
KtstrCommand::PerfDelta {
base,
base_ref,
filter,
relevant,
default_branch,
kernel,
threshold,
policy,
noise_adjust,
noise_spread_threshold,
no_phases,
phases_only,
steps_only,
phase,
phase_threshold,
profile,
nextest_profile,
all_metrics,
fail_threshold,
must_fail,
args: passthrough,
} => {
let args = perf_delta::PerfDeltaArgs {
passthrough: &passthrough,
base: base.as_deref(),
base_ref: base_ref.as_deref(),
filter: filter.as_deref(),
relevant,
default_branch: &default_branch,
kernel: kernel.as_deref(),
threshold,
policy: policy.as_deref(),
noise_adjust,
noise_spread_threshold,
profile: profile.as_deref(),
nextest_profile: nextest_profile.as_deref(),
all_metrics,
fail_threshold,
must_fail: must_fail.as_deref(),
phase_display: ktstr::cli::PhaseDisplayOptions {
no_phases,
phases_only,
steps_only,
phase,
phase_threshold,
},
};
match perf_delta::run(&args) {
Ok(0) => Ok(()),
Ok(code) => std::process::exit(code),
Err(e) => Err(format!("{e:#}")),
}
}
cmd @ (KtstrCommand::Kernel { .. }
| KtstrCommand::Verifier { .. }
| KtstrCommand::Completions { .. }
| KtstrCommand::ShowHost
| KtstrCommand::ShowThresholds { .. }
| KtstrCommand::Affected { .. }
| KtstrCommand::Export { .. }
| KtstrCommand::Locks { .. }
| KtstrCommand::Shell { .. }) => dispatch_admin_command(cmd),
}
}
fn dispatch_admin_command(command: KtstrCommand) -> Result<(), String> {
match command {
KtstrCommand::Kernel { command } => match command {
KernelCommand::List {
json,
kernel,
include_eol,
} => match kernel {
Some(k) => ktstr::cli::kernel_list_range_preview(json, &k, include_eol)
.map_err(|e| format!("{e:#}")),
None => ktstr::cli::kernel_list(json).map_err(|e| format!("{e:#}")),
},
KernelCommand::Build {
kernel,
force,
clean,
cpu_cap,
extra_kconfig,
skip_sha256,
include_eol,
} => kernel::kernel_build(
kernel,
force,
clean,
cpu_cap,
extra_kconfig,
skip_sha256,
include_eol,
),
KernelCommand::Clean {
keep,
force,
corrupt_only,
} => ktstr::cli::kernel_clean(keep, force, corrupt_only).map_err(|e| format!("{e:#}")),
},
KtstrCommand::Verifier {
kernel,
raw,
profile,
nextest_profile,
scheduler,
include_eol,
args,
} => verifier::run_verifier(
kernel,
raw,
profile,
nextest_profile,
scheduler,
include_eol,
args,
),
KtstrCommand::Completions { shell, binary } => {
misc::run_completions(shell, &binary);
Ok(())
}
KtstrCommand::Affected {
base,
base_ref,
default_branch,
} => affected::run(base.as_deref(), base_ref.as_deref(), &default_branch)
.map_err(|e| format!("{e:#}")),
KtstrCommand::ShowHost => {
print!("{}", ktstr::cli::show_host());
Ok(())
}
KtstrCommand::ShowThresholds { test } => match ktstr::cli::show_thresholds(&test) {
Ok(s) => {
print!("{s}");
Ok(())
}
Err(e) => Err(format!("{e:#}")),
},
KtstrCommand::Export {
test,
output,
package,
release,
} => misc::run_export(test, output, package, release),
KtstrCommand::Locks { json, watch } => {
ktstr::cli::list_locks(json, watch).map_err(|e| format!("{e:#}"))
}
KtstrCommand::Shell {
kernel,
test,
topology,
include_files,
memory_mib,
dmesg,
exec,
exec_timeout,
no_perf_mode,
cpu_cap,
disk,
} => match misc::run_shell(
kernel,
test,
topology,
include_files,
memory_mib,
dmesg,
exec,
exec_timeout,
no_perf_mode,
cpu_cap,
disk,
) {
Ok(opt) => std::process::exit(opt.unwrap_or(0)),
Err(e) => Err(e),
},
KtstrCommand::Test { .. }
| KtstrCommand::Coverage { .. }
| KtstrCommand::LlvmCov { .. }
| KtstrCommand::Stats { .. }
| KtstrCommand::Replay { .. }
| KtstrCommand::PerfDelta { .. } => unreachable!(
"run-group variants are handled by dispatch_run_command and never forwarded here"
),
}
}