Make package lists no longer lag

This commit is contained in:
Hellx2 2024-08-18 16:38:53 +10:00
parent 601319addf
commit a5e5fa5e15
6 changed files with 165 additions and 130 deletions

16
Cargo.lock generated
View file

@ -48,6 +48,12 @@ dependencies = [
"target-lexicon", "target-lexicon",
] ]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -399,6 +405,15 @@ dependencies = [
"hashbrown", "hashbrown",
] ]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.153"
@ -425,6 +440,7 @@ name = "oreon-system-manager"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"gtk4", "gtk4",
"itertools",
] ]
[[package]] [[package]]

View file

@ -7,3 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
gtk = { version = "0.9.0", package = "gtk4" } gtk = { version = "0.9.0", package = "gtk4" }
itertools = "0.13.0"

View file

@ -1,6 +1,9 @@
use std::process::Command;
use gtk::{ use gtk::{
prelude::BoxExt, Align, Button, ListBox, Orientation, ScrolledWindow, SearchBar, SearchEntry, prelude::BoxExt, Align, Button, ListBox, Orientation, ScrolledWindow, SearchBar, SearchEntry,
}; };
use itertools::Itertools;
pub mod objects; pub mod objects;
@ -135,3 +138,59 @@ pub fn installed_list() -> ScrolledWindow {
scrollable scrollable
} }
pub fn get_driver_details() -> Vec<String> {
let basic_driver_details = String::from_utf8(
std::process::Command::new("lspci")
.output()
.expect("Failed to run 'lspci'!")
.stdout,
)
.expect("Failed to convert the 'lspci' output to a string.");
let advanced_driver_details = String::from_utf8(
std::process::Command::new("lspci")
.arg("-k")
.output()
.expect("Failed to run 'lspci -k'!")
.stdout,
)
.expect("Failed to convert the 'lspci -k' output to a string.");
let pci_ids: Vec<&str> = basic_driver_details
.lines()
.map(|x| x.split_whitespace().next().unwrap_or(""))
.filter(|x| !x.is_empty())
.collect();
let mut driver_names = vec![];
for i in 0..(pci_ids.len() - 1) {
driver_names.push(
advanced_driver_details
.split_once(pci_ids[i])
.expect("Failed to find PCI ID!")
.1
.split_once(pci_ids[i + 1])
.expect("Failed to get next PCI ID!")
.0
.lines()
.filter(|x| x.trim().contains("driver"))
.map(|x| {
x.split(":")
.nth(1)
.expect("Failed to find colon in driver definition.")
.trim()
})
.collect::<String>(),
);
}
driver_names
.iter()
.filter(|x| !x.is_empty())
.map(|x| x.to_owned())
.dedup()
.sorted()
.collect()
}

View file

@ -126,3 +126,14 @@ fn on_startup(_: &Application) {
gtk::STYLE_PROVIDER_PRIORITY_USER, gtk::STYLE_PROVIDER_PRIORITY_USER,
); );
} }
#[cfg(test)]
mod tests {
use crate::drivers::get_driver_details;
#[test]
fn test_drivers() {
dbg!(get_driver_details());
panic!();
}
}

View file

@ -6,6 +6,7 @@ use std::process::Command;
use gtk::{Align, ListBox, ScrolledWindow, SearchBar, SearchEntry}; use gtk::{Align, ListBox, ScrolledWindow, SearchBar, SearchEntry};
pub static mut FULL_PKG_LIST: Vec<String> = vec![];
pub static mut PACKAGES_LIST: Option<ListBox> = None; pub static mut PACKAGES_LIST: Option<ListBox> = None;
pub static mut PKG_LIST: Vec<String> = vec![]; pub static mut PKG_LIST: Vec<String> = vec![];
pub static mut PKG_LIST_INDEX: usize = 0; pub static mut PKG_LIST_INDEX: usize = 0;
@ -56,45 +57,43 @@ pub fn browse() -> gtk::Box {
.halign(Align::Fill) .halign(Align::Fill)
.hexpand(true) .hexpand(true)
.build(), .build(),
);
FULL_PKG_LIST = String::from_utf8(
Command::new("dnf")
.args(["list", "--available"])
.output()
.unwrap()
.stdout,
) )
}; .unwrap()
.lines()
.map(|x| {
let y = x.to_string();
let b = y
.split_whitespace()
.next()
.unwrap_or("")
.split(".")
.next()
.unwrap();
b.to_string()
})
.filter(|x| {
!x.trim().is_empty()
&& !x.contains("=")
&& !skip_list.contains(&x.to_lowercase().trim())
})
.collect();
// TODO: Make this part asynchronous so that the app opens faster PKG_LIST = FULL_PKG_LIST.clone();
let pkg_list = String::from_utf8(
Command::new("dnf")
.args(["list", "--available"])
.output()
.unwrap()
.stdout,
)
.unwrap();
unsafe {
/* /*
Gets the list of packages, which also needs to be static Gets the list of packages, which also needs to be static
mutable for the same reason as PACKAGES_LIST, and remove mutable for the same reason as PACKAGES_LIST, and remove
the description and architecture details, and also filter the description and architecture details, and also filter
out the lines that aren't actually packages. out the lines that aren't actually packages.
*/ */
PKG_LIST = pkg_list
.lines()
.map(|x| {
let y = x.to_string();
let b = y
.split_whitespace()
.next()
.unwrap_or("")
.split(".")
.next()
.unwrap();
b.to_string()
})
.filter(|x| {
!x.trim().is_empty()
&& !x.contains("=")
&& !skip_list.contains(&x.to_lowercase().trim())
})
.collect();
/* /*
Add buttons for the first 50 packages in the list, to Add buttons for the first 50 packages in the list, to
@ -102,7 +101,7 @@ pub fn browse() -> gtk::Box {
package and a button for it in the memory at the same time, package and a button for it in the memory at the same time,
which has caused as much as 1.4GB of RAM usage during tests. which has caused as much as 1.4GB of RAM usage during tests.
*/ */
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].to_vec() { for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].to_vec() {
PKG_LIST_INDEX += 1; PKG_LIST_INDEX += 1;
let pkg_btn = Button::builder() let pkg_btn = Button::builder()
.label(pkg) .label(pkg)
@ -164,7 +163,7 @@ pub fn browse() -> gtk::Box {
pkgs_entry.connect_search_changed(move |x| { pkgs_entry.connect_search_changed(move |x| {
let f = x.clone(); let f = x.clone();
unsafe { search(&f, &skip_list) } unsafe { search(&f) }
}); });
pkgs_search.connect_entry(&pkgs_entry); pkgs_search.connect_entry(&pkgs_entry);
@ -188,44 +187,20 @@ Function that takes a search entry and updates
the package lists accordingly, skipping the values the package lists accordingly, skipping the values
stated in `skip_list` stated in `skip_list`
*/ */
unsafe fn search(f: &SearchEntry, skip_list: &Vec<&str>) { unsafe fn search(f: &SearchEntry) {
/*
Get a list of installed packages from DNF
TODO: Make this asynchronous
*/
let pkg_list = String::from_utf8(
Command::new("dnf")
.args(["search", f.text().to_string().as_str()])
.output()
.unwrap()
.stdout,
)
.unwrap();
/* /*
Reinitialize PKG_LIST with an extra predicate Reinitialize PKG_LIST with an extra predicate
in the filter closure to ensure that the list in the filter closure to ensure that the list
of packages contains only ones that match the of packages contains only ones that match the
query query
*/ */
PKG_LIST = pkg_list PKG_LIST = FULL_PKG_LIST
.lines() .iter()
.map(|x| {
let y = x.to_string();
let b = y
.split_whitespace()
.next()
.unwrap_or("")
.split(".")
.next()
.unwrap();
b.to_string()
})
.filter(|x| { .filter(|x| {
!x.trim().is_empty() x.to_lowercase()
&& !x.contains("=") .contains(f.text().to_string().to_lowercase().as_str())
&& !skip_list.contains(&x.to_lowercase().trim())
}) })
.map(|x| x.clone())
.collect(); .collect();
/* /*

View file

@ -4,10 +4,13 @@ use gtk::{
}; };
use std::process::Command; use std::process::Command;
use itertools::Itertools;
use gtk::{Align, ListBox, ScrolledWindow, SearchBar, SearchEntry}; use gtk::{Align, ListBox, ScrolledWindow, SearchBar, SearchEntry};
use super::show_package; use super::show_package;
pub static mut FULL_PKG_LIST: Vec<String> = vec![];
pub static mut PACKAGES_LIST: Option<ListBox> = None; pub static mut PACKAGES_LIST: Option<ListBox> = None;
pub static mut PKG_LIST: Vec<String> = vec![]; pub static mut PKG_LIST: Vec<String> = vec![];
pub static mut PKG_LIST_INDEX: usize = 0; pub static mut PKG_LIST_INDEX: usize = 0;
@ -62,45 +65,41 @@ pub fn installed() -> gtk::Box {
.halign(Align::Fill) .halign(Align::Fill)
.hexpand(true) .hexpand(true)
.build(), .build(),
) );
};
// TODO: Make this part asynchronous so that the app opens faster
let pkg_list = String::from_utf8(
Command::new("dnf")
.args(["list", "--installed"])
.output()
.unwrap()
.stdout,
)
.unwrap();
unsafe {
/* /*
Gets the list of packages, which also needs to be static Gets the list of packages, which also needs to be static
mutable for the same reason as PACKAGES_LIST, and remove mutable for the same reason as PACKAGES_LIST, and remove
the description and architecture details, and also filter the description and architecture details, and also filter
out the lines that aren't actually packages. out the lines that aren't actually packages.
*/ */
PKG_LIST = pkg_list FULL_PKG_LIST = String::from_utf8(
.lines() Command::new("dnf")
.map(|x| { .args(["list", "--installed"])
let y = x.to_string(); .output()
let b = y .unwrap()
.split_whitespace() .stdout,
.next() )
.unwrap_or("") .unwrap()
.split(".") .lines()
.next() .map(|x| {
.unwrap(); let y = x.to_string();
b.to_string() let b = y
}) .split_whitespace()
.filter(|x| { .next()
!x.trim().is_empty() .unwrap_or("")
&& !x.contains("=") .split(".")
&& !skip_list.contains(&x.to_lowercase().trim()) .next()
}) .unwrap();
.collect(); b.to_string()
})
.filter(|x| {
!x.trim().is_empty()
&& !x.contains("=")
&& !skip_list.contains(&x.to_lowercase().trim())
})
.dedup()
.collect::<Vec<String>>();
/* /*
Add buttons for the first 50 packages in the list, to Add buttons for the first 50 packages in the list, to
@ -108,7 +107,7 @@ pub fn installed() -> gtk::Box {
package and a button for it in the memory at the same time, package and a button for it in the memory at the same time,
which has caused as much as 1.4GB of RAM usage during tests. which has caused as much as 1.4GB of RAM usage during tests.
*/ */
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].to_vec() { for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].to_vec() {
PKG_LIST_INDEX += 1; PKG_LIST_INDEX += 1;
let pkg_btn = Button::builder() let pkg_btn = Button::builder()
.label(pkg) .label(pkg)
@ -144,9 +143,9 @@ pub fn installed() -> gtk::Box {
.unwrap() .unwrap()
.connect_edge_reached(|_, edge| { .connect_edge_reached(|_, edge| {
if edge == PositionType::Bottom { if edge == PositionType::Bottom {
for i in PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(PKG_LIST.len())) { for i in PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(FULL_PKG_LIST.len())) {
let pkg_btn = Button::builder() let pkg_btn = Button::builder()
.label(PKG_LIST[i].as_str()) .label(FULL_PKG_LIST[i].as_str())
.css_classes(["package-name"]) .css_classes(["package-name"])
.build(); .build();
@ -168,7 +167,7 @@ pub fn installed() -> gtk::Box {
pkgs_entry.connect_search_changed(move |x| { pkgs_entry.connect_search_changed(move |x| {
let f = x.clone(); let f = x.clone();
unsafe { search(&f, &skip_list) } unsafe { search(&f) }
}); });
pkgs_search.connect_entry(&pkgs_entry); pkgs_search.connect_entry(&pkgs_entry);
@ -192,46 +191,20 @@ Function that takes a search entry and updates
the package lists accordingly, skipping the values the package lists accordingly, skipping the values
stated in `skip_list` stated in `skip_list`
*/ */
unsafe fn search(f: &SearchEntry, skip_list: &Vec<&str>) { unsafe fn search(f: &SearchEntry) {
/*
Get a list of installed packages from DNF
TODO: Make this asynchronous
*/
let pkg_list = String::from_utf8(
Command::new("dnf")
.args(["list", "--installed"])
.output()
.unwrap()
.stdout,
)
.unwrap();
/* /*
Reinitialize PKG_LIST with an extra predicate Reinitialize PKG_LIST with an extra predicate
in the filter closure to ensure that the list in the filter closure to ensure that the list
of packages contains only ones that match the of packages contains only ones that match the
query query
*/ */
PKG_LIST = pkg_list PKG_LIST = FULL_PKG_LIST
.lines() .iter()
.map(|x| {
let y = x.to_string();
let b = y
.split_whitespace()
.next()
.unwrap_or("")
.split(".")
.next()
.unwrap();
b.to_string()
})
.filter(|x| { .filter(|x| {
!x.trim().is_empty() x.to_lowercase()
&& !x.contains("=") .contains(f.text().to_string().to_lowercase().as_str())
&& !skip_list.contains(&x.to_lowercase().trim())
&& x.to_lowercase()
.contains(f.text().to_string().to_lowercase().as_str())
}) })
.map(|x| x.clone())
.collect(); .collect();
/* /*