Make package lists no longer lag
This commit is contained in:
parent
601319addf
commit
a5e5fa5e15
6 changed files with 165 additions and 130 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -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]]
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -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!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue