212 lines
6.6 KiB
Rust
212 lines
6.6 KiB
Rust
#![warn(clippy::all, clippy::pedantic)]
|
|
|
|
mod cli;
|
|
use {
|
|
clap::ArgMatches,
|
|
cli::cli,
|
|
hpk::{CreationError, Creator, Dependency, InstallMessage, Installer, Message, Specs, Version},
|
|
indicatif::{ProgressBar, ProgressStyle},
|
|
ron::ser::{to_writer_pretty, PrettyConfig},
|
|
std::{
|
|
env,
|
|
error::Error,
|
|
ffi::OsStr,
|
|
fmt,
|
|
fs::File,
|
|
io::{self, BufWriter, ErrorKind},
|
|
path::PathBuf,
|
|
sync::mpsc,
|
|
thread,
|
|
},
|
|
};
|
|
|
|
static TEMPLATE: &str = "[ {prefix} ] {wide_bar}{pos:>5.cyan}/{len:5.green}{msg:>30}";
|
|
|
|
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());
|
|
if matches.get_flag("edit") {
|
|
cli::edit(specsfile.to_str().unwrap())?;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
let creator = Creator::new(&dir, specs.clone())?;
|
|
let (sender, receiver) = mpsc::channel();
|
|
let len = creator.len();
|
|
let pb = ProgressBar::new(len as u64);
|
|
pb.set_style(ProgressStyle::with_template(TEMPLATE).unwrap());
|
|
pb.set_prefix("Adding files");
|
|
pb.println(format!(
|
|
"Creating package {}-{}_{}.tar.zst",
|
|
&specs.name, &specs.version, &specs.release
|
|
));
|
|
let handle = thread::spawn(move || {
|
|
for msg in receiver.iter() {
|
|
match msg {
|
|
Message::MemberAdded(s) => {
|
|
pb.set_message(s.split('/').last().unwrap().to_string());
|
|
pb.inc(1);
|
|
}
|
|
Message::Success(_s) => {
|
|
pb.inc(1);
|
|
pb.finish_and_clear();
|
|
}
|
|
}
|
|
}
|
|
Ok::<(), CreationError>(())
|
|
});
|
|
creator.create(&outdir, sender)?;
|
|
match handle.join() {
|
|
Ok(_) => {
|
|
println!("Package created successfully");
|
|
Ok(())
|
|
}
|
|
Err(e) => Err(io::Error::new(ErrorKind::Other, format!("{e:?}")).into()),
|
|
}
|
|
}
|
|
|
|
fn install_local<P: AsRef<OsStr> + fmt::Display>(
|
|
archive: P,
|
|
root: P,
|
|
) -> Result<(), Box<dyn Error>> {
|
|
let (sender, receiver) = mpsc::channel();
|
|
let pb = ProgressBar::new(0);
|
|
pb.set_style(ProgressStyle::with_template(TEMPLATE).unwrap());
|
|
pb.println(format!("Installing package {}", archive,));
|
|
let installer = Installer::new_for_file(root, archive)?;
|
|
let handle = thread::spawn(move || {
|
|
for msg in receiver.iter() {
|
|
match msg {
|
|
InstallMessage::ArchiveLen(len) => pb.set_length(len.try_into().unwrap()),
|
|
InstallMessage::LinkCreated(link) => {
|
|
pb.inc(1);
|
|
}
|
|
InstallMessage::DirectoryCreated(dir) => {
|
|
pb.inc(1);
|
|
}
|
|
InstallMessage::FileInstalled(file) => {
|
|
pb.inc(1);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
});
|
|
installer.install(sender)?;
|
|
match handle.join() {
|
|
Ok(hooks) => {
|
|
println!("hooks: {hooks:?}");
|
|
Ok(())
|
|
}
|
|
Err(_) => Err(io::Error::new(ErrorKind::Other, "Unknown thread error").into()),
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|