374 lines
17 KiB
Rust
Raw Normal View History

2024-06-18 15:45:10 +03:00
use crate::content::get_running_kernel_info;
2024-06-19 01:44:47 +03:00
use crate::{KernelBranch, RunningKernelInfo};
2024-06-18 15:45:10 +03:00
use adw::prelude::*;
2024-06-19 02:44:51 +03:00
use duct::cmd;
2024-06-18 15:45:10 +03:00
use glib::*;
use gtk::prelude::*;
use gtk::*;
2024-06-19 02:44:51 +03:00
use std::cell::RefCell;
use std::error::Error;
2024-06-18 15:45:10 +03:00
use std::fs;
use std::fs::*;
2024-06-19 02:44:51 +03:00
use std::io::BufRead;
use std::io::BufReader;
use std::process::Command;
2024-06-19 01:44:47 +03:00
use std::rc::Rc;
2024-06-19 02:14:07 +03:00
use std::time::*;
2024-06-19 01:44:47 +03:00
2024-06-19 02:44:51 +03:00
pub fn kernel_pkg_page(
content_stack: &gtk::Stack,
window: &adw::ApplicationWindow,
selected_kernel_branch: &Rc<RefCell<KernelBranch>>,
) -> gtk::Box {
2024-06-19 01:44:47 +03:00
let selected_kernel_branch_clone0 = selected_kernel_branch.borrow().clone();
2024-06-18 15:45:10 +03:00
let main_box = gtk::Box::builder()
.hexpand(true)
.vexpand(true)
.orientation(Orientation::Vertical)
.build();
let main_label = gtk::Label::builder()
2024-06-19 02:44:51 +03:00
.label(format!(
"Available Kernel Packages for {}",
&selected_kernel_branch_clone0.name
))
2024-06-18 15:45:10 +03:00
.hexpand(true)
.margin_start(10)
.margin_end(10)
.margin_bottom(20)
.margin_top(20)
.build();
main_label.add_css_class("symbolic-accent-bg");
2024-06-19 01:44:47 +03:00
main_label.add_css_class("size-20-font");
2024-06-18 15:45:10 +03:00
2024-06-19 01:44:47 +03:00
let searchbar = gtk::SearchEntry::builder()
.search_delay(500)
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.margin_start(15)
2024-06-18 15:45:10 +03:00
.build();
2024-06-19 01:44:47 +03:00
searchbar.add_css_class("rounded-all-25");
2024-06-18 15:45:10 +03:00
2024-06-19 01:44:47 +03:00
let packages_boxedlist = gtk::ListBox::builder()
.selection_mode(SelectionMode::None)
2024-06-18 15:45:10 +03:00
.build();
2024-06-19 01:44:47 +03:00
packages_boxedlist.add_css_class("boxed-list");
2024-06-19 02:14:07 +03:00
let rows_size_group = gtk::SizeGroup::new(SizeGroupMode::Both);
2024-06-19 02:44:51 +03:00
add_package_rows(
&packages_boxedlist,
&selected_kernel_branch_clone0.db,
&window,
&rows_size_group,
);
2024-06-18 15:45:10 +03:00
2024-06-19 01:44:47 +03:00
let packages_viewport = gtk::ScrolledWindow::builder()
.hscrollbar_policy(PolicyType::Never)
2024-06-18 15:45:10 +03:00
.vexpand(true)
2024-06-19 01:44:47 +03:00
.hexpand(true)
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.margin_start(15)
.height_request(390)
.child(&packages_boxedlist)
2024-06-18 15:45:10 +03:00
.build();
let window_bottombar = gtk::Box::builder()
.hexpand(true)
.homogeneous(true)
2024-06-19 01:44:47 +03:00
.vexpand(true)
.valign(Align::End)
2024-06-18 15:45:10 +03:00
.margin_bottom(15)
.margin_start(15)
.margin_end(15)
.margin_start(15)
.build();
let back_button = gtk::Button::builder()
.halign(Align::Start)
.label("Back")
.build();
back_button.add_css_class("pill");
2024-06-19 01:20:46 +03:00
back_button.connect_clicked(clone!(@weak content_stack, @weak main_box => move |_| {
content_stack.set_visible_child_name("content_page");
content_stack.remove(&main_box);
2024-06-18 15:45:10 +03:00
}));
window_bottombar.append(&back_button);
main_box.append(&main_label);
2024-06-19 01:44:47 +03:00
main_box.append(&searchbar);
main_box.append(&packages_viewport);
2024-06-18 15:45:10 +03:00
main_box.append(&window_bottombar);
main_box
}
2024-06-19 02:44:51 +03:00
fn add_package_rows(
boxedlist: &gtk::ListBox,
data: &str,
window: &adw::ApplicationWindow,
rows_size_group: &gtk::SizeGroup,
2024-06-19 02:14:07 +03:00
) {
2024-06-18 15:45:10 +03:00
let res: serde_json::Value = serde_json::from_str(&data).expect("Unable to parse");
2024-06-19 02:14:07 +03:00
if let serde_json::Value::Array(kernels) = &res["kernels"] {
for kernel in kernels {
let kernel_name = kernel["name"].as_str().to_owned().unwrap().to_string();
let kernel_package = kernel["package"].as_str().to_owned().unwrap().to_string();
2024-06-19 02:44:51 +03:00
let kernel_description = kernel["description"]
.as_str()
.to_owned()
.unwrap()
.to_string();
2024-06-19 02:14:07 +03:00
let (log_loop_sender, log_loop_receiver) = async_channel::unbounded();
let log_loop_sender: async_channel::Sender<String> = log_loop_sender.clone();
let (log_status_loop_sender, log_status_loop_receiver) = async_channel::unbounded();
let log_status_loop_sender: async_channel::Sender<bool> =
log_status_loop_sender.clone();
2024-06-19 02:44:51 +03:00
let (kernel_status_loop_sender, kernel_status_loop_receiver) =
async_channel::unbounded();
2024-06-19 02:14:07 +03:00
let kernel_status_loop_sender: async_channel::Sender<bool> =
kernel_status_loop_sender.clone();
std::thread::spawn(move || loop {
2024-06-19 02:44:51 +03:00
// let command_installed_status = std::Command::new("dpkg")
// .args(["-s", &kernel_package_ind2])
2024-06-19 02:14:07 +03:00
// .output()
// .unwrap();
//if command_installed_status.status.success() {
// kernel_status_loop_sender.send_blocking(true).expect("channel needs to be open")
//} else {
// kernel_status_loop_sender.send_blocking(false).expect("channel needs to be open")
//}
std::thread::sleep(Duration::from_secs(6));
2024-06-19 02:44:51 +03:00
kernel_status_loop_sender
.send_blocking(true)
.expect("channel needs to be open")
2024-06-19 02:14:07 +03:00
});
2024-06-19 02:44:51 +03:00
2024-06-19 02:14:07 +03:00
let kernel_expander_row = adw::ExpanderRow::new();
2024-06-19 02:44:51 +03:00
let kernel_package_label = gtk::Label::builder().label(&kernel_package).build();
2024-06-19 02:14:07 +03:00
let kernel_status_icon = gtk::Image::builder()
.icon_name("emblem-default")
.pixel_size(24)
.visible(false)
.tooltip_text("Installed")
.build();
2024-06-19 02:44:51 +03:00
let kernel_description_label = gtk::Label::builder().label(&kernel_description).build();
2024-06-19 02:14:07 +03:00
let kernel_content_row = adw::ActionRow::builder().build();
let kernel_install_button = gtk::Button::builder()
.margin_start(5)
.margin_top(5)
.margin_bottom(5)
.valign(gtk::Align::Center)
.label("Install")
.tooltip_text("Install this kernel")
.sensitive(false)
.build();
kernel_install_button.add_css_class("suggested-action");
let kernel_remove_button = gtk::Button::builder()
.margin_end(5)
.margin_top(5)
.margin_bottom(5)
.valign(gtk::Align::Center)
.label("Uninstall")
.tooltip_text("Uninstall this kernel")
.sensitive(false)
.build();
let kernel_action_box = gtk::Box::builder().homogeneous(true).build();
kernel_remove_button.add_css_class("destructive-action");
kernel_expander_row.add_prefix(&kernel_package_label);
kernel_expander_row.add_suffix(&kernel_status_icon);
kernel_expander_row.set_title(&kernel_name);
//kernel_expander_row.set_subtitle(&kernel.clone().version);
//
kernel_content_row.add_prefix(&kernel_description_label);
kernel_action_box.append(&kernel_remove_button);
kernel_action_box.append(&kernel_install_button);
kernel_content_row.add_suffix(&kernel_action_box);
kernel_expander_row.add_row(&kernel_content_row);
rows_size_group.add_widget(&kernel_action_box);
//
let kernel_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
kernel_status_loop_context.spawn_local(clone!(@weak kernel_remove_button, @weak kernel_install_button, @strong kernel_status_loop_receiver => async move {
while let Ok(kernel_status_state) = kernel_status_loop_receiver.recv().await {
if kernel_status_state == true {
kernel_status_icon.set_visible(true);
kernel_install_button.set_sensitive(false);
kernel_remove_button.set_sensitive(true);
} else {
kernel_status_icon.set_visible(false);
kernel_remove_button.set_sensitive(false);
kernel_install_button.set_sensitive(true);
}
}
}));
//
let kernel_install_log_terminal_buffer = gtk::TextBuffer::builder().build();
let kernel_install_log_terminal = gtk::TextView::builder()
.vexpand(true)
.hexpand(true)
.editable(false)
.buffer(&kernel_install_log_terminal_buffer)
.build();
let kernel_install_log_terminal_scroll = gtk::ScrolledWindow::builder()
.width_request(400)
.height_request(200)
.vexpand(true)
.hexpand(true)
.child(&kernel_install_log_terminal)
.build();
let kernel_install_dialog = adw::MessageDialog::builder()
.transient_for(window)
.hide_on_close(true)
.extra_child(&kernel_install_log_terminal_scroll)
.width_request(400)
.height_request(200)
.heading("Installing Kernel")
.build();
2024-06-19 02:44:51 +03:00
kernel_install_dialog.add_response("kernel_install_dialog_ok", "OK");
kernel_install_dialog
.add_response("kernel_install_dialog_reboot", "Reboot Now (Optional)");
2024-06-19 02:14:07 +03:00
kernel_install_dialog.set_response_appearance(
"kernel_install_dialog_reboot",
adw::ResponseAppearance::Suggested,
);
//
//
let log_loop_context = MainContext::default();
// The main loop executes the asynchronous block
log_loop_context.spawn_local(clone!(@weak kernel_install_log_terminal_buffer, @weak kernel_install_dialog, @strong log_loop_receiver => async move {
while let Ok(state) = log_loop_receiver.recv().await {
kernel_install_log_terminal_buffer.insert(&mut kernel_install_log_terminal_buffer.end_iter(), &("\n".to_string() + &state))
}
}));
let log_status_loop_context = MainContext::default();
// The main loop executes the asynchronous block
log_status_loop_context.spawn_local(clone!(@weak kernel_install_dialog, @strong log_status_loop_receiver => async move {
while let Ok(state) = log_status_loop_receiver.recv().await {
if state == true {
kernel_install_dialog.set_response_enabled("kernel_install_dialog_ok", true);
//if get_current_username().unwrap() == "pikaos" {
// kernel_install_dialog.set_response_enabled("kernel_install_dialog_reboot", false);
//} else {
// kernel_install_dialog.set_response_enabled("kernel_install_dialog_reboot", true);
//}
kernel_install_dialog.set_response_enabled("kernel_install_dialog_reboot", true);
kernel_install_dialog.set_body("Kernel installation was successful!");
} else {
kernel_install_dialog.set_response_enabled("kernel_install_dialog_ok", true);
kernel_install_dialog.set_body("Kernel Installation Failed!");
kernel_install_dialog.set_response_enabled("kernel_install_dialog_reboot", false);
}
}
}));
//
kernel_install_log_terminal_buffer.connect_changed(clone!(@weak kernel_install_log_terminal, @weak kernel_install_log_terminal_buffer,@weak kernel_install_log_terminal_scroll => move |_|{
if kernel_install_log_terminal_scroll.vadjustment().upper() - kernel_install_log_terminal_scroll.vadjustment().value() > 100.0 {
kernel_install_log_terminal_scroll.vadjustment().set_value(kernel_install_log_terminal_scroll.vadjustment().upper())
}
}));
//
kernel_install_button.connect_clicked(clone!(@weak kernel_install_log_terminal,@weak kernel_install_log_terminal_buffer, @weak kernel_install_dialog, @strong log_loop_sender, @strong log_status_loop_sender, @strong kernel_package => move |_| {
kernel_install_log_terminal_buffer.delete(&mut kernel_install_log_terminal_buffer.bounds().0, &mut kernel_install_log_terminal_buffer.bounds().1);
kernel_install_dialog.set_response_enabled("kernel_install_dialog_ok", false);
kernel_install_dialog.set_response_enabled("kernel_install_dialog_reboot", false);
kernel_install_dialog.set_body("");
kernel_install_dialog.choose(None::<&gio::Cancellable>, move |choice| {
if choice == "kernel_install_dialog_reboot" {
Command::new("systemctl")
.arg("reboot")
.spawn()
.expect("systemctl reboot failed to start");
}
});
let log_status_loop_sender_clone = log_status_loop_sender.clone();
let log_loop_sender_clone= log_loop_sender.clone();
let kernel_package_clone = kernel_package.clone();
std::thread::spawn(move || {
let command = kernel_modify(log_loop_sender_clone, &kernel_package_clone);
match command {
Ok(_) => {
println!("Status: kernel modify Successful");
log_status_loop_sender_clone.send_blocking(true).expect("The channel needs to be open.");
}
Err(_) => {
println!("Status: kernel modify Failed");
log_status_loop_sender_clone.send_blocking(false).expect("The channel needs to be open.");
}
}
});
}));
kernel_remove_button.connect_clicked(clone!(@weak kernel_install_log_terminal,@weak kernel_install_log_terminal_buffer, @weak kernel_install_dialog, @strong log_loop_sender, @strong log_status_loop_sender, @strong kernel_package => move |_| {
kernel_install_log_terminal_buffer.delete(&mut kernel_install_log_terminal_buffer.bounds().0, &mut kernel_install_log_terminal_buffer.bounds().1);
kernel_install_dialog.set_response_enabled("kernel_install_dialog_ok", false);
kernel_install_dialog.set_response_enabled("kernel_install_dialog_reboot", false);
kernel_install_dialog.set_body("");
kernel_install_dialog.choose(None::<&gio::Cancellable>, move |choice| {
if choice == "kernel_install_dialog_reboot" {
Command::new("systemctl")
.arg("reboot")
.spawn()
.expect("systemctl reboot failed to start");
}
});
let log_status_loop_sender_clone = log_status_loop_sender.clone();
let log_loop_sender_clone= log_loop_sender.clone();
let kernel_package_clone = kernel_package.clone();
std::thread::spawn(move || {
let command = kernel_modify(log_loop_sender_clone, &kernel_package_clone);
match command {
Ok(_) => {
println!("Status: kernel modify Successful");
log_status_loop_sender_clone.send_blocking(true).expect("The channel needs to be open.");
}
Err(_) => {
println!("Status: kernel modify Failed");
log_status_loop_sender_clone.send_blocking(false).expect("The channel needs to be open.");
}
}
});
}));
//
boxedlist.append(&kernel_expander_row);
2024-06-19 02:44:51 +03:00
}
};
2024-06-19 02:14:07 +03:00
}
const KERNEL_MODIFY_PROG: &str = r###"
#! /bin/bash
DRIVER="$0"
/usr/lib/pika/drivers/modify-driver.sh "${DRIVER}"
"###;
fn kernel_modify(
log_loop_sender: async_channel::Sender<String>,
kernel_pkg: &str,
) -> Result<(), std::boxed::Box<dyn Error + Send + Sync>> {
let (pipe_reader, pipe_writer) = os_pipe::pipe()?;
let child = cmd!("bash", "-c", KERNEL_MODIFY_PROG, kernel_pkg)
.stderr_to_stdout()
.stdout_file(pipe_writer)
.start()?;
for line in BufReader::new(pipe_reader).lines() {
log_loop_sender
.send_blocking(line?)
.expect("Channel needs to be opened.")
}
child.wait()?;
Ok(())
2024-06-19 02:44:51 +03:00
}