use super::{
create::{BundleCreateCommand, BundleFormat},
pack::bundlev1::BundleV1,
select::{picker::FilePicker, spec::BundleSpec},
};
use anyhow::{Context, Result};
use std::{
cmp::Ordering,
fs::{self, File},
io::Read,
thread,
time::Duration,
};
use tracing::{error, info, warn};
pub(super) fn select(cli: &BundleCreateCommand) -> Result<()> {
let bundle_dir = cli
.bundle_spec
.canonicalize()
.unwrap()
.parent()
.unwrap()
.to_path_buf();
let mut file = File::open(&cli.bundle_spec)?;
let mut file_str = String::new();
file.read_to_string(&mut file_str)?;
let bundle_config: BundleSpec = match toml::from_str(&file_str) {
Ok(x) => x,
Err(e) => {
error!("failed to load bundle specification",);
return Err(e.into());
}
};
if let Err(e) = bundle_config.validate() {
error!("failed to validate bundle specification");
return Err(e);
};
let build_dir = cli.build_dir.join(&bundle_config.bundle.name);
if build_dir.exists() {
warn!("build dir {} aleady exists", build_dir.to_str().unwrap());
for i in (1..=5).rev() {
warn!(
"recursively removing {} in {i} second{}",
build_dir.to_str().unwrap(),
if i != 1 { "s" } else { "" }
);
thread::sleep(Duration::from_secs(1));
}
thread::sleep(Duration::from_secs(2));
fs::remove_dir_all(&build_dir)?;
}
fs::create_dir_all(&build_dir).context("while creating build dir")?;
let mut picker = FilePicker::new(bundle_config.clone(), build_dir.clone(), bundle_dir.clone())?;
let sources: Vec<String> = picker.iter_sources().map(|x| x.to_string()).collect();
for source in sources {
picker.add_source(cli, &source)?;
}
picker.finish(true)?;
info!("summary is below:\n{}", picker.stats.make_string());
match picker.stats.compare_patch_found_applied() {
Ordering::Equal => {}
Ordering::Greater => {
warn!("some patches were not applied");
}
Ordering::Less => {
warn!("some patches applied multiple times");
}
}
{
let mut file = File::open(build_dir.join("content/SHA256SUM"))?;
let mut hash = String::new();
file.read_to_string(&mut hash)?;
let hash = hash.trim();
if hash != bundle_config.bundle.expected_hash {
warn!("final bundle hash doesn't match bundle configuration:");
warn!("bundle hash is {hash}");
warn!("config hash is {}", bundle_config.bundle.expected_hash);
} else {
info!("final bundle hash matches configuration");
info!("hash is {hash}");
}
}
Ok(())
}
pub(super) fn pack(cli: &BundleCreateCommand) -> Result<()> {
let mut file = File::open(&cli.bundle_spec)?;
let mut file_str = String::new();
file.read_to_string(&mut file_str)?;
let bundle_config: BundleSpec = toml::from_str(&file_str)?;
let build_dir = cli.build_dir.join(&bundle_config.bundle.name);
if !build_dir.join("content").is_dir() {
error!(
"content directory `{}/content` doesn't exist, can't continue",
build_dir.to_str().unwrap()
);
return Ok(());
}
let target_name = format!("{}.ttb", &bundle_config.bundle.name);
let target = build_dir.join(&target_name);
if target.exists() {
if target.is_file() {
warn!("target bundle `{target_name}` exists, removing");
fs::remove_file(&target)?;
} else {
error!("target bundle `{target_name}` exists and isn't a file, can't continue");
return Ok(());
}
}
match cli.format {
BundleFormat::BundleV1 => {
BundleV1::make(Box::new(File::create(target)?), build_dir.clone())?
}
}
Ok(())
}