diff --git a/Cargo.lock b/Cargo.lock index e18b29f..9044ac3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1675,7 +1675,7 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "nix-data" version = "0.0.2" -source = "git+https://github.com/snowflakelinux/nix-data#a75a234c2ffa661b6d3f6d276dc372677e5e2c74" +source = "git+https://github.com/snowflakelinux/nix-data#42d0e42536627cdce50c522f161617b797f670be" dependencies = [ "anyhow", "brotli", @@ -2461,18 +2461,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" dependencies = [ "proc-macro2", "quote", @@ -2797,9 +2797,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" dependencies = [ "proc-macro2", "quote", diff --git a/default.nix b/default.nix index 286a8ac..2063838 100644 --- a/default.nix +++ b/default.nix @@ -20,7 +20,7 @@ pkgs.stdenv.mkDerivation rec { cargoDeps = pkgs.rustPlatform.fetchCargoTarball { inherit src; name = "${pname}-${version}"; - hash = "sha256-QaAWND3AF+/Bg38J0yzYzbU6FtIiBpLL21oKMa5RYwU="; + hash = "sha256-OmHjQkK1MGes9hbJ0LEGdP1wA8ohAJEon0ycoNppl0E="; }; nativeBuildInputs = with pkgs; [ diff --git a/nsc-helper/src/main.rs b/nsc-helper/src/main.rs index 065d7fa..7f55491 100644 --- a/nsc-helper/src/main.rs +++ b/nsc-helper/src/main.rs @@ -12,12 +12,18 @@ enum SubCommands { /// Write stdin to file in path output #[arg(short, long)] output: String, + /// How many generations to keep + #[arg(short, long)] + generations: Option, /// Run `nixos-rebuild` with the given arguments arguments: Vec, }, Rebuild { /// Run `nixos-rebuild` with the given arguments arguments: Vec, + /// How many generations to keep + #[arg(short, long)] + generations: Option, }, Channel { /// Whether to rebuild the system after updating channels @@ -29,6 +35,9 @@ enum SubCommands { /// Write stdin to file in path output #[arg(short, long)] output: String, + /// How many generations to keep + #[arg(short, long)] + generations: Option, /// Run `nixos-rebuild` with the given arguments arguments: Vec, }, @@ -45,6 +54,9 @@ enum SubCommands { /// Write stdin to file in path output #[arg(short, long)] output: String, + /// How many generations to keep + #[arg(short, long)] + generations: Option, /// Run `nixos-rebuild` with the given arguments arguments: Vec, }, @@ -65,10 +77,14 @@ fn main() { } match derived_subcommands { - SubCommands::Config { output, arguments } => { + SubCommands::Config { + output, + generations, + arguments, + } => { let old = fs::read_to_string(&output); match write_file(&output) { - Ok(_) => match rebuild(arguments) { + Ok(_) => match rebuild(arguments, generations) { Ok(_) => {} Err(err) => { eprintln!("{}", err); @@ -86,7 +102,10 @@ fn main() { } }; } - SubCommands::Rebuild { arguments } => match rebuild(arguments) { + SubCommands::Rebuild { + generations, + arguments, + } => match rebuild(arguments, generations) { Ok(_) => (), Err(err) => { eprintln!("{}", err); @@ -97,6 +116,7 @@ fn main() { rebuild: dorebuild, update, output, + generations, arguments, } => { if update { @@ -108,7 +128,7 @@ fn main() { match channel() { Ok(_) => { if dorebuild { - match rebuild(arguments) { + match rebuild(arguments, generations) { Ok(_) => (), Err(err) => { eprintln!("{}", err); @@ -128,6 +148,7 @@ fn main() { flakepath, update, output, + generations, arguments, } => { if update { @@ -139,7 +160,7 @@ fn main() { match flake(&flakepath) { Ok(_) => { if dorebuild { - match rebuild(arguments) { + match rebuild(arguments, generations) { Ok(_) => (), Err(err) => { eprintln!("{}", err); @@ -166,18 +187,38 @@ fn write_file(path: &str) -> Result<(), Box> { Ok(()) } -fn rebuild(args: Vec) -> Result<(), Box> { +fn rebuild(args: Vec, generations: Option) -> Result<(), Box> { let mut cmd = Command::new("nixos-rebuild").args(args).spawn()?; let x = cmd.wait()?; - if x.success() { - Ok(()) - } else { + if !x.success() { eprintln!("nixos-rebuild failed with exit code {}", x.code().unwrap()); - Err(Box::new(io::Error::new( + return Err(Box::new(io::Error::new( io::ErrorKind::Other, "nixos-rebuild failed", - ))) + ))); } + if let Some(g) = generations { + if g > 0 { + let mut cmd = Command::new("nix-env") + .arg("--delete-generations") + .arg("-p") + .arg("/nix/var/nix/profiles/system") + .arg(&format!("+{}", g)) + .spawn()?; + let x = cmd.wait()?; + if !x.success() { + eprintln!( + "nix-env --delete-generations failed with exit code {}", + x.code().unwrap() + ); + return Err(Box::new(io::Error::new( + io::ErrorKind::Other, + "nix-env failed", + ))); + } + } + } + Ok(()) } fn channel() -> Result<(), Box> { diff --git a/src/ui/installedpage.rs b/src/ui/installedpage.rs index 84fd1c9..4b9005b 100644 --- a/src/ui/installedpage.rs +++ b/src/ui/installedpage.rs @@ -228,7 +228,6 @@ impl FactoryComponent for InstalledItemModel { type Init = InstalledItem; type Input = InstalledItemInputMsg; type Output = InstalledItemMsg; - type Widgets = InstalledItemWidgets; type ParentWidget = adw::gtk::ListBox; type ParentInput = InstalledPageMsg; diff --git a/src/ui/installworker.rs b/src/ui/installworker.rs index 6402c92..8726d92 100644 --- a/src/ui/installworker.rs +++ b/src/ui/installworker.rs @@ -16,8 +16,7 @@ pub struct InstallAsyncHandler { #[tracker::no_eq] process: Option>, work: Option, - systemconfig: Option, - flakeargs: Option, + config: NixDataConfig, pid: Option, syspkgs: SystemPkgs, userpkgs: UserPkgs, @@ -47,8 +46,12 @@ impl Worker for InstallAsyncHandler { Self { process: None, work: None, - systemconfig: None, - flakeargs: None, + config: NixDataConfig { + systemconfig: None, + flake: None, + flakearg: None, + generations: None + }, pid: None, syspkgs: params.syspkgs, userpkgs: params.userpkgs, @@ -60,16 +63,7 @@ impl Worker for InstallAsyncHandler { self.reset(); match msg { InstallAsyncHandlerMsg::SetConfig(config) => { - self.systemconfig = config.systemconfig; - self.flakeargs = if let Some(flake) = config.flake { - if let Some(flakearg) = config.flakearg { - Some(format!("{}#{}", flake, flakearg)) - } else { - Some(flake) - } - } else { - None - } + self.config = config; } InstallAsyncHandlerMsg::SetPkgTypes(syspkgs, userpkgs) => { self.syspkgs = syspkgs; @@ -80,8 +74,7 @@ impl Worker for InstallAsyncHandler { if work.block { return; } - let systemconfig = self.systemconfig.clone(); - let rebuildargs = self.flakeargs.clone(); + let config = self.config.clone(); match work.pkgtype { InstallType::User => match work.action { PkgAction::Install => { @@ -268,7 +261,7 @@ impl Worker for InstallAsyncHandler { }, InstallType::System => { REBUILD_BROKER.send(RebuildMsg::Show); - if let Some(systemconfig) = systemconfig { + if let Some(systemconfig) = &config.systemconfig { match work.action { PkgAction::Install => { info!("Installing system package: {}", work.pkg); @@ -276,8 +269,7 @@ impl Worker for InstallAsyncHandler { match installsys( work.pkg.to_string(), work.action.clone(), - systemconfig, - rebuildargs, + config, sender.clone(), ) .await @@ -305,8 +297,7 @@ impl Worker for InstallAsyncHandler { match installsys( work.pkg.to_string(), work.action.clone(), - systemconfig, - rebuildargs, + config, sender.clone(), ) .await @@ -350,10 +341,19 @@ impl Worker for InstallAsyncHandler { async fn installsys( pkg: String, action: PkgAction, - systemconfig: String, - flakeargs: Option, + config: NixDataConfig, _sender: ComponentSender, ) -> Result { + let systemconfig = config.systemconfig.unwrap_or_default(); + let flakeargs = if let Some(flake) = config.flake { + if let Some(flakearg) = config.flakearg { + Some(format!("{}#{}", flake, flakearg)) + } else { + Some(flake) + } + } else { + None + }; let mut p = pkg; let f = fs::read_to_string(&systemconfig)?; if let Ok(s) = nix_editor::read::getwithvalue(&f, "environment.systemPackages") { @@ -415,6 +415,8 @@ async fn installsys( let mut cmd = tokio::process::Command::new("pkexec") .arg(&exe) .arg("config") + .arg("--generations") + .arg(config.generations.unwrap_or(0).to_string()) .arg("--output") .arg(&systemconfig) .arg("--") diff --git a/src/ui/updateworker.rs b/src/ui/updateworker.rs index 329cc2a..5360537 100644 --- a/src/ui/updateworker.rs +++ b/src/ui/updateworker.rs @@ -17,8 +17,7 @@ use super::{ pub struct UpdateAsyncHandler { #[tracker::no_eq] process: Option>, - systemconfig: String, - flakeargs: Option, + config: NixDataConfig, syspkgs: SystemPkgs, userpkgs: UserPkgs, } @@ -60,8 +59,12 @@ impl Worker for UpdateAsyncHandler { fn init(params: Self::Init, _sender: relm4::ComponentSender) -> Self { Self { process: None, - systemconfig: String::new(), - flakeargs: None, + config: NixDataConfig { + systemconfig: None, + flake: None, + flakearg: None, + generations: None + }, syspkgs: params.syspkgs, userpkgs: params.userpkgs, tracker: 0, @@ -71,27 +74,17 @@ impl Worker for UpdateAsyncHandler { fn update(&mut self, msg: Self::Input, sender: ComponentSender) { match msg { UpdateAsyncHandlerMsg::UpdateConfig(config) => { - self.systemconfig = config.systemconfig.unwrap_or_default(); - self.flakeargs = if let Some(flake) = config.flake { - if let Some(flakearg) = config.flakearg { - Some(format!("{}#{}", flake, flakearg)) - } else { - Some(flake) - } - } else { - None - } + self.config = config; } UpdateAsyncHandlerMsg::UpdatePkgTypes(syspkgs, userpkgs) => { self.syspkgs = syspkgs; self.userpkgs = userpkgs; } UpdateAsyncHandlerMsg::UpdateSystem => { - let systemconfig = self.systemconfig.clone(); - let flakeargs = self.flakeargs.clone(); + let config = self.config.clone(); let syspkgs = self.syspkgs.clone(); relm4::spawn(async move { - let result = runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs, None).await; + let result = runcmd(NscCmd::All, config, syspkgs, None).await; match result { Ok(true) => { sender.output(UpdatePageMsg::DoneWorking); @@ -104,12 +97,11 @@ impl Worker for UpdateAsyncHandler { }); } UpdateAsyncHandlerMsg::UpdateSystemRemove(pkgs) => { - let systemconfig = self.systemconfig.clone(); - let flakeargs = self.flakeargs.clone(); + let config = self.config.clone(); let syspkgs = self.syspkgs.clone(); relm4::spawn(async move { let result = - runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs, Some(pkgs)).await; + runcmd(NscCmd::All, config, syspkgs, Some(pkgs)).await; match result { Ok(true) => { sender.output(UpdatePageMsg::DoneWorking); @@ -122,16 +114,15 @@ impl Worker for UpdateAsyncHandler { }); } UpdateAsyncHandlerMsg::RebuildSystem => { - let systemconfig = self.systemconfig.clone(); - let flakeargs = self.flakeargs.clone(); + let config = self.config.clone(); let syspkgs = self.syspkgs.clone(); relm4::spawn(async move { let result = match syspkgs { SystemPkgs::Legacy => { - runcmd(NscCmd::Rebuild, systemconfig, flakeargs, syspkgs, None).await + runcmd(NscCmd::Rebuild, config, syspkgs, None).await } SystemPkgs::Flake => { - runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs, None).await + runcmd(NscCmd::All, config, syspkgs, None).await } SystemPkgs::None => Ok(true), }; @@ -183,12 +174,11 @@ impl Worker for UpdateAsyncHandler { }); } UpdateAsyncHandlerMsg::UpdateAll => { - let systemconfig = self.systemconfig.clone(); - let flakeargs = self.flakeargs.clone(); + let config = self.config.clone(); let syspkgs = self.syspkgs.clone(); let userpkgs = self.userpkgs.clone(); relm4::spawn(async move { - let result = runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs, None).await; + let result = runcmd(NscCmd::All, config, syspkgs, None).await; match result { Ok(true) => { match match userpkgs { @@ -212,12 +202,17 @@ impl Worker for UpdateAsyncHandler { }); } UpdateAsyncHandlerMsg::UpdateAllRemove(userrmpkgs, sysrmpkgs) => { - let systemconfig = self.systemconfig.clone(); - let flakeargs = self.flakeargs.clone(); + let config = self.config.clone(); let syspkgs = self.syspkgs.clone(); let userpkgs = self.userpkgs.clone(); relm4::spawn(async move { - let result = runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs, Some(sysrmpkgs)).await; + let result = runcmd( + NscCmd::All, + config, + syspkgs, + Some(sysrmpkgs), + ) + .await; match result { Ok(true) => { match match userpkgs { @@ -246,11 +241,20 @@ impl Worker for UpdateAsyncHandler { async fn runcmd( cmd: NscCmd, - systemconfig: String, - flakeargs: Option, + config: NixDataConfig, syspkgs: SystemPkgs, rmpkgs: Option>, ) -> Result { + let systemconfig = config.systemconfig.unwrap_or_default(); + let flakeargs = if let Some(flake) = config.flake { + if let Some(flakearg) = config.flakearg { + Some(format!("{}#{}", flake, flakearg)) + } else { + Some(flake) + } + } else { + None + }; let f = fs::read_to_string(&systemconfig)?; let exe = match std::env::current_exe() { Ok(mut e) => { @@ -293,6 +297,8 @@ async fn runcmd( NscCmd::Rebuild => tokio::process::Command::new("pkexec") .arg(&exe) .arg("rebuild") + .arg("--generations") + .arg(config.generations.unwrap_or(0).to_string()) .arg("--") .arg("switch") .args(&rebuildargs) @@ -318,6 +324,8 @@ async fn runcmd( .arg("channel") .arg("--rebuild") .arg("--update") + .arg("--generations") + .arg(config.generations.unwrap_or(0).to_string()) .arg("--output") .arg(&systemconfig) .arg("--") @@ -337,6 +345,8 @@ async fn runcmd( .arg(&exe) .arg("channel") .arg("--rebuild") + .arg("--generations") + .arg(config.generations.unwrap_or(0).to_string()) .arg("--") .arg("switch") .args(&rebuildargs) @@ -360,6 +370,8 @@ async fn runcmd( .arg("--flakepath") .arg(&flakepath) .arg("--update") + .arg("--generations") + .arg(config.generations.unwrap_or(0).to_string()) .arg("--output") .arg(&systemconfig) .arg("--") @@ -382,6 +394,8 @@ async fn runcmd( .arg("--rebuild") .arg("--flakepath") .arg(&flakepath) + .arg("--generations") + .arg(config.generations.unwrap_or(0).to_string()) .arg("--") .arg("switch") .arg("--impure") @@ -434,31 +448,28 @@ async fn updateprofile(rmpkgs: Option>) -> Result { if let Some(rmpkgs) = rmpkgs { if !rmpkgs.is_empty() { let mut cmd = tokio::process::Command::new("nix") - .arg("profile") - .arg("remove") - .args( - &rmpkgs - .iter() - .map(|x| format!( - "legacyPackages.x86_64-linux.{}", - x - )) - .collect::>() + .arg("profile") + .arg("remove") + .args( + &rmpkgs + .iter() + .map(|x| format!("legacyPackages.x86_64-linux.{}", x)) + .collect::>(), ) - // Allow updating potential unfree packages - .arg("--impure") - .stderr(Stdio::piped()) - .spawn()?; + // Allow updating potential unfree packages + .arg("--impure") + .stderr(Stdio::piped()) + .spawn()?; - let stderr = cmd.stderr.take().unwrap(); - let reader = tokio::io::BufReader::new(stderr); + let stderr = cmd.stderr.take().unwrap(); + let reader = tokio::io::BufReader::new(stderr); - let mut lines = reader.lines(); - while let Ok(Some(line)) = lines.next_line().await { - REBUILD_BROKER.send(RebuildMsg::UpdateText(line.to_string())); - trace!("CAUGHT NIX PROFILE LINE: {}", line); - } - cmd.wait().await?; + let mut lines = reader.lines(); + while let Ok(Some(line)) = lines.next_line().await { + REBUILD_BROKER.send(RebuildMsg::UpdateText(line.to_string())); + trace!("CAUGHT NIX PROFILE LINE: {}", line); + } + cmd.wait().await?; } } diff --git a/src/ui/welcome.rs b/src/ui/welcome.rs index 1b7d62c..4b0e4f1 100644 --- a/src/ui/welcome.rs +++ b/src/ui/welcome.rs @@ -224,6 +224,7 @@ impl SimpleComponent for WelcomeModel { systemconfig: self.confpath.as_ref().map(|x| x.to_string_lossy().to_string()), flake: self.flakepath.as_ref().map(|x| x.to_string_lossy().to_string()), flakearg: None, + generations: None, }; sender.output(AppMsg::LoadConfig(config)); self.hidden = true; diff --git a/src/ui/window.rs b/src/ui/window.rs index 7f6f879..201cd21 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -415,6 +415,7 @@ impl Component for AppModel { systemconfig: None, flake: None, flakearg: None, + generations: None, }, true, ) @@ -673,6 +674,7 @@ impl Component for AppModel { systemconfig: systemconfig.clone(), flake: self.config.flake.clone(), flakearg: self.config.flakearg.clone(), + generations: self.config.generations, }; if editconfig(self.config.clone()).is_err() { warn!("Failed to update config"); @@ -711,6 +713,7 @@ impl Component for AppModel { systemconfig: self.config.systemconfig.clone(), flake: flake.clone(), flakearg, + generations: self.config.generations, }; if editconfig(self.config.clone()).is_err() { warn!("Failed to update config");