Split off from hpk
crate
This commit is contained in:
commit
e8aa73bf9d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
1820
Cargo.lock
generated
Normal file
1820
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
Cargo.toml
Normal file
29
Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
[package]
|
||||||
|
name = "hpk-cli"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "hpk"
|
||||||
|
path = "src/hpk.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "bootstrap"
|
||||||
|
path = "src/bootstrap.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "4.1"
|
||||||
|
hpk = { git = "https://git.hitchhiker-linux.org/jeang3nie/hpk.git" }
|
||||||
|
ron = "0.8"
|
||||||
|
|
||||||
|
[dependencies.package-bootstrap]
|
||||||
|
version = "0.1.0"
|
||||||
|
features = ["mangen"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
|
lto = true
|
||||||
|
strip = true
|
30
src/bootstrap.rs
Normal file
30
src/bootstrap.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use {
|
||||||
|
clap::{Arg, Command},
|
||||||
|
hpk_cli::cli,
|
||||||
|
package_bootstrap::Bootstrap,
|
||||||
|
std::{error::Error, path::PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let matches = Command::new("bootstrap")
|
||||||
|
.about("install the software")
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.args([
|
||||||
|
Arg::new("arch")
|
||||||
|
.help("the architecture of the binary to be installed")
|
||||||
|
.short('a')
|
||||||
|
.long("arch")
|
||||||
|
.num_args(1),
|
||||||
|
Arg::new("output")
|
||||||
|
.help("the output directory for the installation")
|
||||||
|
.required(true)
|
||||||
|
.num_args(1),
|
||||||
|
])
|
||||||
|
.get_matches();
|
||||||
|
let outdir = matches.get_one::<String>("output").unwrap().to_string();
|
||||||
|
let outdir = PathBuf::from(&outdir);
|
||||||
|
let arch = matches.get_one::<String>("arch").map(|x| x.to_string());
|
||||||
|
Bootstrap::new("hpk", cli()).install(&outdir, arch, 1)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
145
src/hpk.rs
Normal file
145
src/hpk.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
use {
|
||||||
|
clap::ArgMatches,
|
||||||
|
hpk_cli::cli,
|
||||||
|
hpk::{Creator, Dependency, Message, Specs, Version},
|
||||||
|
ron::ser::{to_writer_pretty, PrettyConfig},
|
||||||
|
std::{
|
||||||
|
env,
|
||||||
|
error::Error,
|
||||||
|
ffi::OsStr,
|
||||||
|
fs::File,
|
||||||
|
io::{self, BufWriter},
|
||||||
|
path::PathBuf,
|
||||||
|
sync::mpsc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let creator = Creator::new(&dir, specs)?;
|
||||||
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
creator.create(&outdir, sender)?;
|
||||||
|
for msg in receiver.iter() {
|
||||||
|
match msg {
|
||||||
|
Message::MemberAdded(_s) => {}
|
||||||
|
Message::Success(s) => println!("{s}"),
|
||||||
|
Message::Failure(s) => {
|
||||||
|
eprint!("{s}");
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, s).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
159
src/lib.rs
Normal file
159
src/lib.rs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
use clap::{value_parser, Arg, ArgAction, Command, ValueHint};
|
||||||
|
|
||||||
|
pub fn cli() -> Command {
|
||||||
|
Command::new("hpk")
|
||||||
|
.about("A package manager for HitchHiker Linux")
|
||||||
|
.author("Nathan Fisher")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
|
.propagate_version(true)
|
||||||
|
.arg_required_else_help(true)
|
||||||
|
.subcommands([
|
||||||
|
create(),
|
||||||
|
init(),
|
||||||
|
search(),
|
||||||
|
info(),
|
||||||
|
install(),
|
||||||
|
remove(),
|
||||||
|
upgrade(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create() -> Command {
|
||||||
|
Command::new("create")
|
||||||
|
.about("Create a new package from a directory of files")
|
||||||
|
.args([
|
||||||
|
Arg::new("directory")
|
||||||
|
.help("the directory where the files are located")
|
||||||
|
.required(true)
|
||||||
|
.num_args(1),
|
||||||
|
Arg::new("output")
|
||||||
|
.help("the location to save the package archive and package.ron [default: current working directory]")
|
||||||
|
.short('o')
|
||||||
|
.long("output")
|
||||||
|
.value_name("directory")
|
||||||
|
.value_hint(ValueHint::DirPath)
|
||||||
|
.num_args(1),
|
||||||
|
Arg::new("specs")
|
||||||
|
.help("path to the package specs file in `ron` format")
|
||||||
|
.short('s')
|
||||||
|
.long("specs")
|
||||||
|
.conflicts_with_all(["name", "package-version", "release", "dependencies"])
|
||||||
|
.num_args(1),
|
||||||
|
Arg::new("name")
|
||||||
|
.help("package name")
|
||||||
|
.short('n')
|
||||||
|
.long("name")
|
||||||
|
.num_args(1)
|
||||||
|
.required_unless_present("specs"),
|
||||||
|
Arg::new("package-version")
|
||||||
|
.help("package version")
|
||||||
|
.short('v')
|
||||||
|
.long("package-version")
|
||||||
|
.num_args(1)
|
||||||
|
.required_unless_present("specs"),
|
||||||
|
Arg::new("release")
|
||||||
|
.help("release number")
|
||||||
|
.short('r')
|
||||||
|
.long("release")
|
||||||
|
.default_value("1")
|
||||||
|
.value_parser(value_parser!(u8)),
|
||||||
|
Arg::new("dependencies")
|
||||||
|
.help("a comma separated list of dependencies")
|
||||||
|
.short('d')
|
||||||
|
.long("dependencies")
|
||||||
|
.value_delimiter(',')
|
||||||
|
.num_args(1..),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init() -> Command {
|
||||||
|
Command::new("init")
|
||||||
|
.about("Initialize a package `specs.ron` file in the current directory")
|
||||||
|
.args([
|
||||||
|
Arg::new("name")
|
||||||
|
.help("package name")
|
||||||
|
.short('n')
|
||||||
|
.long("name")
|
||||||
|
.num_args(1),
|
||||||
|
Arg::new("package-version")
|
||||||
|
.help("package version")
|
||||||
|
.short('v')
|
||||||
|
.long("package-version")
|
||||||
|
.num_args(1),
|
||||||
|
Arg::new("release")
|
||||||
|
.help("release number")
|
||||||
|
.short('r')
|
||||||
|
.long("release")
|
||||||
|
.default_value("1")
|
||||||
|
.value_parser(value_parser!(usize)),
|
||||||
|
Arg::new("dependencies")
|
||||||
|
.help("a comma separated list of dependencies")
|
||||||
|
.short('d')
|
||||||
|
.long("dependencies")
|
||||||
|
.value_delimiter(',')
|
||||||
|
.num_args(1..),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search() -> Command {
|
||||||
|
Command::new("search")
|
||||||
|
.about("Search for packages")
|
||||||
|
.visible_alias("se")
|
||||||
|
.args([
|
||||||
|
Arg::new("installed")
|
||||||
|
.help("only list installed packages")
|
||||||
|
.short('i')
|
||||||
|
.long("installed")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("remote")
|
||||||
|
.help("do not list installed packages")
|
||||||
|
.short('r')
|
||||||
|
.long("remote")
|
||||||
|
.conflicts_with("installed")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("names")
|
||||||
|
.help("only search in package names, not descriptions")
|
||||||
|
.short('n')
|
||||||
|
.long("names")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
Arg::new("query").use_value_delimiter(false).required(true),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info() -> Command {
|
||||||
|
Command::new("info")
|
||||||
|
.about("Display information about a specific package")
|
||||||
|
.arg(Arg::new("name").required(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install() -> Command {
|
||||||
|
Command::new("install")
|
||||||
|
.about("Install packages")
|
||||||
|
.visible_aliases(["in", "add"])
|
||||||
|
.args([
|
||||||
|
Arg::new("package")
|
||||||
|
.required_unless_present("local")
|
||||||
|
.conflicts_with("local")
|
||||||
|
.num_args(1..),
|
||||||
|
Arg::new("local")
|
||||||
|
.help("install a package from the filesystem")
|
||||||
|
.short('l')
|
||||||
|
.long("local")
|
||||||
|
.value_name("package")
|
||||||
|
.value_hint(ValueHint::FilePath)
|
||||||
|
.num_args(1..),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove() -> Command {
|
||||||
|
Command::new("remove")
|
||||||
|
.about("Remove packages")
|
||||||
|
.visible_aliases(["rm", "del"])
|
||||||
|
.arg(Arg::new("package").required(true).num_args(1..))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upgrade() -> Command {
|
||||||
|
Command::new("upgrade")
|
||||||
|
.about("Upgrade packages")
|
||||||
|
.visible_aliases(["update", "up", "sync"])
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user