use std::fs;
use std::path::PathBuf;
use anyhow::{bail, Context as AnyhowContext, Result};
use clap::Parser;
use crate::config::Config;
use crate::context::Context;
use crate::lockfile::{lock_context, write_lockfile};
use crate::metadata::{load_metadata, Annotations, Cargo};
use crate::rendering::{write_outputs, Renderer};
use crate::splicing::SplicingManifest;
#[derive(Parser, Debug)]
#[clap(about = "Command line options for the `generate` subcommand", version)]
pub struct GenerateOptions {
#[clap(long, env = "CARGO")]
pub cargo: Option<PathBuf>,
#[clap(long, env = "RUSTC")]
pub rustc: Option<PathBuf>,
#[clap(long)]
pub config: PathBuf,
#[clap(long)]
pub splicing_manifest: PathBuf,
#[clap(long)]
pub lockfile: Option<PathBuf>,
#[clap(long)]
pub cargo_lockfile: PathBuf,
#[clap(long)]
pub repository_dir: PathBuf,
#[clap(long)]
pub cargo_config: Option<PathBuf>,
#[clap(long)]
pub repin: bool,
#[clap(long)]
pub metadata: Option<PathBuf>,
#[clap(long)]
pub dry_run: bool,
}
pub fn generate(opt: GenerateOptions) -> Result<()> {
let config = Config::try_from_path(&opt.config)?;
if !opt.repin {
if let Some(lockfile) = &opt.lockfile {
let context = Context::try_from_path(lockfile)?;
let outputs = Renderer::new(
config.rendering,
config.supported_platform_triples,
config.generate_target_compatible_with,
)
.render(&context)?;
write_outputs(outputs, &opt.repository_dir, opt.dry_run)?;
return Ok(());
}
}
let cargo_bin = Cargo::new(match opt.cargo {
Some(bin) => bin,
None => bail!("The `--cargo` argument is required when generating unpinned content"),
});
let rustc_bin = match &opt.rustc {
Some(bin) => bin,
None => bail!("The `--rustc` argument is required when generating unpinned content"),
};
let metadata_path = match &opt.metadata {
Some(path) => path,
None => bail!("The `--metadata` argument is required when generating unpinned content"),
};
let (cargo_metadata, cargo_lockfile) = load_metadata(metadata_path)?;
let annotations = Annotations::new(cargo_metadata, cargo_lockfile.clone(), config.clone())?;
let context = Context::new(annotations)?;
let outputs = Renderer::new(
config.rendering.clone(),
config.supported_platform_triples.clone(),
config.generate_target_compatible_with,
)
.render(&context)?;
write_outputs(outputs, &opt.repository_dir, opt.dry_run)?;
if let Some(lockfile) = opt.lockfile {
let splicing_manifest = SplicingManifest::try_from_path(&opt.splicing_manifest)?;
let lock_content =
lock_context(context, &config, &splicing_manifest, &cargo_bin, rustc_bin)?;
write_lockfile(lock_content, &lockfile, opt.dry_run)?;
}
fs::write(&opt.cargo_lockfile, cargo_lockfile.to_string())
.context("Failed to write Cargo.lock file back to the workspace.")?;
Ok(())
}