mirror of
https://github.com/snowfallorg/nix-software-center.git
synced 2024-10-26 23:19:24 +03:00
Add systemless support
This commit is contained in:
parent
8810c03fe8
commit
2a25c197f4
@ -36,7 +36,14 @@ pub fn checkcache(syspkgs: SystemPkgs, userpkgs: UserPkgs, config: NscConfig) ->
|
||||
SystemPkgs::Flake => {
|
||||
setupflakepkgscache(config)?;
|
||||
}
|
||||
SystemPkgs::None => {}
|
||||
}
|
||||
|
||||
if userpkgs == UserPkgs::Env && syspkgs != SystemPkgs::Legacy {
|
||||
setupupdatecache()?;
|
||||
setupnewestver()?;
|
||||
}
|
||||
|
||||
if userpkgs == UserPkgs::Profile {
|
||||
setupprofilepkgscache()?;
|
||||
}
|
||||
@ -318,7 +325,12 @@ fn setupprofilepkgscache() -> Result<(), Box<dyn Error>> {
|
||||
// nix-instantiate --eval -E '(builtins.getFlake "/home/user/nix").inputs.nixpkgs.outPath'
|
||||
// nix-env -f /nix/store/sjmq1gphj1arbzf4aqqnygd9pf4hkfkf-source -qa --json > packages.json
|
||||
fn setupupdatecache() -> Result<(), Box<dyn Error>> {
|
||||
let dlver = fs::read_to_string("/run/current-system/nixos-version")?;
|
||||
let output = Command::new("nix-instantiate")
|
||||
.arg("--eval")
|
||||
.arg("-E")
|
||||
.arg("with import <nixpkgs> {}; pkgs.lib.version")
|
||||
.output()?;
|
||||
let dlver = String::from_utf8(output.stdout)?.replace("\"", "");
|
||||
|
||||
let mut relver = dlver.split('.').collect::<Vec<&str>>().join(".")[0..5].to_string();
|
||||
|
||||
@ -373,8 +385,12 @@ fn setupupdatecache() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
fn setupnewestver() -> Result<(), Box<dyn Error>> {
|
||||
let version = fs::read_to_string("/run/current-system/nixos-version")?;
|
||||
|
||||
let output = Command::new("nix-instantiate")
|
||||
.arg("--eval")
|
||||
.arg("-E")
|
||||
.arg("with import <nixpkgs> {}; pkgs.lib.version")
|
||||
.output()?;
|
||||
let version = String::from_utf8(output.stdout)?.replace("\"", "");
|
||||
let mut relver = version.split('.').collect::<Vec<&str>>().join(".")[0..5].to_string();
|
||||
|
||||
if version.len() >= 8 && &version[5..8] == "pre" {
|
||||
|
@ -10,8 +10,9 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
|
||||
pub struct NscConfig {
|
||||
pub systemconfig: String,
|
||||
pub systemconfig: Option<String>,
|
||||
pub flake: Option<String>,
|
||||
pub flakearg: Option<String>,
|
||||
}
|
||||
|
||||
pub fn getconfig() -> Option<NscConfig> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use flate2::bufread::GzDecoder;
|
||||
use ijson::IString;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
use std::{self, fs::File, collections::HashMap, error::Error, env, io::BufReader};
|
||||
use log::*;
|
||||
@ -179,9 +180,12 @@ pub async fn readpkgs() -> Result<HashMap<String, Package>, Box<dyn Error + Sen
|
||||
let mut files = s.split("\n---\n").collect::<Vec<_>>();
|
||||
files.remove(0);
|
||||
for f in files {
|
||||
let appstream: AppData = serde_yaml::from_str(f)?;
|
||||
if let Some(p) = pkgs.get_mut(&appstream.package.to_string()) {
|
||||
p.appdata = Some(appstream);
|
||||
if let Ok(appstream) = serde_yaml::from_str::<AppData>(f) {
|
||||
if let Some(p) = pkgs.get_mut(&appstream.package.to_string()) {
|
||||
p.appdata = Some(appstream);
|
||||
}
|
||||
} else {
|
||||
warn!("Failed to parse some appstream data");
|
||||
}
|
||||
}
|
||||
Ok(pkgs)
|
||||
@ -190,6 +194,11 @@ pub async fn readpkgs() -> Result<HashMap<String, Package>, Box<dyn Error + Sen
|
||||
pub fn readlegacysyspkgs() -> Result<HashMap<String, String>, Box<dyn Error + Send + Sync>> {
|
||||
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
|
||||
let cachefile = format!("{}/syspackages.json", cachedir);
|
||||
if let Ok(f) = fs::read_to_string(&cachefile) {
|
||||
if f.trim().is_empty() {
|
||||
return Ok(HashMap::new());
|
||||
}
|
||||
}
|
||||
let file = File::open(cachefile)?;
|
||||
let reader = BufReader::new(file);
|
||||
let newpkgs: HashMap<String, String> = simd_json::serde::from_reader(reader)?;
|
||||
@ -199,6 +208,11 @@ pub fn readlegacysyspkgs() -> Result<HashMap<String, String>, Box<dyn Error + S
|
||||
pub fn readflakesyspkgs() -> Result<HashMap<String, String>, Box<dyn Error + Send + Sync>> {
|
||||
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
|
||||
let cachefile = format!("{}/syspackages.json", cachedir);
|
||||
if let Ok(f) = fs::read_to_string(&cachefile) {
|
||||
if f.trim().is_empty() {
|
||||
return Ok(HashMap::new());
|
||||
}
|
||||
}
|
||||
let file = File::open(cachefile)?;
|
||||
let reader = BufReader::new(file);
|
||||
let newpkgs: HashMap<String, FlakeJson> = simd_json::serde::from_reader(reader)?;
|
||||
@ -209,6 +223,11 @@ pub fn readflakesyspkgs() -> Result<HashMap<String, String>, Box<dyn Error + Se
|
||||
pub fn readprofilepkgs() -> Result<HashMap<String, String>, Box<dyn Error + Send + Sync>> {
|
||||
let cachedir = format!("{}/.cache/nix-software-center/", env::var("HOME")?);
|
||||
let cachefile = format!("{}/profilepackages.json", cachedir);
|
||||
if let Ok(f) = fs::read_to_string(&cachefile) {
|
||||
if f.trim().is_empty() {
|
||||
return Ok(HashMap::new());
|
||||
}
|
||||
}
|
||||
let file = File::open(cachefile)?;
|
||||
let reader = BufReader::new(file);
|
||||
let profilepkgs: HashMap<String, FlakeJson> = simd_json::serde::from_reader(reader)?;
|
||||
|
@ -13,12 +13,14 @@ pub struct InstalledPageModel {
|
||||
#[tracker::no_eq]
|
||||
installedsystemlist: FactoryVecDeque<InstalledItemModel>,
|
||||
userpkgtype: UserPkgs,
|
||||
systempkgtype: SystemPkgs,
|
||||
updatetracker: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InstalledPageMsg {
|
||||
Update(Vec<InstalledItem>, Vec<InstalledItem>),
|
||||
UpdatePkgTypes(SystemPkgs, UserPkgs),
|
||||
OpenRow(usize, InstallType),
|
||||
Remove(InstalledItem),
|
||||
UnsetBusy(WorkPkg),
|
||||
@ -26,7 +28,7 @@ pub enum InstalledPageMsg {
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for InstalledPageModel {
|
||||
type InitParams = UserPkgs;
|
||||
type InitParams = (SystemPkgs, UserPkgs);
|
||||
type Input = InstalledPageMsg;
|
||||
type Output = AppMsg;
|
||||
type Widgets = InstalledPageWidgets;
|
||||
@ -43,6 +45,8 @@ impl SimpleComponent for InstalledPageModel {
|
||||
set_margin_all: 15,
|
||||
set_spacing: 15,
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_visible: !model.installeduserlist.is_empty(),
|
||||
set_halign: gtk::Align::Start,
|
||||
add_css_class: "title-4",
|
||||
set_label: match model.userpkgtype {
|
||||
@ -52,6 +56,8 @@ impl SimpleComponent for InstalledPageModel {
|
||||
},
|
||||
#[local_ref]
|
||||
installeduserlist -> gtk::ListBox {
|
||||
#[watch]
|
||||
set_visible: !model.installeduserlist.is_empty(),
|
||||
set_valign: gtk::Align::Start,
|
||||
add_css_class: "boxed-list",
|
||||
set_selection_mode: gtk::SelectionMode::None,
|
||||
@ -62,12 +68,16 @@ impl SimpleComponent for InstalledPageModel {
|
||||
}
|
||||
},
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_visible: !model.installedsystemlist.is_empty(),
|
||||
set_halign: gtk::Align::Start,
|
||||
add_css_class: "title-4",
|
||||
set_label: "System (configuration.nix)",
|
||||
},
|
||||
#[local_ref]
|
||||
installedsystemlist -> gtk::ListBox {
|
||||
#[watch]
|
||||
set_visible: !model.installedsystemlist.is_empty(),
|
||||
set_valign: gtk::Align::Start,
|
||||
add_css_class: "boxed-list",
|
||||
set_selection_mode: gtk::SelectionMode::None,
|
||||
@ -83,7 +93,7 @@ impl SimpleComponent for InstalledPageModel {
|
||||
}
|
||||
|
||||
fn init(
|
||||
userpkgtype: Self::InitParams,
|
||||
(systempkgtype, userpkgtype): Self::InitParams,
|
||||
root: &Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
@ -92,6 +102,7 @@ impl SimpleComponent for InstalledPageModel {
|
||||
installedsystemlist: FactoryVecDeque::new(gtk::ListBox::new(), &sender.input),
|
||||
updatetracker: 0,
|
||||
userpkgtype,
|
||||
systempkgtype,
|
||||
tracker: 0
|
||||
};
|
||||
|
||||
@ -119,6 +130,10 @@ impl SimpleComponent for InstalledPageModel {
|
||||
installedsystemlist_guard.push_back(installedsystem);
|
||||
}
|
||||
}
|
||||
InstalledPageMsg::UpdatePkgTypes(systempkgtype, userpkgtype) => {
|
||||
self.systempkgtype = systempkgtype;
|
||||
self.userpkgtype = userpkgtype;
|
||||
}
|
||||
InstalledPageMsg::OpenRow(row, pkgtype) => {
|
||||
match pkgtype {
|
||||
InstallType::User => {
|
||||
|
@ -1,14 +1,14 @@
|
||||
use crate::parse::config::NscConfig;
|
||||
|
||||
use super::pkgpage::{InstallType, PkgAction, PkgMsg, WorkPkg};
|
||||
use super::window::{UserPkgs, SystemPkgs};
|
||||
use super::window::{SystemPkgs, UserPkgs};
|
||||
use log::*;
|
||||
use relm4::*;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
use std::process::Stdio;
|
||||
use std::{fs, io};
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
|
||||
use log::*;
|
||||
|
||||
#[tracker::track]
|
||||
#[derive(Debug)]
|
||||
@ -16,7 +16,7 @@ pub struct InstallAsyncHandler {
|
||||
#[tracker::no_eq]
|
||||
process: Option<JoinHandle<()>>,
|
||||
work: Option<WorkPkg>,
|
||||
systemconfig: String,
|
||||
systemconfig: Option<String>,
|
||||
flakeargs: Option<String>,
|
||||
pid: Option<u32>,
|
||||
syspkgs: SystemPkgs,
|
||||
@ -26,6 +26,7 @@ pub struct InstallAsyncHandler {
|
||||
#[derive(Debug)]
|
||||
pub enum InstallAsyncHandlerMsg {
|
||||
SetConfig(NscConfig),
|
||||
SetPkgTypes(SystemPkgs, UserPkgs),
|
||||
Process(WorkPkg),
|
||||
CancelProcess,
|
||||
SetPid(Option<u32>),
|
||||
@ -46,7 +47,7 @@ impl Worker for InstallAsyncHandler {
|
||||
Self {
|
||||
process: None,
|
||||
work: None,
|
||||
systemconfig: String::new(),
|
||||
systemconfig: None,
|
||||
flakeargs: None,
|
||||
pid: None,
|
||||
syspkgs: params.syspkgs,
|
||||
@ -60,8 +61,21 @@ impl Worker for InstallAsyncHandler {
|
||||
match msg {
|
||||
InstallAsyncHandlerMsg::SetConfig(config) => {
|
||||
self.systemconfig = config.systemconfig;
|
||||
self.flakeargs = config.flake;
|
||||
self.flakeargs = if let Some(flake) = config.flake {
|
||||
if let Some(flakearg) = config.flakearg {
|
||||
Some(format!("{}#{}", flake, flakearg))
|
||||
} else {
|
||||
Some(flake)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
InstallAsyncHandlerMsg::SetPkgTypes(syspkgs, userpkgs) => {
|
||||
self.syspkgs = syspkgs;
|
||||
self.userpkgs = userpkgs;
|
||||
}
|
||||
|
||||
InstallAsyncHandlerMsg::Process(work) => {
|
||||
if work.block {
|
||||
return;
|
||||
@ -69,240 +83,246 @@ impl Worker for InstallAsyncHandler {
|
||||
let systemconfig = self.systemconfig.clone();
|
||||
let rebuildargs = self.flakeargs.clone();
|
||||
match work.pkgtype {
|
||||
InstallType::User => {
|
||||
match work.action {
|
||||
PkgAction::Install => {
|
||||
info!("Installing user package: {}", work.pkg);
|
||||
match self.userpkgs {
|
||||
UserPkgs::Env => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix-env")
|
||||
.arg("-iA")
|
||||
.arg(format!("nixos.{}", work.pkg))
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix-env");
|
||||
InstallType::User => match work.action {
|
||||
PkgAction::Install => {
|
||||
info!("Installing user package: {}", work.pkg);
|
||||
match self.userpkgs {
|
||||
UserPkgs::Env => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix-env")
|
||||
.arg("-iA")
|
||||
.arg(format!("nixos.{}", work.pkg))
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix-env");
|
||||
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
}
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
}
|
||||
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
UserPkgs::Profile => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix")
|
||||
.arg("profile")
|
||||
.arg("install")
|
||||
.arg(format!("nixpkgs#{}", work.pkg))
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix profile");
|
||||
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
UserPkgs::Profile => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix")
|
||||
.arg("profile")
|
||||
.arg("install")
|
||||
.arg(format!("nixpkgs#{}", work.pkg))
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix profile");
|
||||
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
}
|
||||
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
PkgAction::Remove => {
|
||||
info!("Removing user package: {}", work.pkg);
|
||||
match self.userpkgs {
|
||||
UserPkgs::Env => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix-env")
|
||||
.arg("-e")
|
||||
.arg(&work.pname)
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix-env");
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
}
|
||||
PkgAction::Remove => {
|
||||
info!("Removing user package: {}", work.pkg);
|
||||
match self.userpkgs {
|
||||
UserPkgs::Env => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix-env")
|
||||
.arg("-e")
|
||||
.arg(&work.pname)
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix-env");
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
}
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
}
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
UserPkgs::Profile => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix")
|
||||
.arg("profile")
|
||||
.arg("remove")
|
||||
.arg(&format!("legacyPackages.x86_64-linux.{}", work.pkg))
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix profile");
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
} }
|
||||
}
|
||||
}));
|
||||
}
|
||||
UserPkgs::Profile => {
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
let mut p = tokio::process::Command::new("nix")
|
||||
.arg("profile")
|
||||
.arg("remove")
|
||||
.arg(&format!(
|
||||
"legacyPackages.x86_64-linux.{}",
|
||||
work.pkg
|
||||
))
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to run nix profile");
|
||||
let stderr = p.stderr.take().unwrap();
|
||||
let reader = tokio::io::BufReader::new(stderr);
|
||||
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
let mut lines = reader.lines();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
trace!("CAUGHT LINE: {}", line);
|
||||
}
|
||||
match p.wait().await {
|
||||
Ok(o) => {
|
||||
if o.success() {
|
||||
info!(
|
||||
"Removed user package: {} success",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
warn!(
|
||||
"Removed user package: {} failed",
|
||||
work.pkg
|
||||
);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
Err(e) => {
|
||||
warn!("Error removing user package: {}", e);
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
InstallType::System => {
|
||||
if let Some(systemconfig) = systemconfig {
|
||||
match work.action {
|
||||
PkgAction::Install => {
|
||||
info!("Installing system package: {}", work.pkg);
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
match installsys(
|
||||
work.pkg.to_string(),
|
||||
work.action.clone(),
|
||||
systemconfig,
|
||||
rebuildargs,
|
||||
sender.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(b) => {
|
||||
if b {
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
sender.output(PkgMsg::FailedProcess(work))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
warn!("Error installing system package: {}", e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
PkgAction::Remove => {
|
||||
info!("Removing system package: {}", work.pkg);
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
match installsys(
|
||||
work.pkg.to_string(),
|
||||
work.action.clone(),
|
||||
systemconfig,
|
||||
rebuildargs,
|
||||
sender.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(b) => {
|
||||
if b {
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
sender.output(PkgMsg::FailedProcess(work))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
warn!("Error removing system package: {}", e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
InstallType::System => match work.action {
|
||||
PkgAction::Install => {
|
||||
info!("Installing system package: {}", work.pkg);
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
match installsys(
|
||||
work.pkg.to_string(),
|
||||
work.action.clone(),
|
||||
systemconfig,
|
||||
rebuildargs,
|
||||
sender.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(b) => {
|
||||
if b {
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
sender.output(PkgMsg::FailedProcess(work))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
warn!("Error installing system package: {}", e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
PkgAction::Remove => {
|
||||
info!("Removing system package: {}", work.pkg);
|
||||
self.process = Some(relm4::spawn(async move {
|
||||
match installsys(
|
||||
work.pkg.to_string(),
|
||||
work.action.clone(),
|
||||
systemconfig,
|
||||
rebuildargs,
|
||||
sender.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(b) => {
|
||||
if b {
|
||||
sender.output(PkgMsg::FinishedProcess(work))
|
||||
} else {
|
||||
sender.output(PkgMsg::FailedProcess(work))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
sender.output(PkgMsg::FailedProcess(work));
|
||||
warn!("Error removing system package: {}", e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
InstallAsyncHandlerMsg::CancelProcess => {
|
||||
|
@ -136,6 +136,7 @@ pub struct PkgInitModel {
|
||||
#[derive(Debug)]
|
||||
pub enum PkgMsg {
|
||||
UpdateConfig(NscConfig),
|
||||
UpdatePkgTypes(SystemPkgs, UserPkgs),
|
||||
Open(Box<PkgInitModel>),
|
||||
LoadScreenshot(String, usize, String),
|
||||
SetError(String, usize),
|
||||
@ -148,10 +149,6 @@ pub enum PkgMsg {
|
||||
RemoveSystem,
|
||||
Cancel,
|
||||
CancelFinished,
|
||||
// FinishedInstallUser(String, String),
|
||||
// FailedInstallUser(String, String),
|
||||
// FinishedRemoveUser(String, String),
|
||||
// FailedRemoveUser(String, String),
|
||||
FinishedProcess(WorkPkg),
|
||||
FailedProcess(WorkPkg),
|
||||
Launch,
|
||||
@ -203,6 +200,9 @@ impl Component for PkgModel {
|
||||
set_label: &model.name
|
||||
},
|
||||
pack_end = >k::MenuButton {
|
||||
#[watch]
|
||||
set_visible: model.syspkgtype != SystemPkgs::None,
|
||||
|
||||
#[watch]
|
||||
set_label: match model.userpkgtype {
|
||||
UserPkgs::Env => {
|
||||
@ -1044,6 +1044,11 @@ impl Component for PkgModel {
|
||||
self.config = config.clone();
|
||||
self.installworker.emit(InstallAsyncHandlerMsg::SetConfig(config));
|
||||
}
|
||||
PkgMsg::UpdatePkgTypes(syspkgs, userpkgs) => {
|
||||
self.syspkgtype = syspkgs.clone();
|
||||
self.userpkgtype = userpkgs.clone();
|
||||
self.installworker.emit(InstallAsyncHandlerMsg::SetPkgTypes(syspkgs, userpkgs));
|
||||
}
|
||||
PkgMsg::Open(pkgmodel) => {
|
||||
self.set_pkg(pkgmodel.pkg);
|
||||
self.set_name(pkgmodel.name);
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::parse::config::NscConfig;
|
||||
|
||||
use super::window::AppMsg;
|
||||
use adw::prelude::*;
|
||||
use relm4::*;
|
||||
@ -9,8 +11,9 @@ use relm4_components::open_dialog::*;
|
||||
#[derive(Debug)]
|
||||
pub struct PreferencesPageModel {
|
||||
hidden: bool,
|
||||
configpath: PathBuf,
|
||||
flake: Option<(PathBuf, String)>,
|
||||
configpath: Option<PathBuf>,
|
||||
flake: Option<PathBuf>,
|
||||
flakearg: Option<String>,
|
||||
#[tracker::no_eq]
|
||||
open_dialog: Controller<OpenDialog>,
|
||||
#[tracker::no_eq]
|
||||
@ -19,13 +22,12 @@ pub struct PreferencesPageModel {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PreferencesPageMsg {
|
||||
Show(PathBuf, Option<(PathBuf, String)>),
|
||||
Show(NscConfig),
|
||||
Open,
|
||||
OpenFlake,
|
||||
SetConfigPath(PathBuf),
|
||||
SetFlake(Option<(PathBuf, String)>),
|
||||
SetFlakePath(PathBuf),
|
||||
SetFlakeArg(String),
|
||||
SetConfigPath(Option<PathBuf>),
|
||||
SetFlakePath(Option<PathBuf>),
|
||||
SetFlakeArg(Option<String>),
|
||||
ModifyFlake,
|
||||
Ignore,
|
||||
}
|
||||
@ -64,7 +66,7 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_label: {
|
||||
let x = model.configpath.file_name().unwrap_or_default().to_str().unwrap_or_default();
|
||||
let x = if let Some(configpath) = &model.configpath { configpath.file_name().unwrap_or_default().to_str().unwrap_or_default() } else { "(None)" };
|
||||
if x.is_empty() {
|
||||
"(None)"
|
||||
} else {
|
||||
@ -77,13 +79,12 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
sender.input(PreferencesPageMsg::Open);
|
||||
}
|
||||
},
|
||||
// gtk::Button {
|
||||
// add_css_class: "flat",
|
||||
// set_icon_name: "view-refresh-symbolic",
|
||||
// connect_clicked[sender] => move |_| {
|
||||
// sender.input(PreferencesPageMsg::SetConfigPath(PathBuf::from("/etc/nixos/configuration.nix")));
|
||||
// }
|
||||
// }
|
||||
gtk::Button {
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(PreferencesPageMsg::SetConfigPath(None));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
add = &adw::ActionRow {
|
||||
@ -92,9 +93,10 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
set_valign: gtk::Align::Center,
|
||||
connect_state_set[sender] => move |_, b| {
|
||||
if b {
|
||||
sender.input(PreferencesPageMsg::SetFlake(Some((PathBuf::new(), String::default()))));
|
||||
sender.input(PreferencesPageMsg::SetFlakePath(Some(PathBuf::new())));
|
||||
} else {
|
||||
sender.input(PreferencesPageMsg::SetFlake(None));
|
||||
sender.input(PreferencesPageMsg::SetFlakePath(None));
|
||||
sender.input(PreferencesPageMsg::SetFlakeArg(None));
|
||||
}
|
||||
gtk::Inhibit(false)
|
||||
} @switched,
|
||||
@ -122,7 +124,7 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
gtk::Label {
|
||||
#[watch]
|
||||
set_label: {
|
||||
let x = if let Some((f, _)) = &model.flake {
|
||||
let x = if let Some(f) = &model.flake {
|
||||
f.file_name().unwrap_or_default().to_str().unwrap_or_default()
|
||||
} else {
|
||||
""
|
||||
@ -153,11 +155,17 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
set_visible: model.flake.is_some(),
|
||||
set_title: "Flake arguments (--flake path/to/flake.nix#<THIS ENTRY>)",
|
||||
connect_changed[sender] => move |x| {
|
||||
sender.input(PreferencesPageMsg::SetFlakeArg(x.text().to_string()));
|
||||
sender.input(PreferencesPageMsg::SetFlakeArg({
|
||||
let text = x.text().to_string();
|
||||
if text.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(text)
|
||||
}}));
|
||||
} @flakeentry,
|
||||
#[track(model.changed(PreferencesPageModel::flake()))]
|
||||
#[block_signal(flakeentry)]
|
||||
set_text: &model.flake.as_ref().map(|(_, a)| a.to_string()).unwrap_or_default()
|
||||
set_text: &model.flakearg.as_ref().unwrap_or(&String::new())
|
||||
}
|
||||
|
||||
}
|
||||
@ -174,20 +182,21 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
.transient_for_native(root)
|
||||
.launch(OpenDialogSettings::default())
|
||||
.forward(&sender.input, |response| match response {
|
||||
OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetConfigPath(path),
|
||||
OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetConfigPath(Some(path)),
|
||||
OpenDialogResponse::Cancel => PreferencesPageMsg::Ignore,
|
||||
});
|
||||
let flake_file_dialog = OpenDialog::builder()
|
||||
.transient_for_native(root)
|
||||
.launch(OpenDialogSettings::default())
|
||||
.forward(&sender.input, |response| match response {
|
||||
OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetFlakePath(path),
|
||||
OpenDialogResponse::Accept(path) => PreferencesPageMsg::SetFlakePath(Some(path)),
|
||||
OpenDialogResponse::Cancel => PreferencesPageMsg::Ignore,
|
||||
});
|
||||
let model = PreferencesPageModel {
|
||||
hidden: true,
|
||||
configpath: PathBuf::new(),
|
||||
configpath: None,
|
||||
flake: None,
|
||||
flakearg: None,
|
||||
open_dialog,
|
||||
flake_file_dialog,
|
||||
tracker: 0,
|
||||
@ -201,41 +210,28 @@ impl SimpleComponent for PreferencesPageModel {
|
||||
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
|
||||
self.reset();
|
||||
match msg {
|
||||
PreferencesPageMsg::Show(path, flake) => {
|
||||
self.configpath = path;
|
||||
self.set_flake(flake);
|
||||
PreferencesPageMsg::Show(config) => {
|
||||
self.configpath = config.systemconfig.as_ref().map(|x| PathBuf::from(x));
|
||||
self.set_flake(config.flake.as_ref().map(|x| PathBuf::from(x)));
|
||||
self.set_flakearg(config.flakearg.clone());
|
||||
self.hidden = false;
|
||||
}
|
||||
PreferencesPageMsg::Open => self.open_dialog.emit(OpenDialogMsg::Open),
|
||||
PreferencesPageMsg::OpenFlake => self.flake_file_dialog.emit(OpenDialogMsg::Open),
|
||||
PreferencesPageMsg::SetConfigPath(path) => {
|
||||
self.configpath = path.clone();
|
||||
sender.output(AppMsg::UpdateSysconfig(path.to_string_lossy().to_string()));
|
||||
}
|
||||
PreferencesPageMsg::SetFlake(flake) => {
|
||||
self.flake = flake;
|
||||
sender.input(PreferencesPageMsg::ModifyFlake)
|
||||
sender.output(AppMsg::UpdateSysconfig(path.map(|x| x.to_string_lossy().to_string())));
|
||||
}
|
||||
PreferencesPageMsg::SetFlakePath(path) => {
|
||||
self.flake = Some((
|
||||
path,
|
||||
self.flake.as_ref().map(|x| x.1.clone()).unwrap_or_default(),
|
||||
));
|
||||
self.flake = path;
|
||||
sender.input(PreferencesPageMsg::ModifyFlake)
|
||||
}
|
||||
PreferencesPageMsg::SetFlakeArg(arg) => {
|
||||
self.flake = Some((
|
||||
self.flake.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
arg,
|
||||
));
|
||||
self.flakearg = arg;
|
||||
sender.input(PreferencesPageMsg::ModifyFlake)
|
||||
}
|
||||
PreferencesPageMsg::ModifyFlake => {
|
||||
let out = self
|
||||
.flake
|
||||
.as_ref()
|
||||
.map(|(path, arg)| format!("{}#{}", path.to_string_lossy(), arg));
|
||||
sender.output(AppMsg::UpdateFlake(out.map(|x| x.strip_suffix('#').unwrap_or(&x).to_string())));
|
||||
sender.output(AppMsg::UpdateFlake(self.flake.as_ref().map(|x| x.to_string_lossy().to_string()), self.flakearg.clone()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ pub struct UpdatePageModel {
|
||||
#[derive(Debug)]
|
||||
pub enum UpdatePageMsg {
|
||||
UpdateConfig(NscConfig),
|
||||
UpdatePkgTypes(SystemPkgs, UserPkgs),
|
||||
Update(Vec<UpdateItem>, Vec<UpdateItem>),
|
||||
OpenRow(usize, InstallType),
|
||||
UpdateSystem,
|
||||
@ -318,6 +319,11 @@ impl SimpleComponent for UpdatePageModel {
|
||||
self.config = config;
|
||||
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateConfig(self.config.clone()));
|
||||
}
|
||||
UpdatePageMsg::UpdatePkgTypes(systype, usertype) => {
|
||||
self.systype = systype.clone();
|
||||
self.usertype = usertype.clone();
|
||||
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdatePkgTypes(self.systype.clone(), self.usertype.clone()));
|
||||
}
|
||||
UpdatePageMsg::Update(updateuserlist, updatesystemlist) => {
|
||||
info!("UpdatePageMsg::Update");
|
||||
debug!("UPDATEUSERLIST: {:?}", updateuserlist);
|
||||
|
@ -15,7 +15,7 @@ use super::{
|
||||
pub struct UpdateAsyncHandler {
|
||||
#[tracker::no_eq]
|
||||
process: Option<JoinHandle<()>>,
|
||||
systemconfig: String,
|
||||
systemconfig: Option<String>,
|
||||
flakeargs: Option<String>,
|
||||
syspkgs: SystemPkgs,
|
||||
userpkgs: UserPkgs,
|
||||
@ -24,6 +24,7 @@ pub struct UpdateAsyncHandler {
|
||||
#[derive(Debug)]
|
||||
pub enum UpdateAsyncHandlerMsg {
|
||||
UpdateConfig(NscConfig),
|
||||
UpdatePkgTypes(SystemPkgs, UserPkgs),
|
||||
|
||||
UpdateChannels,
|
||||
UpdateChannelsAndSystem,
|
||||
@ -53,7 +54,7 @@ impl Worker for UpdateAsyncHandler {
|
||||
fn init(params: Self::InitParams, _sender: relm4::ComponentSender<Self>) -> Self {
|
||||
Self {
|
||||
process: None,
|
||||
systemconfig: String::default(),
|
||||
systemconfig: None,
|
||||
flakeargs: None,
|
||||
syspkgs: params.syspkgs,
|
||||
userpkgs: params.userpkgs,
|
||||
@ -65,14 +66,26 @@ impl Worker for UpdateAsyncHandler {
|
||||
match msg {
|
||||
UpdateAsyncHandlerMsg::UpdateConfig(config) => {
|
||||
self.systemconfig = config.systemconfig;
|
||||
self.flakeargs = config.flake;
|
||||
self.flakeargs = if let Some(flake) = config.flake {
|
||||
if let Some(flakearg) = config.flakearg {
|
||||
Some(format!("{}#{}", flake, flakearg))
|
||||
} else {
|
||||
Some(flake)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
UpdateAsyncHandlerMsg::UpdatePkgTypes(syspkgs, userpkgs) => {
|
||||
self.syspkgs = syspkgs;
|
||||
self.userpkgs = userpkgs;
|
||||
}
|
||||
UpdateAsyncHandlerMsg::UpdateChannels => {
|
||||
let systenconfig = self.systemconfig.clone();
|
||||
let systemconfig = self.systemconfig.clone();
|
||||
let flakeargs = self.flakeargs.clone();
|
||||
let syspkgs = self.syspkgs.clone();
|
||||
relm4::spawn(async move {
|
||||
let result = runcmd(NscCmd::Channel, systenconfig, flakeargs, syspkgs).await;
|
||||
let result = runcmd(NscCmd::Channel, systemconfig, flakeargs, syspkgs).await;
|
||||
match result {
|
||||
Ok(true) => {
|
||||
sender.output(UpdatePageMsg::DoneWorking);
|
||||
@ -102,13 +115,14 @@ impl Worker for UpdateAsyncHandler {
|
||||
});
|
||||
}
|
||||
UpdateAsyncHandlerMsg::RebuildSystem => {
|
||||
let systenconfig = self.systemconfig.clone();
|
||||
let systemconfig = self.systemconfig.clone();
|
||||
let flakeargs = self.flakeargs.clone();
|
||||
let syspkgs = self.syspkgs.clone();
|
||||
relm4::spawn(async move {
|
||||
let result = match syspkgs {
|
||||
SystemPkgs::Legacy => runcmd(NscCmd::Rebuild, systenconfig, flakeargs, syspkgs).await,
|
||||
SystemPkgs::Flake => runcmd(NscCmd::All, systenconfig, flakeargs, syspkgs).await,
|
||||
SystemPkgs::Legacy => runcmd(NscCmd::Rebuild, systemconfig, flakeargs, syspkgs).await,
|
||||
SystemPkgs::Flake => runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs).await,
|
||||
SystemPkgs::None => Ok(true),
|
||||
};
|
||||
match result {
|
||||
Ok(true) => {
|
||||
@ -174,7 +188,7 @@ impl Worker for UpdateAsyncHandler {
|
||||
|
||||
async fn runcmd(
|
||||
cmd: NscCmd,
|
||||
_systemconfig: String,
|
||||
_systemconfig: Option<String>,
|
||||
flakeargs: Option<String>,
|
||||
syspkgs: SystemPkgs,
|
||||
) -> Result<bool, Box<dyn Error + Send + Sync>> {
|
||||
@ -245,6 +259,7 @@ async fn runcmd(
|
||||
.args(&rebuildargs)
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?,
|
||||
SystemPkgs::None => return Ok(true),
|
||||
},
|
||||
};
|
||||
|
||||
@ -286,7 +301,7 @@ async fn updateprofile() -> Result<bool, Box<dyn Error + Send + Sync>> {
|
||||
let mut cmd = tokio::process::Command::new("nix")
|
||||
.arg("profile")
|
||||
.arg("upgrade")
|
||||
.arg("'.*'")
|
||||
.arg(".*")
|
||||
// Allow updating potential unfree packages
|
||||
.arg("--impure")
|
||||
.stderr(Stdio::piped())
|
||||
|
@ -27,6 +27,7 @@ pub enum WelcomeMsg {
|
||||
Close,
|
||||
UpdateConfPath(PathBuf),
|
||||
UpdateFlakePath(PathBuf),
|
||||
ClearConfPath,
|
||||
ClearFlakePath,
|
||||
OpenConf,
|
||||
OpenFlake,
|
||||
@ -102,6 +103,14 @@ impl SimpleComponent for WelcomeModel {
|
||||
sender.input(WelcomeMsg::OpenConf);
|
||||
}
|
||||
},
|
||||
add_suffix = >k::Button {
|
||||
set_halign: gtk::Align::Center,
|
||||
set_valign: gtk::Align::Center,
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
connect_clicked[sender] => move |_| {
|
||||
sender.input(WelcomeMsg::ClearConfPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
gtk::ListBox {
|
||||
@ -150,10 +159,8 @@ impl SimpleComponent for WelcomeModel {
|
||||
}
|
||||
},
|
||||
},
|
||||
#[name(btn)]
|
||||
#[name(continuebtn)]
|
||||
gtk::Button {
|
||||
#[watch]
|
||||
set_sensitive: model.confpath.is_some(),
|
||||
add_css_class: "pill",
|
||||
add_css_class: "suggested-action",
|
||||
set_label: "Continue",
|
||||
@ -191,8 +198,6 @@ impl SimpleComponent for WelcomeModel {
|
||||
OpenDialogResponse::Cancel => WelcomeMsg::Ignore,
|
||||
});
|
||||
|
||||
|
||||
|
||||
let model = WelcomeModel {
|
||||
hidden: true,
|
||||
confpath: if Path::new("/etc/nixos/configuration.nix").exists() { Some(PathBuf::from("/etc/nixos/configuration.nix")) } else { None }, // parent_window.configpath.to_string(),
|
||||
@ -205,7 +210,7 @@ impl SimpleComponent for WelcomeModel {
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
widgets.btn.grab_focus();
|
||||
widgets.continuebtn.grab_focus();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
@ -217,14 +222,13 @@ impl SimpleComponent for WelcomeModel {
|
||||
self.hidden = false;
|
||||
}
|
||||
WelcomeMsg::Close => {
|
||||
if let Some(confpath) = &self.confpath {
|
||||
let config = NscConfig {
|
||||
systemconfig: confpath.to_string_lossy().to_string(),
|
||||
flake: self.flakepath.as_ref().map(|x| x.to_string_lossy().to_string()),
|
||||
};
|
||||
sender.output(AppMsg::LoadConfig(config));
|
||||
self.hidden = true;
|
||||
}
|
||||
let config = NscConfig {
|
||||
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,
|
||||
};
|
||||
sender.output(AppMsg::LoadConfig(config));
|
||||
self.hidden = true;
|
||||
}
|
||||
WelcomeMsg::UpdateConfPath(s) => {
|
||||
info!("Set configuration path to {}", s.to_string_lossy());
|
||||
@ -234,6 +238,9 @@ impl SimpleComponent for WelcomeModel {
|
||||
info!("Set flake path to {}", s.to_string_lossy());
|
||||
self.set_flakepath(Some(s));
|
||||
}
|
||||
WelcomeMsg::ClearConfPath => {
|
||||
self.set_confpath(None);
|
||||
}
|
||||
WelcomeMsg::ClearFlakePath => {
|
||||
info!("Clear flake path");
|
||||
self.set_flakepath(None);
|
||||
|
127
src/ui/window.rs
127
src/ui/window.rs
@ -31,6 +31,7 @@ enum MainPage {
|
||||
pub enum SystemPkgs {
|
||||
Legacy,
|
||||
Flake,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@ -87,8 +88,8 @@ pub struct AppModel {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppMsg {
|
||||
UpdateSysconfig(String),
|
||||
UpdateFlake(Option<String>),
|
||||
UpdateSysconfig(Option<String>),
|
||||
UpdateFlake(Option<String>, Option<String>),
|
||||
TryLoad,
|
||||
ReloadUpdate,
|
||||
LoadConfig(NscConfig),
|
||||
@ -351,25 +352,31 @@ impl Component for AppModel {
|
||||
|
||||
let (config, welcome) = if let Some(config) = getconfig() {
|
||||
debug!("Got config: {:?}", config);
|
||||
if !Path::new(&config.systemconfig).exists() {
|
||||
warn!("Invalid system config path: {}", config.systemconfig);
|
||||
(config, true)
|
||||
} else if let Some(flakepath) = &config.flake {
|
||||
let mut out = false;
|
||||
if let Some(configpath) = &config.systemconfig {
|
||||
if !Path::new(configpath).exists() {
|
||||
warn!("Invalid system config path: {}", configpath);
|
||||
out = true
|
||||
}
|
||||
}
|
||||
if let Some(flakepath) = &config.flake {
|
||||
if !Path::new(&flakepath).exists() {
|
||||
warn!("Invalid flake path: {}", flakepath);
|
||||
(config, true)
|
||||
out = true
|
||||
} else {
|
||||
(config, false)
|
||||
out = false
|
||||
}
|
||||
} else {
|
||||
(config, false)
|
||||
out = false
|
||||
}
|
||||
(config, out)
|
||||
} else {
|
||||
// Show welcome page
|
||||
debug!("No config found");
|
||||
(NscConfig {
|
||||
systemconfig: String::from("/etc/nixos/configuration.nix"),
|
||||
systemconfig: None,
|
||||
flake: None,
|
||||
flakearg: None,
|
||||
}, true)
|
||||
};
|
||||
|
||||
@ -392,22 +399,27 @@ impl Component for AppModel {
|
||||
UserPkgs::Env
|
||||
};
|
||||
|
||||
let syspkgtype = match fs::read_to_string("/run/current-system/nixos-version") {
|
||||
Ok(s) => {
|
||||
if !Path::new("/nix/var/nix/profiles/per-user/root/channels/nixos").exists() || config.flake.is_some() {
|
||||
SystemPkgs::Flake
|
||||
} else if let Some(last) = s.split('.').last() {
|
||||
if last.len() == 7 || last == "dirty" || last == "git" {
|
||||
let syspkgtype = if config.systemconfig.is_none() {
|
||||
SystemPkgs::None
|
||||
} else {
|
||||
match fs::read_to_string("/run/current-system/nixos-version") {
|
||||
Ok(s) => {
|
||||
if !Path::new("/nix/var/nix/profiles/per-user/root/channels/nixos").exists() || config.flake.is_some() {
|
||||
SystemPkgs::Flake
|
||||
} else if let Some(last) = s.split('.').last() {
|
||||
if last.len() == 7 || last == "dirty" || last == "git" {
|
||||
SystemPkgs::Flake
|
||||
} else {
|
||||
SystemPkgs::Legacy
|
||||
}
|
||||
} else {
|
||||
SystemPkgs::Legacy
|
||||
}
|
||||
} else {
|
||||
SystemPkgs::Legacy
|
||||
}
|
||||
Err(_) => SystemPkgs::None,
|
||||
}
|
||||
Err(_) => SystemPkgs::Legacy,
|
||||
};
|
||||
|
||||
debug!("userpkgtype: {:?}", userpkgtype);
|
||||
debug!("syspkgtype: {:?}", syspkgtype);
|
||||
|
||||
@ -433,7 +445,7 @@ impl Component for AppModel {
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), identity);
|
||||
let installedpage = InstalledPageModel::builder()
|
||||
.launch(userpkgtype.clone())
|
||||
.launch((syspkgtype.clone(), userpkgtype.clone()))
|
||||
.forward(sender.input_sender(), identity);
|
||||
let updatepage = UpdatePageModel::builder()
|
||||
.launch(UpdatePageInit { window: root.clone().upcast(), systype: syspkgtype.clone(), usertype: userpkgtype.clone(), config: config.clone() })
|
||||
@ -558,26 +570,55 @@ impl Component for AppModel {
|
||||
}
|
||||
AppMsg::UpdateSysconfig(systemconfig) => {
|
||||
self.config = NscConfig {
|
||||
systemconfig,
|
||||
systemconfig: systemconfig.clone(),
|
||||
flake: self.config.flake.clone(),
|
||||
flakearg: self.config.flakearg.clone(),
|
||||
};
|
||||
if editconfig(self.config.clone()).is_err() {
|
||||
warn!("Failed to update config");
|
||||
}
|
||||
|
||||
if systemconfig.is_some() {
|
||||
if self.syspkgtype == SystemPkgs::None {
|
||||
if self.config.flake.is_some() {
|
||||
self.syspkgtype = SystemPkgs::Flake;
|
||||
} else {
|
||||
self.syspkgtype = SystemPkgs::Legacy;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.syspkgtype = SystemPkgs::None;
|
||||
}
|
||||
|
||||
self.pkgpage.emit(PkgMsg::UpdateConfig(self.config.clone()));
|
||||
self.updatepage.emit(UpdatePageMsg::UpdateConfig(self.config.clone()));
|
||||
sender.input(AppMsg::UpdatePkgs(None))
|
||||
self.pkgpage.emit(PkgMsg::UpdatePkgTypes(self.syspkgtype.clone(), self.userpkgtype.clone()));
|
||||
self.updatepage.emit(UpdatePageMsg::UpdatePkgTypes(self.syspkgtype.clone(), self.userpkgtype.clone()));
|
||||
self.installedpage.emit(InstalledPageMsg::UpdatePkgTypes(self.syspkgtype.clone(), self.userpkgtype.clone()));
|
||||
sender.input(AppMsg::UpdatePkgs(None));
|
||||
|
||||
}
|
||||
AppMsg::UpdateFlake(flake) => {
|
||||
AppMsg::UpdateFlake(flake, flakearg) => {
|
||||
self.config = NscConfig {
|
||||
systemconfig: self.config.systemconfig.clone(),
|
||||
flake,
|
||||
flake: flake.clone(),
|
||||
flakearg,
|
||||
};
|
||||
if editconfig(self.config.clone()).is_err() {
|
||||
warn!("Failed to update config");
|
||||
}
|
||||
|
||||
if flake.is_some() {
|
||||
self.syspkgtype = SystemPkgs::Flake;
|
||||
} else {
|
||||
self.syspkgtype = SystemPkgs::Legacy;
|
||||
}
|
||||
|
||||
self.pkgpage.emit(PkgMsg::UpdateConfig(self.config.clone()));
|
||||
self.updatepage.emit(UpdatePageMsg::UpdateConfig(self.config.clone()));
|
||||
self.pkgpage.emit(PkgMsg::UpdatePkgTypes(self.syspkgtype.clone(), self.userpkgtype.clone()));
|
||||
self.updatepage.emit(UpdatePageMsg::UpdatePkgTypes(self.syspkgtype.clone(), self.userpkgtype.clone()));
|
||||
self.installedpage.emit(InstalledPageMsg::UpdatePkgTypes(self.syspkgtype.clone(), self.userpkgtype.clone()));
|
||||
}
|
||||
AppMsg::Initialize(pkgs, recommendedapps, syspkgs, categoryrec, categoryall, profilepkgs) => {
|
||||
self.syspkgs = syspkgs;
|
||||
@ -938,11 +979,15 @@ impl Component for AppModel {
|
||||
Ok(pcurrpkgs)
|
||||
}
|
||||
|
||||
let systempkgs = match getsystempkgs(&self.config.systemconfig) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
self.installedsystempkgs.clone()
|
||||
let systempkgs = if let Some(sysconfig) = &self.config.systemconfig {
|
||||
match getsystempkgs(sysconfig) {
|
||||
Ok(x) => x,
|
||||
Err(_) => {
|
||||
self.installedsystempkgs.clone()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HashSet::new()
|
||||
};
|
||||
|
||||
let userpkgs = match self.userpkgtype {
|
||||
@ -1221,6 +1266,7 @@ impl Component for AppModel {
|
||||
})
|
||||
}
|
||||
}
|
||||
SystemPkgs::None => {}
|
||||
}
|
||||
self.updatepage.emit(UpdatePageMsg::Update(updateuseritems, updatesystemitems));
|
||||
}
|
||||
@ -1321,18 +1367,19 @@ impl Component for AppModel {
|
||||
let preferencespage = PreferencesPageModel::builder()
|
||||
.launch(self.mainwindow.clone().upcast())
|
||||
.forward(sender.input_sender(), identity);
|
||||
if let Some(flake) = &self.config.flake {
|
||||
let flakeparts = flake.split('#').collect::<Vec<&str>>();
|
||||
if let Some(p) = flakeparts.first() {
|
||||
let path = PathBuf::from(p);
|
||||
let args = flakeparts.get(1).unwrap_or(&"").to_string();
|
||||
preferencespage.emit(PreferencesPageMsg::Show(PathBuf::from(&self.config.systemconfig), Some((path, args))))
|
||||
} else {
|
||||
preferencespage.emit(PreferencesPageMsg::Show(PathBuf::from(&self.config.systemconfig), None))
|
||||
}
|
||||
} else {
|
||||
preferencespage.emit(PreferencesPageMsg::Show(PathBuf::from(&self.config.systemconfig), None))
|
||||
}
|
||||
preferencespage.emit(PreferencesPageMsg::Show(self.config.clone()));
|
||||
// if let Some(flake) = &self.config.flake {
|
||||
// let flakeparts = flake.split('#').collect::<Vec<&str>>();
|
||||
// if let Some(p) = flakeparts.first() {
|
||||
// let path = PathBuf::from(p);
|
||||
// let args = flakeparts.get(1).unwrap_or(&"").to_string();
|
||||
// preferencespage.emit(PreferencesPageMsg::Show(PathBuf::from(&self.config.systemconfig), Some((path, args))))
|
||||
// } else {
|
||||
// preferencespage.emit(PreferencesPageMsg::Show(PathBuf::from(&self.config.systemconfig), None))
|
||||
// }
|
||||
// } else {
|
||||
// preferencespage.emit(PreferencesPageMsg::Show(PathBuf::from(&self.config.systemconfig), None))
|
||||
// }
|
||||
}
|
||||
AppMsg::AddInstalledToWorkQueue(work) => {
|
||||
let p = match work.pkgtype {
|
||||
|
@ -109,6 +109,9 @@ impl Worker for WindowAsyncHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
SystemPkgs::None => {
|
||||
HashMap::new()
|
||||
}
|
||||
};
|
||||
|
||||
let profilepkgs = match userpkgs {
|
||||
|
Loading…
Reference in New Issue
Block a user