Compare commits

...

2 Commits

Author SHA1 Message Date
Nathan Fisher af41d1c006 Fix bug introduced revolving around the ustar `prefix` field. GNU tar
was not giving the full path to each file and ignoring the `prefix`
field. On investigation, the field is only to be used if the filename
is longer than 100 bytes. Since the library code had been simplified to
always use the prefix field this caused all filenames shorter than 100
bytes to fail.

Also updated `package-bootstrap` to the latest patch release, which has
a fix for completions being installed into the base directory rather
than the appropriate subdirectory.
2023-05-05 19:07:44 -04:00
Nathan Fisher ccf6d5301a Add shells hook 2023-04-29 23:40:17 -04:00
9 changed files with 374 additions and 218 deletions

146
Cargo.lock generated
View File

@ -19,42 +19,51 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.2.6"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"concolor-override",
"concolor-query",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "0.3.5"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
[[package]]
name = "anstyle-parse"
version = "0.1.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-wincon"
version = "0.2.0"
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys 0.45.0",
"windows-sys 0.48.0",
]
[[package]]
@ -110,9 +119,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.12.0"
version = "3.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8"
[[package]]
name = "byteorder"
@ -153,18 +162,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.2.1"
version = "4.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.2.1"
version = "4.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd"
dependencies = [
"anstream",
"anstyle",
@ -175,9 +184,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.2.0"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd"
checksum = "1a19591b2ab0e3c04b588a0e04ddde7b9eaa423646d1b4a8092879216bf47473"
dependencies = [
"clap",
]
@ -219,19 +228,10 @@ dependencies = [
]
[[package]]
name = "concolor-override"
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
[[package]]
name = "concolor-query"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
dependencies = [
"windows-sys 0.45.0",
]
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "console"
@ -264,9 +264,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181"
checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
dependencies = [
"libc",
]
@ -357,7 +357,7 @@ dependencies = [
"proc-macro2",
"quote",
"scratch",
"syn 2.0.14",
"syn 2.0.15",
]
[[package]]
@ -374,7 +374,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.14",
"syn 2.0.15",
]
[[package]]
@ -480,9 +480,9 @@ dependencies = [
[[package]]
name = "flate2"
version = "1.0.25"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
dependencies = [
"crc32fast",
"miniz_oxide",
@ -680,9 +680,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.141"
version = "0.2.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
[[package]]
name = "link-cplusplus"
@ -695,9 +695,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.3.1"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
[[package]]
name = "log"
@ -725,9 +725,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.6.2"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
@ -781,9 +781,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "package-bootstrap"
version = "0.2.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b733f09d474cde789d5a1f62eae77e27749f65a88306a9f60d37d7f5193f2beb"
checksum = "b44f1db147048186ea8be34e803e16ad50a5eb47c9ab6a8e098276a6c8d112dd"
dependencies = [
"clap",
"clap_complete",
@ -799,9 +799,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pkg-config"
version = "0.3.26"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "portable-atomic"
@ -899,9 +899,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.37.11"
version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [
"bitflags",
"errno",
@ -1009,22 +1009,22 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.160"
version = "1.0.162"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.160"
version = "1.0.162"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.14",
"syn 2.0.15",
]
[[package]]
@ -1074,9 +1074,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.14"
version = "2.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
dependencies = [
"proc-macro2",
"quote",
@ -1115,7 +1115,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.14",
"syn 2.0.15",
]
[[package]]
@ -1417,7 +1417,7 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets 0.48.0",
"windows-targets",
]
[[package]]
@ -1435,37 +1435,13 @@ dependencies = [
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
"windows-targets",
]
[[package]]
@ -1569,9 +1545,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "winnow"
version = "0.4.1"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
dependencies = [
"memchr",
]

16
specs.ron Normal file
View File

@ -0,0 +1,16 @@
Specs(
name: "hpk",
version: SemVer(SemVer(
major: 0,
minor: 1,
patch: 0,
)),
release: 1,
description: "The HitchHiker Package Keeper",
long_description: "",
dependencies: [],
users: None,
groups: None,
shells: None,
post_install: None,
)

View File

@ -9,10 +9,7 @@ mod cli;
use {
clap::ArgMatches,
cli::cli,
hpk::{
CreationError, Creator, Dependency, InstallMessage, Installer, Message, Specs,
Version,
},
hpk::{CreationError, Creator, Dependency, InstallMessage, Installer, Message, Specs, Version},
indicatif::{ProgressBar, ProgressStyle},
ron::ser::{to_writer_pretty, PrettyConfig},
std::{
@ -102,6 +99,7 @@ fn create(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
Message::Success(_s) => {
pb.inc(1);
pb.finish_and_clear();
break;
}
}
}
@ -117,6 +115,18 @@ fn create(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
}
}
fn install(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
let Some(root) = matches.get_one::<String>("root") else {
unreachable!();
};
if let Some(archive) = matches.get_one::<String>("local") {
install_local(archive, root)?;
} else if let Some(package) = matches.get_one::<String>("package") {
unimplemented!();
}
Ok(())
}
fn install_local<P: AsRef<OsStr> + fmt::Display>(
archive: P,
root: P,
@ -158,7 +168,7 @@ fn install_local<P: AsRef<OsStr> + fmt::Display>(
}
fn init(matches: &ArgMatches) -> Result<PathBuf, Box<dyn Error>> {
let specsfile = PathBuf::from("package.specs");
let specsfile = PathBuf::from("specs.ron");
let cfg = PrettyConfig::new().struct_names(true);
let buf = File::create(&specsfile)?;
let writer = BufWriter::new(buf);
@ -171,10 +181,6 @@ 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!();
}

View File

@ -1,8 +1,11 @@
use crate::{Group, InstallError, InstallMessage, User};
use std::{
fs::OpenOptions,
io::{Read, Seek, SeekFrom, Write},
path::PathBuf,
process::{Command, Output},
sync::mpsc::Sender,
thread,
};
#[derive(Debug, Clone)]
@ -14,6 +17,7 @@ pub struct Hooks {
pinstall: Vec<PathBuf>,
users: Vec<User>,
groups: Vec<Group>,
shells: Vec<PathBuf>,
}
impl Default for Hooks {
@ -26,6 +30,7 @@ impl Default for Hooks {
pinstall: vec![],
users: vec![],
groups: vec![],
shells: vec![],
}
}
}
@ -61,87 +66,224 @@ impl Hooks {
self.groups.push(group);
}
pub fn makewhatis(
&self,
sender: Sender<InstallMessage>,
) -> Result<Option<Output>, InstallError> {
if self.man {
let output = Command::new("makewhatis")
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::Man)?;
Ok(Some(output))
} else {
Ok(None)
}
pub fn push_shell(&mut self, shell: PathBuf) {
self.shells.push(shell);
}
pub fn compile_schemas(
&self,
sender: Sender<InstallMessage>,
) -> Result<Option<Output>, InstallError> {
pub fn run(self, sender: Sender<InstallMessage>) -> Result<(), InstallError> {
let Some(root) = self.root.to_str().map(|x| x.to_string()) else {
return Err(InstallError::BadPath);
};
let mut threads = vec![];
if !self.users.is_empty() {
let sender = sender.clone();
let root = root.clone();
let users = self.users;
threads.push(thread::spawn(move || {
create_users(users, &root, sender)?;
Ok::<(), InstallError>(())
}));
}
if !self.groups.is_empty() {
let sender = sender.clone();
let root = root.clone();
let groups = self.groups;
threads.push(thread::spawn(move || {
create_groups(groups, &root, sender)?;
Ok::<(), InstallError>(())
}));
}
if !self.shells.is_empty() {
let sender = sender.clone();
let root = root.clone();
let shells = self.shells;
threads.push(thread::spawn(move || {
append_shells(shells, &root, sender)?;
Ok::<(), InstallError>(())
}));
}
if self.man && root.as_str() == "/" {
let sender = sender.clone();
threads.push(thread::spawn(move || {
install_man(sender)?;
Ok::<(), InstallError>(())
}));
}
if self.glib_schema {
let mut dir = self.root.clone();
dir.push("usr");
dir.push("share");
dir.push("glib-2.0");
dir.push("schemas");
let output = Command::new("glib-compile-schemas")
.arg(dir.to_str().unwrap())
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::GlibSchemas)?;
Ok(Some(output))
} else {
Ok(None)
let sender = sender.clone();
let root = root.clone();
threads.push(thread::spawn(move || {
compile_schemas(&root, sender)?;
Ok::<(), InstallError>(())
}));
}
if !self.info.is_empty() {
let sender = sender.clone();
let root = PathBuf::from(&root);
let pages = self.info;
threads.push(thread::spawn(move || {
install_info(pages, root, sender)?;
Ok::<(), InstallError>(())
}));
}
if !self.pinstall.is_empty() {
let scripts = self.pinstall;
threads.push(thread::spawn(move || {
run_pinstall(scripts, root.into(), sender)?;
Ok::<(), InstallError>(())
}));
}
for th in threads {
if let Err(e) = th.join() {
eprintln!("{e:?}");
}
}
}
pub fn install_info(&self, sender: Sender<InstallMessage>) -> Result<(), InstallError> {
let root = self.root.clone();
self.info.iter().try_for_each(|page| {
let p = root.clone();
let page = p.join(page);
let Some(dir) = page.parent() else {
return Err(InstallError::BadPath);
};
let mut dir = dir.to_path_buf();
dir.push("dir");
let Some(page) = page.to_str() else {
return Err(InstallError::BadPath);
};
let Some(dir) = dir.to_str() else {
return Err(InstallError::BadPath);
};
Command::new("install-info")
.args([page, dir])
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::Info(page.to_string()))?;
Ok(())
})?;
Ok(())
}
pub fn run_pinstall(&self, sender: Sender<InstallMessage>) -> Result<(), InstallError> {
let root = self.root.clone();
self.pinstall.iter().try_for_each(|pinstall| {
let p = root.clone();
let pinstall = p.join(pinstall);
let Some(root) = root.to_str() else {
return Err(InstallError::BadPath);
};
let Some(pinstall) = pinstall.to_str() else {
return Err(InstallError::BadPath);
};
let output = Command::new("/bin/sh")
.arg(pinstall)
.env("HPOK_ROOT", root)
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::PostInstall(output))?;
Ok(())
})?;
Ok(())
}
}
pub fn append_shells(
shells: Vec<PathBuf>,
root: &str,
sender: Sender<InstallMessage>,
) -> Result<(), InstallError> {
shells.iter().try_for_each(|shell| {
let s = PathBuf::from("/");
let shell = s.join(shell);
let Some(shell) = shell.to_str().map(|x| x.to_string()) else {
return Err(InstallError::BadPath);
};
let mut f = PathBuf::from(root);
f.push("etc");
f.push("shells");
let mut fd = OpenOptions::new().read(true).write(true).open(&f)?;
let meta = fd.metadata()?;
let len = meta.len();
let pos = fd.seek(SeekFrom::Start(len - 1))?;
if !pos == len - 1 {
eprintln!("Bad seek operation in /etc/shells");
}
let mut buf = [0; 1];
fd.read_exact(&mut buf)?;
if !buf[0] == b'\n' {
write!(fd, "\n")?;
}
write!(fd, "{shell}")?;
sender.send(InstallMessage::ShellAdded(shell))?;
Ok::<(), InstallError>(())
})?;
Ok(())
}
pub fn create_users(
users: Vec<User>,
root: &str,
sender: Sender<InstallMessage>,
) -> Result<(), InstallError> {
users.iter().try_for_each(|user| {
let mut cmd = Command::new("useradd");
cmd.args(["-rs", "/sbin/nologin", "-R", root]);
if let Some(uid) = user.uid {
cmd.args(["-u", &format!("{uid}")]);
}
cmd.arg(&user.name);
let _output = cmd.output().map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::UserCreated(user.clone()))?;
Ok::<(), InstallError>(())
})?;
Ok(())
}
pub fn create_groups(
groups: Vec<Group>,
root: &str,
sender: Sender<InstallMessage>,
) -> Result<(), InstallError> {
groups.iter().try_for_each(|group| {
let mut cmd = Command::new("groupadd");
cmd.args(["-r", "-R", root]);
if let Some(gid) = group.gid {
cmd.args(["-u", &format!("{gid}")]);
}
cmd.arg(&group.name);
let _output = cmd.output().map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::GroupCreated(group.clone()))?;
Ok::<(), InstallError>(())
})?;
Ok(())
}
pub fn install_man(sender: Sender<InstallMessage>) -> Result<Output, InstallError> {
let output = Command::new("makewhatis")
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::Man)?;
Ok(output)
}
pub fn compile_schemas(root: &str, sender: Sender<InstallMessage>) -> Result<Output, InstallError> {
let mut dir = PathBuf::from(root);
dir.push("usr");
dir.push("share");
dir.push("glib-2.0");
dir.push("schemas");
let output = Command::new("glib-compile-schemas")
.arg(dir.to_str().unwrap())
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::GlibSchemas)?;
Ok(output)
}
pub fn install_info(
pages: Vec<PathBuf>,
root: PathBuf,
sender: Sender<InstallMessage>,
) -> Result<(), InstallError> {
pages.iter().try_for_each(|page| {
let page = root.join(page);
let Some(dir) = page.parent() else {
return Err(InstallError::BadPath);
};
let mut dir = dir.to_path_buf();
dir.push("dir");
let Some(page) = page.to_str() else {
return Err(InstallError::BadPath);
};
let Some(dir) = dir.to_str() else {
return Err(InstallError::BadPath);
};
Command::new("install-info")
.args([page, dir])
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::Info(page.to_string()))?;
Ok(())
})?;
Ok(())
}
pub fn run_pinstall(
scripts: Vec<PathBuf>,
root: PathBuf,
sender: Sender<InstallMessage>,
) -> Result<(), InstallError> {
scripts.iter().try_for_each(|pinstall| {
let p = root.clone();
let pinstall = p.join(pinstall);
let Some(root) = root.to_str() else {
return Err(InstallError::BadPath);
};
let Some(pinstall) = pinstall.to_str() else {
return Err(InstallError::BadPath);
};
let output = Command::new("/bin/sh")
.arg(pinstall)
.env("HPOK_ROOT", root)
.output()
.map_err(Into::<InstallError>::into)?;
sender.send(InstallMessage::PostInstall(output))?;
Ok(())
})?;
Ok(())
}

View File

@ -50,6 +50,8 @@ pub enum InstallMessage {
UserCreated(User),
/// A `Group` has been successfully created
GroupCreated(Group),
/// A shell has been added to '/etc/shells'
ShellAdded(String),
/// The output of the post install script
PostInstall(Output),
/// Update the mandoc db
@ -100,14 +102,13 @@ impl<T: io::Read> Installer<T> {
pr_node.write(&mut buf)?;
let package: Package = ron::de::from_bytes(&buf)?;
if let Some(ref users) = package.users {
users
.iter()
.for_each(|u| hooks.push_user(u.clone()));
users.iter().for_each(|u| hooks.push_user(u.clone()));
}
if let Some(ref groups) = package.groups {
groups
.iter()
.for_each(|g| hooks.push_group(g.clone()));
groups.iter().for_each(|g| hooks.push_group(g.clone()));
}
if let Some(ref shells) = package.shells {
shells.iter().for_each(|s| hooks.push_shell(s.clone()));
}
let mut db_pkgdir = crate::get_dbdir(Some(self.root.clone()));
db_pkgdir.push(&package.name);
@ -139,10 +140,7 @@ impl<T: io::Read> Installer<T> {
let mut h = hooks.lock().unwrap();
h.push_man();
} else if s.contains("/share/info") {
hooks
.lock()
.unwrap()
.push_info(fpath.to_str().unwrap());
hooks.lock().unwrap().push_info(fpath.to_str().unwrap());
} else if s.contains("/share/glib-2.0/schemas") {
let mut h = hooks.lock().unwrap();
h.push_glib_schema();
@ -237,11 +235,7 @@ fn pop_appstream(archive: &mut Archive, db_pkgdir: &Path) -> Result<(), Error> {
Ok(())
}
fn pop_pinstall(
archive: &mut Archive,
hooks: &mut Hooks,
pkgname: &str,
) -> Result<(), Error> {
fn pop_pinstall(archive: &mut Archive, hooks: &mut Hooks, pkgname: &str) -> Result<(), Error> {
let pinstall = archive.pop("postinstall.sh");
if let Some(node) = pinstall {
let mut path: PathBuf = ["/", "tmp", "hpk", pkgname].iter().collect();

View File

@ -12,7 +12,7 @@ use {
fs,
fs::File,
io::{BufWriter, Write},
path::Path,
path::{Path, PathBuf},
},
};
@ -56,6 +56,8 @@ pub struct Package {
pub users: Option<Vec<User>>,
/// an optional list of groups to be created upon installation
pub groups: Option<Vec<Group>>,
/// applicable only if this package contains a shell
pub shells: Option<Vec<PathBuf>>,
/// an optional post installation shell script to be run
pub post_install: Option<String>,
}
@ -71,6 +73,7 @@ impl From<Specs> for Package {
dependencies: value.dependencies,
users: value.users,
groups: value.groups,
shells: value.shells,
post_install: value.post_install,
..Default::default()
}
@ -126,4 +129,8 @@ impl Package {
&& (self.version > other.version
|| (self.version == other.version && self.release > other.release))
}
pub fn resolve_deps(&self, queue: &mut Vec<Package>) -> Result<(), Box<dyn Error>> {
unimplemented!();
}
}

View File

@ -2,6 +2,7 @@ use {
super::{Group, User},
crate::{Dependency, Version},
serde::{Deserialize, Serialize},
std::path::PathBuf,
};
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
@ -22,6 +23,8 @@ pub struct Specs {
pub users: Option<Vec<User>>,
/// an optional list of groups to be created upon installation
pub groups: Option<Vec<Group>>,
/// applicable only if this package contains a shell
pub shells: Option<Vec<PathBuf>>,
/// an optional post installation shell script to be run
pub post_install: Option<String>,
}

View File

@ -125,7 +125,7 @@ impl Header {
///
/// let header = Header::new("test/1.txt").unwrap();
/// let filename = header.filename().unwrap();
/// assert_eq!(filename.as_str(), "1.txt");
/// assert_eq!(filename.as_str(), "test/1.txt");
/// ```
pub fn filename(&self) -> Result<String, fmt::Error> {
let mut s = String::new();
@ -220,14 +220,18 @@ impl Header {
}
/// Gets the path to the file minus it's final component
/// > Note: the ustar format only uses this field if the
/// > complete filename would be longer than 100 bytes.
/// > If the combined filename is shorter, this function
/// > returns `None`.
///
/// # Example
/// ```
/// use hpk::tar::Header;
///
/// let header = Header::new("test/1.txt").unwrap();
/// let prefix = header.prefix().unwrap();
/// assert_eq!(prefix.as_str(), "test");
/// let prefix = header.prefix();
/// assert!(prefix.is_none());
/// ```
pub fn prefix(&self) -> Option<String> {
let mut s = String::new();
@ -272,20 +276,24 @@ impl Header {
let meta = fs::symlink_metadata(filename)?;
let (filename, prefix) = {
// Original tar has a maximum file name length of 100 bytes. The ustar
// revision allows storing the path prefix separately, with 100 bytes
// reserved for the file name and 150 bytes for the rest of the path.
let path = PathBuf::from(&filename);
let name = match path.file_name().and_then(OsStr::to_str) {
Some(n) => n.to_string(),
None => {
return Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"Cannot get file name",
)))
}
};
let dir = path.parent().map(|x| format!("{}", x.display()));
(name, dir)
// revision allows storing the path prefix separately if the combined
// length is more than 100 bytes.
if filename.len() > 100 {
let path = PathBuf::from(&filename);
let name = match path.file_name().and_then(OsStr::to_str) {
Some(n) => n.to_string(),
None => {
return Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"Cannot get file name",
)))
}
};
let dir = path.parent().map(|x| format!("{}", x.display()));
(name, dir)
} else {
(filename.to_string(), None)
}
};
/* Fill in metadata */
@ -338,20 +346,24 @@ impl Header {
let mut header = Header::default();
let (filename, prefix) = {
// Original tar has a maximum file name length of 100 bytes. The ustar
// revision allows storing the path prefix separately, with 100 bytes
// reserved for the file name and 150 bytes for the rest of the path.
let path = PathBuf::from(&filename);
let name = match path.file_name().and_then(OsStr::to_str) {
Some(n) => n.to_string(),
None => {
return Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"Cannot get file name",
)))
}
};
let dir = path.parent().map(|x| format!("{}", x.display()));
(name, dir)
// revision allows storing the path prefix separately if the combined
// length is more than 100 bytes.
if filename.len() > 100 {
let path = PathBuf::from(&filename);
let name = match path.file_name().and_then(OsStr::to_str) {
Some(n) => n.to_string(),
None => {
return Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"Cannot get file name",
)))
}
};
let dir = path.parent().map(|x| format!("{}", x.display()));
(name, dir)
} else {
(filename.to_string(), None)
}
};
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
let mode = format!("{:07o}", meta.st_mode());

Binary file not shown.