Ciborium replaced with bincode, and pacwrap-agent attained UX parity
- Refactored libalpm events into their own module - Agent parameters are acquired via a temporary file attached to the container (Still TODO: Provide a shared communication channel) - filesystem state files now contain magic values with file header verification - Miscellaneous tidy up work
This commit is contained in:
parent
f3b2b3861d
commit
b84f90d17d
15 changed files with 283 additions and 216 deletions
|
@ -1,54 +1,71 @@
|
||||||
use std::{fs, io::Stdin, process::exit};
|
use std::{fs::{self, File}, process::exit, os::unix::prelude::FileExt, env};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use pacwrap_core::{constants::{BOLD, RESET},
|
use pacwrap_core::{sync::{self, AlpmConfigData,
|
||||||
utils::{print_error, print_warning},
|
|
||||||
sync::{self, AlpmConfigData,
|
|
||||||
query_event,
|
|
||||||
progress_event::{self, ProgressEvent},
|
|
||||||
utils::{erroneous_transaction,
|
utils::{erroneous_transaction,
|
||||||
erroneous_preparation},
|
erroneous_preparation},
|
||||||
transaction::{TransactionMetadata,
|
transaction::{TransactionHandle,
|
||||||
TransactionHandle,
|
|
||||||
TransactionType,
|
TransactionType,
|
||||||
|
TransactionMetadata,
|
||||||
|
TransactionParameters,
|
||||||
Error,
|
Error,
|
||||||
Result}}};
|
Result, MAGIC_NUMBER},
|
||||||
|
event::{download::{DownloadCallback, download_event}, progress::{ProgressEvent, callback}, query::questioncb}},
|
||||||
|
utils::{print_error, print_warning, read_le_32}, constants::{RESET, BOLD}};
|
||||||
|
|
||||||
pub fn transact() {
|
pub fn transact() {
|
||||||
let mut stdin = std::io::stdin();
|
let mut header_buffer = vec![0; 7];
|
||||||
let alpm_remotes: AlpmConfigData = deserialize_stdin(&mut stdin);
|
let mut file = match File::open("/tmp/agent_params") {
|
||||||
let mode: TransactionType = deserialize_stdin(&mut stdin);
|
Ok(file) => file,
|
||||||
let alpm = sync::instantiate_alpm_agent(&alpm_remotes);
|
Err(_) => {
|
||||||
let mut meta: TransactionMetadata = deserialize_stdin(&mut stdin);
|
if let Ok(var) = env::var("SHELL") {
|
||||||
let mut handle = TransactionHandle::new(alpm, &mut meta);
|
if ! var.is_empty() {
|
||||||
|
print_error("Direct execution of this binary is unsupported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(error) = conduct_transaction(&mut handle, mode) {
|
exit(2);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(error) = file.read_exact_at(&mut header_buffer, 0) {
|
||||||
|
print_error(format!("'{}/tmp/agent_params{}': {error}", *BOLD, *RESET));
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
let magic = read_le_32(&header_buffer, 0);
|
||||||
|
let major: u8 = env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap();
|
||||||
|
let minor: u8 = env!("CARGO_PKG_VERSION_MINOR").parse().unwrap();
|
||||||
|
let patch: u8 = env!("CARGO_PKG_VERSION_PATCH").parse().unwrap();
|
||||||
|
|
||||||
|
if magic != MAGIC_NUMBER {
|
||||||
|
print_error(format!("Magic number {magic} != {MAGIC_NUMBER}"));
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if major != header_buffer[4] || minor != header_buffer[5] || patch != header_buffer[6] {
|
||||||
|
print_error(format!("{major}.{minor}.{patch} != {}.{}.{}", header_buffer[4], header_buffer[5], header_buffer[6]));
|
||||||
|
exit(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
let params: TransactionParameters = deserialize(&mut file);
|
||||||
|
let alpm_remotes: AlpmConfigData = deserialize(&mut file);
|
||||||
|
let mut metadata: TransactionMetadata = deserialize(&mut file);
|
||||||
|
let alpm = sync::instantiate_alpm_agent(&alpm_remotes);
|
||||||
|
let mut handle = TransactionHandle::new(alpm, &mut metadata);
|
||||||
|
|
||||||
|
if let Err(error) = conduct_transaction(&mut handle, params) {
|
||||||
print_error(error);
|
print_error(error);
|
||||||
handle.alpm_mut().trans_release().ok();
|
handle.alpm_mut().trans_release().ok();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_stdin<T: for<'de> Deserialize<'de>>(stdin: &mut Stdin) -> T {
|
fn conduct_transaction(handle: &mut TransactionHandle, agent: TransactionParameters) -> Result<()> {
|
||||||
match ciborium::from_reader::<T, &mut Stdin>(stdin) {
|
|
||||||
Ok(meta) => meta,
|
|
||||||
Err(err) => {
|
|
||||||
if let ciborium::de::Error::Semantic(_, error) = err {
|
|
||||||
match error.contains("integer `10`") {
|
|
||||||
false => print_error(format!("Deserialization failure occurred with input from {}STDIN{}: {error}", *BOLD, *RESET)),
|
|
||||||
true => print_error("Interactive user input is not supported by this program."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn conduct_transaction(handle: &mut TransactionHandle, action: TransactionType) -> Result<()> {
|
|
||||||
let flags = handle.retrieve_flags();
|
let flags = handle.retrieve_flags();
|
||||||
let mode = handle.get_mode().clone();
|
let mode = agent.mode();
|
||||||
|
let action = agent.action();
|
||||||
|
|
||||||
if let Err(error) = handle.alpm_mut().trans_init(flags.1.unwrap()) {
|
if let Err(error) = handle.alpm_mut().trans_init(flags.1.unwrap()) {
|
||||||
Err(Error::InitializationFailure(error.to_string().into()))?
|
Err(Error::InitializationFailure(error.to_string().into()))?
|
||||||
|
@ -68,9 +85,9 @@ fn conduct_transaction(handle: &mut TransactionHandle, action: TransactionType)
|
||||||
erroneous_preparation(error)?
|
erroneous_preparation(error)?
|
||||||
}
|
}
|
||||||
|
|
||||||
handle.alpm().set_progress_cb(ProgressEvent::new(&action), progress_event::callback(&mode));
|
handle.alpm().set_progress_cb(ProgressEvent::new(&action), callback(&mode));
|
||||||
handle.alpm().set_question_cb((), query_event::questioncb);
|
handle.alpm().set_question_cb((), questioncb);
|
||||||
//handle.alpm().set_dl_cb(DownloadCallback::new(), dl_event::download_event);
|
handle.alpm().set_dl_cb(DownloadCallback::new(agent.bytes(), agent.files()), download_event);
|
||||||
|
|
||||||
if let Err(error) = handle.alpm_mut().trans_commit() {
|
if let Err(error) = handle.alpm_mut().trans_commit() {
|
||||||
erroneous_transaction(error)?
|
erroneous_transaction(error)?
|
||||||
|
@ -85,3 +102,13 @@ fn conduct_transaction(handle: &mut TransactionHandle, action: TransactionType)
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize<T: for<'de> Deserialize<'de>>(stdin: &mut File) -> T {
|
||||||
|
match bincode::deserialize_from::<&mut File, T>(stdin) {
|
||||||
|
Ok(meta) => meta,
|
||||||
|
Err(error) => {
|
||||||
|
print_error(format!("Deserilization error: {}", error.as_ref()));
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use pacwrap_core::utils::{print_error, Arguments, arguments::Operand};
|
use pacwrap_core::utils::{print_error, Arguments, arguments::Operand};
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
mod agent;
|
mod agent;
|
||||||
|
|
||||||
|
@ -9,14 +8,6 @@ fn main() {
|
||||||
|
|
||||||
match param {
|
match param {
|
||||||
Operand::Value("transact") => agent::transact(),
|
Operand::Value("transact") => agent::transact(),
|
||||||
_ => print_error(arguments.invalid_operand().to_string())
|
_ => print_error("Direct execution of this binary is unsupported.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
struct Test {
|
|
||||||
string: String,
|
|
||||||
version_major: i16,
|
|
||||||
version_minor: i16,
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ lazy_static! {
|
||||||
pub static ref CACHE_DIR: &'static str = env_default("PACWRAP_CACHE_DIR", PACWRAP_CACHE_DIR);
|
pub static ref CACHE_DIR: &'static str = env_default("PACWRAP_CACHE_DIR", PACWRAP_CACHE_DIR);
|
||||||
pub static ref CONFIG_DIR: &'static str = env_default("PACWRAP_CONFIG_DIR", PACWRAP_CONFIG_DIR);
|
pub static ref CONFIG_DIR: &'static str = env_default("PACWRAP_CONFIG_DIR", PACWRAP_CONFIG_DIR);
|
||||||
pub static ref DATA_DIR: &'static str = env_default("PACWRAP_DATA_DIR", PACWRAP_DATA_DIR);
|
pub static ref DATA_DIR: &'static str = env_default("PACWRAP_DATA_DIR", PACWRAP_DATA_DIR);
|
||||||
|
pub static ref PACWRAP_AGENT_FILE: &'static str = format!("/run/user/{}/pacwrap_agent_{}", geteuid(), &id()).leak();
|
||||||
pub static ref XDG_RUNTIME_DIR: String = format!("/run/user/{}", geteuid());
|
pub static ref XDG_RUNTIME_DIR: String = format!("/run/user/{}", geteuid());
|
||||||
pub static ref DBUS_SOCKET: String = format!("/run/user/{}/pacwrap_dbus_{}", geteuid(), &id());
|
pub static ref DBUS_SOCKET: String = format!("/run/user/{}/pacwrap_dbus_{}", geteuid(), &id());
|
||||||
pub static ref LOG_LOCATION: &'static str = format!("{}/pacwrap.log", *DATA_DIR).leak();
|
pub static ref LOG_LOCATION: &'static str = format!("{}/pacwrap.log", *DATA_DIR).leak();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{process::{Child, Command, Stdio}, io::Error, env::var};
|
use std::{process::{Child, Command}, io::Error, env::var};
|
||||||
|
|
||||||
use crate::{constants::{BWRAP_EXECUTABLE, self},
|
use crate::{constants::{BWRAP_EXECUTABLE, self, PACWRAP_AGENT_FILE},
|
||||||
config::InstanceHandle,
|
config::InstanceHandle,
|
||||||
ErrorKind};
|
ErrorKind};
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ pub fn execute_agent(ins: &InstanceHandle) -> Result<Child,Error> {
|
||||||
|
|
||||||
Command::new(BWRAP_EXECUTABLE)
|
Command::new(BWRAP_EXECUTABLE)
|
||||||
.env_clear()
|
.env_clear()
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.arg("--bind").arg(&ins.vars().root()).arg("/mnt")
|
.arg("--bind").arg(&ins.vars().root()).arg("/mnt")
|
||||||
.arg("--tmpfs").arg("/tmp")
|
.arg("--tmpfs").arg("/tmp")
|
||||||
.arg("--tmpfs").arg("/etc")
|
.arg("--tmpfs").arg("/etc")
|
||||||
.arg("--symlink").arg("/mnt/usr").arg("/usr")
|
.arg("--symlink").arg("/mnt/usr").arg("/usr")
|
||||||
|
.arg("--ro-bind").arg(*PACWRAP_AGENT_FILE).arg("/tmp/agent_params")
|
||||||
.arg("--ro-bind").arg(format!("{}/lib", dist_img)).arg("/lib64")
|
.arg("--ro-bind").arg(format!("{}/lib", dist_img)).arg("/lib64")
|
||||||
.arg("--ro-bind").arg(format!("{}/bin", dist_img)).arg("/bin")
|
.arg("--ro-bind").arg(format!("{}/bin", dist_img)).arg("/bin")
|
||||||
.arg("--ro-bind").arg("/etc/resolv.conf").arg("/etc/resolv.conf")
|
.arg("--ro-bind").arg("/etc/resolv.conf").arg("/etc/resolv.conf")
|
||||||
|
|
|
@ -7,7 +7,7 @@ use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::{utils::{print_warning, print_error},
|
use crate::{utils::{print_warning, print_error},
|
||||||
constants::{BAR_GREEN, RESET, BOLD, ARROW_RED, CACHE_DIR, DATA_DIR, CONFIG_DIR},
|
constants::{BAR_GREEN, RESET, BOLD, ARROW_RED, CACHE_DIR, DATA_DIR, CONFIG_DIR},
|
||||||
sync::dl_event::DownloadCallback,
|
sync::event::download::{DownloadCallback, download_event},
|
||||||
config::{InsVars,
|
config::{InsVars,
|
||||||
InstanceHandle,
|
InstanceHandle,
|
||||||
cache::InstanceCache}};
|
cache::InstanceCache}};
|
||||||
|
@ -18,9 +18,7 @@ lazy_static! {
|
||||||
static ref DEFAULT_ALPM_CONF: AlpmConfigData = AlpmConfigData::new();
|
static ref DEFAULT_ALPM_CONF: AlpmConfigData = AlpmConfigData::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod progress_event;
|
pub mod event;
|
||||||
pub mod dl_event;
|
|
||||||
pub mod query_event;
|
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
pub mod filesystem;
|
pub mod filesystem;
|
||||||
|
@ -104,7 +102,7 @@ fn synchronize_database(cache: &InstanceCache, force: bool) {
|
||||||
let mut handle = alpm_handle(&ins.vars(), db_path, &*DEFAULT_ALPM_CONF);
|
let mut handle = alpm_handle(&ins.vars(), db_path, &*DEFAULT_ALPM_CONF);
|
||||||
|
|
||||||
println!("{} {}Synchronising package databases...{}", *BAR_GREEN, *BOLD, *RESET);
|
println!("{} {}Synchronising package databases...{}", *BAR_GREEN, *BOLD, *RESET);
|
||||||
handle.set_dl_cb(DownloadCallback::new(0, 0), dl_event::download_event);
|
handle.set_dl_cb(DownloadCallback::new(0, 0), download_event);
|
||||||
|
|
||||||
if let Err(err) = handle.syncdbs_mut().update(force) {
|
if let Err(err) = handle.syncdbs_mut().update(force) {
|
||||||
print_error(format!("Unable to initialize transaction: {}.",err.to_string()));
|
print_error(format!("Unable to initialize transaction: {}.",err.to_string()));
|
||||||
|
|
16
pacwrap-core/src/sync/event.rs
Normal file
16
pacwrap-core/src/sync/event.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
pub mod download;
|
||||||
|
pub mod query;
|
||||||
|
pub mod progress;
|
||||||
|
|
||||||
|
fn whitespace(total: usize, current: usize) -> String {
|
||||||
|
let mut whitespace = String::new();
|
||||||
|
let difference = total-current;
|
||||||
|
|
||||||
|
if difference > 0 {
|
||||||
|
for _ in 0..difference {
|
||||||
|
whitespace.push_str(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
whitespace
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ use dialoguer::console::Term;
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
use super::utils::whitespace;
|
use super::whitespace;
|
||||||
|
|
||||||
lazy_static!{
|
lazy_static!{
|
||||||
static ref INIT: ProgressStyle = ProgressStyle::with_template(" {spinner:.green} {msg}")
|
static ref INIT: ProgressStyle = ProgressStyle::with_template(" {spinner:.green} {msg}")
|
||||||
|
@ -92,7 +92,8 @@ pub fn download_event(file: &str, download: AnyDownloadEvent, this: &mut Downloa
|
||||||
this.files_done += 1;
|
this.files_done += 1;
|
||||||
|
|
||||||
total.set_message(format!("Total ({}{}/{})",
|
total.set_message(format!("Total ({}{}/{})",
|
||||||
whitespace(this.total_files_len, this.files_done.to_string().len()),
|
whitespace(this.total_files_len,
|
||||||
|
this.files_done.to_string().len()),
|
||||||
this.files_done,
|
this.files_done,
|
||||||
this.total_files));
|
this.total_files));
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use alpm::Progress;
|
use alpm::Progress;
|
||||||
use dialoguer::console::Term;
|
use dialoguer::console::Term;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
|
||||||
use crate::constants::{BOLD, RESET};
|
use crate::{constants::{BOLD, RESET}, sync::transaction::{TransactionType, TransactionMode}};
|
||||||
|
use super::whitespace;
|
||||||
use super::{utils::whitespace, transaction::{TransactionType, TransactionMode}};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ProgressEvent {
|
pub struct ProgressEvent {
|
||||||
progress: ProgressBar,
|
progress: ProgressBar,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
style: ProgressStyle,
|
style: ProgressStyle,
|
||||||
current: Rc<str>,
|
current: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgressEvent {
|
impl ProgressEvent {
|
||||||
|
@ -60,7 +57,7 @@ pub fn condensed(progress: Progress, pkgname: &str, percent: i32, howmany: usize
|
||||||
let progress_name: String = name(progress,pkgname);
|
let progress_name: String = name(progress,pkgname);
|
||||||
let whitespace = whitespace(total.to_string().len(), pos.to_string().len());
|
let whitespace = whitespace(total.to_string().len(), pos.to_string().len());
|
||||||
|
|
||||||
if this.current.as_ref() != "" {
|
if this.current != "" {
|
||||||
this.progress = ProgressBar::new(howmany as u64);
|
this.progress = ProgressBar::new(howmany as u64);
|
||||||
this.progress.set_message(format!("({}{whitespace}{pos}{}/{}{total}{}) {progress_name}", *BOLD, *RESET, *BOLD, *RESET));
|
this.progress.set_message(format!("({}{whitespace}{pos}{}/{}{total}{}) {progress_name}", *BOLD, *RESET, *BOLD, *RESET));
|
||||||
this.progress.set_style(this.style.clone());
|
this.progress.set_style(this.style.clone());
|
||||||
|
@ -95,7 +92,7 @@ fn name(progress: Progress, pkgname: &str) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident(progress: Progress, pkgname: &str) -> Rc<str> {
|
fn ident(progress: Progress, pkgname: &str) -> String {
|
||||||
match progress {
|
match progress {
|
||||||
Progress::KeyringStart => "keyring",
|
Progress::KeyringStart => "keyring",
|
||||||
Progress::IntegrityStart => "integrity",
|
Progress::IntegrityStart => "integrity",
|
|
@ -1,84 +1,53 @@
|
||||||
use std::fmt;
|
use std::{fs::{self, File, Metadata},
|
||||||
use std::fs::{self, File, Metadata};
|
io::Read,
|
||||||
use std::os::unix::fs::symlink;
|
os::unix::fs::symlink,
|
||||||
use std::os::unix::prelude::MetadataExt;
|
os::unix::prelude::MetadataExt,
|
||||||
use std::path::Path;
|
path::Path,
|
||||||
use std::sync::Arc;
|
sync::{Arc, mpsc::{Sender, self, Receiver}},
|
||||||
use std::sync::mpsc::{Sender, self, Receiver};
|
collections::{HashMap, HashSet}};
|
||||||
|
|
||||||
use dialoguer::console::Term;
|
use dialoguer::console::Term;
|
||||||
use rayon::prelude::*;
|
use rayon::{prelude::*, {ThreadPool, ThreadPoolBuilder}};
|
||||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use indicatif::{ProgressBar, ProgressStyle, ProgressDrawTarget};
|
use indicatif::{ProgressBar, ProgressStyle, ProgressDrawTarget};
|
||||||
use serde::{Serialize, Deserialize, Deserializer, Serializer, de::Visitor};
|
use serde::{Serialize, Deserialize};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
use crate::ErrorKind;
|
use crate::{ErrorKind,
|
||||||
use crate::config::{InstanceHandle, InstanceCache, InstanceType::*};
|
config::{InstanceHandle, InstanceCache, InstanceType::*},
|
||||||
use crate::constants::{RESET, BOLD, ARROW_CYAN, BAR_GREEN, DATA_DIR};
|
constants::{RESET, BOLD, ARROW_CYAN, BAR_GREEN, DATA_DIR},
|
||||||
use crate::utils::{print_warning, print_error};
|
utils::{print_warning, print_error, read_le_32}};
|
||||||
|
|
||||||
impl Serialize for FileType {
|
static VERSION: u32 = 1;
|
||||||
fn serialize<D: Serializer>(&self, serializer: D) -> Result<D::Ok, D::Error>
|
static MAGIC_NUMBER: u32 = 408948530;
|
||||||
where D: serde::Serializer {
|
|
||||||
serializer.serialize_i64(self.as_integer())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl <'de>Deserialize<'de> for FileType {
|
|
||||||
fn deserialize<D: Deserializer<'de>>(serializer: D) -> Result<Self, D::Error>
|
|
||||||
where D: serde::Deserializer<'de> {
|
|
||||||
serializer.deserialize_i64(FileTypeVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FileTypeVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for FileTypeVisitor {
|
|
||||||
type Value = FileType;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(formatter, "an integer between `0` and `2`")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
|
|
||||||
where E: serde::de::Error, {
|
|
||||||
let value = v.into();
|
|
||||||
|
|
||||||
if let FileType::Invalid(v) = value {
|
|
||||||
Err(E::invalid_value(serde::de::Unexpected::Signed(v), &self))?
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
struct FileSystemState {
|
struct FileSystemState {
|
||||||
|
magic: u32,
|
||||||
|
version: u32,
|
||||||
files: IndexMap<Arc<str>, (FileType, Arc<str>)>
|
files: IndexMap<Arc<str>, (FileType, Arc<str>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileSystemState {
|
impl FileSystemState {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
files: IndexMap::new()
|
magic: MAGIC_NUMBER,
|
||||||
|
version: VERSION,
|
||||||
|
files: IndexMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
enum FileType {
|
enum FileType {
|
||||||
HardLink,
|
HardLink,
|
||||||
SymLink,
|
SymLink,
|
||||||
Directory,
|
Directory,
|
||||||
Invalid(i64),
|
Invalid(i8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<i64> for FileType {
|
impl From<i8> for FileType {
|
||||||
fn from(integer: i64) -> Self {
|
fn from(integer: i8) -> Self {
|
||||||
match integer {
|
match integer {
|
||||||
2 => Self::Directory,
|
2 => Self::Directory,
|
||||||
1 => Self::SymLink,
|
1 => Self::SymLink,
|
||||||
|
@ -100,23 +69,11 @@ impl From<Metadata> for FileType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileType {
|
|
||||||
fn as_integer(&self) -> i64 {
|
|
||||||
match self {
|
|
||||||
Self::Directory => 2,
|
|
||||||
Self::SymLink => 1,
|
|
||||||
Self::HardLink => 0,
|
|
||||||
Self::Invalid(i) => *i,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SyncMessage {
|
enum SyncMessage {
|
||||||
LinkComplete(Arc<str>),
|
LinkComplete(Arc<str>),
|
||||||
SaveState(Arc<str>, FileSystemState),
|
SaveState(Arc<str>, FileSystemState),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct FileSystemStateSync<'a> {
|
pub struct FileSystemStateSync<'a> {
|
||||||
state_map: HashMap<Arc<str>, FileSystemState>,
|
state_map: HashMap<Arc<str>, FileSystemState>,
|
||||||
state_map_prev: HashMap<Arc<str>, FileSystemState>,
|
state_map_prev: HashMap<Arc<str>, FileSystemState>,
|
||||||
|
@ -228,39 +185,53 @@ impl <'a>FileSystemStateSync<'a> {
|
||||||
return st.clone()
|
return st.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut header_buffer = vec![0; 8];
|
||||||
let path = format!("{}/state/{}.dat", *DATA_DIR, instance);
|
let path = format!("{}/state/{}.dat", *DATA_DIR, instance);
|
||||||
let file = match File::open(&path) {
|
let mut file = match File::open(&path) {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let state = FileSystemState::new();
|
|
||||||
|
|
||||||
if err.kind() != std::io::ErrorKind::NotFound {
|
if err.kind() != std::io::ErrorKind::NotFound {
|
||||||
print_warning(format!("Reading '{}': {}", path, err.kind()));
|
print_error(format!("'{}': {}", path, err.kind()));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state_map_prev.insert(instance.clone(), state.clone());
|
return self.blank_state(instance);
|
||||||
return state
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match ciborium::from_reader::<FileSystemState, File>(file) {
|
if let Err(error) = file.read_exact(&mut header_buffer) {
|
||||||
|
print_error(format!("'{}{instance}{}.dat': {error}", *BOLD, *RESET));
|
||||||
|
return self.blank_state(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
let magic = read_le_32(&header_buffer, 0);
|
||||||
|
let version = read_le_32(&header_buffer, 4);
|
||||||
|
|
||||||
|
if magic != MAGIC_NUMBER {
|
||||||
|
print_warning(format!("'{}{instance}{}.dat': Magic number mismatch ({MAGIC_NUMBER} != {magic})", *BOLD, *RESET));
|
||||||
|
return self.blank_state(instance);
|
||||||
|
} else if version != VERSION {
|
||||||
|
return self.blank_state(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
match bincode::deserialize_from::<&File, FileSystemState>(&file) {
|
||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
self.state_map_prev.insert(instance.clone(), state.clone());
|
self.state_map_prev.insert(instance.clone(), state.clone());
|
||||||
state
|
state
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let state = FileSystemState::new();
|
print_error(format!("Deserialization failure occurred with '{}{instance}{}.dat': {}", *BOLD, *RESET, err.as_ref()));
|
||||||
|
return self.blank_state(instance);
|
||||||
if let ciborium::de::Error::Semantic(_, error) = err {
|
|
||||||
print_error(format!("Deserialization failure occurred with '{}{instance}{}.dat': {error}", *BOLD, *RESET));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.state_map_prev.insert(instance.clone(), state.clone());
|
|
||||||
state
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn blank_state(&mut self, instance: &Arc<str>) -> FileSystemState {
|
||||||
|
let state = FileSystemState::new();
|
||||||
|
|
||||||
|
self.state_map_prev.insert(instance.clone(), state.clone());
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
fn write(&mut self, tx: Sender<()>, ds: FileSystemState, dep: Arc<str>) {
|
fn write(&mut self, tx: Sender<()>, ds: FileSystemState, dep: Arc<str>) {
|
||||||
let path: &str = &format!("{}/state/{}.dat", *DATA_DIR, dep);
|
let path: &str = &format!("{}/state/{}.dat", *DATA_DIR, dep);
|
||||||
let output = match File::create(path) {
|
let output = match File::create(path) {
|
||||||
|
@ -272,7 +243,7 @@ impl <'a>FileSystemStateSync<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pool().unwrap().spawn(move ||{
|
self.pool().unwrap().spawn(move ||{
|
||||||
if let Err(err) = ciborium::into_writer(&ds, output) {
|
if let Err(err) = bincode::serialize_into(output, &ds) {
|
||||||
print_error(format!("Serialization failure occurred with '{}{dep}{}.dat': {}", *BOLD, *RESET, err.to_string()));
|
print_error(format!("Serialization failure occurred with '{}{dep}{}.dat': {}", *BOLD, *RESET, err.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{borrow::Cow, collections::HashSet, fmt::{Display, Formatter}};
|
use std::{borrow::Cow, collections::HashSet, fmt::{Display, Formatter}, fs::remove_file};
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use alpm::{Alpm, PackageReason, TransFlag};
|
use alpm::{Alpm, PackageReason, TransFlag};
|
||||||
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{config,
|
use crate::{config,
|
||||||
config::InstanceHandle,
|
config::InstanceHandle,
|
||||||
constants::{RESET, BOLD, ARROW_CYAN, BAR_CYAN, ARROW_RED},
|
constants::{RESET, BOLD, ARROW_CYAN, BAR_CYAN, ARROW_RED, PACWRAP_AGENT_FILE},
|
||||||
sync::{
|
sync::{
|
||||||
resolver_local::LocalDependencyResolver,
|
resolver_local::LocalDependencyResolver,
|
||||||
resolver::DependencyResolver,
|
resolver::DependencyResolver,
|
||||||
|
@ -29,8 +29,15 @@ mod stage;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
pub static MAGIC_NUMBER: u32 = 663445956;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
AgentError,
|
TransactionFailureAgent,
|
||||||
|
ParameterAcquisitionFailure,
|
||||||
|
DeserializationFailure,
|
||||||
|
InvalidMagicNumber,
|
||||||
|
AgentVersionMismatch,
|
||||||
NothingToDo,
|
NothingToDo,
|
||||||
DependentContainerMissing(String),
|
DependentContainerMissing(String),
|
||||||
RecursionDepthExceeded(isize),
|
RecursionDepthExceeded(isize),
|
||||||
|
@ -104,6 +111,19 @@ pub struct TransactionMetadata<'a> {
|
||||||
flags: (u8, u32)
|
flags: (u8, u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct TransactionParameters {
|
||||||
|
magic: u32,
|
||||||
|
ver_major: u8,
|
||||||
|
ver_minor: u8,
|
||||||
|
ver_patch: u8,
|
||||||
|
bytes: u64,
|
||||||
|
files: u64,
|
||||||
|
action: TransactionType,
|
||||||
|
mode: TransactionMode,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
impl TransactionMode {
|
impl TransactionMode {
|
||||||
fn bool(&self) -> bool {
|
fn bool(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
@ -188,6 +208,10 @@ impl Display for Error {
|
||||||
Self::InitializationFailure(msg) => write!(fmter, "Failure to initialize transaction: {msg}"),
|
Self::InitializationFailure(msg) => write!(fmter, "Failure to initialize transaction: {msg}"),
|
||||||
Self::PreparationFailure(msg) => write!(fmter, "Failure to prepare transaction: {msg}"),
|
Self::PreparationFailure(msg) => write!(fmter, "Failure to prepare transaction: {msg}"),
|
||||||
Self::TransactionFailure(msg) => write!(fmter, "Failure to commit transaction: {msg}"),
|
Self::TransactionFailure(msg) => write!(fmter, "Failure to commit transaction: {msg}"),
|
||||||
|
Self::DeserializationFailure => write!(fmter, "Deserialization of input parameters failed."),
|
||||||
|
Self::ParameterAcquisitionFailure => write!(fmter, "Failure to acquire agent runtime parameters."),
|
||||||
|
Self::AgentVersionMismatch => write!(fmter, "Agent binary mismatch."),
|
||||||
|
Self::InvalidMagicNumber => write!(fmter, "Deserialization of input parameters failed: Invalid magic number."),
|
||||||
Self::InternalError(msg) => write!(fmter, "Internal failure: {msg}"),
|
Self::InternalError(msg) => write!(fmter, "Internal failure: {msg}"),
|
||||||
_ => write!(fmter, "Nothing to do."),
|
_ => write!(fmter, "Nothing to do."),
|
||||||
}
|
}
|
||||||
|
@ -396,14 +420,16 @@ impl <'a>TransactionHandle<'a> {
|
||||||
|
|
||||||
fn release_on_fail(self, error: Error) {
|
fn release_on_fail(self, error: Error) {
|
||||||
match error {
|
match error {
|
||||||
Error::AgentError => (), _ => print_error(error),
|
Error::TransactionFailureAgent => (), _ => print_error(error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove_file(*PACWRAP_AGENT_FILE).ok();
|
||||||
println!("{} Transaction failed.", *ARROW_RED);
|
println!("{} Transaction failed.", *ARROW_RED);
|
||||||
drop(self);
|
drop(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self) {
|
pub fn release(self) {
|
||||||
|
remove_file(*PACWRAP_AGENT_FILE).ok();
|
||||||
drop(self);
|
drop(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,3 +465,34 @@ impl <'a>TransactionHandle<'a> {
|
||||||
&self.meta
|
&self.meta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TransactionParameters {
|
||||||
|
fn new(t_type: TransactionType, t_mode: TransactionMode, dl_size: u64, amount: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
magic: MAGIC_NUMBER,
|
||||||
|
ver_major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
|
||||||
|
ver_minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
|
||||||
|
ver_patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
|
||||||
|
bytes: dl_size,
|
||||||
|
files: amount as u64,
|
||||||
|
action: t_type,
|
||||||
|
mode: t_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bytes(&self) -> u64 {
|
||||||
|
self.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn files(&self) -> usize {
|
||||||
|
self.files as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mode(&self) -> TransactionMode {
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn action(&self) -> TransactionType {
|
||||||
|
self.action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,24 +1,28 @@
|
||||||
use std::process::ChildStdin;
|
use std::{fs::File, path::Path};
|
||||||
|
|
||||||
use alpm::Alpm;
|
use alpm::Alpm;
|
||||||
use dialoguer::console::Term;
|
use dialoguer::console::Term;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use crate::{exec::utils::execute_agent, sync::{DEFAULT_ALPM_CONF, utils::erroneous_preparation, self}};
|
|
||||||
use simplebyteunit::simplebyteunit::{SI, ToByteUnit};
|
use simplebyteunit::simplebyteunit::{SI, ToByteUnit};
|
||||||
|
|
||||||
use crate::constants::{RESET, BOLD, DIM};
|
use crate::{exec::utils::execute_agent,
|
||||||
|
sync::{DEFAULT_ALPM_CONF, utils::erroneous_preparation, self},
|
||||||
|
ErrorKind,
|
||||||
|
utils::prompt::prompt,
|
||||||
|
constants::{PACWRAP_AGENT_FILE, RESET, BOLD, DIM},
|
||||||
|
config::InstanceHandle,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::utils::prompt::prompt;
|
|
||||||
use crate::config::InstanceHandle;
|
|
||||||
use super::{Transaction,
|
use super::{Transaction,
|
||||||
TransactionState,
|
TransactionState,
|
||||||
TransactionHandle,
|
TransactionHandle,
|
||||||
TransactionAggregator,
|
TransactionAggregator,
|
||||||
TransactionFlags,
|
TransactionFlags,
|
||||||
|
TransactionParameters,
|
||||||
Result,
|
Result,
|
||||||
Error};
|
Error};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct Commit {
|
pub struct Commit {
|
||||||
state: TransactionState,
|
state: TransactionState,
|
||||||
keyring: bool,
|
keyring: bool,
|
||||||
|
@ -53,56 +57,72 @@ impl Transaction for Commit {
|
||||||
erroneous_preparation(error)?
|
erroneous_preparation(error)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(result) = confirm(&self.state, ag, handle) {
|
let result = confirm(&self.state, ag, handle);
|
||||||
|
let download = result.1.unwrap_or((0,0));
|
||||||
|
|
||||||
|
if let Some(result) = result.0 {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle.set_alpm(None);
|
handle.set_alpm(None);
|
||||||
|
write_agent_params(ag, handle, download)?;
|
||||||
|
|
||||||
match execute_agent(inshandle) {
|
let mut agent = match execute_agent(inshandle) {
|
||||||
Ok(mut child) => {
|
Ok(child) => child,
|
||||||
let stdin = child.stdin.take().unwrap();
|
Err(error) => Err(Error::TransactionFailure(format!("Execution of agent failed: {}", error)))?,
|
||||||
|
};
|
||||||
|
|
||||||
write_to_stdin(&*DEFAULT_ALPM_CONF, &stdin)?;
|
match agent.wait() {
|
||||||
write_to_stdin(ag.action(), &stdin)?;
|
Ok(exit_status) => match exit_status.code().unwrap_or(-1) {
|
||||||
write_to_stdin(handle.metadata(), &stdin)?;
|
0 => {
|
||||||
|
if self.keyring {
|
||||||
|
ag.keyring_update(inshandle)?;
|
||||||
|
}
|
||||||
|
|
||||||
match child.wait() {
|
handle.set_alpm(Some(sync::instantiate_alpm(inshandle)));
|
||||||
Ok(exit_status) => match exit_status.code().unwrap_or(0) {
|
handle.apply_configuration(inshandle, ag.flags().intersects(TransactionFlags::CREATE));
|
||||||
1 => Err(Error::AgentError),
|
ag.logger().log(format!("container {instance}'s {state} transaction complete")).ok();
|
||||||
0 => {
|
state_transition(&self.state, handle, true)
|
||||||
if self.keyring {
|
},
|
||||||
ag.keyring_update(inshandle)?;
|
1 => Err(Error::TransactionFailureAgent),
|
||||||
}
|
2 => Err(Error::ParameterAcquisitionFailure),
|
||||||
|
3 => Err(Error::DeserializationFailure),
|
||||||
handle.set_alpm(Some(sync::instantiate_alpm(inshandle)));
|
4 => Err(Error::InvalidMagicNumber),
|
||||||
handle.apply_configuration(inshandle, ag.flags().intersects(TransactionFlags::CREATE));
|
5 => Err(Error::AgentVersionMismatch),
|
||||||
ag.logger().log(format!("container {instance}'s {state} transaction complete")).ok();
|
_ => Err(Error::TransactionFailure(format!("Generic failure of agent: Exit code {}", exit_status.code().unwrap_or(-1))))?,
|
||||||
state_transition(&self.state, handle, true)
|
|
||||||
},
|
|
||||||
_ => Err(Error::TransactionFailure(format!("Generic failure of agent: Exit code {}", exit_status.code().unwrap_or(0))))?,
|
|
||||||
},
|
|
||||||
Err(error) => Err(Error::TransactionFailure(format!("Execution of agent failed: {}", error)))?,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Err(error) => Err(Error::TransactionFailure(format!("Execution of agent failed: {}", error)))?,
|
Err(error) => Err(Error::TransactionFailure(format!("Execution of agent failed: {}", error)))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_stdin<T: for<'de> Serialize>(input: &T, stdin: &ChildStdin) -> Result<()> {
|
fn write_agent_params(ag: &TransactionAggregator, handle: &TransactionHandle, download: (u64, usize)) -> Result<()> {
|
||||||
match ciborium::into_writer::<T, &ChildStdin>(input, stdin) {
|
let f = match File::create(Path::new(*PACWRAP_AGENT_FILE)) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(error) => Err(ErrorKind::IOError((*PACWRAP_AGENT_FILE).into(), error.kind()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
serialize(&TransactionParameters::new(*ag.action(), *handle.get_mode(), download.0, download.1), &f)?;
|
||||||
|
serialize(&*DEFAULT_ALPM_CONF, &f)?;
|
||||||
|
serialize(handle.metadata(), &f)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize<T: for<'de> Serialize>(input: &T, file: &File) -> Result<()> {
|
||||||
|
match bincode::serialize_into::<&File, T>(file, input) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(error) => Err(Error::TransactionFailure(format!("Agent data serialization failed: {}", error))),
|
Err(error) => Err(Error::TransactionFailure(format!("Agent data serialization failed: {}", error))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(state: &TransactionState, ag: &mut TransactionAggregator, handle: &mut TransactionHandle) -> Option<Result<TransactionState>> {
|
fn confirm(state: &TransactionState, ag: &mut TransactionAggregator, handle: &mut TransactionHandle) -> (Option<Result<TransactionState>>, Option<(u64, usize)>) {
|
||||||
|
let mut download = None;
|
||||||
|
|
||||||
if ! handle.get_mode().bool() || ag.flags().intersects(TransactionFlags::DATABASE_ONLY | TransactionFlags::FORCE_DATABASE) {
|
if ! handle.get_mode().bool() || ag.flags().intersects(TransactionFlags::DATABASE_ONLY | TransactionFlags::FORCE_DATABASE) {
|
||||||
summary(handle.alpm());
|
download = Some(summary(handle.alpm()));
|
||||||
|
|
||||||
if ag.flags().contains(TransactionFlags::PREVIEW) {
|
if ag.flags().contains(TransactionFlags::PREVIEW) {
|
||||||
return Some(state_transition(state, handle, false));
|
return (Some(state_transition(state, handle, false)), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! ag.flags().contains(TransactionFlags::NO_CONFIRM) {
|
if ! ag.flags().contains(TransactionFlags::NO_CONFIRM) {
|
||||||
|
@ -110,13 +130,13 @@ fn confirm(state: &TransactionState, ag: &mut TransactionAggregator, handle: &mu
|
||||||
let query = format!("Proceed with {action}?");
|
let query = format!("Proceed with {action}?");
|
||||||
|
|
||||||
if let Err(_) = prompt("::", format!("{}{query}{}", *BOLD, *RESET), true) {
|
if let Err(_) = prompt("::", format!("{}{query}{}", *BOLD, *RESET), true) {
|
||||||
return Some(state_transition(state, handle, false));
|
return (Some(state_transition(state, handle, false)), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handle.alpm_mut().trans_release().ok();
|
handle.alpm_mut().trans_release().ok();
|
||||||
None
|
(None, download)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_transition<'a>(state: &TransactionState, handle: &mut TransactionHandle, updated: bool) -> Result<TransactionState> {
|
fn state_transition<'a>(state: &TransactionState, handle: &mut TransactionHandle, updated: bool) -> Result<TransactionState> {
|
||||||
|
@ -129,8 +149,7 @@ fn state_transition<'a>(state: &TransactionState, handle: &mut TransactionHandle
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
fn summary(handle: &Alpm) -> (u64, usize) {
|
||||||
fn summary(handle: &Alpm) {
|
|
||||||
let mut installed_size_old: i64 = 0;
|
let mut installed_size_old: i64 = 0;
|
||||||
let mut installed_size: i64 = 0;
|
let mut installed_size: i64 = 0;
|
||||||
let mut download: i64 = 0;
|
let mut download: i64 = 0;
|
||||||
|
@ -184,8 +203,8 @@ fn summary(handle: &Alpm) {
|
||||||
|
|
||||||
if download > 0 {
|
if download > 0 {
|
||||||
println!("{}Total Download Size{}: {}", *BOLD, *RESET, download.to_byteunit(SI));
|
println!("{}Total Download Size{}: {}", *BOLD, *RESET, download.to_byteunit(SI));
|
||||||
//handle.set_dl_cb(DownloadCallback::new(download as u64, files_to_download), dl_event::download_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
|
(download as u64, files_to_download)
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,18 +60,6 @@ impl AlpmUtils for Alpm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn whitespace(total: usize, current: usize) -> String {
|
|
||||||
let difference = total-current;
|
|
||||||
let mut whitespace = String::new();
|
|
||||||
if difference > 0 {
|
|
||||||
for _ in 0..difference {
|
|
||||||
whitespace.push_str(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
whitespace
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn erroneous_transaction<'a>(error: (CommitResult<'a>, alpm::Error)) -> Result<()> {
|
pub fn erroneous_transaction<'a>(error: (CommitResult<'a>, alpm::Error)) -> Result<()> {
|
||||||
match error.0 {
|
match error.0 {
|
||||||
CommitResult::FileConflict(file) => {
|
CommitResult::FileConflict(file) => {
|
||||||
|
|
|
@ -52,7 +52,6 @@ pub fn is_color_terminal() -> bool {
|
||||||
is_dumb && isatty(0).is_ok() && isatty(1).is_ok()
|
is_dumb && isatty(0).is_ok() && isatty(1).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn is_truecolor_terminal() -> bool {
|
pub fn is_truecolor_terminal() -> bool {
|
||||||
let colorterm = match var("COLORTERM") {
|
let colorterm = match var("COLORTERM") {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
|
@ -66,6 +65,10 @@ pub fn is_truecolor_terminal() -> bool {
|
||||||
is_color_terminal() && colorterm
|
is_color_terminal() && colorterm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_le_32(vec: &Vec<u8>, pos: usize) -> u32 {
|
||||||
|
((vec[pos+0] as u32) << 0) + ((vec[pos+1] as u32) << 8) + ((vec[pos+2] as u32) << 16) + ((vec[pos+3] as u32) << 24)
|
||||||
|
}
|
||||||
|
|
||||||
fn wait_on_process(mut child: Child) {
|
fn wait_on_process(mut child: Child) {
|
||||||
child.wait().ok();
|
child.wait().ok();
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,5 +154,3 @@ impl Display for InvalidArgument {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue