Add rebuild output window

This commit is contained in:
Victor Fuentes 2022-11-01 14:27:22 -04:00
parent f355d40336
commit 0e9d1105f7
No known key found for this signature in database
GPG Key ID: 0A88B68D6A9ACAE0
10 changed files with 535 additions and 341 deletions

65
Cargo.lock generated
View File

@ -198,9 +198,9 @@ checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "bytemuck"
version = "1.12.1"
version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da"
checksum = "5aec14f5d4e6e3f927cd0c81f72e5710d95ee9019fbeb4b3021193867491bfd8"
[[package]]
name = "byteorder"
@ -250,9 +250,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.73"
version = "1.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574"
[[package]]
name = "cfg-expr"
@ -1230,9 +1230,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "0.14.20"
version = "0.14.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064"
dependencies = [
"bytes",
"futures-channel",
@ -1617,7 +1617,7 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix-data"
version = "0.0.2"
source = "git+https://github.com/snowflakelinux/nix-data?rev=a5168c768e8cf8bd3e1afe1772f8e05e5b03ed95#a5168c768e8cf8bd3e1afe1772f8e05e5b03ed95"
source = "git+https://github.com/snowflakelinux/nix-data#33479e595f14142f15fb6ec29cc585352c2c7703"
dependencies = [
"anyhow",
"csv",
@ -1669,6 +1669,7 @@ dependencies = [
"serde_json",
"serde_yaml",
"sha256",
"sourceview5",
"spdx",
"sqlx",
"tokio",
@ -1751,9 +1752,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "opaque-debug"
@ -1967,14 +1968,14 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "png"
version = "0.17.6"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f0e7f4c94ec26ff209cee506314212639d6c91b80afb82984819fafce9df01c"
checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638"
dependencies = [
"bitflags",
"crc32fast",
"flate2",
"miniz_oxide 0.5.4",
"miniz_oxide 0.6.2",
]
[[package]]
@ -2500,6 +2501,42 @@ dependencies = [
"winapi",
]
[[package]]
name = "sourceview5"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "922cc28db6bec169868319262dd932f6403e5ce95dad0d2bb6fcc9ac03be7f10"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"gdk-pixbuf",
"gdk4",
"gio",
"glib",
"gtk4",
"libc",
"pango",
"sourceview5-sys",
]
[[package]]
name = "sourceview5-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73277b2a53923aeecd212a89379dce7e6c687fe35fe6dd41d9b0d7b3d4c2eb0b"
dependencies = [
"gdk-pixbuf-sys",
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"gtk4-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "spdx"
version = "0.9.0"
@ -2777,9 +2814,9 @@ dependencies = [
[[package]]
name = "tiff"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7259662e32d1e219321eb309d5f9d898b779769d81b76e762c07c8e5d38fcb65"
checksum = "9f71e422515e83e3ab8a03d4781d05ebf864fc61f4546e6ecffa58cbd34181a0"
dependencies = [
"flate2",
"jpeg-decoder",

View File

@ -9,6 +9,7 @@ relm4 = { version = "0.5.0-beta.4", features = ["all"] }
relm4-components = { package = "relm4-components", version = "0.5.0-beta.4"}
adw = { package = "libadwaita", version = "0.2", features = ["v1_2", "gtk_v4_6"] }
gtk = { package = "gtk4", version = "0.5", features = ["v4_6"] }
sourceview5 = { version = "0.5", features = ["v5_4"] }
tokio = { version = "1.21", features = ["rt", "macros", "time", "rt-multi-thread", "sync", "process"] }
tracker = "0.1"
@ -17,7 +18,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
nix-editor = "0.3.0-beta.1"
nix-data = { git = "https://github.com/snowflakelinux/nix-data", rev = "a5168c768e8cf8bd3e1afe1772f8e05e5b03ed95" }
nix-data = { git = "https://github.com/snowflakelinux/nix-data" }
sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls" , "sqlite" ] }

View File

@ -57,6 +57,7 @@
pango
pkg-config
polkit
sqlite
wrapGAppsHook4
nixos-appstream-data
];

View File

@ -1,12 +1,13 @@
use super::pkgpage::{InstallType, PkgAction, PkgMsg, WorkPkg};
use super::window::{SystemPkgs, UserPkgs};
use super::rebuild::RebuildMsg;
use super::window::{SystemPkgs, UserPkgs, REBUILD_BROKER};
use log::*;
use nix_data::config::configfile::NixDataConfig;
use relm4::*;
use std::error::Error;
use anyhow::{Result, anyhow};
use std::path::Path;
use std::process::Stdio;
use std::{fs, io};
use std::fs;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
#[tracker::track]
@ -265,6 +266,7 @@ impl Worker for InstallAsyncHandler {
}
},
InstallType::System => {
REBUILD_BROKER.send(RebuildMsg::Show);
if let Some(systemconfig) = systemconfig {
match work.action {
PkgAction::Install => {
@ -281,12 +283,15 @@ impl Worker for InstallAsyncHandler {
{
Ok(b) => {
if b {
REBUILD_BROKER.send(RebuildMsg::FinishSuccess);
sender.output(PkgMsg::FinishedProcess(work))
} else {
REBUILD_BROKER.send(RebuildMsg::FinishError(None));
sender.output(PkgMsg::FailedProcess(work))
}
}
Err(e) => {
REBUILD_BROKER.send(RebuildMsg::FinishError(None));
sender.output(PkgMsg::FailedProcess(work));
warn!("Error installing system package: {}", e);
}
@ -307,12 +312,15 @@ impl Worker for InstallAsyncHandler {
{
Ok(b) => {
if b {
REBUILD_BROKER.send(RebuildMsg::FinishSuccess);
sender.output(PkgMsg::FinishedProcess(work))
} else {
REBUILD_BROKER.send(RebuildMsg::FinishError(None));
sender.output(PkgMsg::FailedProcess(work))
}
}
Err(e) => {
REBUILD_BROKER.send(RebuildMsg::FinishError(None));
sender.output(PkgMsg::FailedProcess(work));
warn!("Error removing system package: {}", e);
}
@ -344,7 +352,7 @@ async fn installsys(
systemconfig: String,
flakeargs: Option<String>,
_sender: ComponentSender<InstallAsyncHandler>,
) -> Result<bool, Box<dyn Error>> {
) -> Result<bool> {
let mut p = pkg;
let f = fs::read_to_string(&systemconfig)?;
if let Ok(s) = nix_editor::read::getwithvalue(&f, "environment.systemPackages") {
@ -352,10 +360,7 @@ async fn installsys(
p = format!("pkgs.{}", p);
}
} else {
return Err(Box::new(io::Error::new(
io::ErrorKind::InvalidData,
"Failed to write configuration.nix",
)));
return Err(anyhow!("Failed to write configuration.nix"));
}
let out = match action {
@ -363,10 +368,7 @@ async fn installsys(
match nix_editor::write::addtoarr(&f, "environment.systemPackages", vec![p]) {
Ok(x) => x,
Err(_) => {
return Err(Box::new(io::Error::new(
io::ErrorKind::InvalidData,
"Failed to write configuration.nix",
)))
return Err(anyhow!("Failed to write configuration.nix"));
}
}
}
@ -374,10 +376,7 @@ async fn installsys(
match nix_editor::write::rmarr(&f, "environment.systemPackages", vec![p]) {
Ok(x) => x,
Err(_) => {
return Err(Box::new(io::Error::new(
io::ErrorKind::InvalidData,
"Failed to write configuration.nix",
)))
return Err(anyhow!("Failed to write configuration.nix"));
}
}
}
@ -419,13 +418,12 @@ async fn installsys(
.arg(&systemconfig)
.arg("--")
.arg("switch")
.arg("--impure")
.args(&rebuildargs)
.stderr(Stdio::piped())
.stdin(Stdio::piped())
.spawn()?;
// sender.input(InstallAsyncHandlerMsg::SetPid(cmd.id()));
cmd.stdin.take().unwrap().write_all(out.as_bytes()).await?;
let stderr = cmd.stderr.take().unwrap();
let reader = tokio::io::BufReader::new(stderr);
@ -433,6 +431,7 @@ async fn installsys(
let mut lines = reader.lines();
while let Ok(Some(line)) = lines.next_line().await {
trace!("CAUGHT LINE: {}", line);
REBUILD_BROKER.send(RebuildMsg::UpdateText(line));
}
if cmd.wait().await?.success() {
Ok(true)

View File

@ -1,17 +1,17 @@
pub mod window;
pub mod windowloading;
pub mod pkgtile;
pub mod categories;
pub mod pkgpage;
pub mod screenshotfactory;
pub mod installworker;
pub mod searchpage;
pub mod installedpage;
pub mod updatepage;
pub mod updatedialog;
pub mod updateworker;
pub mod about;
pub mod preferencespage;
pub mod categories;
pub mod categorypage;
pub mod categorytile;
pub mod installedpage;
pub mod installworker;
pub mod pkgpage;
pub mod pkgtile;
pub mod preferencespage;
pub mod rebuild;
pub mod screenshotfactory;
pub mod searchpage;
pub mod updatepage;
pub mod updateworker;
pub mod welcome;
pub mod window;
pub mod windowloading;

244
src/ui/rebuild.rs Normal file
View File

@ -0,0 +1,244 @@
use super::window::AppMsg;
use adw::prelude::*;
use log::{info, trace};
use relm4::*;
use sourceview5::prelude::*;
#[tracker::track]
pub struct RebuildModel {
hidden: bool,
text: String,
status: RebuildStatus,
config: String,
path: String,
flake: Option<String>,
scheme: Option<sourceview5::StyleScheme>,
}
#[derive(Debug)]
pub enum RebuildMsg {
Show,
FinishSuccess,
FinishError(Option<String>),
UpdateText(String),
Close,
SetScheme(String),
Quit,
}
#[derive(PartialEq)]
enum RebuildStatus {
Building,
Success,
Error,
}
#[relm4::component(pub)]
impl SimpleComponent for RebuildModel {
type Init = gtk::Window;
type Input = RebuildMsg;
type Output = AppMsg;
type Widgets = RebuildWidgets;
view! {
dialog = adw::Window {
set_transient_for: Some(&parent_window),
set_modal: true,
#[track(model.changed(RebuildModel::hidden()))]
set_default_width: 500,
#[track(model.changed(RebuildModel::hidden()))]
set_default_height: 200,//295),
set_resizable: true,
#[watch]
set_visible: !model.hidden,
add_css_class: "dialog",
add_css_class: "message",
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
#[name(statusstack)]
gtk::Stack {
set_margin_top: 20,
set_transition_type: gtk::StackTransitionType::Crossfade,
set_vhomogeneous: false,
#[name(building)]
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,
gtk::Spinner {
#[watch]
set_spinning: true,
set_height_request: 60,
},
gtk::Label {
set_label: "Building...",
add_css_class: "title-1",
},
},
#[name(success)]
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,
gtk::Image {
add_css_class: "success",
set_icon_name: Some("object-select-symbolic"),
set_pixel_size: 128,
},
gtk::Label {
set_label: "Done!",
add_css_class: "title-1",
},
gtk::Label {
set_label: "Rebuild successful!",
add_css_class: "dim-label",
}
},
#[name(error)]
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,
gtk::Image {
add_css_class: "error",
set_icon_name: Some("dialog-error-symbolic"),
set_pixel_size: 128,
},
gtk::Label {
set_label: "Error!",
add_css_class: "title-1",
},
gtk::Label {
set_label: "Rebuild failed! See below for error message.",
add_css_class: "dim-label",
}
}
},
gtk::Frame {
set_margin_all: 20,
#[name(scrollwindow)]
gtk::ScrolledWindow {
set_max_content_height: 500,
set_min_content_height: 100,
#[name(outview)]
sourceview5::View {
set_editable: false,
set_cursor_visible: false,
set_monospace: true,
set_top_margin: 5,
set_bottom_margin: 5,
set_left_margin: 5,
set_vexpand: true,
set_hexpand: true,
set_vscroll_policy: gtk::ScrollablePolicy::Minimum,
#[wrap(Some)]
set_buffer: outbuf = &sourceview5::Buffer {
#[track(model.changed(RebuildModel::scheme()))]
set_style_scheme: model.scheme.as_ref(),
#[track(model.changed(RebuildModel::text()))]
set_text: &model.text,
}
}
}
},
gtk::Box {
add_css_class: "dialog-action-area",
set_orientation: gtk::Orientation::Horizontal,
set_homogeneous: true,
#[track(model.changed(RebuildModel::status()))]
set_visible: model.status != RebuildStatus::Building,
gtk::Button {
set_label: "Close",
#[track(model.changed(RebuildModel::status()))]
set_visible: model.status != RebuildStatus::Building,
connect_clicked[sender] => move |_| {
sender.input(RebuildMsg::Close)
}
}
}
}
}
}
fn pre_view() {
match model.status {
RebuildStatus::Building => {
statusstack.set_visible_child(building);
}
RebuildStatus::Success => statusstack.set_visible_child(success),
RebuildStatus::Error => statusstack.set_visible_child(error),
}
}
fn post_view() {
let adj = scrollwindow.vadjustment();
if model.status == RebuildStatus::Building {
adj.set_upper(adj.upper() + 20.0);
}
adj.set_value(adj.upper());
if model.status != RebuildStatus::Building {
outview.scroll_to_mark(&outview.buffer().get_insert(), 0.0, true, 0.0, 0.0);
scrollwindow.hadjustment().set_value(0.0);
}
}
fn init(
parent_window: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = RebuildModel {
hidden: true,
text: String::new(),
status: RebuildStatus::Building,
config: String::new(),
path: String::new(),
flake: None,
scheme: None,
tracker: 0,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>) {
self.reset();
match msg {
RebuildMsg::Show => {
self.update_hidden(|x| *x = false);
self.update_text(|x| x.clear());
self.set_status(RebuildStatus::Building);
}
RebuildMsg::UpdateText(s) => {
info!("RebuildMsg::UpdateText({})", s);
let newtext = if self.text.is_empty() {
s
} else {
format!("{}\n{}", self.text, s)
};
self.set_text(newtext);
trace!("NEWTEXT: {}", self.text);
}
RebuildMsg::FinishSuccess => {
self.set_status(RebuildStatus::Success);
}
RebuildMsg::FinishError(msg) => {
if let Some(s) = msg {
self.set_text(s)
}
self.update_hidden(|x| *x = false);
self.set_status(RebuildStatus::Error);
}
RebuildMsg::Close => {
self.update_hidden(|x| *x = true);
self.update_text(|x| x.clear());
}
RebuildMsg::SetScheme(scheme) => {
self.set_scheme(sourceview5::StyleSchemeManager::default().scheme(&scheme));
}
RebuildMsg::Quit => {
sender.output(AppMsg::Close);
}
}
}
}

View File

@ -1,137 +0,0 @@
use adw::prelude::*;
use relm4::*;
use super::updatepage::UpdatePageMsg;
#[derive(Debug)]
pub struct UpdateDialogModel {
hidden: bool,
message: String,
done: bool,
failed: bool,
}
#[derive(Debug)]
pub enum UpdateDialogMsg {
Show(String),
Close,
Done,
Failed,
}
#[relm4::component(pub)]
impl SimpleComponent for UpdateDialogModel {
type Init = gtk::Window;
type Input = UpdateDialogMsg;
type Output = UpdatePageMsg;
type Widgets = UpdateDialogWidgets;
view! {
dialog = adw::Window {
#[watch]
set_visible: !model.hidden,
set_transient_for: Some(&parent_window),
set_modal: true,
set_resizable: false,
set_default_width: 500,
set_default_height: 200,
add_css_class: "dialog",
add_css_class: "message",
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_halign: gtk::Align::Fill,
set_valign: gtk::Align::Fill,
set_hexpand: true,
set_vexpand: true,
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
set_hexpand: true,
set_vexpand: true,
set_margin_all: 15,
set_spacing: 10,
gtk::Label {
#[watch]
set_visible: !model.message.is_empty(),
add_css_class: "title-1",
#[watch]
set_label: &model.message,
},
if model.done {
gtk::Image {
add_css_class: "success",
set_icon_name: Some("emblem-ok-symbolic"),
set_pixel_size: 128,
}
} else if model.failed {
gtk::Image {
add_css_class: "error",
set_icon_name: Some("dialog-error-symbolic"),
set_pixel_size: 128,
}
} else {
gtk::Spinner {
#[watch]
set_visible: !model.done,
#[watch]
set_spinning: !model.done,
}
}
},
gtk::Box {
#[watch]
set_visible: model.done || model.failed,
add_css_class: "dialog-action-area",
set_valign: gtk::Align::End,
set_vexpand: true,
set_orientation: gtk::Orientation::Horizontal,
set_homogeneous: true,
gtk::Button {
set_label: "Close",
connect_clicked[sender] => move |_| {
sender.input(UpdateDialogMsg::Close);
}
}
},
}
}
}
fn init(
parent_window: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = UpdateDialogModel {
hidden: true,
done: false,
failed: false,
message: String::default(),
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
match msg {
UpdateDialogMsg::Show(desc) => {
self.message = desc;
self.hidden = false;
self.done = false;
self.failed = false;
}
UpdateDialogMsg::Close => {
self.hidden = true;
}
UpdateDialogMsg::Done => {
self.done = true;
}
UpdateDialogMsg::Failed => {
self.failed = true;
}
}
}
}

View File

@ -1,6 +1,6 @@
use crate::APPINFO;
use super::{pkgpage::InstallType, window::*, updatedialog::{UpdateDialogModel, UpdateDialogMsg}, updateworker::{UpdateAsyncHandler, UpdateAsyncHandlerMsg, UpdateAsyncHandlerInit}};
use super::{pkgpage::InstallType, window::*, updateworker::{UpdateAsyncHandler, UpdateAsyncHandlerMsg, UpdateAsyncHandlerInit}, rebuild::RebuildMsg};
use adw::prelude::*;
use nix_data::config::configfile::NixDataConfig;
use relm4::{factory::*, gtk::pango, *};
@ -16,8 +16,6 @@ pub struct UpdatePageModel {
updatesystemlist: FactoryVecDeque<UpdateItemModel>,
channelupdate: Option<(String, String)>,
#[tracker::no_eq]
updatedialog: Controller<UpdateDialogModel>,
#[tracker::no_eq]
updateworker: WorkerController<UpdateAsyncHandler>,
config: NixDataConfig,
systype: SystemPkgs,
@ -34,11 +32,10 @@ pub enum UpdatePageMsg {
UpdateSystem,
UpdateAllUser,
UpdateUser(String),
UpdateChannels,
UpdateSystemAndChannels,
// UpdateChannels,
// UpdateSystemAndChannels,
UpdateAll,
DoneWorking,
DoneLoading,
FailedWorking,
}
@ -87,101 +84,101 @@ impl SimpleComponent for UpdatePageModel {
}
}
},
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
#[watch]
set_visible: model.channelupdate.is_some(),
gtk::Label {
set_halign: gtk::Align::Start,
add_css_class: "title-4",
set_label: "Channels",
},
},
gtk::ListBox {
set_valign: gtk::Align::Start,
add_css_class: "boxed-list",
set_selection_mode: gtk::SelectionMode::None,
#[watch]
set_visible: model.channelupdate.is_some(),
adw::PreferencesRow {
set_activatable: false,
set_can_focus: false,
#[wrap(Some)]
set_child = &gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 10,
set_margin_all: 10,
adw::Bin {
set_valign: gtk::Align::Center,
gtk::Image {
add_css_class: "icon-dropshadow",
set_halign: gtk::Align::Start,
set_icon_name: Some("application-x-addon"),
set_pixel_size: 64,
}
},
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_halign: gtk::Align::Fill,
set_valign: gtk::Align::Center,
set_hexpand: true,
set_spacing: 2,
gtk::Label {
set_halign: gtk::Align::Start,
set_label: "nixos",
set_ellipsize: pango::EllipsizeMode::End,
set_lines: 1,
set_wrap: true,
set_max_width_chars: 0,
},
gtk::Label {
set_halign: gtk::Align::Start,
add_css_class: "dim-label",
add_css_class: "caption",
set_label: {
&(if let Some((old, new)) = &model.channelupdate {
format!("{}{}", old, new)
} else {
String::default()
})
},
set_visible: model.channelupdate.is_some(),
set_ellipsize: pango::EllipsizeMode::End,
set_lines: 1,
set_wrap: true,
set_max_width_chars: 0,
},
},
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
set_halign: gtk::Align::End,
set_valign: gtk::Align::Center,
gtk::Button {
add_css_class: "suggested-action",
set_valign: gtk::Align::Center,
set_halign: gtk::Align::End,
set_label: "Update channel and system",
set_can_focus: false,
connect_clicked[sender] => move |_| {
sender.input(UpdatePageMsg::UpdateSystemAndChannels);
}
},
gtk::Button {
set_valign: gtk::Align::Center,
set_halign: gtk::Align::End,
set_label: "Update channel only",
set_can_focus: false,
connect_clicked[sender] => move |_| {
sender.input(UpdatePageMsg::UpdateChannels);
}
},
}
}
}
},
// gtk::Box {
// set_orientation: gtk::Orientation::Horizontal,
// set_hexpand: true,
// #[watch]
// set_visible: model.channelupdate.is_some(),
// gtk::Label {
// set_halign: gtk::Align::Start,
// add_css_class: "title-4",
// set_label: "Channels",
// },
// },
// gtk::ListBox {
// set_valign: gtk::Align::Start,
// add_css_class: "boxed-list",
// set_selection_mode: gtk::SelectionMode::None,
// #[watch]
// set_visible: model.channelupdate.is_some(),
// adw::PreferencesRow {
// set_activatable: false,
// set_can_focus: false,
// #[wrap(Some)]
// set_child = &gtk::Box {
// set_orientation: gtk::Orientation::Horizontal,
// set_hexpand: true,
// set_spacing: 10,
// set_margin_all: 10,
// adw::Bin {
// set_valign: gtk::Align::Center,
// gtk::Image {
// add_css_class: "icon-dropshadow",
// set_halign: gtk::Align::Start,
// set_icon_name: Some("application-x-addon"),
// set_pixel_size: 64,
// }
// },
// gtk::Box {
// set_orientation: gtk::Orientation::Vertical,
// set_halign: gtk::Align::Fill,
// set_valign: gtk::Align::Center,
// set_hexpand: true,
// set_spacing: 2,
// gtk::Label {
// set_halign: gtk::Align::Start,
// set_label: "nixos",
// set_ellipsize: pango::EllipsizeMode::End,
// set_lines: 1,
// set_wrap: true,
// set_max_width_chars: 0,
// },
// gtk::Label {
// set_halign: gtk::Align::Start,
// add_css_class: "dim-label",
// add_css_class: "caption",
// set_label: {
// &(if let Some((old, new)) = &model.channelupdate {
// format!("{} → {}", old, new)
// } else {
// String::default()
// })
// },
// set_visible: model.channelupdate.is_some(),
// set_ellipsize: pango::EllipsizeMode::End,
// set_lines: 1,
// set_wrap: true,
// set_max_width_chars: 0,
// },
// },
// gtk::Box {
// set_orientation: gtk::Orientation::Vertical,
// set_spacing: 5,
// set_halign: gtk::Align::End,
// set_valign: gtk::Align::Center,
// gtk::Button {
// add_css_class: "suggested-action",
// set_valign: gtk::Align::Center,
// set_halign: gtk::Align::End,
// set_label: "Update channel and system",
// set_can_focus: false,
// connect_clicked[sender] => move |_| {
// sender.input(UpdatePageMsg::UpdateSystemAndChannels);
// }
// },
// gtk::Button {
// set_valign: gtk::Align::Center,
// set_halign: gtk::Align::End,
// set_label: "Update channel only",
// set_can_focus: false,
// connect_clicked[sender] => move |_| {
// sender.input(UpdatePageMsg::UpdateChannels);
// }
// },
// }
// }
// }
// },
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
@ -234,7 +231,7 @@ impl SimpleComponent for UpdatePageModel {
set_halign: gtk::Align::End,
set_hexpand: true,
set_valign: gtk::Align::Center,
set_label: "Update All",
set_label: "Update",
connect_clicked[sender] => move |_|{
sender.input(UpdatePageMsg::UpdateSystem);
},
@ -282,9 +279,6 @@ impl SimpleComponent for UpdatePageModel {
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let updatedialog = UpdateDialogModel::builder()
.launch(initparams.window.upcast())
.forward(sender.input_sender(), identity);
let updateworker = UpdateAsyncHandler::builder()
.detach_worker(UpdateAsyncHandlerInit { syspkgs: initparams.systype.clone(), userpkgs: initparams.usertype.clone() })
.forward(sender.input_sender(), identity);
@ -297,7 +291,6 @@ impl SimpleComponent for UpdatePageModel {
updatesystemlist: FactoryVecDeque::new(gtk::ListBox::new(), sender.input_sender()),
channelupdate: None,
updatetracker: 0,
updatedialog,
updateworker,
config,
systype: initparams.systype,
@ -329,13 +322,13 @@ impl SimpleComponent for UpdatePageModel {
info!("UpdatePageMsg::Update");
debug!("UPDATEUSERLIST: {:?}", updateuserlist);
debug!("UPDATESYSTEMLIST: {:?}", updatesystemlist);
self.channelupdate = match nix_data::cache::channel::uptodate() {
Ok(x) => {
x
},
Err(_) => None,
};
debug!("CHANNELUPDATE: {:?}", self.channelupdate);
// self.channelupdate = match nix_data::cache::channel::uptodate() {
// Ok(x) => {
// x
// },
// Err(_) => None,
// };
// debug!("CHANNELUPDATE: {:?}", self.channelupdate);
self.update_updatetracker(|_| ());
let mut updateuserlist_guard = self.updateuserlist.guard();
updateuserlist_guard.clear();
@ -347,6 +340,16 @@ impl SimpleComponent for UpdatePageModel {
for updatesystem in updatesystemlist {
updatesystemlist_guard.push_back(updatesystem);
}
updatesystemlist_guard.push_back(UpdateItem {
pkg: None,
name: "NixOS".to_string(),
pname: "nixos".to_string(),
summary: None,
icon: None,
pkgtype: InstallType::System,
verfrom: None,
verto: None,
});
}
UpdatePageMsg::OpenRow(row, pkgtype) => match pkgtype {
InstallType::User => {
@ -366,38 +369,36 @@ impl SimpleComponent for UpdatePageModel {
}
}
},
UpdatePageMsg::UpdateChannels => {
self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating channels...")));
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateChannels);
}
UpdatePageMsg::UpdateSystemAndChannels => {
self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating system and channels...")));
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateChannelsAndSystem);
}
// UpdatePageMsg::UpdateChannels => {
// self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating channels...")));
// self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateChannels);
// }
// UpdatePageMsg::UpdateSystemAndChannels => {
// self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating system and channels...")));
// self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateChannelsAndSystem);
// }
UpdatePageMsg::UpdateSystem => {
self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating system...")));
self.updateworker.emit(UpdateAsyncHandlerMsg::RebuildSystem);
REBUILD_BROKER.send(RebuildMsg::Show);
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateSystem);
}
UpdatePageMsg::UpdateUser(pkg) => {
info!("UPDATE USER PKG: {}", pkg);
warn!("unimplemented");
}
UpdatePageMsg::UpdateAllUser => {
self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating all user packages...")));
REBUILD_BROKER.send(RebuildMsg::Show);
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateUserPkgs);
}
UpdatePageMsg::UpdateAll => {
self.updatedialog.emit(UpdateDialogMsg::Show(String::from("Updating everything...")));
REBUILD_BROKER.send(RebuildMsg::Show);
self.updateworker.emit(UpdateAsyncHandlerMsg::UpdateAll);
}
UpdatePageMsg::DoneWorking => {
REBUILD_BROKER.send(RebuildMsg::FinishSuccess);
sender.output(AppMsg::UpdateInstalledPkgs);
}
UpdatePageMsg::DoneLoading => {
self.updatedialog.emit(UpdateDialogMsg::Done);
}
UpdatePageMsg::FailedWorking => {
self.updatedialog.emit(UpdateDialogMsg::Failed);
REBUILD_BROKER.send(RebuildMsg::FinishError(None));
}
}
}

View File

@ -1,9 +1,12 @@
use nix_data::config::configfile::NixDataConfig;
use relm4::*;
use std::{error::Error, path::Path, process::Stdio};
use std::{path::Path, process::Stdio};
use tokio::io::AsyncBufReadExt;
use anyhow::Result;
use log::*;
use crate::ui::{rebuild::RebuildMsg, window::REBUILD_BROKER};
use super::{
updatepage::UpdatePageMsg,
window::{SystemPkgs, UserPkgs},
@ -25,8 +28,10 @@ pub enum UpdateAsyncHandlerMsg {
UpdateConfig(NixDataConfig),
UpdatePkgTypes(SystemPkgs, UserPkgs),
UpdateChannels,
UpdateChannelsAndSystem,
// UpdateChannels,
// UpdateChannelsAndSystem,
UpdateSystem,
RebuildSystem,
UpdateUserPkgs,
@ -79,35 +84,52 @@ impl Worker for UpdateAsyncHandler {
self.syspkgs = syspkgs;
self.userpkgs = userpkgs;
}
UpdateAsyncHandlerMsg::UpdateChannels => {
// UpdateAsyncHandlerMsg::UpdateChannels => {
// let systemconfig = self.systemconfig.clone();
// let flakeargs = self.flakeargs.clone();
// let syspkgs = self.syspkgs.clone();
// relm4::spawn(async move {
// let result = runcmd(NscCmd::Channel, systemconfig, flakeargs, syspkgs).await;
// match result {
// Ok(true) => {
// sender.output(UpdatePageMsg::DoneWorking);
// }
// _ => {
// warn!("UPDATE CHANNEL FAILED");
// sender.output(UpdatePageMsg::FailedWorking);
// }
// }
// });
// }
// UpdateAsyncHandlerMsg::UpdateChannelsAndSystem => {
// let systenconfig = self.systemconfig.clone();
// let flakeargs = self.flakeargs.clone();
// let syspkgs = self.syspkgs.clone();
// relm4::spawn(async move {
// let result = runcmd(NscCmd::All, systenconfig, flakeargs, syspkgs).await;
// match result {
// Ok(true) => {
// sender.output(UpdatePageMsg::DoneWorking);
// }
// _ => {
// warn!("UPDATE CHANNEL AND SYSTEM FAILED");
// sender.output(UpdatePageMsg::FailedWorking);
// }
// }
// });
// }
UpdateAsyncHandlerMsg::UpdateSystem => {
let systemconfig = self.systemconfig.clone();
let flakeargs = self.flakeargs.clone();
let syspkgs = self.syspkgs.clone();
relm4::spawn(async move {
let result = runcmd(NscCmd::Channel, systemconfig, flakeargs, syspkgs).await;
let result = runcmd(NscCmd::All, systemconfig, flakeargs, syspkgs).await;
match result {
Ok(true) => {
sender.output(UpdatePageMsg::DoneWorking);
}
_ => {
warn!("UPDATE CHANNEL FAILED");
sender.output(UpdatePageMsg::FailedWorking);
}
}
});
}
UpdateAsyncHandlerMsg::UpdateChannelsAndSystem => {
let systenconfig = self.systemconfig.clone();
let flakeargs = self.flakeargs.clone();
let syspkgs = self.syspkgs.clone();
relm4::spawn(async move {
let result = runcmd(NscCmd::All, systenconfig, flakeargs, syspkgs).await;
match result {
Ok(true) => {
sender.output(UpdatePageMsg::DoneWorking);
}
_ => {
warn!("UPDATE CHANNEL AND SYSTEM FAILED");
warn!("UPDATE SYSTEM FAILED");
sender.output(UpdatePageMsg::FailedWorking);
}
}
@ -190,7 +212,7 @@ async fn runcmd(
_systemconfig: Option<String>,
flakeargs: Option<String>,
syspkgs: SystemPkgs,
) -> Result<bool, Box<dyn Error + Send + Sync>> {
) -> Result<bool> {
let exe = match std::env::current_exe() {
Ok(mut e) => {
e.pop(); // root/bin
@ -255,6 +277,7 @@ async fn runcmd(
.arg(flakepath)
.arg("--")
.arg("switch")
.arg("--impure")
.args(&rebuildargs)
.stderr(Stdio::piped())
.spawn()?,
@ -267,6 +290,7 @@ async fn runcmd(
let mut lines = reader.lines();
while let Ok(Some(line)) = lines.next_line().await {
REBUILD_BROKER.send(RebuildMsg::UpdateText(line.to_string()));
trace!("CAUGHT REBUILD LINE: {}", line);
}
if cmd.wait().await?.success() {
@ -276,7 +300,7 @@ async fn runcmd(
}
}
async fn updateenv() -> Result<bool, Box<dyn Error + Send + Sync>> {
async fn updateenv() -> Result<bool> {
let mut cmd = tokio::process::Command::new("nix-env")
.arg("-u")
.stderr(Stdio::piped())
@ -287,6 +311,7 @@ async fn updateenv() -> Result<bool, Box<dyn Error + Send + Sync>> {
let mut lines = reader.lines();
while let Ok(Some(line)) = lines.next_line().await {
REBUILD_BROKER.send(RebuildMsg::UpdateText(line.to_string()));
trace!("CAUGHT NIXENV LINE: {}", line);
}
if cmd.wait().await?.success() {
@ -296,7 +321,7 @@ async fn updateenv() -> Result<bool, Box<dyn Error + Send + Sync>> {
}
}
async fn updateprofile() -> Result<bool, Box<dyn Error + Send + Sync>> {
async fn updateprofile() -> Result<bool> {
let mut cmd = tokio::process::Command::new("nix")
.arg("profile")
.arg("upgrade")
@ -311,6 +336,7 @@ async fn updateprofile() -> Result<bool, Box<dyn Error + Send + Sync>> {
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);
}
if cmd.wait().await?.success() {

View File

@ -4,7 +4,7 @@ use crate::{
config::{editconfig, getconfig},
packages::{AppData, LicenseEnum, PkgMaintainer, Platform},
},
ui::{installedpage::InstalledItem, pkgpage::PkgPageInit, welcome::WelcomeMsg},
ui::{installedpage::InstalledItem, pkgpage::PkgPageInit, welcome::WelcomeMsg, rebuild::RebuildMsg},
APPINFO,
};
use adw::prelude::*;
@ -32,9 +32,11 @@ use super::{
searchpage::{SearchItem, SearchPageModel, SearchPageMsg},
updatepage::{UpdateItem, UpdatePageInit, UpdatePageModel, UpdatePageMsg},
welcome::WelcomeModel,
windowloading::{LoadErrorModel, LoadErrorMsg, WindowAsyncHandler, WindowAsyncHandlerMsg},
windowloading::{LoadErrorModel, LoadErrorMsg, WindowAsyncHandler, WindowAsyncHandlerMsg}, rebuild::RebuildModel,
};
pub static REBUILD_BROKER: MessageBroker<RebuildModel> = MessageBroker::new();
#[derive(PartialEq)]
enum Page {
FrontPage,
@ -109,6 +111,8 @@ pub struct AppModel {
updatepage: Controller<UpdatePageModel>,
viewstack: adw::ViewStack,
installedpagebusy: Vec<(String, InstallType)>,
#[tracker::no_eq]
rebuild: Controller<RebuildModel>,
}
#[derive(Debug)]
@ -146,8 +150,8 @@ pub enum AppMsg {
RemoveInstalledBusy(WorkPkg),
OpenCategoryPage(PkgCategory),
LoadCategory(PkgCategory),
UpdateRecPkgs(Vec<String>),
SetDarkMode(bool),
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -490,6 +494,9 @@ impl Component for AppModel {
config: config.clone(),
})
.forward(sender.input_sender(), identity);
let rebuild = RebuildModel::builder()
.launch_with_broker(root.clone().upcast(), &REBUILD_BROKER)
.forward(sender.input_sender(), identity);
let viewstack = adw::ViewStack::new();
let model = AppModel {
@ -523,9 +530,18 @@ impl Component for AppModel {
updatepage,
viewstack,
installedpagebusy: vec![],
rebuild,
tracker: 0,
};
{
let sender = sender.clone();
adw::StyleManager::default()
.connect_dark_notify(move |x| sender.input(AppMsg::SetDarkMode(x.is_dark())));
}
sender.input(AppMsg::SetDarkMode(adw::StyleManager::default().is_dark()));
if welcome {
let welcomepage = WelcomeModel::builder()
.launch(root.clone().upcast())
@ -582,6 +598,7 @@ impl Component for AppModel {
frontvs.set_icon_name(Some("nsc-home-symbolic"));
installedvs.set_icon_name(Some("nsc-installed-symbolic"));
updatesvs.set_icon_name(Some("nsc-update-symbolic"));
ComponentParts { model, widgets }
}
@ -1803,6 +1820,11 @@ FROM pkgs JOIN meta ON (pkgs.attribute = meta.attribute) WHERE pkgs.attribute =
AppAsyncMsg::LoadCategory(category, catrec, catall)
});
}
AppMsg::SetDarkMode(dark) => {
info!("AppMsg::SetDarkMode({})", dark);
let scheme = if dark { "Adwaita-dark" } else { "Adwaita" };
self.rebuild.emit(RebuildMsg::SetScheme(scheme.to_string()));
}
}
}