use crate::{Config, SOLARCONFIGNAME, SolarError, ToolTrait};
use clap::Parser;
use derive_getters::Getters;
use rust_terminal::Terminal;
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
fs::{self, File},
io::Write,
path::{Path, PathBuf},
};
use toml::{Value, map::Map};
static TOML_NAME: &str = "deny.toml";
#[derive(Parser, Clone, Default, PartialEq, Debug, Serialize, Deserialize, Getters)]
pub struct CargoDeny {
#[arg(short, long, default_value = ".")]
#[serde(skip)]
destination: PathBuf,
#[arg(short, long, num_args = 0..)]
allow_licenses: Option<Vec<String>>,
}
impl CargoDeny {
pub fn new(destination: PathBuf, allow_licenses: Option<Vec<String>>) -> Self {
Self {
destination,
allow_licenses,
}
}
fn ensure_tool_installed(&self) -> Result<(), SolarError> {
let output = Terminal::command()
.current_dir(&self.destination)
.run("cargo", ["install", "--list"])?;
if !String::from_utf8(output.stdout)?.contains("cargo-deny") {
Terminal::command()
.current_dir(&self.destination)
.piped()
.run("cargo", ["install", "cargo-deny"])?;
}
Ok(())
}
fn generate_toml(&self) -> Result<String, SolarError> {
let allowed_licenses = self
.allow_licenses
.as_ref()
.ok_or("No allowed licenses were specified.")?;
let mut toml_config: Map<String, Value> = Map::new();
let mut allow_list = HashMap::new();
allow_list.insert("allow", allowed_licenses.clone());
let licenses_section = Value::from(allow_list);
toml_config.insert("licenses".to_string(), licenses_section);
Ok(toml::to_string_pretty(&toml_config)?)
}
}
impl ToolTrait for CargoDeny {
fn set_dest(&mut self, dest: &Path) {
self.destination = dest.to_path_buf();
}
fn install(&mut self) -> Result<(), SolarError> {
if fs::exists(self.destination.join(TOML_NAME))? {
return Err(SolarError::from(
"Current installation found. Use cargo-deny to make changes to the current installation. Only use cargo-solar to uninstall completely.",
));
}
let config = Config::new_empty(&self.destination.join(SOLARCONFIGNAME));
self.ensure_tool_installed()?;
let toml_contents = &self.generate_toml()?.into_bytes();
let mut deny_config = File::create(self.destination.join(TOML_NAME))?;
deny_config.write_all(toml_contents)?;
config.set_cargo_deny(Some(self.clone())).save()?;
Ok(())
}
fn uninstall(&mut self) -> Result<(), SolarError> {
let config = Config::load_from(&self.destination)?;
config
.cargo_deny()
.as_ref()
.ok_or("No cargo_deny configuration inside config file.")?;
fs::remove_file(self.destination.join("deny.toml"))?;
let config = config.set_cargo_deny(None);
match config.is_empty() {
true => fs::remove_file(config.path())?,
false => config.save()?,
}
Ok(())
}
}