Library is almost working but install_package no worky :c
This commit is contained in:
parent
ba36e3b7fc
commit
af2897efb1
4 changed files with 27323 additions and 34 deletions
|
@ -15,7 +15,9 @@ path = "src/lib/lib.rs"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
bytes = "1.10.1"
|
bytes = "1.10.1"
|
||||||
flate2 = "1.1.0"
|
flate2 = "1.1.0"
|
||||||
|
gpgme = { version = "0.11.0", features = ["v1_18"] }
|
||||||
reqwest = { version = "0.12.12", features = ["blocking"] }
|
reqwest = { version = "0.12.12", features = ["blocking"] }
|
||||||
|
ruzstd = "0.8.0"
|
||||||
sha256 = "1.6.0"
|
sha256 = "1.6.0"
|
||||||
tar = "0.4.44"
|
tar = "0.4.44"
|
||||||
time = { version = "0.3.39", features = ["formatting"] }
|
time = { version = "0.3.39", features = ["formatting"] }
|
||||||
|
|
26958
src/lib/archlinux.gpg
Normal file
26958
src/lib/archlinux.gpg
Normal file
File diff suppressed because it is too large
Load diff
379
src/lib/lib.rs
379
src/lib/lib.rs
|
@ -5,6 +5,7 @@
|
||||||
clippy::empty_docs,
|
clippy::empty_docs,
|
||||||
clippy::missing_panics_doc
|
clippy::missing_panics_doc
|
||||||
)]
|
)]
|
||||||
|
#![feature(str_as_str)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
|
@ -14,6 +15,7 @@ use std::{
|
||||||
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
|
use gpgme::SignatureSummary;
|
||||||
|
|
||||||
/// A descriptor of a repository.
|
/// A descriptor of a repository.
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug)]
|
||||||
|
@ -23,7 +25,7 @@ pub struct RepoDescriptor {
|
||||||
/// The architecture to use.
|
/// The architecture to use.
|
||||||
arch: String,
|
arch: String,
|
||||||
/// The hash of the (repo).db file.
|
/// The hash of the (repo).db file.
|
||||||
hash: Option<Vec<u8>>
|
hash: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepoDescriptor {
|
impl RepoDescriptor {
|
||||||
|
@ -54,20 +56,21 @@ impl RepoDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The hash of the (repo).db file.
|
/// The hash of the (repo).db file.
|
||||||
pub fn hash(&self) -> Option<Vec<u8>> {
|
pub fn hash(&self) -> Option<String> {
|
||||||
self.hash.clone()
|
self.hash.clone()
|
||||||
}
|
}
|
||||||
/// Sets [`hash`].
|
/// Sets [`hash`].
|
||||||
/// [`hash`]: [RepoDescriptor::hash]
|
/// [`hash`]: [RepoDescriptor::hash]
|
||||||
pub fn set_hash(&mut self, hash: Option<Vec<u8>>) -> &mut Self {
|
pub fn set_hash(&mut self, hash: Option<String>) -> &mut Self {
|
||||||
self.hash = hash;
|
self.hash = hash;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats the repo descriptor into a string.
|
/// Formats the repo descriptor into a string.
|
||||||
|
#[allow(clippy::missing_panics_doc)] // function won't ever actually panic
|
||||||
pub fn format(&self) -> String {
|
pub fn format(&self) -> String {
|
||||||
if self.hash().is_some() {
|
if self.hash().is_some() {
|
||||||
format!("{:x?}-{}-{}", self.hash().unwrap(), self.repo(), self.arch())
|
format!("{}-{}-{}", self.hash().unwrap(), self.repo(), self.arch())
|
||||||
} else {
|
} else {
|
||||||
format!("{}-{}", self.repo(), self.arch())
|
format!("{}-{}", self.repo(), self.arch())
|
||||||
}
|
}
|
||||||
|
@ -120,6 +123,7 @@ impl Package {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mirror to use.
|
/// A mirror to use.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Mirror(url::Url);
|
pub struct Mirror(url::Url);
|
||||||
|
|
||||||
impl Mirror {
|
impl Mirror {
|
||||||
|
@ -187,16 +191,32 @@ pub fn get_current_user() -> OsString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the base dir for pacwoman. Use this instead of hard-coding /pacwoman for the case
|
||||||
|
/// of debugging in a different directory.
|
||||||
|
///
|
||||||
|
/// This directory is not guaranteed to exist! If you need it to, use [base_dir]!
|
||||||
|
pub fn get_base_dir() -> PathBuf {
|
||||||
|
PathBuf::from("/home/arthur/pacwoman/debug")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as [get_base_dir]; however, this function will create the directory if it doesn't
|
||||||
|
/// exist. If [std::fs::create_dir_all] returns an error, it will be propagated.
|
||||||
|
pub fn base_dir() -> std::io::Result<PathBuf> {
|
||||||
|
let dir = get_base_dir();
|
||||||
|
std::fs::create_dir_all(&dir)?;
|
||||||
|
Ok(dir)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the config directory. If for the entire system, then it will be /pacwoman/config, otherwise
|
/// Get the config directory. If for the entire system, then it will be /pacwoman/config, otherwise
|
||||||
/// it will be /pacwomand/user/{user name from [get_current_user]}/config.
|
/// it will be /pacwomand/user/{user name from [get_current_user]}/config.
|
||||||
///
|
///
|
||||||
/// This directory is not guaranteed to exist! If you need it to, use [config_directory]!
|
/// This directory is not guaranteed to exist! If you need it to, use [config_directory]!
|
||||||
pub fn get_config_directory(system: bool) -> PathBuf {
|
pub fn get_config_directory(system: bool) -> PathBuf {
|
||||||
if system {
|
if system {
|
||||||
PathBuf::from("/pacwoman/config")
|
get_base_dir().join("config")
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from(format!(
|
get_base_dir().join(format!(
|
||||||
"/pacwoman/user/{}/config",
|
"user/{}/config",
|
||||||
get_current_user().to_string_lossy()
|
get_current_user().to_string_lossy()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -211,15 +231,15 @@ pub fn config_directory(system: bool) -> std::io::Result<PathBuf> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the store directory. If for the entire system, then it will be /pacwoman/store, otherwise
|
/// Get the store directory. If for the entire system, then it will be /pacwoman/store, otherwise
|
||||||
/// it will be /pacwomand/user/{user name from [get_current_user]}/store.
|
/// it will be /pacwoman/user/{user name from [get_current_user]}/store.
|
||||||
///
|
///
|
||||||
/// This directory is not guaranteed to exist! If you need it to, use [store_directory]!
|
/// This directory is not guaranteed to exist! If you need it to, use [store_directory]!
|
||||||
pub fn get_store_directory(system: bool) -> PathBuf {
|
pub fn get_store_directory(system: bool) -> PathBuf {
|
||||||
if system {
|
if system {
|
||||||
PathBuf::from("/home/arthur/pacwoman/store")
|
get_base_dir().join("store")
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from(format!(
|
get_base_dir().join(format!(
|
||||||
"/home/arthur/pacwoman/user/{}/store",
|
"user/{}/store",
|
||||||
get_current_user().to_string_lossy()
|
get_current_user().to_string_lossy()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -234,6 +254,8 @@ pub fn store_directory(system: bool) -> std::io::Result<PathBuf> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the store directory for a repo.
|
/// Gets the store directory for a repo.
|
||||||
|
///
|
||||||
|
/// This directory is not guaranteed to exist! See [repo_store_directory] if you need it too.
|
||||||
pub fn get_repo_store_directory(system: bool, repo: RepoDescriptor) -> PathBuf {
|
pub fn get_repo_store_directory(system: bool, repo: RepoDescriptor) -> PathBuf {
|
||||||
get_store_directory(system).join(repo.format())
|
get_store_directory(system).join(repo.format())
|
||||||
}
|
}
|
||||||
|
@ -251,7 +273,7 @@ pub fn repo_store_directory(system: bool, repo: RepoDescriptor) -> std::io::Resu
|
||||||
///
|
///
|
||||||
/// This directory is not guaranteed to exist! If you need it to, use [index_directory]!
|
/// This directory is not guaranteed to exist! If you need it to, use [index_directory]!
|
||||||
pub fn get_index_directory() -> PathBuf {
|
pub fn get_index_directory() -> PathBuf {
|
||||||
PathBuf::from("/home/arthur/pacwoman/index")
|
get_base_dir().join("index")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [get_index_directory]; however, this function will create the directory if it doesn't
|
/// Same as [get_index_directory]; however, this function will create the directory if it doesn't
|
||||||
|
@ -278,6 +300,41 @@ pub fn repo_index_dir(repo: RepoDescriptor) -> std::io::Result<PathBuf> {
|
||||||
Ok(dir)
|
Ok(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Directory for storing GPG keys and other miscellaneous GPG stuff.
|
||||||
|
///
|
||||||
|
/// This directory is not guaranteed to exist! See [gpg_dir] if you need it too.
|
||||||
|
pub fn get_gpg_dir() -> PathBuf {
|
||||||
|
get_base_dir().join("keys")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as [get_gpg_dir], except it will create the directory if it doesn't exist.
|
||||||
|
/// If [std::fs::create_dir_all] returns an error, it will be propagated.
|
||||||
|
pub fn gpg_dir() -> std::io::Result<PathBuf> {
|
||||||
|
let dir = get_gpg_dir();
|
||||||
|
std::fs::create_dir_all(&dir)?;
|
||||||
|
Ok(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Directory for storing binaries. Equivalent to the root directory. Contains directories such
|
||||||
|
/// as etc, usr, var, and others.
|
||||||
|
///
|
||||||
|
/// This directory is not guaranteed to exist! See [bin_dir] if you need it too.
|
||||||
|
pub fn get_bin_dir(system: bool) -> PathBuf {
|
||||||
|
if system {
|
||||||
|
get_base_dir().join("bin")
|
||||||
|
} else {
|
||||||
|
get_base_dir().join(format!("user/{}/bin", get_current_user().to_string_lossy()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as [get_bin_dir], except it will create the directory if it doesn't exist.
|
||||||
|
/// If [std::fs::create_dir_all] returns an error, it will be propagated.
|
||||||
|
pub fn bin_dir(system: bool) -> std::io::Result<PathBuf> {
|
||||||
|
let dir = get_bin_dir(system);
|
||||||
|
std::fs::create_dir_all(&dir)?;
|
||||||
|
Ok(dir)
|
||||||
|
}
|
||||||
|
|
||||||
/// Populates the index with information for a certain repo from a certain mirror. Will
|
/// Populates the index with information for a certain repo from a certain mirror. Will
|
||||||
/// overwrite any symlink for the repo.
|
/// overwrite any symlink for the repo.
|
||||||
///
|
///
|
||||||
|
@ -415,7 +472,7 @@ pub fn populate_index(mirror: Mirror, repo: RepoDescriptor) -> std::io::Result<P
|
||||||
|
|
||||||
/// Get a list of hashes provided by the repo.
|
/// Get a list of hashes provided by the repo.
|
||||||
#[allow(clippy::missing_panics_doc)] // Shouldn't ever panic, but could be wrong.
|
#[allow(clippy::missing_panics_doc)] // Shouldn't ever panic, but could be wrong.
|
||||||
pub fn read_repos(repo: RepoDescriptor) -> std::io::Result<Vec<PathBuf>> {
|
pub fn read_repos(repo: RepoDescriptor) -> std::io::Result<Vec<(PathBuf, String)>> {
|
||||||
let mut repos = std::fs::OpenOptions::new()
|
let mut repos = std::fs::OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(index_directory()?.join("REPOS"))?;
|
.open(index_directory()?.join("REPOS"))?;
|
||||||
|
@ -433,9 +490,9 @@ pub fn read_repos(repo: RepoDescriptor) -> std::io::Result<Vec<PathBuf>> {
|
||||||
for hash in line.split_once(": ").unwrap().1.split(" ") {
|
for hash in line.split_once(": ").unwrap().1.split(" ") {
|
||||||
strings.push(hash.to_owned() + &repo.format());
|
strings.push(hash.to_owned() + &repo.format());
|
||||||
}
|
}
|
||||||
let mut out: Vec<PathBuf> = vec![];
|
let mut out: Vec<(PathBuf, String)> = vec![];
|
||||||
for ele in strings {
|
for ele in strings {
|
||||||
out.push(index_directory()?.join(PathBuf::from(ele)));
|
out.push((index_directory()?.join(PathBuf::from(&ele)), ele));
|
||||||
}
|
}
|
||||||
return Ok(out);
|
return Ok(out);
|
||||||
}
|
}
|
||||||
|
@ -478,6 +535,9 @@ pub fn locate_package(
|
||||||
let repo = prefix
|
let repo = prefix
|
||||||
.strip_suffix(&("-".to_string() + &arch))
|
.strip_suffix(&("-".to_string() + &arch))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.split_once("-")
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let descriptor = RepoDescriptor::new()
|
let descriptor = RepoDescriptor::new()
|
||||||
|
@ -542,10 +602,10 @@ pub struct PackageDesc {
|
||||||
/// MD5 checksum of the package. Recommended not to use and to instead use [`sha256sum`].
|
/// MD5 checksum of the package. Recommended not to use and to instead use [`sha256sum`].
|
||||||
/// Stored as hex in the desc file.
|
/// Stored as hex in the desc file.
|
||||||
/// [`sha256sum`]: [PackageDesc::sha256sum]
|
/// [`sha256sum`]: [PackageDesc::sha256sum]
|
||||||
pub md5sum: Vec<u8>,
|
pub md5sum: String,
|
||||||
/// SHA256 checksum of the package.
|
/// SHA256 checksum of the package.
|
||||||
/// Stored as hex in the desc file.
|
/// Stored as hex in the desc file.
|
||||||
pub sha256sum: Vec<u8>,
|
pub sha256sum: String,
|
||||||
/// PGP signature of the package.
|
/// PGP signature of the package.
|
||||||
/// Stored as base64 in the desc file.
|
/// Stored as base64 in the desc file.
|
||||||
pub pgpsig: Vec<u8>,
|
pub pgpsig: Vec<u8>,
|
||||||
|
@ -640,12 +700,12 @@ pub fn read_desc(package: String, repo: RepoDescriptor) -> std::io::Result<Packa
|
||||||
|
|
||||||
if let Some(loc) = desc_data.iter().position(|item| (*item) == "%MD5SUM%") {
|
if let Some(loc) = desc_data.iter().position(|item| (*item) == "%MD5SUM%") {
|
||||||
let loc = loc + 1; // value is on next line
|
let loc = loc + 1; // value is on next line
|
||||||
out.md5sum = desc_data[loc].as_bytes().to_vec();
|
out.md5sum = desc_data[loc].to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(loc) = desc_data.iter().position(|item| (*item) == "%SHA256SUM%") {
|
if let Some(loc) = desc_data.iter().position(|item| (*item) == "%SHA256SUM%") {
|
||||||
let loc = loc + 1; // value is on next line
|
let loc = loc + 1; // value is on next line
|
||||||
out.sha256sum = desc_data[loc].as_bytes().to_vec();
|
out.sha256sum = desc_data[loc].to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(loc) = desc_data.iter().position(|item| (*item) == "%PGPSIG%") {
|
if let Some(loc) = desc_data.iter().position(|item| (*item) == "%PGPSIG%") {
|
||||||
|
@ -789,19 +849,56 @@ pub fn read_desc(package: String, repo: RepoDescriptor) -> std::io::Result<Packa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the [gpgme] context and sets the appropriate properties.
|
||||||
|
pub fn get_gpg_ctx() -> std::io::Result<gpgme::Context> {
|
||||||
|
let mut gpg_ctx = gpgme::Context::from_protocol(gpgme::Protocol::OpenPgp)?;
|
||||||
|
gpg_ctx.set_engine_home_dir(gpg_dir()?.to_string_lossy().into_owned())?;
|
||||||
|
Ok(gpg_ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The PGP public key file for arch linux signing keys.
|
||||||
|
const ARCHLINUX_PGP_PUBLIC_KEY: &[u8] = include_bytes!("archlinux.gpg");
|
||||||
|
|
||||||
|
/// Initalizes the GPG keyring and other GPG stuff.
|
||||||
|
pub fn init_gpg() -> std::io::Result<()> {
|
||||||
|
let mut gpg_ctx = get_gpg_ctx()?;
|
||||||
|
|
||||||
|
print!("Generating master key...");
|
||||||
|
gpg_ctx.generate_key::<Vec<u8>, Vec<u8>>(
|
||||||
|
r#"<GnupgKeyParms format="internal">
|
||||||
|
Key-Type: RSA
|
||||||
|
Key-Length: 4096
|
||||||
|
Key-Usage: sign
|
||||||
|
Name-Real: Pacwoman Keyring Master Key
|
||||||
|
Name-Email: pacwoman@localhost
|
||||||
|
Expire-Date: 0
|
||||||
|
%no-protection
|
||||||
|
</GnupgKeyParms>"#,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
println!(" Done.");
|
||||||
|
|
||||||
|
gpg_ctx.import(ARCHLINUX_PGP_PUBLIC_KEY)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Downloads, verifies, and unpacks a package from the provided mirror. The package value
|
||||||
|
/// provided should be the file name provided in a [PackageDesc].
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// Panics if there are any errors with downloading because right now I don't feel like
|
||||||
|
/// implementing it to fail gently.
|
||||||
pub fn receive_package(
|
pub fn receive_package(
|
||||||
mirror: Mirror,
|
mirror: Mirror,
|
||||||
repo: RepoDescriptor,
|
repo: RepoDescriptor,
|
||||||
package: String,
|
package: String,
|
||||||
system: bool,
|
system: bool,
|
||||||
) -> std::io::Result<PathBuf> {
|
) -> std::io::Result<PathBuf> {
|
||||||
if repo.hash().is_none() {
|
|
||||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "need hash in repo descriptor"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = index_directory()?
|
let path = index_directory()?
|
||||||
.join(repo.format())
|
.join(repo.format())
|
||||||
.join(package)
|
.join(&package)
|
||||||
.join("desc");
|
.join("desc");
|
||||||
|
|
||||||
let mut desc = std::fs::OpenOptions::new().read(true).open(path)?;
|
let mut desc = std::fs::OpenOptions::new().read(true).open(path)?;
|
||||||
|
@ -814,25 +911,245 @@ pub fn receive_package(
|
||||||
|
|
||||||
let desc_hash = sha256::digest(desc_data);
|
let desc_hash = sha256::digest(desc_data);
|
||||||
|
|
||||||
let desc = read_desc(package, repo)?;
|
let desc = read_desc(package.clone(), repo.clone())?;
|
||||||
|
|
||||||
let url = mirror.substitute(&repo.repo(), &repo.arch(), &desc.filename);
|
let sig_url = mirror.substitute(
|
||||||
|
&repo.clone().repo(),
|
||||||
|
&repo.arch(),
|
||||||
|
&(desc.filename.clone() + ".sig"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let url = mirror.substitute(&repo.repo(), &repo.arch(), &desc.filename.clone());
|
||||||
|
|
||||||
let dir = repo_store_directory(system, repo)?.join(format!("{}-{}", desc_hash, package));
|
let dir = repo_store_directory(system, repo)?.join(format!("{}-{}", desc_hash, package));
|
||||||
|
|
||||||
|
if std::fs::exists(index_directory()?.join("RECIEVED"))? {
|
||||||
|
let mut packages = std::fs::OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(index_directory()?.join("RECIEVED"))?;
|
||||||
|
|
||||||
|
let mut packages_data = String::new();
|
||||||
|
|
||||||
|
packages.read_to_string(&mut packages_data)?;
|
||||||
|
|
||||||
|
drop(packages);
|
||||||
|
|
||||||
|
let packages: Vec<&str> = packages_data.split("\n").collect();
|
||||||
|
|
||||||
|
if packages.contains(&format!("{}-{}", desc_hash, package).as_str()) {
|
||||||
|
return Ok(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::create_dir_all(&dir)?;
|
||||||
|
|
||||||
|
let sig_data = reqwest::blocking::get(sig_url)
|
||||||
|
.unwrap()
|
||||||
|
.bytes()
|
||||||
|
.unwrap()
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
let package_data = reqwest::blocking::get(url)
|
||||||
|
.unwrap()
|
||||||
|
.bytes()
|
||||||
|
.unwrap()
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
|
let mut gpg_ctx = get_gpg_ctx()?;
|
||||||
|
let res = gpg_ctx
|
||||||
|
.verify_detached(&sig_data, &package_data)?
|
||||||
|
.signatures()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.summary();
|
||||||
|
|
||||||
|
match res {
|
||||||
|
SignatureSummary::VALID | SignatureSummary::GREEN => {}
|
||||||
|
sum => {
|
||||||
|
if !sum.is_empty() {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::InvalidData,
|
||||||
|
format!("signature invalid, error {:#?}", sum),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sum = sha256::digest(&package_data);
|
||||||
|
|
||||||
|
if desc.sha256sum != sum {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::InvalidData,
|
||||||
|
"SHA256 checksum does not match provided sum in desc, try updating the index or try receiving the package again",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut reader = package_data.reader();
|
||||||
|
|
||||||
|
let tar = ruzstd::decoding::StreamingDecoder::new(&mut reader).unwrap();
|
||||||
|
let mut archive = tar::Archive::new(tar);
|
||||||
|
archive.unpack(&dir)?;
|
||||||
|
|
||||||
|
let mut packages = std::fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.truncate(false)
|
||||||
|
.open(index_directory()?.join("RECIEVED"))?;
|
||||||
|
|
||||||
|
packages.write_fmt(format_args!("{}-{}\n", desc_hash, package))?;
|
||||||
|
drop(packages);
|
||||||
|
|
||||||
|
Ok(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recieves a package and all of it's dependencies. Returns a list of paths to each package.
|
||||||
|
pub fn recieve_package_and_dependencies(
|
||||||
|
mirror: Mirror,
|
||||||
|
repo: RepoDescriptor,
|
||||||
|
package: String,
|
||||||
|
system: bool,
|
||||||
|
) -> std::io::Result<Vec<PathBuf>> {
|
||||||
|
let mut out: Vec<PathBuf> = vec![];
|
||||||
|
out.push(receive_package(
|
||||||
|
mirror.clone(),
|
||||||
|
repo.clone(),
|
||||||
|
package.clone(),
|
||||||
|
system,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let path = index_directory()?
|
||||||
|
.join(repo.clone().format())
|
||||||
|
.join(&package)
|
||||||
|
.join("desc");
|
||||||
|
|
||||||
|
let mut desc = std::fs::OpenOptions::new().read(true).open(path)?;
|
||||||
|
|
||||||
|
let mut desc_data = String::new();
|
||||||
|
|
||||||
|
desc.read_to_string(&mut desc_data)?;
|
||||||
|
|
||||||
|
drop(desc);
|
||||||
|
|
||||||
|
let desc = read_desc(package.clone(), repo.clone())?;
|
||||||
|
|
||||||
|
for package in desc.depends {
|
||||||
|
println!("{}", package);
|
||||||
|
out.push(receive_package(
|
||||||
|
mirror.clone(),
|
||||||
|
repo.clone(),
|
||||||
|
locate_package(package)?[0].0.clone(),
|
||||||
|
system,
|
||||||
|
)?);
|
||||||
|
}
|
||||||
|
println!("recieved all dependencies");
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recieves a package and it's dependencies and installs it.
|
||||||
|
#[allow(clippy::missing_panics_doc)] // won't ever actually panic
|
||||||
|
pub fn install_package(
|
||||||
|
mirror: Mirror,
|
||||||
|
repo: RepoDescriptor,
|
||||||
|
package: String,
|
||||||
|
system: bool,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
let out = bin_dir(system)?;
|
||||||
|
for path in recieve_package_and_dependencies(mirror, repo, package, system)? {
|
||||||
|
println!("{}", path.to_string_lossy());
|
||||||
|
println!("{}", out.to_string_lossy());
|
||||||
|
|
||||||
|
if std::fs::exists(index_directory()?.join("INSTALLED"))? {
|
||||||
|
let mut packages = std::fs::OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(index_directory()?.join("INSTALLED"))?;
|
||||||
|
|
||||||
|
let mut packages_data = String::new();
|
||||||
|
|
||||||
|
packages.read_to_string(&mut packages_data)?;
|
||||||
|
|
||||||
|
drop(packages);
|
||||||
|
|
||||||
|
let packages: Vec<&str> = packages_data.split("\n").collect();
|
||||||
|
|
||||||
|
if packages.contains(&(path.file_name().unwrap().to_string_lossy().as_str())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in std::fs::read_dir(&path)? {
|
||||||
|
println!("entry");
|
||||||
|
let entry = entry?;
|
||||||
|
|
||||||
|
if entry.file_name() == *".BUILDINFO"
|
||||||
|
|| entry.file_name() == *".MTREE"
|
||||||
|
|| entry.file_name() == *".PKGINFO"
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
println!("{}", entry.file_name().to_string_lossy());
|
||||||
|
|
||||||
|
if entry.file_type()?.is_dir() {
|
||||||
|
std::fs::create_dir_all(out.join(entry.path()))?;
|
||||||
|
} else {
|
||||||
|
std::fs::create_dir_all(out.join(entry.path().parent().unwrap()))?;
|
||||||
|
std::fs::remove_file(out.join(entry.path()))?;
|
||||||
|
std::os::unix::fs::symlink(path.join(entry.path()), out.join(entry.path()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::os::unix::fs::chroot(&out)?;
|
||||||
|
|
||||||
|
if !std::process::Command::new("/usr/bin/bash")
|
||||||
|
.arg("-c")
|
||||||
|
.arg("source /.INSTALL && post_install && post_upgrade")
|
||||||
|
.current_dir(&out)
|
||||||
|
.spawn()?
|
||||||
|
.wait()?
|
||||||
|
.success()
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"[WARN] .INSTALL script for package {} failed!",
|
||||||
|
path.file_name().unwrap().to_string_lossy()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::os::unix::fs::chroot(".")?;
|
||||||
|
|
||||||
|
std::fs::remove_file(out.join(".INSTALL"))?;
|
||||||
|
|
||||||
|
let mut packages = std::fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.truncate(false)
|
||||||
|
.open(index_directory()?.join("INSTALLED"))?;
|
||||||
|
|
||||||
|
packages.write_fmt(format_args!(
|
||||||
|
"{}\n",
|
||||||
|
path.file_name().unwrap().to_string_lossy()
|
||||||
|
))?;
|
||||||
|
drop(packages);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates all of the necessary directories, for the system if root or the pacwoman user, and
|
/// Creates all of the necessary directories, for the system if root or the pacwoman user, and
|
||||||
/// for the current user if not. If [std::fs::create_dir_all] returns an error, it will be
|
/// for the current user if not. If [std::fs::create_dir_all] returns an error, it will be
|
||||||
/// propagated.
|
/// propagated.
|
||||||
pub fn create_directories() -> Result<(), std::io::Error> {
|
pub fn create_directories() -> Result<(), std::io::Error> {
|
||||||
if users::get_effective_uid() == 0 || get_current_user() == "pacwoman" {
|
if users::get_effective_uid() == 0
|
||||||
store_directory(false)?;
|
|| get_current_user() == "pacwoman"
|
||||||
config_directory(false)?;
|
|| get_current_user() == "arthur"
|
||||||
index_directory()?;
|
{
|
||||||
} else {
|
|
||||||
store_directory(true)?;
|
store_directory(true)?;
|
||||||
config_directory(true)?;
|
config_directory(true)?;
|
||||||
|
index_directory()?;
|
||||||
|
gpg_dir()?;
|
||||||
|
bin_dir(true)?;
|
||||||
|
} else {
|
||||||
|
store_directory(false)?;
|
||||||
|
config_directory(false)?;
|
||||||
|
bin_dir(false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -5,7 +5,10 @@
|
||||||
clippy::empty_docs
|
clippy::empty_docs
|
||||||
)]
|
)]
|
||||||
|
|
||||||
fn main() {
|
fn main() -> std::io::Result<()> {
|
||||||
|
pacwoman::create_directories()?;
|
||||||
|
//pacwoman::init_gpg()?;
|
||||||
|
|
||||||
pacwoman::populate_index(
|
pacwoman::populate_index(
|
||||||
pacwoman::Mirror::new(url::Url::parse(
|
pacwoman::Mirror::new(url::Url::parse(
|
||||||
"https://geo.mirror.pkgbuild.com/$repo/os/$arch",
|
"https://geo.mirror.pkgbuild.com/$repo/os/$arch",
|
||||||
|
@ -13,5 +16,14 @@ fn main() {
|
||||||
pacwoman::RepoDescriptor::new()
|
pacwoman::RepoDescriptor::new()
|
||||||
.set_repo("core".to_string())
|
.set_repo("core".to_string())
|
||||||
.set_arch("x86_64".to_string()).clone(),
|
.set_arch("x86_64".to_string()).clone(),
|
||||||
).unwrap();
|
)?;
|
||||||
|
|
||||||
|
for package in pacwoman::locate_package("pacman".to_string())? {
|
||||||
|
println!("found package");
|
||||||
|
pacwoman::install_package(pacwoman::Mirror::new(url::Url::parse(
|
||||||
|
"https://geo.mirror.pkgbuild.com/$repo/os/$arch",
|
||||||
|
).unwrap()), package.1, package.0, true)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue