use cargo::core::Workspace;
use cargo::Config;
use cargo_cyclonedx::generator::SbomGenerator;
use std::{
io::{self},
path::PathBuf,
};
use anyhow::Result;
use clap::Parser;
use env_logger::Builder;
use log::LevelFilter;
#[deny(clippy::all)]
#[deny(warnings)]
mod cli;
use cli::{Args, Opts};
fn main() -> anyhow::Result<()> {
let Opts::Bom(args) = Opts::parse();
let mut config = Config::default()?;
setup_logging(&args, &mut config)?;
let manifest_path = locate_manifest(&args)?;
let cli_config = args.as_config()?;
let ws = Workspace::new(&manifest_path, &config)?;
log::trace!("SBOM generation started");
let boms = SbomGenerator::create_sboms(ws, &cli_config)?;
log::trace!("SBOM generation finished");
log::trace!("SBOM output started");
for bom in boms {
bom.write_to_file()?;
}
log::trace!("SBOM output finished");
Ok(())
}
fn setup_logging(args: &Args, config: &mut Config) -> anyhow::Result<()> {
let mut builder = Builder::new();
builder.filter_module("cargo::", LevelFilter::Error);
let level_filter = if args.quiet {
LevelFilter::Off
} else {
match args.verbose {
0 => LevelFilter::Error,
1 => LevelFilter::Info,
2 => LevelFilter::Debug,
_ => LevelFilter::Trace,
}
};
builder.filter_level(level_filter);
builder.parse_default_env(); builder.try_init()?;
config.configure(
args.verbose,
args.quiet,
None,
false,
false,
false,
&None,
&[],
&[],
)?;
Ok(())
}
fn locate_manifest(args: &Args) -> Result<PathBuf, io::Error> {
if let Some(manifest_path) = &args.manifest_path {
let manifest_path = manifest_path.canonicalize()?;
log::info!(
"Using manually specified Cargo.toml manifest located at: {}",
manifest_path.to_string_lossy()
);
Ok(manifest_path)
} else {
let manifest_path = std::env::current_dir()?.join("Cargo.toml");
log::info!(
"Using Cargo.toml manifest located at: {}",
manifest_path.to_string_lossy()
);
Ok(manifest_path)
}
}