From 95a75dcd76ae19b9af5e9509e07c5ac3c617d13c Mon Sep 17 00:00:00 2001 From: theMZet Date: Fri, 29 May 2026 22:56:15 +0200 Subject: [PATCH] feat: export subcommand --- src/main.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6638b1e..0397493 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::path::PathBuf; +use std::{ + ffi::OsStr, + io::Write, + path::PathBuf, + process::{Command, Stdio}, +}; use clap::Parser; use clap_derive::{Parser, Subcommand}; @@ -35,6 +40,8 @@ compile_error!("'yay' and 'paru' are mutually exclusive and cannot be enabled to #[cfg(not(target_os = "linux"))] compile_error!("Only (Arch) linux is supported!"); +const PRIVLAGE_ESCELATE_COMMAND: &str = "sudo"; + #[derive(Parser)] struct Args { #[arg(long, global = true)] @@ -68,6 +75,10 @@ enum Commands { #[arg(short, long)] /// When specified, the new world file content will be writen to stdout stdout: bool, + + #[arg(short, long)] + /// When given will transfer ignore values to the new world file + persist_ignore: bool, }, /// Writes diffrents between the world file and the system Diff, @@ -89,7 +100,77 @@ fn main() -> Result<()> { match args.command { Commands::Sync => todo!(), - Commands::Export { overwrite, stdout } => todo!(), + Commands::Export { + overwrite, + stdout, + persist_ignore, + } => { + let mut world = match World::load_from(world_path.clone()) { + Ok(x) => x, + Err(_) => World::new_empty(), + }; + + let mut state = get_system_state()?; + + if persist_ignore { + state.ignore = world.get_packages().ignore.clone(); + } + + let world_state = world.get_mut_packages(); + + *world_state = state; + + let text_world = toml::to_string_pretty(&world)?; + + if stdout { + println!("{}", &text_world); + return Ok(()); + } + + if !overwrite && root_file_exists(world_path.as_os_str())? { + eprintln!("File Already exists!"); + return Ok(()); + } + + if let Some(parent_path) = world_path.parent() { + let status = Command::new(PRIVLAGE_ESCELATE_COMMAND) + .arg("mkdir") + .arg("-p") + .arg(parent_path) + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .status()?; + + if !status.success() { + return Err("Making directories for the world file went unsuccessful!".into()); + } + } + + let mut child = Command::new(PRIVLAGE_ESCELATE_COMMAND) + .arg("tee") + .arg(world_path) + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .stderr(Stdio::inherit()) + .spawn()?; + + let c_stdin = child.stdin.as_mut(); + if c_stdin.is_none() { + return Err("Unabled to pass data to file!".into()); + } + c_stdin.unwrap().write_all(text_world.as_bytes())?; + + let status = child.wait()?; + + if !status.success() { + return Err("Couldn't write to a file!".into()); + } + + if !args.quiet { + println!("State succesfully saved in the world file!"); + } + } Commands::Diff => { let world = World::load_from(world_path).unwrap_or(World::new_empty()); let world_state = world.get_packages(); @@ -156,3 +237,16 @@ fn main() -> Result<()> { } Ok(()) } + +fn root_file_exists(path: &OsStr) -> std::io::Result { + let status = Command::new(PRIVLAGE_ESCELATE_COMMAND) + .arg("test") + .arg("-e") + .arg(path) + .stdin(Stdio::inherit()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status()?; + + Ok(status.success()) +}