Implement push update diff

This commit is contained in:
Wildan M 2026-03-19 15:30:54 +07:00
parent 23b7937698
commit b8b2225449
No known key found for this signature in database
GPG Key ID: 01AC53185C679C79
5 changed files with 138 additions and 18 deletions

View File

@ -5,13 +5,13 @@ use cookbook::cook::cook_build::{build, get_stage_dirs, remove_stage_dir};
use cookbook::cook::fetch::{fetch, fetch_offline};
use cookbook::cook::fs::{create_target_dir, run_command};
use cookbook::cook::ident;
use cookbook::cook::package::package;
use cookbook::cook::package::{package, package_handle_push};
use cookbook::cook::pty::{PtyOut, UnixSlavePty, flush_pty, setup_pty};
use cookbook::cook::script::KILL_ALL_PID;
use cookbook::cook::tree::{self, WalkTreeEntry};
use cookbook::log_to_pty;
use cookbook::recipe::{CookRecipe, recipes_flatten_package_names, recipes_mark_as_deps};
use pkg::PackageName;
use pkg::{PackageName, PackageState};
use ratatui::Terminal;
use ratatui::layout::{Constraint, Direction, Layout, Position, Rect};
use ratatui::prelude::TermionBackend;
@ -798,15 +798,17 @@ fn handle_push(recipes: &Vec<CookRecipe>, config: &CliConfig) -> anyhow::Result<
_is_last: bool,
entry: &WalkTreeEntry|
-> anyhow::Result<()> {
let public_path = "build/id_ed25519.pub.toml";
let r = match entry {
WalkTreeEntry::Built(archive_path, _) => {
let sysroot_dir = PUSH_SYSROOT_DIR.get().unwrap();
pkgar::extract(public_path, archive_path.as_path(), sysroot_dir).context(format!(
"failed to install '{}' in '{}'",
archive_path.display(),
sysroot_dir.display(),
))
let install_path = PUSH_SYSROOT_DIR.get().unwrap();
let mut state =
PackageState::from_sysroot(install_path).map_err(|e| anyhow!("{e:?}"))?;
let r = package_handle_push(&mut state, archive_path, &install_path, false)
.map_err(|e| anyhow!("{e:?}"));
if matches!(r, Ok(false)) {
state.to_sysroot(install_path)?;
}
r
}
WalkTreeEntry::NotBuilt => Err(anyhow!(
"Package {} has not been built",
@ -817,7 +819,11 @@ fn handle_push(recipes: &Vec<CookRecipe>, config: &CliConfig) -> anyhow::Result<
}
};
match r {
Ok(()) => {
Ok(true) => {
print_cached(&CliCommand::Push, Some(package_name));
Ok(())
}
Ok(false) => {
print_success(&CliCommand::Push, Some(package_name));
Ok(())
}

View File

@ -12,6 +12,7 @@ use walkdir::{DirEntry, WalkDir};
use crate::{
config::translate_mirror,
cook::pty::{PtyOut, spawn_to_pipe},
wrap_io_err,
};
//TODO: pub(crate) for all of these functions
@ -314,6 +315,10 @@ pub fn download_wget(url: &str, dest: &PathBuf, logger: &PtyOut) -> Result<(), S
Ok(())
}
pub fn read_to_string(path: &Path) -> crate::Result<String> {
fs::read_to_string(path).map_err(wrap_io_err!(path, "Reading file to string"))
}
/// get commit rev and return if it's detached or not
pub fn get_git_head_rev(dir: &PathBuf) -> Result<(String, bool), String> {
let git_head = dir.join(".git/HEAD");

View File

@ -3,7 +3,7 @@ use std::{
path::{Path, PathBuf},
};
use pkg::{Package, PackageName, PackagePrefix};
use pkg::{InstallState, Package, PackageName, PackagePrefix, PackageState};
use pkgar::ext::PackageSrcExt;
use pkgar_core::HeaderFlags;
@ -252,3 +252,48 @@ fn get_package_name_inner(name: &str, package: Option<&str>) -> String {
}
prefix_name
}
pub fn package_handle_push(
state: &mut PackageState,
archive_path: &Path,
sysroot_dir: &Path,
reinstall: bool,
) -> crate::Result<bool> {
let archive_toml = archive_path.with_extension("toml");
let pkey_path = "build/id_ed25519.pub.toml";
let pkg_toml = Package::from_file(&archive_toml)?;
match state.installed.get(&pkg_toml.name) {
Some(s) if !reinstall && pkg_toml.blake3 == s.blake3 => Ok(true),
Some(s) => {
// "local" is what remote name from installer is hardcoded into
let remote_name = "local".to_string();
let install_state =
InstallState::from_package(&pkg_toml, remote_name, s.manual, s.dependents.clone());
// TODO: use pkgar::replace unless forced reinstall
pkgar::extract(pkey_path, &archive_path, sysroot_dir)?;
state.installed.insert(pkg_toml.name.clone(), install_state);
Ok(false)
}
None => {
// "local" is what remote name from installer is hardcoded into
let remote_name = "local".to_string();
// TODO: Handle manual & depedents
let install_state =
InstallState::from_package(&pkg_toml, remote_name, true, BTreeSet::new());
pkgar::extract(pkey_path, &archive_path, sysroot_dir)?;
// TODO: Inject dependencies
// TODO: Check if we need to inject remote key
state.installed.insert(pkg_toml.name.clone(), install_state);
Ok(false)
}
}
}

View File

@ -15,3 +15,70 @@ pub const REMOTE_PKG_SOURCE: &str = "https://static.redox-os.org/pkg";
pub fn is_redox() -> bool {
cfg!(target_os = "redox")
}
// Errors
use std::io;
use std::path::PathBuf;
#[derive(Debug)]
pub enum Error {
Io {
source: io::Error,
path: Option<PathBuf>,
context: &'static str,
},
Package(pkg::PackageError),
Pkgar(pkgar::Error),
Other(String),
}
macro_rules! wrap_io_err {
($context:expr) => {
|source| crate::Error::Io {
source,
path: None,
context: $context,
}
};
($path:expr, $context:expr) => {
|source| crate::Error::Io {
source,
path: Some($path.to_path_buf()),
context: $context,
}
};
}
impl From<String> for Error {
fn from(value: String) -> Self {
Error::Other(value)
}
}
impl From<pkg::PackageError> for Error {
fn from(value: pkg::PackageError) -> Self {
Error::Package(value)
}
}
impl From<pkgar::Error> for Error {
fn from(value: pkgar::Error) -> Self {
match value {
pkgar::Error::Io {
source,
path,
context,
} => Error::Io {
source,
path,
context,
},
_ => Error::Pkgar(value),
}
}
}
pub(crate) type Result<T> = std::result::Result<T, Error>;
pub(crate) use wrap_io_err;

View File

@ -7,10 +7,7 @@ use std::{
use pkg::{PackageError, PackageName, recipes};
use regex::Regex;
use serde::{
Deserialize, Serialize,
de::{Error as DeErrorT, value::Error as DeError},
};
use serde::{Deserialize, Serialize};
use crate::{WALK_DEPTH, cook::package as cook_package};
@ -198,9 +195,9 @@ impl Recipe {
return Err(PackageError::FileMissing(file.clone()));
}
let toml = fs::read_to_string(&file)
.map_err(|err| PackageError::Parse(DeError::custom(err), Some(file.clone())))?;
let recipe: Recipe = toml::from_str(&toml)
.map_err(|err| PackageError::Parse(DeError::custom(err), Some(file.clone())))?;
.map_err(|err| PackageError::FileError(err.raw_os_error(), file.clone()))?;
let recipe: Recipe =
toml::from_str(&toml).map_err(|err| PackageError::Parse(err, Some(file.clone())))?;
Ok(recipe)
}