Updated CHANGELOG.md, documented a bunch of stuff and fixed a lot of warnings.
This commit is contained in:
parent
be2f789652
commit
af8365675d
9 changed files with 204 additions and 89 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -2,17 +2,17 @@
|
|||
|
||||
Commit 1
|
||||
- Removed `on_shutdown` function from `src/main.rs`, as it was uselessly dropping memory that was automatically dropped right after the function ended.
|
||||
- Finished the documentation for `src/main.rs`, `src/packages/installed.rs`, `src/packages/browse.rs`, and `src/packages/mod.rs`
|
||||
- Finished the documentation for `src/main.rs`, `src/packages/installed.rs`, `src/packages/browse.rs`, and `src/packages/mod.rs`.
|
||||
- Renamed `show_installed_package` to `show_package`, and merged it into `src/packages/mod.rs` instead of having copies in two files.
|
||||
- Added this changelog.
|
||||
- Updated `inst.sh` so that it no longer copies `style.css` to the `/usr/share/oreon-system-manager` directory.
|
||||
|
||||
Commit 2
|
||||
- Moved `drivers` to it's own module folder
|
||||
- Added `src/drivers/mod.rs` and `src/drivers/objects.rs`
|
||||
- Moved `drivers` to it's own module folder.
|
||||
- Added `src/drivers/mod.rs` and `src/drivers/objects.rs`.
|
||||
|
||||
Commit 3
|
||||
- Fixed crash on package description fetch
|
||||
- Fixed crash on package description fetch.
|
||||
|
||||
Commit 4
|
||||
- Added very basic support for Docker images.
|
||||
|
@ -20,3 +20,9 @@ Commit 4
|
|||
Commit 5
|
||||
- Added almost full support for Docker images.
|
||||
- Created an interface between Rust and the `docker image inspect` command using Serde.
|
||||
|
||||
Commit 6
|
||||
- Documented everything in the containers module.
|
||||
- Switched to using `cargo clippy` and fixed all of the warnings that it showed.
|
||||
- Renamed `src/containers/core.rs` to `src/containers/api.rs`.
|
||||
- Moved the `Image` struct to the `api` submodule instead of having it in the main `containers` module.
|
||||
|
|
|
@ -2,6 +2,38 @@ use std::collections::BTreeMap;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/**
|
||||
Struct for a docker image, with the basic
|
||||
details from the `docker images` command.
|
||||
*/
|
||||
pub struct Image {
|
||||
pub repository: String,
|
||||
pub tag: String,
|
||||
pub id: String,
|
||||
pub created: String,
|
||||
pub size: String,
|
||||
}
|
||||
|
||||
/*
|
||||
Implement `FromStr` for `Image` so that
|
||||
the output of the `docker images` command
|
||||
can be parsed into computer-interpretable
|
||||
data.
|
||||
*/
|
||||
impl std::str::FromStr for Image {
|
||||
type Err = String;
|
||||
fn from_str(value: &str) -> Result<Self, String> {
|
||||
let parts: Vec<String> = value.split_whitespace().map(|x| x.to_owned()).collect();
|
||||
Ok(Self {
|
||||
repository: parts[0].clone(),
|
||||
tag: parts[1].clone(),
|
||||
id: parts[2].clone(),
|
||||
created: parts[3..(parts.len() - 1)].join(" "),
|
||||
size: parts[parts.len() - 1].clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A struct for handling the output of the `docker image inspect`
|
||||
command.
|
||||
|
@ -25,6 +57,10 @@ pub struct ImageInspectData {
|
|||
pub metadata: IIMetadata,
|
||||
}
|
||||
|
||||
/*
|
||||
Implementation to allow for testing data, should be removed
|
||||
in release versions to reduce the file size and line count.
|
||||
*/
|
||||
impl Default for ImageInspectData {
|
||||
fn default() -> Self {
|
||||
ImageInspectData {
|
||||
|
@ -47,6 +83,7 @@ impl Default for ImageInspectData {
|
|||
}
|
||||
}
|
||||
|
||||
/// The struct for the `config` property of `ImageInspectData`
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct IIConfig {
|
||||
pub hostname: String,
|
||||
|
@ -70,6 +107,10 @@ pub struct IIConfig {
|
|||
pub labels: Option<IIConfigLabels>,
|
||||
}
|
||||
|
||||
/*
|
||||
Implementation to allow for testing data, should be removed
|
||||
in release versions to reduce the file size and line count.
|
||||
*/
|
||||
impl Default for IIConfig {
|
||||
fn default() -> Self {
|
||||
IIConfig {
|
||||
|
@ -94,14 +135,20 @@ impl Default for IIConfig {
|
|||
}
|
||||
}
|
||||
|
||||
/// Type for the `labels` property of `IIConfig`
|
||||
pub type IIConfigLabels = BTreeMap<String, String>;
|
||||
|
||||
/// Struct for the `graph_driver` property of `ImageInspectData`
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct IIGraphDriver {
|
||||
pub data: GraphDriverData,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
/*
|
||||
Implementation to allow for testing data, should be removed
|
||||
in release versions to reduce the file size and line count.
|
||||
*/
|
||||
impl Default for IIGraphDriver {
|
||||
fn default() -> Self {
|
||||
IIGraphDriver {
|
||||
|
@ -111,12 +158,18 @@ impl Default for IIGraphDriver {
|
|||
}
|
||||
}
|
||||
|
||||
/// The `data` property of `IIGraphDriver`
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct GraphDriverData {
|
||||
pub merged_dir: String,
|
||||
pub upper_dir: String,
|
||||
pub work_dir: String,
|
||||
}
|
||||
|
||||
/*
|
||||
Implementation to allow for testing data, should be removed
|
||||
in release versions to reduce the file size and line count.
|
||||
*/
|
||||
impl Default for GraphDriverData {
|
||||
fn default() -> GraphDriverData {
|
||||
GraphDriverData {
|
||||
|
@ -127,12 +180,17 @@ impl Default for GraphDriverData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Struct for defining the `rootfs` property of `ImageInspectData`
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct IIRootFS {
|
||||
pub r#type: String,
|
||||
pub layers: Vec<String>,
|
||||
}
|
||||
|
||||
/*
|
||||
Implementation to allow for testing data, should be removed
|
||||
in release versions to reduce the file size and line count.
|
||||
*/
|
||||
impl Default for IIRootFS {
|
||||
fn default() -> Self {
|
||||
IIRootFS {
|
||||
|
@ -142,11 +200,16 @@ impl Default for IIRootFS {
|
|||
}
|
||||
}
|
||||
|
||||
/// Struct for the `metadata` property of `ImageInspectData`
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct IIMetadata {
|
||||
pub last_tag_time: String,
|
||||
}
|
||||
|
||||
/*
|
||||
Implementation to allow for testing data, should be removed
|
||||
in release versions to reduce the file size and line count.
|
||||
*/
|
||||
impl Default for IIMetadata {
|
||||
fn default() -> Self {
|
||||
IIMetadata {
|
|
@ -4,13 +4,17 @@ use gtk::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
containers::{self, core::ImageInspectData},
|
||||
containers::api::{change_keys, Image, ImageInspectData},
|
||||
pkexec,
|
||||
};
|
||||
|
||||
use super::Image;
|
||||
|
||||
/**
|
||||
Subsection of the containers page to display
|
||||
Docker imags provided from the `docker images`
|
||||
command.
|
||||
*/
|
||||
pub fn images() -> gtk::Box {
|
||||
// Box for displaying the list of images.
|
||||
let images_box = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.build();
|
||||
|
@ -26,6 +30,7 @@ pub fn images() -> gtk::Box {
|
|||
.map(|x| x.parse::<Image>().unwrap())
|
||||
.collect::<Vec<Image>>();
|
||||
|
||||
// Test image, remove in the main build.
|
||||
images.push(Image {
|
||||
repository: "Test".to_owned(),
|
||||
tag: "something".to_owned(),
|
||||
|
@ -34,12 +39,22 @@ pub fn images() -> gtk::Box {
|
|||
size: "100MB".to_owned(),
|
||||
});
|
||||
|
||||
/*
|
||||
Loop through each of the images listed
|
||||
from the `docker images` command and
|
||||
create buttons and details for each of
|
||||
them.
|
||||
*/
|
||||
for image in images {
|
||||
let image_box = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.css_classes(["image-box"])
|
||||
.build();
|
||||
|
||||
/*
|
||||
Generate boxes for each of these that show
|
||||
[property name]: [value]
|
||||
*/
|
||||
image_box.append(&gen_box("Repository", &image.repository));
|
||||
image_box.append(&gen_box("Tag", &image.tag));
|
||||
image_box.append(&gen_box("Image ID", &image.id));
|
||||
|
@ -52,7 +67,12 @@ pub fn images() -> gtk::Box {
|
|||
.build();
|
||||
|
||||
image_button.connect_clicked(|x| {
|
||||
/*
|
||||
Show the details for the image through a
|
||||
function.
|
||||
*/
|
||||
show_image(
|
||||
// Get the image's unique image ID.
|
||||
x.child()
|
||||
.expect("Failed to get image_button child!")
|
||||
.downcast::<gtk::Box>()
|
||||
|
@ -79,17 +99,37 @@ pub fn images() -> gtk::Box {
|
|||
images_box
|
||||
}
|
||||
|
||||
fn show_image(image_id: &str) {
|
||||
/**
|
||||
Function for showing the details of a Docker
|
||||
image as a new window.
|
||||
*/
|
||||
pub fn show_image(image_id: &str) {
|
||||
/*
|
||||
Parse the details of the docker image inspect
|
||||
command output through the `core.rs` interface.
|
||||
*/
|
||||
let image_details: Vec<ImageInspectData> =
|
||||
serde_json::from_str::<Vec<ImageInspectData>>(&containers::core::change_keys(
|
||||
serde_json::from_str::<Vec<ImageInspectData>>(&change_keys(
|
||||
pkexec("docker image inspect ".to_owned() + image_id, false)
|
||||
.expect("This error should never occur"),
|
||||
))
|
||||
.expect("Failed to get data");
|
||||
|
||||
/*
|
||||
Shadow it with the first value, since there
|
||||
will only be one item in the list when using
|
||||
the image's ID.
|
||||
|
||||
TODO: Check that this is true.
|
||||
*/
|
||||
let image_details = image_details[0].clone();
|
||||
|
||||
// TODO: Display the data.
|
||||
/*
|
||||
Create a window to store all of the image's
|
||||
data from the inspect command.
|
||||
|
||||
TODO: Display the data.
|
||||
*/
|
||||
let image_window = Window::builder()
|
||||
.title(format!("Image ID {image_id}").as_str())
|
||||
.default_width(600)
|
||||
|
@ -101,6 +141,12 @@ fn show_image(image_id: &str) {
|
|||
.css_classes(["image-showbox"])
|
||||
.build();
|
||||
|
||||
/*
|
||||
Generate boxes for each of the components
|
||||
of the image in the following format:
|
||||
|
||||
[component name]: [value]
|
||||
*/
|
||||
main_box.append(&gen_box("Author", &image_details.author));
|
||||
main_box.append(&gen_box("Comment", &image_details.comment));
|
||||
main_box.append(&gen_box("Id", &image_details.id));
|
||||
|
@ -117,6 +163,14 @@ fn show_image(image_id: &str) {
|
|||
image_window.present();
|
||||
}
|
||||
|
||||
/**
|
||||
Function to generate a box for a property
|
||||
of some object, in the following format:
|
||||
|
||||
[property name]: [value]
|
||||
|
||||
Where [property name] is in bold.
|
||||
*/
|
||||
pub fn gen_box(name: &str, content: &str) -> gtk::Box {
|
||||
let return_box = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use gtk::{prelude::BoxExt, Stack, StackSidebar};
|
||||
use images::images;
|
||||
|
||||
pub mod core;
|
||||
pub mod api;
|
||||
pub mod images;
|
||||
|
||||
/**
|
||||
Page for managing Docker containers and images.
|
||||
|
||||
## TODO
|
||||
- Move to it's own file/folder
|
||||
- Add the following pages: "Containers", "Images", "Browse"
|
||||
*/
|
||||
pub fn containers() -> gtk::Box {
|
||||
|
@ -20,6 +17,7 @@ pub fn containers() -> gtk::Box {
|
|||
.css_classes(["containers-box"])
|
||||
.build();
|
||||
|
||||
// Stack to contain each of the pages.
|
||||
let containers_stack = Stack::builder()
|
||||
.halign(gtk::Align::Fill)
|
||||
.valign(gtk::Align::Fill)
|
||||
|
@ -27,12 +25,14 @@ pub fn containers() -> gtk::Box {
|
|||
.vexpand(true)
|
||||
.build();
|
||||
|
||||
// Sidebar to allow the user to switch between pages.
|
||||
let containers_sidebar = StackSidebar::builder()
|
||||
.stack(&containers_stack)
|
||||
.halign(gtk::Align::Start)
|
||||
.valign(gtk::Align::Fill)
|
||||
.build();
|
||||
|
||||
// Add each of the pages to the stack.
|
||||
containers_stack.add_titled(&images(), Some("images"), "Images");
|
||||
|
||||
// Start the docker daemon if it isn't running.
|
||||
|
@ -40,31 +40,13 @@ pub fn containers() -> gtk::Box {
|
|||
crate::pkexec("dockerd".to_owned(), true);
|
||||
}
|
||||
|
||||
// Append a new label as a title and return the box.
|
||||
/*
|
||||
Append the page switcher sidebar and the stack, in that order.
|
||||
This is necessary, since otherwise the sidebar will be on the
|
||||
wrong side.
|
||||
*/
|
||||
containers_box.append(&containers_sidebar);
|
||||
containers_box.append(&containers_stack);
|
||||
|
||||
containers_box
|
||||
}
|
||||
|
||||
pub struct Image {
|
||||
pub repository: String,
|
||||
pub tag: String,
|
||||
pub id: String,
|
||||
pub created: String,
|
||||
pub size: String,
|
||||
}
|
||||
|
||||
impl FromStr for Image {
|
||||
type Err = String;
|
||||
fn from_str(value: &str) -> Result<Self, String> {
|
||||
let parts: Vec<String> = value.split_whitespace().map(|x| x.to_owned()).collect();
|
||||
Ok(Self {
|
||||
repository: parts[0].clone(),
|
||||
tag: parts[1].clone(),
|
||||
id: parts[2].clone(),
|
||||
created: parts[3..(parts.len() - 2)].join(" "),
|
||||
size: parts[(parts.len() - 2)..parts.len()].join(" "),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,15 +126,13 @@ pub fn installed_list() -> ScrolledWindow {
|
|||
list.append(&btn);
|
||||
}
|
||||
|
||||
let scrollable = ScrolledWindow::builder()
|
||||
ScrolledWindow::builder()
|
||||
.child(&list)
|
||||
.width_request(300)
|
||||
.height_request(600)
|
||||
.halign(Align::Start)
|
||||
.css_classes(["installed_list"])
|
||||
.build();
|
||||
|
||||
scrollable
|
||||
.build()
|
||||
}
|
||||
|
||||
pub fn get_driver_details() -> Vec<String> {
|
||||
|
@ -175,7 +173,7 @@ pub fn get_driver_details() -> Vec<String> {
|
|||
.lines()
|
||||
.filter(|x| x.trim().contains("driver"))
|
||||
.map(|x| {
|
||||
x.split(":")
|
||||
x.split(':')
|
||||
.nth(1)
|
||||
.expect("Failed to find colon in driver definition.")
|
||||
.trim()
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::assigning_clones)]
|
||||
|
||||
use gtk::{
|
||||
prelude::{BoxExt, ButtonExt, EditableExt},
|
||||
Button, PositionType,
|
||||
|
@ -44,7 +46,7 @@ pub fn browse() -> gtk::Box {
|
|||
List of names to skip when searching, this is to remove the
|
||||
labels "Available Packages", "Last refreshed at ..." and "Installed Packages"
|
||||
*/
|
||||
let skip_list = vec!["available", "installed", "last"];
|
||||
let skip_list = ["available", "installed", "last"];
|
||||
|
||||
/*
|
||||
Initialize the packages list, needs to be a static
|
||||
|
@ -75,14 +77,14 @@ pub fn browse() -> gtk::Box {
|
|||
.split_whitespace()
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.split(".")
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap();
|
||||
b.to_string()
|
||||
})
|
||||
.filter(|x| {
|
||||
!x.trim().is_empty()
|
||||
&& !x.contains("=")
|
||||
&& !x.contains('=')
|
||||
&& !skip_list.contains(&x.to_lowercase().trim())
|
||||
})
|
||||
.dedup()
|
||||
|
@ -103,7 +105,7 @@ pub fn browse() -> gtk::Box {
|
|||
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.
|
||||
*/
|
||||
for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].to_vec() {
|
||||
for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].iter() {
|
||||
PKG_LIST_INDEX += 1;
|
||||
let pkg_btn = Button::builder()
|
||||
.label(pkg)
|
||||
|
@ -139,9 +141,11 @@ pub fn browse() -> gtk::Box {
|
|||
.unwrap()
|
||||
.connect_edge_reached(|_, edge| {
|
||||
if edge == PositionType::Bottom {
|
||||
for i in PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(PKG_LIST.len())) {
|
||||
for i in
|
||||
PKG_LIST[PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(PKG_LIST.len()))].iter()
|
||||
{
|
||||
let pkg_btn = Button::builder()
|
||||
.label(PKG_LIST[i].as_str())
|
||||
.label(i.as_str())
|
||||
.css_classes(["package-name"])
|
||||
.build();
|
||||
|
||||
|
@ -202,7 +206,7 @@ unsafe fn search(f: &SearchEntry) {
|
|||
x.to_lowercase()
|
||||
.contains(f.text().to_string().to_lowercase().as_str())
|
||||
})
|
||||
.map(|x| x.clone())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
/*
|
||||
|
@ -233,7 +237,7 @@ unsafe fn search(f: &SearchEntry) {
|
|||
either 50 or the length of the list, whichever
|
||||
is less, and make buttons in the list for each
|
||||
*/
|
||||
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].to_vec() {
|
||||
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].iter() {
|
||||
PKG_LIST_INDEX += 1;
|
||||
let pkg_btn = Button::builder()
|
||||
.label(pkg)
|
||||
|
|
|
@ -51,7 +51,7 @@ pub fn installed() -> gtk::Box {
|
|||
List of names to skip when searching, this is to remove the
|
||||
labels "Available Packages", "Last refreshed at ..." and "Installed Packages"
|
||||
*/
|
||||
let skip_list = vec!["available", "installed", "last"];
|
||||
let skip_list = ["available", "installed", "last"];
|
||||
|
||||
/*
|
||||
Initialize the packages list, needs to be a static
|
||||
|
@ -88,14 +88,14 @@ pub fn installed() -> gtk::Box {
|
|||
.split_whitespace()
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.split(".")
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap();
|
||||
b.to_string()
|
||||
})
|
||||
.filter(|x| {
|
||||
!x.trim().is_empty()
|
||||
&& !x.contains("=")
|
||||
&& !x.contains('=')
|
||||
&& !skip_list.contains(&x.to_lowercase().trim())
|
||||
})
|
||||
.dedup()
|
||||
|
@ -107,7 +107,7 @@ pub fn installed() -> gtk::Box {
|
|||
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.
|
||||
*/
|
||||
for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].to_vec() {
|
||||
for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].iter() {
|
||||
PKG_LIST_INDEX += 1;
|
||||
let pkg_btn = Button::builder()
|
||||
.label(pkg)
|
||||
|
@ -143,19 +143,23 @@ pub fn installed() -> gtk::Box {
|
|||
.unwrap()
|
||||
.connect_edge_reached(|_, edge| {
|
||||
if edge == PositionType::Bottom {
|
||||
for i in PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(FULL_PKG_LIST.len())) {
|
||||
let pkg_btn = Button::builder()
|
||||
.label(FULL_PKG_LIST[i].as_str())
|
||||
.css_classes(["package-name"])
|
||||
.build();
|
||||
(PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(FULL_PKG_LIST.len()))).for_each(
|
||||
|i| {
|
||||
let pkg_btn = Button::builder()
|
||||
.label(FULL_PKG_LIST[i].as_str())
|
||||
.css_classes(["package-name"])
|
||||
.build();
|
||||
|
||||
pkg_btn.connect_clicked(|x| {
|
||||
show_package(x.label().map(|x| x.to_string()).unwrap_or("".to_owned()));
|
||||
});
|
||||
PACKAGES_LIST.as_ref().unwrap().append(&pkg_btn);
|
||||
pkg_btn.connect_clicked(|x| {
|
||||
show_package(
|
||||
x.label().map(|x| x.to_string()).unwrap_or("".to_owned()),
|
||||
);
|
||||
});
|
||||
PACKAGES_LIST.as_ref().unwrap().append(&pkg_btn);
|
||||
|
||||
PKG_LIST_INDEX += 1;
|
||||
}
|
||||
PKG_LIST_INDEX += 1;
|
||||
},
|
||||
);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
@ -204,7 +208,7 @@ unsafe fn search(f: &SearchEntry) {
|
|||
x.to_lowercase()
|
||||
.contains(f.text().to_string().to_lowercase().as_str())
|
||||
})
|
||||
.map(|x| x.clone())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
/*
|
||||
|
@ -235,7 +239,7 @@ unsafe fn search(f: &SearchEntry) {
|
|||
either 50 or the length of the list, whichever
|
||||
is less, and make buttons in the list for each
|
||||
*/
|
||||
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].to_vec() {
|
||||
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].iter() {
|
||||
PKG_LIST_INDEX += 1;
|
||||
let pkg_btn = Button::builder()
|
||||
.label(pkg)
|
||||
|
|
|
@ -112,11 +112,11 @@ fn show_package(pkg: String) {
|
|||
*/
|
||||
for line in info.lines() {
|
||||
if let Some(e) = line.trim().strip_prefix("Version") {
|
||||
version = e.split_once(":").unwrap().1.trim();
|
||||
version = e.split_once(':').unwrap().1.trim();
|
||||
} else if let Some(e) = line.trim().strip_prefix("Size") {
|
||||
size = e.split_once(":").unwrap().1.trim();
|
||||
size = e.split_once(':').unwrap().1.trim();
|
||||
} else if let Some(e) = line.trim().strip_prefix("License") {
|
||||
license = e.split_once(":").unwrap().1.trim();
|
||||
license = e.split_once(':').unwrap().1.trim();
|
||||
}
|
||||
if line.trim().starts_with("Description") {
|
||||
break;
|
||||
|
@ -135,12 +135,12 @@ fn show_package(pkg: String) {
|
|||
("", info)
|
||||
})
|
||||
.1
|
||||
.split_once(":")
|
||||
.split_once(':')
|
||||
.unwrap()
|
||||
.1
|
||||
.trim()
|
||||
.lines()
|
||||
.map(|x| x.split_once(":").unwrap_or(("", x)).1.trim().to_owned() + "\n")
|
||||
.map(|x| x.split_once(':').unwrap_or(("", x)).1.trim().to_owned() + "\n")
|
||||
.collect::<String>();
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,7 +51,7 @@ pub fn updates() -> gtk::Box {
|
|||
List of names to skip when searching, this is to remove the
|
||||
labels "Available Packages", "Last refreshed at ..." and "Installed Packages"
|
||||
*/
|
||||
let skip_list = vec!["available", "installed", "last"];
|
||||
let skip_list = ["available", "installed", "last"];
|
||||
|
||||
/*
|
||||
Initialize the packages list, needs to be a static
|
||||
|
@ -88,14 +88,14 @@ pub fn updates() -> gtk::Box {
|
|||
.split_whitespace()
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.split(".")
|
||||
.split('.')
|
||||
.next()
|
||||
.unwrap();
|
||||
b.to_string()
|
||||
})
|
||||
.filter(|x| {
|
||||
!x.trim().is_empty()
|
||||
&& !x.contains("=")
|
||||
&& !x.contains('=')
|
||||
&& !skip_list.contains(&x.to_lowercase().trim())
|
||||
})
|
||||
.dedup()
|
||||
|
@ -107,7 +107,7 @@ pub fn updates() -> gtk::Box {
|
|||
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.
|
||||
*/
|
||||
for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].to_vec() {
|
||||
for pkg in FULL_PKG_LIST[0..(50.min(FULL_PKG_LIST.len()))].iter() {
|
||||
PKG_LIST_INDEX += 1;
|
||||
let pkg_btn = Button::builder()
|
||||
.label(pkg)
|
||||
|
@ -143,19 +143,23 @@ pub fn updates() -> gtk::Box {
|
|||
.unwrap()
|
||||
.connect_edge_reached(|_, edge| {
|
||||
if edge == PositionType::Bottom {
|
||||
for i in PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(FULL_PKG_LIST.len())) {
|
||||
let pkg_btn = Button::builder()
|
||||
.label(FULL_PKG_LIST[i].as_str())
|
||||
.css_classes(["package-name"])
|
||||
.build();
|
||||
(PKG_LIST_INDEX..((PKG_LIST_INDEX + 50).min(FULL_PKG_LIST.len()))).for_each(
|
||||
|i| {
|
||||
let pkg_btn = Button::builder()
|
||||
.label(FULL_PKG_LIST[i].as_str())
|
||||
.css_classes(["package-name"])
|
||||
.build();
|
||||
|
||||
pkg_btn.connect_clicked(|x| {
|
||||
show_package(x.label().map(|x| x.to_string()).unwrap_or("".to_owned()));
|
||||
});
|
||||
PACKAGES_LIST.as_ref().unwrap().append(&pkg_btn);
|
||||
pkg_btn.connect_clicked(|x| {
|
||||
show_package(
|
||||
x.label().map(|x| x.to_string()).unwrap_or("".to_owned()),
|
||||
);
|
||||
});
|
||||
PACKAGES_LIST.as_ref().unwrap().append(&pkg_btn);
|
||||
|
||||
PKG_LIST_INDEX += 1;
|
||||
}
|
||||
PKG_LIST_INDEX += 1;
|
||||
},
|
||||
);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
@ -204,7 +208,7 @@ unsafe fn search(f: &SearchEntry) {
|
|||
x.to_lowercase()
|
||||
.contains(f.text().to_string().to_lowercase().as_str())
|
||||
})
|
||||
.map(|x| x.clone())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
/*
|
||||
|
@ -235,7 +239,7 @@ unsafe fn search(f: &SearchEntry) {
|
|||
either 50 or the length of the list, whichever
|
||||
is less, and make buttons in the list for each
|
||||
*/
|
||||
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].to_vec() {
|
||||
for pkg in PKG_LIST[0..(50.min(PKG_LIST.len()))].iter() {
|
||||
PKG_LIST_INDEX += 1;
|
||||
let pkg_btn = Button::builder()
|
||||
.label(pkg)
|
||||
|
|
Loading…
Reference in a new issue