diff --git a/.github/release-body.md b/.github/release-body.md
index 6339c93..31b0f6c 100644
--- a/.github/release-body.md
+++ b/.github/release-body.md
@@ -1,7 +1,14 @@
-### 2022-07-23
+### 2022-08-04
+
+### Chores
++ dependencies updated, [d9801cdf372521fe5624a8d68fac83ed39ef81f4]
++ linting: nursery, pedantic, unused_unwraps, [1bd61d4ce8b369d6d078201add3eea0f59fe0dea], [1263662bd9412afacddbc10721bf216ae3a843f1], [ca3315a69f593ad705eb637f227f195edd7781b2]
+
+### Features
++ build all production targets on release, [44f8140eaec330abe5a94f3ddae9e8b223688aa8]
### Fixes
-+ remove reqwest dependency, [10ff8bab5f01f097fd6cdec60b2be947f238197b]
++ toml keywords, [dd2d82d114537e09dbeb12f360157f0e68e7846e]
see CHANGELOG.md for more details
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..660f195
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,45 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "lldb",
+ "request": "launch",
+ "name": "Debug executable 'oxker'",
+ "cargo": {
+ "args": [
+ "build",
+ "--bin=oxker",
+ "--package=oxker"
+ ],
+ "filter": {
+ "name": "oxker",
+ "kind": "bin"
+ }
+ },
+ "args": [],
+ "cwd": "${workspaceFolder}"
+ },
+ {
+ "type": "lldb",
+ "request": "launch",
+ "name": "Debug unit tests in executable 'oxker'",
+ "cargo": {
+ "args": [
+ "test",
+ "--no-run",
+ "--bin=oxker",
+ "--package=oxker"
+ ],
+ "filter": {
+ "name": "oxker",
+ "kind": "bin"
+ }
+ },
+ "args": [],
+ "cwd": "${workspaceFolder}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ed95b3..602b578 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+# v0.1.3
+### 2022-08-04
+
+### Chores
++ dependencies updated, [d9801cdf](https://github.com/mrjackwills/oxker/commit/d9801cdf372521fe5624a8d68fac83ed39ef81f4),
++ linting: nursery, pedantic, unused_unwraps, [1bd61d4c](https://github.com/mrjackwills/oxker/commit/1bd61d4ce8b369d6d078201add3eea0f59fe0dea),, [1263662b](https://github.com/mrjackwills/oxker/commit/1263662bd9412afacddbc10721bf216ae3a843f1),, [ca3315a6](https://github.com/mrjackwills/oxker/commit/ca3315a69f593ad705eb637f227f195edd7781b2),
+
+### Features
++ build all production targets on release, [44f8140e](https://github.com/mrjackwills/oxker/commit/44f8140eaec330abe5a94f3ddae9e8b223688aa8),
+
+### Fixes
++ toml keywords, [dd2d82d1](https://github.com/mrjackwills/oxker/commit/dd2d82d114537e09dbeb12f360157f0e68e7846e),
+
# v0.1.2
### 2022-07-23
diff --git a/Cargo.toml b/Cargo.toml
index 3e5be83..3d7654b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "oxker"
-version = "0.1.2"
+version = "0.1.3"
edition = "2021"
authors = ["Jack Wills "]
description = "a simple tui to view & control docker containers"
@@ -8,7 +8,7 @@ repository = "https://github.com/mrjackwills/oxker"
homepage = "https://github.com/mrjackwills/oxker"
license = "MIT"
readme = "README.md"
-keywords = ["docker", "tui", "tui-rs", "tokio"]
+keywords = ["docker", "tui", "tui-rs", "tokio", "terminal", "podman", "container"]
categories = ["command-line-utilities"]
[dependencies]
diff --git a/create_release.sh b/create_release.sh
index 50a90e9..4fe3c85 100755
--- a/create_release.sh
+++ b/create_release.sh
@@ -179,11 +179,26 @@ cargo_test () {
ask_continue
}
+# Build all releases that GitHub workflow would
+# This will download GB's of docker images
+cargo_build () {
+ cargo install cross
+ cargo build --release
+ ask_continue
+ cross build --target aarch64-unknown-linux-musl --release
+ ask_continue
+ cross build --target arm-unknown-linux-musleabihf --release
+ ask_continue
+ cross build --target x86_64-pc-windows-gnu --release
+ ask_continue
+}
+
# Full flow to create a new release
release_flow() {
check_git
get_git_remote_url
cargo_test
+ cargo_build
cd "${CWD}" || error_close "Can't find ${CWD}"
check_tag
diff --git a/src/app_data/container_state.rs b/src/app_data/container_state.rs
index 4dbb32b..183186c 100644
--- a/src/app_data/container_state.rs
+++ b/src/app_data/container_state.rs
@@ -68,15 +68,10 @@ impl StatefulList {
String::from("")
} else {
let len = self.items.len();
- let c = if let Some(value) = self.state.selected() {
- if len > 0 {
- value + 1
- } else {
- value
- }
- } else {
- 0
- };
+ let c = self
+ .state
+ .selected()
+ .map_or(0, |value| if len > 0 { value + 1 } else { value });
format!("{}/{}", c, self.items.len())
}
}
@@ -95,7 +90,7 @@ pub enum State {
}
impl State {
- pub fn get_color(&self) -> Color {
+ pub const fn get_color(&self) -> Color {
match self {
Self::Running => Color::Green,
Self::Removing => Color::LightRed,
@@ -105,7 +100,7 @@ impl State {
}
}
// Dirty way to create order for the state, rather than impl Ord
- pub fn order(&self) -> &'static str {
+ pub const fn order(&self) -> &'static str {
match self {
Self::Running => "a",
Self::Paused => "b",
@@ -158,7 +153,7 @@ pub enum DockerControls {
}
impl DockerControls {
- pub fn get_color(&self) -> Color {
+ pub const fn get_color(&self) -> Color {
match self {
Self::Start => Color::Green,
Self::Stop => Color::Red,
@@ -205,7 +200,7 @@ pub struct CpuStats {
}
impl CpuStats {
- pub fn new(value: f64) -> Self {
+ pub const fn new(value: f64) -> Self {
Self { value }
}
}
@@ -228,7 +223,7 @@ impl Ord for CpuStats {
fn cmp(&self, other: &Self) -> Ordering {
if self.value > other.value {
Ordering::Greater
- } else if self.value == other.value {
+ } else if (self.value - other.value).abs() < 0.01 {
Ordering::Equal
} else {
Ordering::Less
@@ -276,7 +271,7 @@ impl Ord for ByteStats {
}
impl ByteStats {
- pub fn new(value: u64) -> Self {
+ pub const fn new(value: u64) -> Self {
Self { value }
}
pub fn update(&mut self, value: u64) {
@@ -352,7 +347,7 @@ impl ContainerItem {
/// Find the max value in the last 30 items in the cpu stats vec
fn max_cpu_stats(&self) -> CpuStats {
match self.cpu_stats.iter().max() {
- Some(value) => value.to_owned(),
+ Some(value) => value.clone(),
None => CpuStats::new(0.0),
}
}
@@ -360,7 +355,7 @@ impl ContainerItem {
/// Find the max value in the last 30 items in the mem stats vec
fn max_mem_stats(&self) -> ByteStats {
match self.mem_stats.iter().max() {
- Some(value) => value.to_owned(),
+ Some(value) => value.clone(),
None => ByteStats::new(0),
}
}
@@ -423,8 +418,8 @@ pub struct Columns {
}
impl Columns {
- // (Column titles, minimum header string length)
- pub fn new() -> Self {
+ /// (Column titles, minimum header string length)
+ pub const fn new() -> Self {
Self {
state: (Header::State, 11),
status: (Header::Status, 16),
diff --git a/src/app_data/mod.rs b/src/app_data/mod.rs
index e2ed0da..39bc5ee 100644
--- a/src/app_data/mod.rs
+++ b/src/app_data/mod.rs
@@ -71,7 +71,7 @@ impl AppData {
self.containers
.items
.iter()
- .position(|i| Some(i.id.to_owned()) == id),
+ .position(|i| Some(i.id.clone()) == id),
);
}
/// Generate a default app_state
@@ -87,8 +87,9 @@ impl AppData {
}
}
- // Current time as unix timestamp
- fn get_systemtime(&self) -> u64 {
+ /// Current time as unix timestamp
+ #[allow(clippy::expect_used)]
+ fn get_systemtime() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("In our known reality, this error should never occur")
@@ -106,7 +107,7 @@ impl AppData {
.selected()
{
output =
- Some(self.containers.items[index].docker_controls.items[control_index].clone())
+ Some(self.containers.items[index].docker_controls.items[control_index].clone());
}
}
output
@@ -115,28 +116,28 @@ impl AppData {
/// Change selected choice of docker commands of selected container
pub fn docker_command_next(&mut self) {
if let Some(index) = self.containers.state.selected() {
- self.containers.items[index].docker_controls.next()
+ self.containers.items[index].docker_controls.next();
}
}
/// Change selected choice of docker commands of selected container
pub fn docker_command_previous(&mut self) {
if let Some(index) = self.containers.state.selected() {
- self.containers.items[index].docker_controls.previous()
+ self.containers.items[index].docker_controls.previous();
}
}
/// Change selected choice of docker commands of selected container
pub fn docker_command_start(&mut self) {
if let Some(index) = self.containers.state.selected() {
- self.containers.items[index].docker_controls.start()
+ self.containers.items[index].docker_controls.start();
}
}
/// Change selected choice of docker commands of selected container
pub fn docker_command_end(&mut self) {
if let Some(index) = self.containers.state.selected() {
- self.containers.items[index].docker_controls.end()
+ self.containers.items[index].docker_controls.end();
}
}
@@ -167,9 +168,9 @@ impl AppData {
.iter()
.skip(index)
.take(1)
- .map(|i| i.id.to_owned())
+ .map(|i| i.id.clone())
.collect::();
- output = Some(id)
+ output = Some(id);
}
output
}
@@ -225,7 +226,7 @@ impl AppData {
Header::Image => match so {
SortedOrder::Asc => self.containers.items.sort_by(|a, b| a.image.cmp(&b.image)),
SortedOrder::Desc => {
- self.containers.items.sort_by(|a, b| b.image.cmp(&a.image))
+ self.containers.items.sort_by(|a, b| b.image.cmp(&a.image));
}
},
Header::Name => match so {
@@ -258,38 +259,37 @@ impl AppData {
/// Get the title for log panel for selected container
/// will be "logs x/x"
pub fn get_log_title(&self) -> String {
- if let Some(index) = self.get_selected_log_index() {
- self.containers.items[index].logs.get_state_title()
- } else {
- String::from("")
- }
+ self.get_selected_log_index().map_or_else(
+ || String::from(""),
+ |index| self.containers.items[index].logs.get_state_title(),
+ )
}
/// select next selected log line
pub fn log_next(&mut self) {
if let Some(index) = self.get_selected_log_index() {
- self.containers.items[index].logs.next()
+ self.containers.items[index].logs.next();
}
}
/// select previous selected log line
pub fn log_previous(&mut self) {
if let Some(index) = self.get_selected_log_index() {
- self.containers.items[index].logs.previous()
+ self.containers.items[index].logs.previous();
}
}
/// select last selected log line
pub fn log_end(&mut self) {
if let Some(index) = self.get_selected_log_index() {
- self.containers.items[index].logs.end()
+ self.containers.items[index].logs.end();
}
}
/// select first selected log line
pub fn log_start(&mut self) {
if let Some(index) = self.get_selected_log_index() {
- self.containers.items[index].logs.start()
+ self.containers.items[index].logs.start();
}
}
@@ -315,7 +315,7 @@ impl AppData {
let mut output = Columns::new();
let count = |x: &String| x.chars().count();
- for container in self.containers.items.iter() {
+ for container in &self.containers.items {
let cpu_count = count(
&container
.cpu_stats
@@ -329,8 +329,8 @@ impl AppData {
container.mem_limit
));
- let net_rx_count = count(&container.rx.to_string());
- let net_tx_count = count(&container.tx.to_string());
+ let rx_count = count(&container.rx.to_string());
+ let tx_count = count(&container.tx.to_string());
let image_count = count(&container.image);
let name_count = count(&container.name);
let state_count = count(&container.state.to_string());
@@ -354,11 +354,11 @@ impl AppData {
if status_count > output.status.1 {
output.status.1 = status_count;
};
- if net_rx_count > output.net_rx.1 {
- output.net_rx.1 = net_rx_count;
+ if rx_count > output.net_rx.1 {
+ output.net_rx.1 = rx_count;
};
- if net_tx_count > output.net_tx.1 {
- output.net_tx.1 = net_tx_count;
+ if tx_count > output.net_tx.1 {
+ output.net_tx.1 = tx_count;
};
}
output
@@ -369,7 +369,7 @@ impl AppData {
self.containers
.items
.iter()
- .map(|i| i.id.to_owned())
+ .map(|i| i.id.clone())
.collect::>()
}
@@ -381,14 +381,14 @@ impl AppData {
/// Update container mem, cpu, & network stats, in single function so only need to call .lock() once
pub fn update_stats(
&mut self,
- id: String,
+ id: &str,
cpu_stat: Option,
mem_stat: Option,
mem_limit: u64,
rx: u64,
tx: u64,
) {
- if let Some(container) = self.get_container_by_id(&id) {
+ if let Some(container) = self.get_container_by_id(id) {
if container.cpu_stats.len() >= 60 {
container.cpu_stats.pop_front();
}
@@ -443,7 +443,7 @@ impl AppData {
.unwrap_or(&vec!["".to_owned()])
.get(0)
.unwrap_or(&String::from(""))
- .to_owned();
+ .clone();
if let Some(c) = name.chars().next() {
if c == '/' {
name.remove(0);
@@ -460,10 +460,10 @@ impl AppData {
let image = i.image.as_ref().unwrap_or(&"".to_owned()).trim().to_owned();
if let Some(current_container) = self.get_container_by_id(id) {
if current_container.name != name {
- current_container.name = name
+ current_container.name = name;
};
if current_container.status != status {
- current_container.status = status
+ current_container.status = status;
};
if current_container.state != state {
current_container.docker_controls.items = DockerControls::gen_vec(&state);
@@ -471,18 +471,17 @@ impl AppData {
// Update the list state, needs to be None if the gen_vec returns an empty vec
match state {
State::Removing | State::Restarting | State::Unknown => {
- current_container.docker_controls.state.select(None)
+ current_container.docker_controls.state.select(None);
}
_ => current_container.docker_controls.start(),
};
current_container.state = state;
};
if current_container.image != image {
- current_container.image = image
+ current_container.image = image;
};
} else {
- let mut container =
- ContainerItem::new(id.to_owned(), status, image, state, name);
+ let mut container = ContainerItem::new(id.clone(), status, image, state, name);
container.logs.end();
self.containers.items.push(container);
}
@@ -491,25 +490,25 @@ impl AppData {
}
/// update logs of a given container, based on id
- pub fn update_log_by_id(&mut self, output: Vec, id: String) {
- let tz = self.get_systemtime();
+ pub fn update_log_by_id(&mut self, output: &[String], id: &str) {
+ let tz = Self::get_systemtime();
let color = self.args.color;
let raw = self.args.raw;
- if let Some(container) = self.get_container_by_id(&id) {
+ if let Some(container) = self.get_container_by_id(id) {
container.last_updated = tz;
let current_len = container.logs.items.len();
- output.iter().for_each(|i| {
+ for i in output.iter() {
let lines = if color {
- log_sanitizer::colorize_logs(i.to_owned())
+ log_sanitizer::colorize_logs(i)
} else if raw {
- log_sanitizer::raw(i.to_owned())
+ log_sanitizer::raw(i.clone())
} else {
- log_sanitizer::remove_ansi(i.to_owned())
+ log_sanitizer::remove_ansi(i)
};
container.logs.items.push(ListItem::new(lines));
- });
+ }
if container.logs.state.selected().is_none()
|| container.logs.state.selected().unwrap_or_default() + 1 == current_len
diff --git a/src/docker_data/mod.rs b/src/docker_data/mod.rs
index 4e09a9a..19019ba 100644
--- a/src/docker_data/mod.rs
+++ b/src/docker_data/mod.rs
@@ -102,11 +102,10 @@ impl DockerData {
let mem_stat = stats.memory_stats.usage.unwrap_or(0);
let mem_limit = stats.memory_stats.limit.unwrap_or(0);
- let some_key = if let Some(networks) = &stats.networks {
- networks.keys().next().map(|x| x.to_owned())
- } else {
- None
- };
+ let some_key = stats
+ .networks
+ .as_ref()
+ .and_then(|networks| networks.keys().next().cloned());
let cpu_stats = Self::calculate_usage(&stats);
@@ -122,7 +121,7 @@ impl DockerData {
if is_running {
app_data.lock().update_stats(
- id.clone(),
+ &id,
Some(cpu_stats),
Some(mem_stat),
mem_limit,
@@ -132,10 +131,9 @@ impl DockerData {
} else {
app_data
.lock()
- .update_stats(id.clone(), None, None, mem_limit, rx, tx);
+ .update_stats(&id, None, None, mem_limit, rx, tx);
}
- let key = SpawnId::Stats(id.to_owned());
- spawns.lock().remove(&key);
+ spawns.lock().remove(&SpawnId::Stats(id.clone()));
}
}
@@ -146,13 +144,13 @@ impl DockerData {
let app_data = Arc::clone(&self.app_data);
let spawns = Arc::clone(&self.spawns);
let is_running = *is_running;
- let id = id.to_owned();
+ let id = id.clone();
- let key = SpawnId::Stats(id.to_owned());
+ let key = SpawnId::Stats(id.clone());
let spawn_contains_id = spawns.lock().contains_key(&key);
let s = tokio::spawn(Self::update_container_stat(
docker,
- id.to_owned(),
+ id.clone(),
app_data,
is_running,
spawns,
@@ -180,7 +178,7 @@ impl DockerData {
containers
.iter()
.filter(|i| i.id.is_some())
- .for_each(|c| output.push(c.to_owned()));
+ .for_each(|c| output.push(c.clone()));
self.app_data.lock().update_containers(&output);
@@ -193,7 +191,7 @@ impl DockerData {
i.id.as_ref().map(|id| {
(
i.state.as_ref().unwrap_or(&String::new()) == "running",
- id.to_owned(),
+ id.clone(),
)
})
})
@@ -230,9 +228,8 @@ impl DockerData {
}
}
}
- let key = SpawnId::Log(id.to_owned());
- spawns.lock().remove(&key);
- app_data.lock().update_log_by_id(output, id.to_owned());
+ spawns.lock().remove(&SpawnId::Log(id.clone()));
+ app_data.lock().update_log_by_id(&output, &id);
}
/// Update all logs, spawn each container into own tokio::spawn thread
@@ -240,10 +237,10 @@ impl DockerData {
for (_, id) in all_ids.iter() {
let docker = Arc::clone(&self.docker);
let timestamps = self.timestamps;
- let id = id.to_owned();
+ let id = id.clone();
let app_data = Arc::clone(&self.app_data);
let spawns = Arc::clone(&self.spawns);
- let key = SpawnId::Log(id.to_owned());
+ let key = SpawnId::Log(id.clone());
let s = tokio::spawn(Self::update_log(
docker, id, timestamps, 0, app_data, spawns,
));
@@ -256,9 +253,9 @@ impl DockerData {
let all_ids = self.update_all_containers().await;
let optional_index = self.app_data.lock().get_selected_log_index();
if let Some(index) = optional_index {
- let id = self.app_data.lock().containers.items[index].id.to_owned();
+ let id = self.app_data.lock().containers.items[index].id.clone();
- let key = SpawnId::Log(id.to_owned());
+ let key = SpawnId::Log(id.clone());
let running = self.spawns.lock().contains_key(&key);
if !running {
@@ -290,7 +287,7 @@ impl DockerData {
}
/// Stop the loading_spin function, and reset gui loading status
- fn stop_loading_spin(&mut self, handle: JoinHandle<()>) {
+ fn stop_loading_spin(&mut self, handle: &JoinHandle<()>) {
handle.abort();
self.gui_state.lock().reset_loading();
}
@@ -315,7 +312,7 @@ impl DockerData {
self.initialised = self.app_data.lock().initialised(&all_ids);
}
self.app_data.lock().init = true;
- self.stop_loading_spin(loading_spin);
+ self.stop_loading_spin(&loading_spin);
}
/// Handle incoming messages, container controls & all container information update
@@ -329,9 +326,9 @@ impl DockerData {
docker.pause_container(&id).await.unwrap_or_else(|_| {
app_data
.lock()
- .set_error(AppError::DockerCommand(DockerControls::Pause))
+ .set_error(AppError::DockerCommand(DockerControls::Pause));
});
- self.stop_loading_spin(loading_spin);
+ self.stop_loading_spin(&loading_spin);
}
DockerMessage::Restart(id) => {
let loading_spin = self.loading_spin().await;
@@ -341,9 +338,9 @@ impl DockerData {
.unwrap_or_else(|_| {
app_data
.lock()
- .set_error(AppError::DockerCommand(DockerControls::Restart))
+ .set_error(AppError::DockerCommand(DockerControls::Restart));
});
- self.stop_loading_spin(loading_spin);
+ self.stop_loading_spin(&loading_spin);
}
DockerMessage::Start(id) => {
let loading_spin = self.loading_spin().await;
@@ -353,28 +350,28 @@ impl DockerData {
.unwrap_or_else(|_| {
app_data
.lock()
- .set_error(AppError::DockerCommand(DockerControls::Start))
+ .set_error(AppError::DockerCommand(DockerControls::Start));
});
- self.stop_loading_spin(loading_spin);
+ self.stop_loading_spin(&loading_spin);
}
DockerMessage::Stop(id) => {
let loading_spin = self.loading_spin().await;
docker.stop_container(&id, None).await.unwrap_or_else(|_| {
app_data
.lock()
- .set_error(AppError::DockerCommand(DockerControls::Stop))
+ .set_error(AppError::DockerCommand(DockerControls::Stop));
});
- self.stop_loading_spin(loading_spin);
+ self.stop_loading_spin(&loading_spin);
}
DockerMessage::Unpause(id) => {
let loading_spin = self.loading_spin().await;
docker.unpause_container(&id).await.unwrap_or_else(|_| {
app_data
.lock()
- .set_error(AppError::DockerCommand(DockerControls::Unpause))
+ .set_error(AppError::DockerCommand(DockerControls::Unpause));
});
- self.stop_loading_spin(loading_spin);
- self.update_everything().await
+ self.stop_loading_spin(&loading_spin);
+ self.update_everything().await;
}
DockerMessage::Update => self.update_everything().await,
DockerMessage::Quit => {
@@ -382,7 +379,7 @@ impl DockerData {
.lock()
.values()
.into_iter()
- .for_each(|i| i.abort());
+ .for_each(tokio::task::JoinHandle::abort);
self.is_running.store(false, Ordering::SeqCst);
}
}
diff --git a/src/input_handler/mod.rs b/src/input_handler/mod.rs
index 9bbdbcc..97d49ee 100644
--- a/src/input_handler/mod.rs
+++ b/src/input_handler/mod.rs
@@ -110,7 +110,7 @@ impl InputHandler {
// Show the info box - with "mouse capture enabled / disabled", for 4000 ms
self.info_sleep = Some(tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(4000)).await;
- gui_state.lock().reset_info_box()
+ gui_state.lock().reset_info_box();
}));
self.mouse_capture = !self.mouse_capture;
@@ -118,14 +118,14 @@ impl InputHandler {
/// Sort containers based on a given header, switch asc to desc if already sorted, else always desc
fn sort(&self, header: Header) {
- let mut output = Some((header.to_owned(), SortedOrder::Desc));
+ let mut output = Some((header.clone(), SortedOrder::Desc));
let mut locked_data = self.app_data.lock();
if let Some((h, order)) = locked_data.get_sorted().as_ref() {
if &SortedOrder::Desc == order && h == &header {
- output = Some((header, SortedOrder::Asc))
+ output = Some((header, SortedOrder::Asc));
}
}
- locked_data.set_sorted(output)
+ locked_data.set_sorted(output);
}
/// Send a quit message to docker, to abort all spawns, if error, quit here instead
@@ -219,13 +219,13 @@ impl InputHandler {
KeyCode::Up | KeyCode::Char('k') => self.previous(),
KeyCode::PageUp => {
for _ in 0..=6 {
- self.previous()
+ self.previous();
}
}
KeyCode::Down | KeyCode::Char('j') => self.next(),
KeyCode::PageDown => {
for _ in 0..=6 {
- self.next()
+ self.next();
}
}
KeyCode::Enter => {
diff --git a/src/main.rs b/src/main.rs
index 30c2141..b7fda0e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,13 @@
+#![forbid(unsafe_code)]
+#![warn(clippy::unused_async, clippy::unwrap_used, clippy::expect_used)]
+// Wanring - These are indeed pedantic
+// #![warn(clippy::pedantic)]
+// #![warn(clippy::nursery)]
+// #![allow(clippy::module_name_repetitions, clippy::doc_markdown)]
+
+// Only allow when debugging
+// #![allow(unused)]
+
use app_data::AppData;
use app_error::AppError;
use bollard::Docker;
@@ -35,23 +45,28 @@ async fn main() {
let (docker_sx, docker_rx) = tokio::sync::mpsc::channel(16);
// Create docker daemon handler, and only spawn up the docker data handler if ping returns non-error
- let docker = Arc::new(Docker::connect_with_socket_defaults().unwrap());
- match docker.ping().await {
- Ok(_) => {
- let docker = Arc::clone(&docker);
- let is_running = Arc::clone(&is_running);
- tokio::spawn(DockerData::init(
- docker_args,
- docker_app_data,
- docker,
- docker_gui_state,
- docker_rx,
- is_running,
- ));
+
+ match Docker::connect_with_socket_defaults() {
+ Ok(docker) => {
+ let docker = Arc::new(docker);
+ match docker.ping().await {
+ Ok(_) => {
+ let docker = Arc::clone(&docker);
+ let is_running = Arc::clone(&is_running);
+ tokio::spawn(DockerData::init(
+ docker_args,
+ docker_app_data,
+ docker,
+ docker_gui_state,
+ docker_rx,
+ is_running,
+ ));
+ }
+ Err(_) => app_data.lock().set_error(AppError::DockerConnect),
+ }
}
Err(_) => app_data.lock().set_error(AppError::DockerConnect),
}
-
let input_app_data = Arc::clone(&app_data);
let (input_sx, input_rx) = tokio::sync::mpsc::channel(16);
@@ -70,13 +85,8 @@ async fn main() {
));
// Debug mode for testing, mostly pointless, doesn't take terminal nor draw gui
- if !args.gui {
- loop {
- info!("in debug mode");
- tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
- }
- } else {
- let update_duration = std::time::Duration::from_millis(args.docker_interval as u64);
+ if args.gui {
+ let update_duration = std::time::Duration::from_millis(u64::from(args.docker_interval));
create_ui(
app_data,
input_sx,
@@ -86,6 +96,11 @@ async fn main() {
update_duration,
)
.await
- .unwrap_or(())
+ .unwrap_or(());
+ } else {
+ loop {
+ info!("in debug mode");
+ tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
+ }
}
}
diff --git a/src/parse_args/mod.rs b/src/parse_args/mod.rs
index d76f88a..a115aed 100644
--- a/src/parse_args/mod.rs
+++ b/src/parse_args/mod.rs
@@ -31,7 +31,7 @@ pub struct CliArgs {
impl CliArgs {
/// Parse cli arguments
pub fn new() -> Self {
- let args = CliArgs::parse();
+ let args = Self::parse();
// Quit the program if the docker update argument is 0
// Should maybe change it to check if less than 100
diff --git a/src/ui/color_match.rs b/src/ui/color_match.rs
index 14543b6..149d74a 100644
--- a/src/ui/color_match.rs
+++ b/src/ui/color_match.rs
@@ -1,36 +1,36 @@
pub mod log_sanitizer {
- use cansi::{categorise_text, Color as CansiColor, Intensity};
+ use cansi::{v3::categorise_text, Color as CansiColor, Intensity};
use tui::{
style::{Color, Modifier, Style},
text::{Span, Spans},
};
/// Attempt to colorize the given string to tui-rs standars
- pub fn colorize_logs(input: String) -> Vec> {
+ pub fn colorize_logs(input: &str) -> Vec> {
vec![Spans::from(
- categorise_text(&input)
+ categorise_text(input)
.into_iter()
.map(|i| {
- let fg_color = color_ansi_to_tui(i.fg_colour);
- let bg_color = color_ansi_to_tui(i.bg_colour);
+ let fg_color = color_ansi_to_tui(i.fg.unwrap_or(CansiColor::White));
+ let bg_color = color_ansi_to_tui(i.bg.unwrap_or(CansiColor::Black));
let style = Style::default().bg(bg_color).fg(fg_color);
- if i.blink {
+ if i.blink.is_some() {
style.add_modifier(Modifier::SLOW_BLINK);
}
- if i.underline {
+ if i.underline.is_some() {
style.add_modifier(Modifier::UNDERLINED);
}
- if i.reversed {
+ if i.reversed.is_some() {
style.add_modifier(Modifier::REVERSED);
}
- if i.intensity == Intensity::Bold {
+ if i.intensity == Some(Intensity::Bold) {
style.add_modifier(Modifier::BOLD);
}
- if i.hidden {
+ if i.hidden.is_some() {
style.add_modifier(Modifier::HIDDEN);
}
- if i.strikethrough {
+ if i.strikethrough.is_some() {
style.add_modifier(Modifier::CROSSED_OUT);
}
Span::styled(i.text.to_owned(), style)
@@ -40,10 +40,10 @@ pub mod log_sanitizer {
}
/// Remove all ansi formatting from a given string and create tui-rs spans
- pub fn remove_ansi(input: String) -> Vec> {
+ pub fn remove_ansi(input: &str) -> Vec> {
let mut output = String::from("");
- for i in categorise_text(&input) {
- output.push_str(i.text)
+ for i in categorise_text(input) {
+ output.push_str(i.text);
}
raw(output)
}
@@ -54,24 +54,22 @@ pub mod log_sanitizer {
}
/// Change from ansi to tui colors
- fn color_ansi_to_tui(color: CansiColor) -> Color {
+ const fn color_ansi_to_tui(color: CansiColor) -> Color {
match color {
- CansiColor::Black => Color::Black,
+ CansiColor::Black | CansiColor::BrightBlack => Color::Black,
CansiColor::Red => Color::Red,
CansiColor::Green => Color::Green,
CansiColor::Yellow => Color::Yellow,
CansiColor::Blue => Color::Blue,
CansiColor::Magenta => Color::Magenta,
CansiColor::Cyan => Color::Cyan,
- CansiColor::White => Color::White,
- CansiColor::BrightBlack => Color::Black,
+ CansiColor::White | CansiColor::BrightWhite => Color::White,
CansiColor::BrightRed => Color::LightRed,
CansiColor::BrightGreen => Color::LightGreen,
CansiColor::BrightYellow => Color::LightYellow,
CansiColor::BrightBlue => Color::LightBlue,
CansiColor::BrightMagenta => Color::LightMagenta,
CansiColor::BrightCyan => Color::LightCyan,
- CansiColor::BrightWhite => Color::White,
}
}
}
diff --git a/src/ui/draw_blocks.rs b/src/ui/draw_blocks.rs
index 3e4b86c..30d594a 100644
--- a/src/ui/draw_blocks.rs
+++ b/src/ui/draw_blocks.rs
@@ -64,7 +64,7 @@ fn generate_block<'a>(
SelectablePanel::Logs => {
format!(" {} {} ", panel.title(), app_data.lock().get_log_title())
}
- _ => String::from(""),
+ SelectablePanel::Commands => String::from(""),
};
block = block.title(title);
if current_selected_panel == panel {
@@ -74,7 +74,7 @@ fn generate_block<'a>(
}
/// Draw the command panel
-pub fn draw_commands(
+pub fn commands(
app_data: &Arc>,
area: Rect,
f: &mut Frame<'_, B>,
@@ -111,12 +111,12 @@ pub fn draw_commands(
let paragraph = Paragraph::new(debug_text)
.block(block)
.alignment(Alignment::Center);
- f.render_widget(paragraph, area)
+ f.render_widget(paragraph, area);
}
}
/// Draw the containers panel
-pub fn draw_containers(
+pub fn containers(
app_data: &Arc>,
area: Rect,
f: &mut Frame<'_, B>,
@@ -196,7 +196,7 @@ pub fn draw_containers(
let paragraph = Paragraph::new(debug_text)
.block(block)
.alignment(Alignment::Center);
- f.render_widget(paragraph, area)
+ f.render_widget(paragraph, area);
} else {
let items = List::new(items)
.block(block)
@@ -208,13 +208,13 @@ pub fn draw_containers(
}
/// Draw the logs panel
-pub fn draw_logs(
+pub fn logs(
app_data: &Arc>,
area: Rect,
f: &mut Frame<'_, B>,
gui_state: &Arc>,
index: Option,
- loading_icon: String,
+ loading_icon: &str,
) {
let block = generate_block(app_data, area, gui_state, SelectablePanel::Logs);
@@ -225,14 +225,14 @@ pub fn draw_logs(
.style(Style::default())
.block(block)
.alignment(Alignment::Center);
- f.render_widget(paragraph, area)
+ f.render_widget(paragraph, area);
} else if let Some(index) = index {
let items = app_data.lock().containers.items[index]
.logs
.items
.iter()
.enumerate()
- .map(|i| i.1.to_owned())
+ .map(|i| i.1.clone())
.collect::>();
let items = List::new(items)
@@ -249,12 +249,12 @@ pub fn draw_logs(
let paragraph = Paragraph::new(debug_text)
.block(block)
.alignment(Alignment::Center);
- f.render_widget(paragraph, area)
+ f.render_widget(paragraph, area);
}
}
/// Draw the cpu + mem charts
-pub fn draw_chart(
+pub fn chart(
f: &mut Frame<'_, B>,
area: Rect,
app_data: &Arc>,
@@ -279,20 +279,10 @@ pub fn draw_chart(
.style(Style::default().fg(Color::Cyan))
.graph_type(GraphType::Line)
.data(&mem.0)];
- let cpu_chart = make_chart(
- cpu.2,
- String::from("cpu"),
- cpu_dataset,
- CpuStats::new(cpu.0.last().unwrap_or(&(0.00, 0.00)).1),
- cpu.1,
- );
- let mem_chart = make_chart(
- mem.2,
- String::from("memory"),
- mem_dataset,
- ByteStats::new(mem.0.last().unwrap_or(&(0.0, 0.0)).1 as u64),
- mem.1,
- );
+ let cpu_stats = CpuStats::new(cpu.0.last().unwrap_or(&(0.00, 0.00)).1);
+ let mem_stats = ByteStats::new(mem.0.last().unwrap_or(&(0.0, 0.0)).1 as u64);
+ let cpu_chart = make_chart(&cpu.2, "cpu", cpu_dataset, &cpu_stats, &cpu.1);
+ let mem_chart = make_chart(&mem.2, "memory", mem_dataset, &mem_stats, &mem.1);
f.render_widget(cpu_chart, area[0]);
f.render_widget(mem_chart, area[1]);
@@ -301,13 +291,13 @@ pub fn draw_chart(
}
/// Create charts
-fn make_chart(
- state: State,
- name: String,
- dataset: Vec,
- current: T,
- max: T,
-) -> Chart {
+fn make_chart<'a, T: Stats + Display>(
+ state: &State,
+ name: &'a str,
+ dataset: Vec>,
+ current: &'a T,
+ max: &'a T,
+) -> Chart<'a> {
let title_color = match state {
State::Running => Color::Green,
_ => state.get_color(),
@@ -351,13 +341,13 @@ fn make_chart(
}
/// Draw heading bar at top of program, always visible
-pub fn draw_heading_bar(
+pub fn heading_bar(
area: Rect,
columns: &Columns,
f: &mut Frame<'_, B>,
has_containers: bool,
- loading_icon: String,
- sorted_by: Option<(Header, SortedOrder)>,
+ loading_icon: &str,
+ sorted_by: &Option<(Header, SortedOrder)>,
gui_state: &Arc>,
) {
let block = || Block::default().style(Style::default().bg(Color::Magenta).fg(Color::Black));
@@ -377,7 +367,7 @@ pub fn draw_heading_bar(
SortedOrder::Desc => suffix = " ⌄",
}
suffix_margin = 2;
- color = Color::White
+ color = Color::White;
};
};
(
@@ -439,11 +429,7 @@ pub fn draw_heading_bar(
.iter()
.map(|i| {
let header_block = gen_header(&i.0, i.1);
- (
- header_block.0,
- i.0.to_owned(),
- Constraint::Max(header_block.1),
- )
+ (header_block.0, i.0.clone(), Constraint::Max(header_block.1))
})
.collect::>();
@@ -500,7 +486,7 @@ fn max_line_width(text: &str) -> usize {
}
/// Draw the help box in the centre of the screen
-pub fn draw_help_box(f: &mut Frame<'_, B>) {
+pub fn help_box(f: &mut Frame<'_, B>) {
let title = format!(" {} ", VERSION);
let description_text = format!("\n{}", DESCRIPTION);
@@ -550,7 +536,7 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) {
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Black));
- let area = draw_popup(
+ let area = popup(
lines as u16,
max_line_width as u16,
f.size(),
@@ -578,7 +564,7 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) {
}
/// Draw an error popup over whole screen
-pub fn draw_error(f: &mut Frame<'_, B>, error: AppError, seconds: Option) {
+pub fn error(f: &mut Frame<'_, B>, error: &AppError, seconds: Option) {
let block = Block::default()
.title(" Error ")
.border_type(BorderType::Rounded)
@@ -614,7 +600,7 @@ pub fn draw_error(f: &mut Frame<'_, B>, error: AppError, seconds: Op
.block(block)
.alignment(Alignment::Center);
- let area = draw_popup(
+ let area = popup(
lines as u16,
max_line_width as u16,
f.size(),
@@ -625,7 +611,7 @@ pub fn draw_error(f: &mut Frame<'_, B>, error: AppError, seconds: Op
}
/// Draw info box in one of the 9 BoxLocations
-pub fn draw_info(f: &mut Frame<'_, B>, text: String) {
+pub fn info(f: &mut Frame<'_, B>, text: String) {
let block = Block::default()
.title("")
.title_alignment(Alignment::Center)
@@ -643,7 +629,7 @@ pub fn draw_info(f: &mut Frame<'_, B>, text: String) {
.block(block)
.alignment(Alignment::Center);
- let area = draw_popup(
+ let area = popup(
lines as u16,
max_line_width as u16,
f.size(),
@@ -654,7 +640,7 @@ pub fn draw_info(f: &mut Frame<'_, B>, text: String) {
}
/// draw a box in the one of the BoxLocations, based on max line width + number of lines
-fn draw_popup(text_lines: u16, text_width: u16, r: Rect, box_location: BoxLocation) -> Rect {
+fn popup(text_lines: u16, text_width: u16, r: Rect, box_location: BoxLocation) -> Rect {
// Make sure blank_space can't be an negative, as will crash
let blank_vertical = if r.height > text_lines {
(r.height - text_lines) / 2
diff --git a/src/ui/gui_state.rs b/src/ui/gui_state.rs
index 34add3e..5711148 100644
--- a/src/ui/gui_state.rs
+++ b/src/ui/gui_state.rs
@@ -30,7 +30,7 @@ pub enum BoxLocation {
}
impl BoxLocation {
- pub fn get_indexes(&self) -> (usize, usize) {
+ pub const fn get_indexes(self) -> (usize, usize) {
match self {
Self::TopLeft => (0, 0),
Self::TopCentre => (0, 1),
@@ -45,8 +45,8 @@ impl BoxLocation {
}
// Should combine and just return a tuple?
- pub fn get_horizontal_constraints(
- &self,
+ pub const fn get_horizontal_constraints(
+ self,
blank_vertical: u16,
text_width: u16,
) -> [Constraint; 3] {
@@ -68,8 +68,8 @@ impl BoxLocation {
],
}
}
- pub fn get_vertical_constraints(
- &self,
+ pub const fn get_vertical_constraints(
+ self,
blank_vertical: u16,
number_lines: u16,
) -> [Constraint; 3] {
@@ -108,7 +108,7 @@ pub enum Loading {
}
impl Loading {
- pub fn next(&self) -> Self {
+ pub const fn next(&self) -> Self {
match self {
Self::One => Self::Two,
Self::Two => Self::Three,
@@ -143,21 +143,21 @@ impl fmt::Display for Loading {
}
impl SelectablePanel {
- pub fn title(self) -> &'static str {
+ pub const fn title(self) -> &'static str {
match self {
Self::Containers => "Containers",
Self::Logs => "Logs",
- _ => "",
+ Self::Commands => "",
}
}
- pub fn next(self) -> Self {
+ pub const fn next(self) -> Self {
match self {
Self::Containers => Self::Commands,
Self::Commands => Self::Logs,
Self::Logs => Self::Containers,
}
}
- pub fn prev(self) -> Self {
+ pub const fn prev(self) -> Self {
match self {
Self::Containers => Self::Logs,
Self::Commands => Self::Containers,
@@ -221,7 +221,7 @@ impl GuiState {
.filter(|i| i.1.intersects(rect))
.collect::>()
.get(0)
- .map(|data| data.0.to_owned())
+ .map(|data| data.0.clone())
}
/// Insert, or updatem header area panel into heading_map
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index 8b7504a..9a529fd 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -30,7 +30,6 @@ use crate::{
app_data::AppData, app_error::AppError, docker_data::DockerMessage,
input_handler::InputMessages,
};
-use draw_blocks::*;
/// Take control of the terminal in order to draw gui
pub async fn create_ui(
@@ -73,7 +72,7 @@ pub async fn create_ui(
}
/// Run a loop to draw the gui
-async fn run_app(
+async fn run_app(
terminal: &mut Terminal,
app_data: Arc>,
sender: Sender,
@@ -94,9 +93,12 @@ async fn run_app(
is_running.store(false, Ordering::SeqCst);
break;
}
- terminal
- .draw(|f| draw_error(f, AppError::DockerConnect, Some(seconds)))
- .unwrap();
+ if terminal
+ .draw(|f| draw_blocks::error(f, &AppError::DockerConnect, Some(seconds)))
+ .is_err()
+ {
+ return Err(AppError::Terminal);
+ }
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
seconds -= 1;
}
@@ -104,7 +106,9 @@ async fn run_app(
} else {
let mut now = Instant::now();
loop {
- terminal.draw(|f| ui(f, &app_data, &gui_state)).unwrap();
+ if terminal.draw(|f| ui(f, &app_data, &gui_state)).is_err() {
+ return Err(AppError::Terminal);
+ }
if crossterm::event::poll(input_poll_rate).unwrap_or_default() {
if let Ok(event) = event::read() {
if let Event::Key(key) = event {
@@ -143,12 +147,8 @@ fn ui(
gui_state: &Arc>,
) {
// set max height for container section, needs +4 to deal with docker commands list and borders
- let mut height = app_data.lock().get_container_len();
- if height < 12 {
- height += 4;
- } else {
- height = 12
- }
+ let height = app_data.lock().get_container_len();
+ let height = if height < 12 { (height + 4) as u16 } else { 12 };
let column_widths = app_data.lock().get_width();
let has_containers = !app_data.lock().containers.items.is_empty();
@@ -194,47 +194,47 @@ fn ui(
.constraints(lower_split.as_ref())
.split(upper_main[1]);
- draw_containers(app_data, top_panel[0], f, gui_state, &column_widths);
+ draw_blocks::containers(app_data, top_panel[0], f, gui_state, &column_widths);
if has_containers {
- draw_commands(app_data, top_panel[1], f, gui_state, log_index);
+ draw_blocks::commands(app_data, top_panel[1], f, gui_state, log_index);
}
- draw_logs(
+ draw_blocks::logs(
app_data,
lower_main[0],
f,
gui_state,
log_index,
- loading_icon.to_owned(),
+ &loading_icon,
);
- draw_heading_bar(
+ draw_blocks::heading_bar(
whole_layout[0],
&column_widths,
f,
has_containers,
- loading_icon,
- sorted_by,
+ &loading_icon,
+ &sorted_by,
gui_state,
);
// only draw charts if there are containers
if has_containers {
- draw_chart(f, lower_main[1], app_data, log_index);
+ draw_blocks::chart(f, lower_main[1], app_data, log_index);
}
if let Some(info) = info_text {
- draw_info(f, info);
+ draw_blocks::info(f, info);
}
// Check if error, and show popup if so
if show_help {
- draw_help_box(f);
+ draw_blocks::help_box(f);
}
if let Some(error) = has_error {
app_data.lock().show_error = true;
- draw_error(f, error, None);
+ draw_blocks::error(f, &error, None);
}
}