use std::path::PathBuf;
use cargo_pgo::bolt::instrument::{BoltInstrumentArgs, bolt_instrument};
use cargo_pgo::bolt::optimize::{BoltOptimizeArgs, bolt_optimize};
use cargo_pgo::build::CargoCommand;
use cargo_pgo::check::environment_info;
use cargo_pgo::clean::clean_artifacts;
use cargo_pgo::get_cargo_ctx;
use cargo_pgo::pgo::instrument::{PgoInstrumentArgs, PgoInstrumentShortcutArgs, pgo_instrument};
use cargo_pgo::pgo::optimize::{PgoOptimizeArgs, pgo_optimize};
use clap::Parser;
use env_logger::Env;
#[derive(clap::Parser, Debug)]
#[clap(author, version, about)]
#[clap(bin_name("cargo"))]
#[clap(disable_help_subcommand(true))]
enum Args {
#[clap(subcommand)]
#[clap(author, version, about)]
Pgo(Subcommand),
}
#[derive(clap::Subcommand, Debug)]
enum Subcommand {
Info,
Instrument(PgoInstrumentArgs),
Build(PgoInstrumentShortcutArgs),
Test(PgoInstrumentShortcutArgs),
Run(PgoInstrumentShortcutArgs),
Bench(PgoInstrumentShortcutArgs),
Optimize(PgoOptimizeArgs),
#[clap(subcommand)]
Bolt(BoltArgs),
Clean(CleanArgs),
}
#[derive(clap::Subcommand, Debug)]
enum BoltArgs {
Build(BoltInstrumentArgs),
Optimize(BoltOptimizeArgs),
}
impl BoltArgs {
fn cargo_args(&self) -> &[String] {
match self {
BoltArgs::Build(args) => args.cargo_args(),
BoltArgs::Optimize(args) => args.cargo_args(),
}
}
}
#[derive(clap::Parser, Debug)]
struct CleanArgs {
#[clap(long)]
profiles_dir: Option<PathBuf>,
}
impl Args {
fn cargo_args(&self) -> &[String] {
match self {
Args::Pgo(args) => match args {
Subcommand::Info => &[],
Subcommand::Instrument(args) => args.cargo_args(),
Subcommand::Build(args)
| Subcommand::Run(args)
| Subcommand::Test(args)
| Subcommand::Bench(args) => args.cargo_args(),
Subcommand::Optimize(args) => args.cargo_args(),
Subcommand::Bolt(args) => args.cargo_args(),
Subcommand::Clean(..) => &[],
},
}
}
fn profiles_dir(&self) -> Option<PathBuf> {
match self {
Args::Pgo(args) => match args {
Subcommand::Info => None,
Subcommand::Instrument(args) => args.profiles_dir().to_owned(),
Subcommand::Build(args)
| Subcommand::Run(args)
| Subcommand::Test(args)
| Subcommand::Bench(args) => args.profiles_dir().to_owned(),
Subcommand::Optimize(args) => args.profiles_dir().to_owned(),
Subcommand::Bolt(..) => None,
Subcommand::Clean(CleanArgs { profiles_dir }) => profiles_dir.to_owned(),
},
}
}
}
fn run() -> anyhow::Result<()> {
let args = Args::parse();
let cargo_args = args.cargo_args();
let profiles_dir = args.profiles_dir();
let ctx = get_cargo_ctx(cargo_args, profiles_dir)?;
let Args::Pgo(args) = args;
match args {
Subcommand::Info => environment_info(),
Subcommand::Instrument(args) => pgo_instrument(ctx, args),
Subcommand::Build(args) => pgo_instrument(ctx, args.into_full_args(CargoCommand::Build)),
Subcommand::Test(args) => pgo_instrument(ctx, args.into_full_args(CargoCommand::Test)),
Subcommand::Run(args) => pgo_instrument(ctx, args.into_full_args(CargoCommand::Run)),
Subcommand::Bench(args) => pgo_instrument(ctx, args.into_full_args(CargoCommand::Bench)),
Subcommand::Optimize(args) => pgo_optimize(ctx, args),
Subcommand::Bolt(BoltArgs::Build(args)) => bolt_instrument(ctx, args),
Subcommand::Bolt(BoltArgs::Optimize(args)) => bolt_optimize(ctx, args),
Subcommand::Clean(..) => clean_artifacts(ctx),
}
}
fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("cargo_pgo=info")).init();
if let Err(error) = run() {
eprintln!("{}", format!("{error:?}").trim_end_matches('\n'));
std::process::exit(1);
}
}