hpk/src/hpk.rs

174 lines
5.4 KiB
Rust
Raw Normal View History

2023-03-28 21:18:55 -04:00
#![warn(clippy::all, clippy::pedantic)]
2023-03-28 17:12:41 -04:00
use {
clap::ArgMatches,
hpk::{Creator, Dependency, Message, Specs, Version},
2023-03-28 19:28:37 -04:00
hpk_cli::cli,
2023-03-28 21:18:55 -04:00
indicatif::{ProgressBar, ProgressStyle},
2023-03-28 17:12:41 -04:00
ron::ser::{to_writer_pretty, PrettyConfig},
std::{
env,
error::Error,
ffi::OsStr,
fs::File,
2023-03-28 21:18:55 -04:00
io::{self, BufWriter, ErrorKind},
2023-03-28 17:12:41 -04:00
path::PathBuf,
2023-03-28 21:18:55 -04:00
sync::mpsc,
2023-03-28 19:28:37 -04:00
thread,
2023-03-28 17:12:41 -04:00
},
};
2023-03-28 21:27:40 -04:00
static TEMPLATE: &str = "[ {prefix} ] {wide_bar}{pos:>5.cyan}/{len:5.green}{msg:>30}";
2023-03-28 17:12:41 -04:00
fn main() -> Result<(), Box<dyn Error>> {
let matches = cli().get_matches();
match matches.subcommand() {
Some(("create", matches)) => create(matches)?,
Some(("init", matches)) => {
let specsfile = init(matches)?;
println!("Created specsfile {}", specsfile.display());
}
Some(("search", matches)) => search(matches)?,
Some(("install", matches)) => install(matches)?,
Some(("remove", matches)) => remove(matches)?,
Some(("upgrade", _)) => upgrade()?,
_ => {}
}
Ok(())
}
fn create(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
let dir = PathBuf::from(matches.get_one::<String>("directory").unwrap().to_string());
let outdir = if let Some(d) = matches.get_one::<String>("output") {
PathBuf::from(&d.to_string())
} else {
env::current_dir()?
};
let mut specs = if let Some(s) = matches.get_one::<String>("specs") {
let path = PathBuf::from(s.to_string());
let fd = File::open(path)?;
ron::de::from_reader(fd)?
} else {
Specs::default()
};
if let Some(n) = matches.get_one::<String>("name") {
specs.name = n.to_string();
}
if let Some(v) = matches.get_one::<String>("package-version") {
specs.version = v.to_string().parse::<Version>()?;
}
if let Some(r) = matches.get_one::<u8>("release") {
specs.release = *r;
}
if let Some(deps) = matches.get_many::<String>("dependencies") {
for d in deps {
let d = Dependency {
name: d.to_string(),
version: (None, None),
};
specs.dependencies.push(d);
}
}
2023-03-28 21:18:55 -04:00
let creator = Creator::new(&dir, specs.clone())?;
2023-03-28 17:12:41 -04:00
let (sender, receiver) = mpsc::channel();
2023-03-28 19:28:37 -04:00
let len = creator.len();
2023-03-28 21:18:55 -04:00
let pb = ProgressBar::new(len as u64);
2023-03-28 21:27:40 -04:00
pb.set_style(ProgressStyle::with_template(TEMPLATE).unwrap());
2023-03-28 21:18:55 -04:00
pb.set_prefix("Adding files");
pb.println(format!(
"Creating package {}-{}_{}.tar.zst",
&specs.name, &specs.version, &specs.release
));
2023-03-28 19:28:37 -04:00
let handle = thread::spawn(move || {
for msg in receiver.iter() {
match msg {
2023-03-28 21:18:55 -04:00
Message::MemberAdded(s) => {
pb.set_message(s.split('/').last().unwrap().to_string());
2023-03-28 19:28:37 -04:00
pb.inc(1);
2023-03-28 21:27:40 -04:00
}
2023-03-28 21:18:55 -04:00
Message::Success(_s) => {
pb.inc(1);
pb.finish_and_clear();
}
2023-03-28 19:28:37 -04:00
Message::Failure(s) => {
eprint!("{s}");
return Err(io::Error::new(io::ErrorKind::Other, s));
}
2023-03-28 17:12:41 -04:00
}
}
2023-03-28 19:28:37 -04:00
Ok(())
});
creator.create(&outdir, sender)?;
match handle.join() {
2023-03-28 21:18:55 -04:00
Ok(_) => {
println!("Package created successfully");
Ok(())
2023-03-28 21:27:40 -04:00
}
2023-03-28 19:28:37 -04:00
Err(e) => Err(io::Error::new(ErrorKind::Other, format!("{e:?}")).into()),
2023-03-28 17:12:41 -04:00
}
}
fn init(matches: &ArgMatches) -> Result<PathBuf, Box<dyn Error>> {
let specsfile = PathBuf::from("package.specs");
let cfg = PrettyConfig::new().struct_names(true);
let buf = File::create(&specsfile)?;
let writer = BufWriter::new(buf);
let specs = create_specs(matches)?;
to_writer_pretty(writer, &specs, cfg)?;
Ok(specsfile)
}
fn search(_matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
unimplemented!();
}
fn install(_matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
unimplemented!();
}
fn remove(_matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
unimplemented!();
}
fn upgrade() -> Result<(), Box<dyn Error>> {
unimplemented!();
}
#[allow(clippy::cast_possible_truncation)]
pub fn create_specs(matches: &ArgMatches) -> Result<Specs, Box<dyn Error>> {
let mut specs = Specs::default();
let mut name: Option<String> = None;
let mut version: Option<Version> = None;
let cwd = env::current_dir()?;
if let Some(dir) = cwd.file_name().and_then(OsStr::to_str) {
if let Some((n, v)) = dir.split_once('-') {
name = Some(n.to_string());
if let Ok(v) = v.parse() {
version = Some(v);
}
}
}
if let Some(name) = matches.get_one::<String>("name") {
specs.name = name.to_string();
} else if let Some(n) = name {
specs.name = n;
}
if let Some(version) = matches.get_one::<String>("package-version") {
specs.version = version.parse()?;
} else if let Some(v) = version {
specs.version = v;
}
if let Some(release) = matches.get_one::<usize>("release") {
specs.release = *release as u8;
}
if let Some(deps) = matches.get_many::<String>("dependencies") {
let deps = deps
.map(|d| Dependency {
name: d.to_string(),
version: (None, None),
})
.collect::<Vec<Dependency>>();
specs.dependencies = deps;
}
Ok(specs)
}