chore: merge release-v0.6.0 into main
This commit is contained in:
+11
-14
@@ -1,26 +1,23 @@
|
|||||||
### 2024-01-05
|
### 2024-01-18
|
||||||
|
|
||||||
### Chores
|
### Chores
|
||||||
+ .devcontainer updated, [2313618eb1493ce41d70847b888c32b65fdc40ea], [5af6b8bcd31c3c38ff5a5799c76dc1cbe1167763], [9b0b6b10c3a0c1d5095490cfd3cda18d252f38f5]
|
+ dependencies updated, [53b4bafbe53312fe41608ddf33e865d474222aaa], [58ef151600e362048a607c8ae61a5edfe80ab1dd], [b6fd35022a99ec0e982ddb154b0450d49c4840e9], [0438c108bdd9815d7eae1b89c47c4e6438f358d6]
|
||||||
+ alpine version bump, [061de032dad935c56c6caab419ecb5c9bbac4c7e]
|
+ files formatted, [1806165c3e266876b2d1806f7b662d09705f3aad]
|
||||||
+ dependencies updated, [0890991ff1a239fe2d556a0c4eac6ae05beb9b50], [0a7b266b2a358a4788ae877ca8a97f08eac4eef2], [333621f1a7321c1fdf73fd35dd7f3ab165a9dc64], [3e51889cd8a552b1da463ae6a40d5de6eec188f5], [a179bb6f6a7e076269fa830f56c0d4a31cf8488a]
|
+ create_release.sh check for unused lint, [d0b27211928f93f8455e1ee5a6a6485c6a21d382]
|
||||||
+ file formatting, [eb5e74ae67d815bf49f241d2baf319e41cf9adf8]
|
|
||||||
+ Rust 1.75.0 linting, [81be75f27fd32a59ebff57e44c5022ff862df84b]
|
|
||||||
|
|
||||||
### Docs
|
### Docs
|
||||||
+ screenshot updated, [0231d1bdcda304300d289243a95044ab3bdce85c]
|
= Readme updated, screenshot added, [7561a93415c1e1f596b15edba95e7b32a939cd90], [4069e5572f81cb689dbb9f735db919e4636cdccc]
|
||||||
+ comment typo, [0ad1ec9d85d6f0cac743b4421d0ad03432c9d717]
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
+ re-arrange columns, container name is now the first column, added a ContainerName & ContainerImage struct via `string_wrapper` macro, closes #32, [e936bb4b78980d0e34a1ef5e9f6f82a9ed0ddc7f]
|
+ Ports section added, closes #21, [65a1afcb0605604ede350a5630c775f94ebb74ee], [7a096a65c40924021fe643fe0aa1067095832df9]
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
+ Docker Commands hidden, [4301e4709f99fc23ee438bf345b0dc698a05dc4e]
|
+ sort arrow now on left of header, [40ddcb727d2c1758d6dd26a58507b85b219f51e2]
|
||||||
+ .gitattributes, [1234ea53897b2ed6ada0eb18cd81b8783a5dc5f5]
|
|
||||||
|
|
||||||
### Refactors
|
### Refactors
|
||||||
+ GitHub workflow action improved, [04b66af2b60c96cfbece0b13109e30b08ef35cc4]
|
+ rename string_wrapper > unit_struct, [27cf53e41f8b379f606c1c27620ee08e79bac57e]
|
||||||
+ sort_containers, [ccf8b55a7495982f72b4fb3af6e11a9bd7465216]
|
|
||||||
+ string_wrapper .get() return `&str`, [a722731c6a77e00d1fb13967b51400aa34e72213]
|
### Tests
|
||||||
|
+ Finally have tests, currently for layout and associated methods, at the moment running the tests will not interfere with any running Docker containers, [4bcf77db776a36e0a8151ecfbda722a66c4ba46c]
|
||||||
|
|
||||||
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
|
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 34 KiB |
@@ -1,3 +1,26 @@
|
|||||||
|
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.6.0'>v0.6.0</a>
|
||||||
|
### 2024-01-18
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
+ dependencies updated, [53b4bafb](https://github.com/mrjackwills/oxker/commit/53b4bafbe53312fe41608ddf33e865d474222aaa), [58ef1516](https://github.com/mrjackwills/oxker/commit/58ef151600e362048a607c8ae61a5edfe80ab1dd), [b6fd3502](https://github.com/mrjackwills/oxker/commit/b6fd35022a99ec0e982ddb154b0450d49c4840e9), [0438c108](https://github.com/mrjackwills/oxker/commit/0438c108bdd9815d7eae1b89c47c4e6438f358d6)
|
||||||
|
+ files formatted, [1806165c](https://github.com/mrjackwills/oxker/commit/1806165c3e266876b2d1806f7b662d09705f3aad)
|
||||||
|
+ create_release.sh check for unused lint, [d0b27211](https://github.com/mrjackwills/oxker/commit/d0b27211928f93f8455e1ee5a6a6485c6a21d382)
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
= Readme updated, screenshot added, [7561a934](https://github.com/mrjackwills/oxker/commit/7561a93415c1e1f596b15edba95e7b32a939cd90), [4069e557](https://github.com/mrjackwills/oxker/commit/4069e5572f81cb689dbb9f735db919e4636cdccc)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
+ Ports section added, closes [#21](https://github.com/mrjackwills/oxker/issues/21), [65a1afcb](https://github.com/mrjackwills/oxker/commit/65a1afcb0605604ede350a5630c775f94ebb74ee), [7a096a65](https://github.com/mrjackwills/oxker/commit/7a096a65c40924021fe643fe0aa1067095832df9)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
+ sort arrow now on left of header, [40ddcb72](https://github.com/mrjackwills/oxker/commit/40ddcb727d2c1758d6dd26a58507b85b219f51e2)
|
||||||
|
|
||||||
|
### Refactors
|
||||||
|
+ rename string_wrapper > unit_struct, [27cf53e4](https://github.com/mrjackwills/oxker/commit/27cf53e41f8b379f606c1c27620ee08e79bac57e)
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
+ Finally have tests, currently for layout and associated methods, at the moment running the tests will not interfere with any running Docker containers, [4bcf77db](https://github.com/mrjackwills/oxker/commit/4bcf77db776a36e0a8151ecfbda722a66c4ba46c)
|
||||||
|
|
||||||
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.5.0'>v0.5.0</a>
|
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.5.0'>v0.5.0</a>
|
||||||
### 2024-01-05
|
### 2024-01-05
|
||||||
|
|
||||||
|
|||||||
Generated
+44
-44
@@ -52,9 +52,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.5"
|
version = "0.6.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
|
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
@@ -127,9 +127,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.5"
|
version = "0.21.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
@@ -139,9 +139,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.4.1"
|
version = "2.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bollard"
|
name = "bollard"
|
||||||
@@ -237,9 +237,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.4.13"
|
version = "4.4.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
|
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -247,9 +247,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.4.12"
|
version = "4.4.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -295,7 +295,7 @@ version = "0.27.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.2",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
@@ -426,9 +426,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.11"
|
version = "0.2.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
|
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -443,9 +443,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.22"
|
version = "0.3.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -484,9 +484,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
@@ -643,9 +643,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.66"
|
version = "0.3.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
|
checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -658,9 +658,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.151"
|
version = "0.2.152"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
@@ -668,7 +668,7 @@ version = "0.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.2",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
]
|
]
|
||||||
@@ -783,7 +783,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxker"
|
name = "oxker"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bollard",
|
"bollard",
|
||||||
@@ -881,9 +881,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.75"
|
version = "1.0.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708"
|
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -933,7 +933,7 @@ version = "0.25.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb"
|
checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.1",
|
"bitflags 2.4.2",
|
||||||
"cassowary",
|
"cassowary",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"indoc",
|
"indoc",
|
||||||
@@ -992,18 +992,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.194"
|
version = "1.0.195"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
|
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.194"
|
version = "1.0.195"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
|
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1110,9 +1110,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.11.2"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
|
checksum = "3b187f0231d56fe41bfb12034819dd2bf336422a5866de41bc3fec4b2e3883e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
@@ -1382,9 +1382,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.14"
|
version = "0.3.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
|
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
@@ -1469,9 +1469,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.89"
|
version = "0.2.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
|
checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
@@ -1479,9 +1479,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.89"
|
version = "0.2.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
|
checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
@@ -1494,9 +1494,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.89"
|
version = "0.2.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
|
checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -1504,9 +1504,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.89"
|
version = "0.2.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1517,9 +1517,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.89"
|
version = "0.2.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
|
|||||||
+6
-7
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "oxker"
|
name = "oxker"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Jack Wills <email@mrjackwills.com>"]
|
authors = ["Jack Wills <email@mrjackwills.com>"]
|
||||||
description = "A simple tui to view & control docker containers"
|
description = "A simple tui to view & control docker containers"
|
||||||
@@ -17,7 +17,7 @@ unsafe_code = "forbid"
|
|||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
expect_used = "warn"
|
expect_used = "warn"
|
||||||
nursery = "warn"
|
nursery = "warn"
|
||||||
pedantic ="warn"
|
pedantic = "warn"
|
||||||
todo = "warn"
|
todo = "warn"
|
||||||
unused_async = "warn"
|
unused_async = "warn"
|
||||||
unwrap_used = "warn"
|
unwrap_used = "warn"
|
||||||
@@ -29,15 +29,15 @@ similar_names = "allow"
|
|||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
bollard = "0.15"
|
bollard = "0.15"
|
||||||
cansi = "2.2"
|
cansi = "2.2"
|
||||||
clap = { version = "4.4", features = ["derive", "unicode", "color"] }
|
clap = { version = "4.4", features = ["color", "derive", "unicode"] }
|
||||||
crossterm = "0.27"
|
crossterm = "0.27"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
parking_lot = { version= "0.12" }
|
parking_lot = { version = "0.12" }
|
||||||
tokio = { version = "1.35", features = ["full"] }
|
tokio = { version = "1.35", features = ["full"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
ratatui = "0.25"
|
ratatui = "0.25"
|
||||||
uuid = { version = "1.6", features = ["v4", "fast-rng"] }
|
uuid = { version = "1.6", features = ["fast-rng", "v4"] }
|
||||||
directories = "5.0"
|
directories = "5.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@@ -46,6 +46,5 @@ directories = "5.0"
|
|||||||
lto = true
|
lto = true
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = 'abort'
|
panic = 'abort'
|
||||||
strip=true
|
strip = true
|
||||||
debug = false
|
debug = false
|
||||||
|
|
||||||
|
|||||||
@@ -157,7 +157,8 @@ see <a href="https://forums.raspberrypi.com/viewtopic.php?t=203128" target='_bla
|
|||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
As of yet untested, needs work
|
~~As of yet untested, needs work~~
|
||||||
|
The work has been done, sp far the tests don't effect any running containers, but this may change in the future.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
cargo test -- --test-threads=1
|
cargo test -- --test-threads=1
|
||||||
|
|||||||
+77
-67
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# rust create_release
|
# rust create_release
|
||||||
# v0.3.1
|
# v0.4.1
|
||||||
|
|
||||||
STAR_LINE='****************************************'
|
STAR_LINE='****************************************'
|
||||||
CWD=$(pwd)
|
CWD=$(pwd)
|
||||||
@@ -12,15 +12,14 @@ YELLOW='\033[0;33m'
|
|||||||
PURPLE='\033[0;35m'
|
PURPLE='\033[0;35m'
|
||||||
RESET='\033[0m'
|
RESET='\033[0m'
|
||||||
|
|
||||||
|
|
||||||
# $1 string - error message
|
# $1 string - error message
|
||||||
error_close() {
|
error_close() {
|
||||||
echo -e "\n${RED}ERROR - EXITED: ${YELLOW}$1${RESET}\n";
|
echo -e "\n${RED}ERROR - EXITED: ${YELLOW}$1${RESET}\n"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# $1 string - question to ask
|
# $1 string - question to ask
|
||||||
ask_yn () {
|
ask_yn() {
|
||||||
printf "%b%s? [y/N]:%b " "${GREEN}" "$1" "${RESET}"
|
printf "%b%s? [y/N]:%b " "${GREEN}" "$1" "${RESET}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,19 +29,19 @@ user_input() {
|
|||||||
echo "$data"
|
echo "$data"
|
||||||
}
|
}
|
||||||
|
|
||||||
update_major () {
|
update_major() {
|
||||||
local bumped_major
|
local bumped_major
|
||||||
bumped_major=$((MAJOR + 1))
|
bumped_major=$((MAJOR + 1))
|
||||||
echo "${bumped_major}.0.0"
|
echo "${bumped_major}.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
update_minor () {
|
update_minor() {
|
||||||
local bumped_minor
|
local bumped_minor
|
||||||
bumped_minor=$((MINOR + 1))
|
bumped_minor=$((MINOR + 1))
|
||||||
echo "${MAJOR}.${bumped_minor}.0"
|
echo "${MAJOR}.${bumped_minor}.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
update_patch () {
|
update_patch() {
|
||||||
local bumped_patch
|
local bumped_patch
|
||||||
bumped_patch=$((PATCH + 1))
|
bumped_patch=$((PATCH + 1))
|
||||||
echo "${MAJOR}.${MINOR}.${bumped_patch}"
|
echo "${MAJOR}.${MINOR}.${bumped_patch}"
|
||||||
@@ -56,8 +55,7 @@ get_git_remote_url() {
|
|||||||
# Check that git status is clean
|
# Check that git status is clean
|
||||||
check_git_clean() {
|
check_git_clean() {
|
||||||
GIT_CLEAN=$(git status --porcelain)
|
GIT_CLEAN=$(git status --porcelain)
|
||||||
if [[ -n $GIT_CLEAN ]]
|
if [[ -n $GIT_CLEAN ]]; then
|
||||||
then
|
|
||||||
error_close "git dirty"
|
error_close "git dirty"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -66,8 +64,7 @@ check_git_clean() {
|
|||||||
check_git() {
|
check_git() {
|
||||||
CURRENT_GIT_BRANCH=$(git branch --show-current)
|
CURRENT_GIT_BRANCH=$(git branch --show-current)
|
||||||
check_git_clean
|
check_git_clean
|
||||||
if [[ ! "$CURRENT_GIT_BRANCH" =~ ^dev$ ]]
|
if [[ ! "$CURRENT_GIT_BRANCH" =~ ^dev$ ]]; then
|
||||||
then
|
|
||||||
error_close "not on dev branch"
|
error_close "not on dev branch"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -79,8 +76,7 @@ ask_changelog_update() {
|
|||||||
printf "%s" "$RELEASE_BODY_TEXT"
|
printf "%s" "$RELEASE_BODY_TEXT"
|
||||||
printf "\n%s\n" "${STAR_LINE}"
|
printf "\n%s\n" "${STAR_LINE}"
|
||||||
ask_yn "accept release body"
|
ask_yn "accept release body"
|
||||||
if [[ "$(user_input)" =~ ^y$ ]]
|
if [[ "$(user_input)" =~ ^y$ ]]; then
|
||||||
then
|
|
||||||
update_release_body_and_changelog "$RELEASE_BODY_TEXT"
|
update_release_body_and_changelog "$RELEASE_BODY_TEXT"
|
||||||
else
|
else
|
||||||
exit
|
exit
|
||||||
@@ -89,17 +85,17 @@ ask_changelog_update() {
|
|||||||
|
|
||||||
# Edit the release-body to include new lines from changelog
|
# Edit the release-body to include new lines from changelog
|
||||||
# add commit urls to changelog
|
# add commit urls to changelog
|
||||||
# $1 RELEASE_BODY
|
# $1 RELEASE_BODY
|
||||||
update_release_body_and_changelog () {
|
update_release_body_and_changelog() {
|
||||||
echo -e
|
echo -e
|
||||||
DATE_SUBHEADING="### $(date +'%Y-%m-%d')\n\n"
|
DATE_SUBHEADING="### $(date +'%Y-%m-%d')\n\n"
|
||||||
RELEASE_BODY_ADDITION="${DATE_SUBHEADING}$1"
|
RELEASE_BODY_ADDITION="${DATE_SUBHEADING}$1"
|
||||||
|
|
||||||
# Put new changelog entries into release-body, add link to changelog
|
# Put new changelog entries into release-body, add link to changelog
|
||||||
echo -e "${RELEASE_BODY_ADDITION}\n\nsee <a href='${GIT_REPO_URL}/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details" > .github/release-body.md
|
echo -e "${RELEASE_BODY_ADDITION}\n\nsee <a href='${GIT_REPO_URL}/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details" >.github/release-body.md
|
||||||
|
|
||||||
# Add subheading with release version and date of release
|
# Add subheading with release version and date of release
|
||||||
echo -e "# <a href='${GIT_REPO_URL}/releases/tag/${NEW_TAG_WITH_V}'>${NEW_TAG_WITH_V}</a>\n${DATE_SUBHEADING}${CHANGELOG_ADDITION}$(cat CHANGELOG.md)" > CHANGELOG.md
|
echo -e "# <a href='${GIT_REPO_URL}/releases/tag/${NEW_TAG_WITH_V}'>${NEW_TAG_WITH_V}</a>\n${DATE_SUBHEADING}${CHANGELOG_ADDITION}$(cat CHANGELOG.md)" >CHANGELOG.md
|
||||||
|
|
||||||
# Update changelog to add links to commits [hex:8](url_with_full_commit)
|
# Update changelog to add links to commits [hex:8](url_with_full_commit)
|
||||||
# "[aaaaaaaaaabbbbbbbbbbccccccccccddddddddd]" -> "[aaaaaaaa](https:/www.../commit/aaaaaaaaaabbbbbbbbbbccccccccccddddddddd)"
|
# "[aaaaaaaaaabbbbbbbbbbccccccccccddddddddd]" -> "[aaaaaaaa](https:/www.../commit/aaaaaaaaaabbbbbbbbbbccccccccccddddddddd)"
|
||||||
@@ -111,20 +107,19 @@ update_release_body_and_changelog () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# update version in cargo.toml, to match selected current version
|
# update version in cargo.toml, to match selected current version
|
||||||
update_version_number_in_files () {
|
update_version_number_in_files() {
|
||||||
sed -i "s|^version = .*|version = \"${MAJOR}.${MINOR}.${PATCH}\"|" Cargo.toml
|
sed -i "s|^version = .*|version = \"${MAJOR}.${MINOR}.${PATCH}\"|" Cargo.toml
|
||||||
}
|
}
|
||||||
|
|
||||||
# Work out the current version, based on git tags
|
# Work out the current version, based on git tags
|
||||||
# create new semver version based on user input
|
# create new semver version based on user input
|
||||||
# Set MAJOR MINOR PATCH
|
# Set MAJOR MINOR PATCH
|
||||||
check_tag () {
|
check_tag() {
|
||||||
LATEST_TAG=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
LATEST_TAG=$(git describe --tags "$(git rev-list --tags --max-count=1)")
|
||||||
echo -e "\nCurrent tag: ${PURPLE}${LATEST_TAG}${RESET}\n"
|
echo -e "\nCurrent tag: ${PURPLE}${LATEST_TAG}${RESET}\n"
|
||||||
echo -e "${YELLOW}Choose new tag version:${RESET}\n"
|
echo -e "${YELLOW}Choose new tag version:${RESET}\n"
|
||||||
if [[ $LATEST_TAG =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$ ]]
|
if [[ $LATEST_TAG =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$ ]]; then
|
||||||
then
|
IFS="." read -r MAJOR MINOR PATCH <<<"${LATEST_TAG:1}"
|
||||||
IFS="." read -r MAJOR MINOR PATCH <<< "${LATEST_TAG:1}"
|
|
||||||
else
|
else
|
||||||
MAJOR="0"
|
MAJOR="0"
|
||||||
MINOR="0"
|
MINOR="0"
|
||||||
@@ -134,51 +129,53 @@ check_tag () {
|
|||||||
OP_MINOR="minor___v$(update_minor)"
|
OP_MINOR="minor___v$(update_minor)"
|
||||||
OP_PATCH="patch___v$(update_patch)"
|
OP_PATCH="patch___v$(update_patch)"
|
||||||
OPTIONS=("$OP_MAJOR" "$OP_MINOR" "$OP_PATCH")
|
OPTIONS=("$OP_MAJOR" "$OP_MINOR" "$OP_PATCH")
|
||||||
select choice in "${OPTIONS[@]}"
|
select choice in "${OPTIONS[@]}"; do
|
||||||
do
|
|
||||||
case $choice in
|
case $choice in
|
||||||
"$OP_MAJOR" )
|
"$OP_MAJOR")
|
||||||
MAJOR=$((MAJOR + 1))
|
MAJOR=$((MAJOR + 1))
|
||||||
MINOR=0
|
MINOR=0
|
||||||
PATCH=0
|
PATCH=0
|
||||||
break;;
|
break
|
||||||
"$OP_MINOR")
|
;;
|
||||||
MINOR=$((MINOR + 1))
|
"$OP_MINOR")
|
||||||
PATCH=0
|
MINOR=$((MINOR + 1))
|
||||||
break;;
|
PATCH=0
|
||||||
"$OP_PATCH")
|
break
|
||||||
PATCH=$((PATCH + 1))
|
;;
|
||||||
break;;
|
"$OP_PATCH")
|
||||||
*)
|
PATCH=$((PATCH + 1))
|
||||||
error_close "invalid option $REPLY"
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error_close "invalid option $REPLY"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# ask continue, or quit
|
# ask continue, or quit
|
||||||
ask_continue () {
|
ask_continue() {
|
||||||
ask_yn "continue"
|
ask_yn "continue"
|
||||||
if [[ ! "$(user_input)" =~ ^y$ ]]
|
if [[ ! "$(user_input)" =~ ^y$ ]]; then
|
||||||
then
|
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# run all tests
|
# run all tests
|
||||||
cargo_test () {
|
cargo_test() {
|
||||||
cargo test -- --test-threads=1
|
cargo test -- --test-threads=1
|
||||||
ask_continue
|
ask_continue
|
||||||
}
|
}
|
||||||
|
|
||||||
# Simulate publishing to crates.io
|
# Simulate publishing to crates.io
|
||||||
cargo_publish () {
|
cargo_publish() {
|
||||||
cargo publish --dry-run
|
cargo publish --dry-run
|
||||||
ask_continue
|
ask_continue
|
||||||
}
|
}
|
||||||
|
|
||||||
# Build all releases that GitHub workflow would
|
# Build all releases that GitHub workflow would
|
||||||
# This will download GB's of docker images
|
# This will download GB's of docker images
|
||||||
cargo_build () {
|
cargo_build() {
|
||||||
cargo install cross
|
cargo install cross
|
||||||
cargo_clean
|
cargo_clean
|
||||||
echo -e "${YELLOW}cross build --target x86_64-unknown-linux-musl --release${RESET}"
|
echo -e "${YELLOW}cross build --target x86_64-unknown-linux-musl --release${RESET}"
|
||||||
@@ -199,9 +196,8 @@ cargo_build () {
|
|||||||
cargo_clean
|
cargo_clean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# $1 text to colourise
|
# $1 text to colourise
|
||||||
release_continue () {
|
release_continue() {
|
||||||
echo -e "\n${PURPLE}$1${RESET}"
|
echo -e "\n${PURPLE}$1${RESET}"
|
||||||
ask_continue
|
ask_continue
|
||||||
}
|
}
|
||||||
@@ -212,14 +208,26 @@ cargo_clean() {
|
|||||||
cargo clean
|
cargo clean
|
||||||
}
|
}
|
||||||
# Check repository for typos
|
# Check repository for typos
|
||||||
check_typos () {
|
check_typos() {
|
||||||
echo -e "\n${PURPLE}check typos${RESET}"
|
echo -e "\n${PURPLE}check typos${RESET}"
|
||||||
typos
|
typos
|
||||||
ask_continue
|
ask_continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Make sure the unused lint isn't used
|
||||||
|
check_allow_unused() {
|
||||||
|
matches_any=$(find . -type d \( -name .git -o -name target \) -prune -o -type f -exec grep -lE '^#!\[allow\(unused\)\]$' {} +)
|
||||||
|
matches_cargo=$(grep "^unused = \"allow\"" ./Cargo.toml)
|
||||||
|
if [ -n "$matches_any" ]; then
|
||||||
|
error_close "\"#[allow(unused)]\" in ${matches_any}"
|
||||||
|
elif [ -n "$matches_cargo" ]; then
|
||||||
|
error_close "\"unused = \"allow\"\" in Cargo.toml"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Full flow to create a new release
|
# Full flow to create a new release
|
||||||
release_flow() {
|
release_flow() {
|
||||||
|
check_allow_unused
|
||||||
check_typos
|
check_typos
|
||||||
|
|
||||||
check_git
|
check_git
|
||||||
@@ -231,20 +239,20 @@ release_flow() {
|
|||||||
|
|
||||||
cd "${CWD}" || error_close "Can't find ${CWD}"
|
cd "${CWD}" || error_close "Can't find ${CWD}"
|
||||||
check_tag
|
check_tag
|
||||||
|
|
||||||
NEW_TAG_WITH_V="v${MAJOR}.${MINOR}.${PATCH}"
|
NEW_TAG_WITH_V="v${MAJOR}.${MINOR}.${PATCH}"
|
||||||
printf "\nnew tag chosen: %s\n\n" "${NEW_TAG_WITH_V}"
|
printf "\nnew tag chosen: %s\n\n" "${NEW_TAG_WITH_V}"
|
||||||
|
|
||||||
RELEASE_BRANCH=release-$NEW_TAG_WITH_V
|
RELEASE_BRANCH=release-$NEW_TAG_WITH_V
|
||||||
echo -e
|
echo -e
|
||||||
ask_changelog_update
|
ask_changelog_update
|
||||||
|
|
||||||
release_continue "checkout ${RELEASE_BRANCH}"
|
release_continue "checkout ${RELEASE_BRANCH}"
|
||||||
git checkout -b "$RELEASE_BRANCH"
|
git checkout -b "$RELEASE_BRANCH"
|
||||||
|
|
||||||
release_continue "update_version_number_in_files"
|
release_continue "update_version_number_in_files"
|
||||||
update_version_number_in_files
|
update_version_number_in_files
|
||||||
|
|
||||||
echo -e "\ncargo fmt"
|
echo -e "\ncargo fmt"
|
||||||
cargo fmt
|
cargo fmt
|
||||||
echo -e "\n${PURPLE}cargo check${RESET}\n"
|
echo -e "\n${PURPLE}cargo check${RESET}\n"
|
||||||
@@ -283,7 +291,6 @@ release_flow() {
|
|||||||
git branch -d "$RELEASE_BRANCH"
|
git branch -d "$RELEASE_BRANCH"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
cmd=(dialog --backtitle "Choose option" --radiolist "choose" 14 80 16)
|
cmd=(dialog --backtitle "Choose option" --radiolist "choose" 14 80 16)
|
||||||
options=(
|
options=(
|
||||||
@@ -297,24 +304,27 @@ main() {
|
|||||||
if [ $exitStatus -ne 0 ]; then
|
if [ $exitStatus -ne 0 ]; then
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
for choice in $choices
|
for choice in $choices; do
|
||||||
do
|
|
||||||
case $choice in
|
case $choice in
|
||||||
0)
|
0)
|
||||||
exit;;
|
exit
|
||||||
1)
|
;;
|
||||||
cargo_test
|
1)
|
||||||
main
|
cargo_test
|
||||||
break;;
|
main
|
||||||
2)
|
break
|
||||||
release_flow
|
;;
|
||||||
break;;
|
2)
|
||||||
3)
|
release_flow
|
||||||
cargo_build
|
break
|
||||||
main
|
;;
|
||||||
break;;
|
3)
|
||||||
|
cargo_build
|
||||||
|
main
|
||||||
|
break
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
main
|
main
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ services:
|
|||||||
ipc: private
|
ipc: private
|
||||||
restart: always
|
restart: always
|
||||||
shm_size: 256MB
|
shm_size: 256MB
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:4040:4040"
|
||||||
networks:
|
networks:
|
||||||
- oxker-example-net
|
- oxker-example-net
|
||||||
deploy:
|
deploy:
|
||||||
|
|||||||
+166
-16
@@ -4,6 +4,7 @@ use std::{
|
|||||||
fmt,
|
fmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use bollard::service::Port;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
style::Color,
|
style::Color,
|
||||||
widgets::{ListItem, ListState},
|
widgets::{ListItem, ListState},
|
||||||
@@ -49,7 +50,7 @@ impl PartialOrd for ContainerId {
|
|||||||
|
|
||||||
/// TODO - use string_wrapper for ContainerId?
|
/// TODO - use string_wrapper for ContainerId?
|
||||||
/// ContainerName and ContainerImage are simple structs, used so can implement custom fmt functions to them
|
/// ContainerName and ContainerImage are simple structs, used so can implement custom fmt functions to them
|
||||||
macro_rules! string_wrapper {
|
macro_rules! unit_struct {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct $name(String);
|
pub struct $name(String);
|
||||||
@@ -60,6 +61,13 @@ macro_rules! string_wrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl From<&str> for $name {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
Self(value.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl$name {
|
impl$name {
|
||||||
pub fn get(&self) -> &str {
|
pub fn get(&self) -> &str {
|
||||||
self.0.as_str()
|
self.0.as_str()
|
||||||
@@ -90,10 +98,51 @@ macro_rules! string_wrapper {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
string_wrapper!(ContainerName);
|
unit_struct!(ContainerName);
|
||||||
string_wrapper!(ContainerImage);
|
unit_struct!(ContainerImage);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ContainerPorts {
|
||||||
|
pub ip: Option<String>,
|
||||||
|
pub private: u16,
|
||||||
|
pub public: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Port> for ContainerPorts {
|
||||||
|
fn from(value: &Port) -> Self {
|
||||||
|
Self {
|
||||||
|
ip: value.ip.clone(),
|
||||||
|
private: value.private_port,
|
||||||
|
public: value.public_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContainerPorts {
|
||||||
|
pub fn len_ip(&self) -> usize {
|
||||||
|
self.ip.as_ref().unwrap_or(&String::new()).chars().count()
|
||||||
|
}
|
||||||
|
pub fn len_private(&self) -> usize {
|
||||||
|
format!("{}", self.private).chars().count()
|
||||||
|
}
|
||||||
|
pub fn len_public(&self) -> usize {
|
||||||
|
format!("{}", self.public.unwrap_or_default())
|
||||||
|
.chars()
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(&self) -> (String, String, String) {
|
||||||
|
(
|
||||||
|
self.ip
|
||||||
|
.as_ref()
|
||||||
|
.map_or(String::new(), std::borrow::ToOwned::to_owned),
|
||||||
|
format!("{}", self.private),
|
||||||
|
self.public.map_or(String::new(), |s| s.to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct StatefulList<T> {
|
pub struct StatefulList<T> {
|
||||||
pub state: ListState,
|
pub state: ListState,
|
||||||
pub items: Vec<T>,
|
pub items: Vec<T>,
|
||||||
@@ -154,7 +203,7 @@ impl<T> StatefulList<T> {
|
|||||||
.state
|
.state
|
||||||
.selected()
|
.selected()
|
||||||
.map_or(0, |value| if len > 0 { value + 1 } else { value });
|
.map_or(0, |value| if len > 0 { value + 1 } else { value });
|
||||||
format!("{c}/{}", self.items.len())
|
format!(" {c}/{}", self.items.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,13 +283,13 @@ impl fmt::Display for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Items for the container control list
|
/// Items for the container control list
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum DockerControls {
|
pub enum DockerControls {
|
||||||
Pause,
|
Pause,
|
||||||
Restart,
|
Restart,
|
||||||
Start,
|
Start,
|
||||||
Stop,
|
Stop,
|
||||||
Unpause,
|
Resume,
|
||||||
Delete,
|
Delete,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +301,7 @@ impl DockerControls {
|
|||||||
Self::Start => Color::Green,
|
Self::Start => Color::Green,
|
||||||
Self::Stop => Color::Red,
|
Self::Stop => Color::Red,
|
||||||
Self::Delete => Color::Gray,
|
Self::Delete => Color::Gray,
|
||||||
Self::Unpause => Color::Blue,
|
Self::Resume => Color::Blue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +309,7 @@ impl DockerControls {
|
|||||||
pub fn gen_vec(state: State) -> Vec<Self> {
|
pub fn gen_vec(state: State) -> Vec<Self> {
|
||||||
match state {
|
match state {
|
||||||
State::Dead | State::Exited => vec![Self::Start, Self::Restart, Self::Delete],
|
State::Dead | State::Exited => vec![Self::Start, Self::Restart, Self::Delete],
|
||||||
State::Paused => vec![Self::Unpause, Self::Stop, Self::Delete],
|
State::Paused => vec![Self::Resume, Self::Stop, Self::Delete],
|
||||||
State::Restarting => vec![Self::Stop, Self::Delete],
|
State::Restarting => vec![Self::Stop, Self::Delete],
|
||||||
State::Running => vec![Self::Pause, Self::Restart, Self::Stop, Self::Delete],
|
State::Running => vec![Self::Pause, Self::Restart, Self::Stop, Self::Delete],
|
||||||
_ => vec![Self::Delete],
|
_ => vec![Self::Delete],
|
||||||
@@ -276,7 +325,7 @@ impl fmt::Display for DockerControls {
|
|||||||
Self::Restart => "restart",
|
Self::Restart => "restart",
|
||||||
Self::Start => "start",
|
Self::Start => "start",
|
||||||
Self::Stop => "stop",
|
Self::Stop => "stop",
|
||||||
Self::Unpause => "resume",
|
Self::Resume => "resume",
|
||||||
};
|
};
|
||||||
write!(f, "{disp}")
|
write!(f, "{disp}")
|
||||||
}
|
}
|
||||||
@@ -416,7 +465,7 @@ impl fmt::Display for LogsTz {
|
|||||||
/// Store the logs alongside a HashSet, each log *should* generate a unique timestamp,
|
/// Store the logs alongside a HashSet, each log *should* generate a unique timestamp,
|
||||||
/// so if we store the timestamp separately in a HashSet, we can then check if we should insert a log line into the
|
/// so if we store the timestamp separately in a HashSet, we can then check if we should insert a log line into the
|
||||||
/// stateful list dependent on whethere the timestamp is in the HashSet or not
|
/// stateful list dependent on whethere the timestamp is in the HashSet or not
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Logs {
|
pub struct Logs {
|
||||||
logs: StatefulList<ListItem<'static>>,
|
logs: StatefulList<ListItem<'static>>,
|
||||||
tz: HashSet<LogsTz>,
|
tz: HashSet<LogsTz>,
|
||||||
@@ -475,23 +524,25 @@ impl Logs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Info for each container
|
/// Info for each container
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ContainerItem {
|
pub struct ContainerItem {
|
||||||
pub created: u64,
|
|
||||||
pub cpu_stats: VecDeque<CpuStats>,
|
pub cpu_stats: VecDeque<CpuStats>,
|
||||||
|
pub created: u64,
|
||||||
pub docker_controls: StatefulList<DockerControls>,
|
pub docker_controls: StatefulList<DockerControls>,
|
||||||
pub id: ContainerId,
|
pub id: ContainerId,
|
||||||
pub image: ContainerImage,
|
pub image: ContainerImage,
|
||||||
|
pub is_oxker: bool,
|
||||||
pub last_updated: u64,
|
pub last_updated: u64,
|
||||||
pub logs: Logs,
|
pub logs: Logs,
|
||||||
pub mem_limit: ByteStats,
|
pub mem_limit: ByteStats,
|
||||||
pub mem_stats: VecDeque<ByteStats>,
|
pub mem_stats: VecDeque<ByteStats>,
|
||||||
pub name: ContainerName,
|
pub name: ContainerName,
|
||||||
|
// todo remove option, can be empty vec
|
||||||
|
pub ports: Vec<ContainerPorts>,
|
||||||
pub rx: ByteStats,
|
pub rx: ByteStats,
|
||||||
pub state: State,
|
pub state: State,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
pub tx: ByteStats,
|
pub tx: ByteStats,
|
||||||
pub is_oxker: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Basic display information, for when running in debug mode
|
/// Basic display information, for when running in debug mode
|
||||||
@@ -509,6 +560,7 @@ impl fmt::Display for ContainerItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerItem {
|
impl ContainerItem {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
/// Create a new container item
|
/// Create a new container item
|
||||||
pub fn new(
|
pub fn new(
|
||||||
created: u64,
|
created: u64,
|
||||||
@@ -516,14 +568,16 @@ impl ContainerItem {
|
|||||||
image: String,
|
image: String,
|
||||||
is_oxker: bool,
|
is_oxker: bool,
|
||||||
name: String,
|
name: String,
|
||||||
|
ports: Vec<ContainerPorts>,
|
||||||
state: State,
|
state: State,
|
||||||
status: String,
|
status: String,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut docker_controls = StatefulList::new(DockerControls::gen_vec(state));
|
let mut docker_controls = StatefulList::new(DockerControls::gen_vec(state));
|
||||||
docker_controls.start();
|
docker_controls.start();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
created,
|
|
||||||
cpu_stats: VecDeque::with_capacity(60),
|
cpu_stats: VecDeque::with_capacity(60),
|
||||||
|
created,
|
||||||
docker_controls,
|
docker_controls,
|
||||||
id,
|
id,
|
||||||
image: image.into(),
|
image: image.into(),
|
||||||
@@ -533,6 +587,7 @@ impl ContainerItem {
|
|||||||
mem_limit: ByteStats::default(),
|
mem_limit: ByteStats::default(),
|
||||||
mem_stats: VecDeque::with_capacity(60),
|
mem_stats: VecDeque::with_capacity(60),
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
|
ports,
|
||||||
rx: ByteStats::default(),
|
rx: ByteStats::default(),
|
||||||
state,
|
state,
|
||||||
status,
|
status,
|
||||||
@@ -594,7 +649,7 @@ impl ContainerItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Container information panel headings + widths, for nice pretty formatting
|
/// Container information panel headings + widths, for nice pretty formatting
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Columns {
|
pub struct Columns {
|
||||||
pub name: (Header, u8),
|
pub name: (Header, u8),
|
||||||
pub state: (Header, u8),
|
pub state: (Header, u8),
|
||||||
@@ -623,3 +678,98 @@ impl Columns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use ratatui::widgets::ListItem;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
app_data::{ContainerImage, Logs},
|
||||||
|
ui::log_sanitizer,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{ByteStats, ContainerName, CpuStats, LogsTz};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Display CpuStats as a string
|
||||||
|
fn test_container_state_cpustats_to_string() {
|
||||||
|
let test = |f: f64, s: &str| {
|
||||||
|
assert_eq!(CpuStats::new(f).to_string(), s);
|
||||||
|
};
|
||||||
|
|
||||||
|
test(0.0, "00.00%");
|
||||||
|
test(1.5, "01.50%");
|
||||||
|
test(15.15, "15.15%");
|
||||||
|
test(150.15, "150.15%");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Display bytestats as a string, convert into correct data unit (Kb, MB, GB)
|
||||||
|
fn test_container_state_bytestats_to_string() {
|
||||||
|
let test = |u: u64, s: &str| {
|
||||||
|
assert_eq!(ByteStats::new(u).to_string(), s);
|
||||||
|
};
|
||||||
|
|
||||||
|
test(0, "0.00 kB");
|
||||||
|
test(150, "0.15 kB");
|
||||||
|
test(1500, "1.50 kB");
|
||||||
|
test(150_000, "150.00 kB");
|
||||||
|
test(1_500_000, "1.50 MB");
|
||||||
|
test(15_000_000, "15.00 MB");
|
||||||
|
test(150_000_000, "150.00 MB");
|
||||||
|
test(1_500_000_000, "1.50 GB");
|
||||||
|
test(15_000_000_000, "15.00 GB");
|
||||||
|
test(150_000_000_000, "150.00 GB");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// ContainerName as string truncated correctly
|
||||||
|
fn test_container_state_container_name_to_string() {
|
||||||
|
let result = ContainerName::from("name_01");
|
||||||
|
assert_eq!(result.to_string(), "name_01");
|
||||||
|
|
||||||
|
let result = ContainerName::from("name_01_name_01_name_01_name_01_");
|
||||||
|
assert_eq!(result.to_string(), "name_01_name_01_name_01_name_…");
|
||||||
|
|
||||||
|
let result = result.get();
|
||||||
|
assert_eq!(result, "name_01_name_01_name_01_name_01_");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// ContainerImage as string truncated correctly
|
||||||
|
fn test_container_state_container_image() {
|
||||||
|
let result = ContainerImage::from("name_01");
|
||||||
|
assert_eq!(result.to_string(), "name_01");
|
||||||
|
|
||||||
|
let result = ContainerImage::from("name_01_name_01_name_01_name_01_");
|
||||||
|
assert_eq!(result.to_string(), "name_01_name_01_name_01_name_…");
|
||||||
|
|
||||||
|
let result = result.get();
|
||||||
|
assert_eq!(result, "name_01_name_01_name_01_name_01_");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Logs can only contain 1 entry per LogzTz
|
||||||
|
fn test_container_state_logz() {
|
||||||
|
let input = "2023-01-14T19:13:30.783138328Z Lorem ipsum dolor sit amet";
|
||||||
|
let tz = LogsTz::from(input);
|
||||||
|
let mut logs = Logs::default();
|
||||||
|
let line = log_sanitizer::remove_ansi(input);
|
||||||
|
|
||||||
|
logs.insert(ListItem::new(line.clone()), tz.clone());
|
||||||
|
logs.insert(ListItem::new(line.clone()), tz.clone());
|
||||||
|
logs.insert(ListItem::new(line), tz);
|
||||||
|
|
||||||
|
assert_eq!(logs.logs.items.len(), 1);
|
||||||
|
|
||||||
|
let input = "2023-01-15T19:13:30.783138328Z Lorem ipsum dolor sit amet";
|
||||||
|
let tz = LogsTz::from(input);
|
||||||
|
let line = log_sanitizer::remove_ansi(input);
|
||||||
|
|
||||||
|
logs.insert(ListItem::new(line.clone()), tz.clone());
|
||||||
|
logs.insert(ListItem::new(line.clone()), tz.clone());
|
||||||
|
logs.insert(ListItem::new(line), tz);
|
||||||
|
|
||||||
|
assert_eq!(logs.logs.items.len(), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1326
-151
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,6 @@ pub enum DockerMessage {
|
|||||||
Restart(ContainerId),
|
Restart(ContainerId),
|
||||||
Start(ContainerId),
|
Start(ContainerId),
|
||||||
Stop(ContainerId),
|
Stop(ContainerId),
|
||||||
Unpause(ContainerId),
|
Resume(ContainerId),
|
||||||
Update,
|
Update,
|
||||||
}
|
}
|
||||||
|
|||||||
+148
-6
@@ -71,6 +71,7 @@ pub struct DockerData {
|
|||||||
impl DockerData {
|
impl DockerData {
|
||||||
/// Use docker stats to calculate current cpu usage
|
/// Use docker stats to calculate current cpu usage
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
// FIX: this can overflow
|
||||||
fn calculate_usage(stats: &Stats) -> f64 {
|
fn calculate_usage(stats: &Stats) -> f64 {
|
||||||
let mut cpu_percentage = 0.0;
|
let mut cpu_percentage = 0.0;
|
||||||
let previous_cpu = stats.precpu_stats.cpu_usage.total_usage;
|
let previous_cpu = stats.precpu_stats.cpu_usage.total_usage;
|
||||||
@@ -150,7 +151,7 @@ impl DockerData {
|
|||||||
|
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.update_stats(&id, cpu_stats, mem_stat, mem_limit, rx, tx);
|
.update_stats_by_id(&id, cpu_stats, mem_stat, mem_limit, rx, tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spawns.lock().remove(&spawn_id);
|
spawns.lock().remove(&spawn_id);
|
||||||
@@ -162,7 +163,6 @@ impl DockerData {
|
|||||||
/// Update all stats, spawn each container into own tokio::spawn thread
|
/// Update all stats, spawn each container into own tokio::spawn thread
|
||||||
fn update_all_container_stats(&mut self, all_ids: &[(State, ContainerId)]) {
|
fn update_all_container_stats(&mut self, all_ids: &[(State, ContainerId)]) {
|
||||||
for (state, id) in all_ids {
|
for (state, id) in all_ids {
|
||||||
// let init = self.init.as_ref().map_or_else(|| None, |x| Some((Arc::clone(x), all_ids.len())));
|
|
||||||
let docker = Arc::clone(&self.docker);
|
let docker = Arc::clone(&self.docker);
|
||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
let spawns = Arc::clone(&self.spawns);
|
let spawns = Arc::clone(&self.spawns);
|
||||||
@@ -387,11 +387,11 @@ impl DockerData {
|
|||||||
});
|
});
|
||||||
self.update_everything().await;
|
self.update_everything().await;
|
||||||
}
|
}
|
||||||
DockerMessage::Unpause(id) => {
|
DockerMessage::Resume(id) => {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let handle = GuiState::start_loading_animation(&gui_state, uuid);
|
let handle = GuiState::start_loading_animation(&gui_state, uuid);
|
||||||
if docker.unpause_container(id.get()).await.is_err() {
|
if docker.unpause_container(id.get()).await.is_err() {
|
||||||
Self::set_error(&app_data, DockerControls::Unpause, &gui_state);
|
Self::set_error(&app_data, DockerControls::Resume, &gui_state);
|
||||||
}
|
}
|
||||||
gui_state.lock().stop_loading_animation(&handle, uuid);
|
gui_state.lock().stop_loading_animation(&handle, uuid);
|
||||||
});
|
});
|
||||||
@@ -436,7 +436,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Send an update message every x ms, where x is the args.docker_interval
|
/// Send an update message every x ms, where x is the args.docker_interval
|
||||||
fn croner(args: &CliArgs, docker_tx: Sender<DockerMessage>) {
|
fn scheduler(args: &CliArgs, docker_tx: Sender<DockerMessage>) {
|
||||||
let update_duration = std::time::Duration::from_millis(u64::from(args.docker_interval));
|
let update_duration = std::time::Duration::from_millis(u64::from(args.docker_interval));
|
||||||
let mut now = std::time::Instant::now();
|
let mut now = std::time::Instant::now();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
@@ -472,10 +472,152 @@ impl DockerData {
|
|||||||
spawns: Arc::new(Mutex::new(HashMap::new())),
|
spawns: Arc::new(Mutex::new(HashMap::new())),
|
||||||
};
|
};
|
||||||
inner.initialise_container_data().await;
|
inner.initialise_container_data().await;
|
||||||
Self::croner(&args, docker_tx);
|
Self::scheduler(&args, docker_tx);
|
||||||
inner.message_handler().await;
|
inner.message_handler().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tests, use redis-test container, check logs exists, and selector of logs, and that it increases, and matches end, when you run restart on the docker containers
|
// tests, use redis-test container, check logs exists, and selector of logs, and that it increases, and matches end, when you run restart on the docker containers
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use bollard::container::{
|
||||||
|
BlkioStats, CPUStats, CPUUsage, MemoryStats, PidsStats, StorageStats, ThrottlingData,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
fn gen_stats(x: u64, y: u64) -> Stats {
|
||||||
|
Stats {
|
||||||
|
read: String::new(),
|
||||||
|
preread: String::new(),
|
||||||
|
num_procs: 0,
|
||||||
|
pids_stats: PidsStats {
|
||||||
|
current: None,
|
||||||
|
limit: None,
|
||||||
|
},
|
||||||
|
network: None,
|
||||||
|
networks: None,
|
||||||
|
memory_stats: MemoryStats {
|
||||||
|
stats: None,
|
||||||
|
max_usage: None,
|
||||||
|
usage: None,
|
||||||
|
failcnt: None,
|
||||||
|
limit: None,
|
||||||
|
commit: None,
|
||||||
|
commit_peak: None,
|
||||||
|
commitbytes: None,
|
||||||
|
commitpeakbytes: None,
|
||||||
|
privateworkingset: None,
|
||||||
|
},
|
||||||
|
blkio_stats: BlkioStats {
|
||||||
|
io_service_bytes_recursive: None,
|
||||||
|
io_serviced_recursive: None,
|
||||||
|
io_queue_recursive: None,
|
||||||
|
io_service_time_recursive: None,
|
||||||
|
io_wait_time_recursive: None,
|
||||||
|
io_merged_recursive: None,
|
||||||
|
io_time_recursive: None,
|
||||||
|
sectors_recursive: None,
|
||||||
|
},
|
||||||
|
cpu_stats: CPUStats {
|
||||||
|
cpu_usage: CPUUsage {
|
||||||
|
percpu_usage: Some(vec![
|
||||||
|
291_593_800,
|
||||||
|
182_192_900,
|
||||||
|
195_048_700,
|
||||||
|
23_032_300,
|
||||||
|
132_928_700,
|
||||||
|
235_555_600,
|
||||||
|
120_225_700,
|
||||||
|
175_752_000,
|
||||||
|
213_060_300,
|
||||||
|
95_321_600,
|
||||||
|
226_821_000,
|
||||||
|
0,
|
||||||
|
109_151_300,
|
||||||
|
0,
|
||||||
|
86_240_200,
|
||||||
|
1_884_400,
|
||||||
|
59_077_300,
|
||||||
|
23_224_900,
|
||||||
|
95_386_300,
|
||||||
|
144_987_400,
|
||||||
|
]),
|
||||||
|
total_usage: 250_000_000,
|
||||||
|
usage_in_usermode: 1_020_000_000,
|
||||||
|
usage_in_kernelmode: 1_030_000_000,
|
||||||
|
},
|
||||||
|
system_cpu_usage: Some(x),
|
||||||
|
online_cpus: Some(1),
|
||||||
|
throttling_data: ThrottlingData {
|
||||||
|
periods: 0,
|
||||||
|
throttled_periods: 0,
|
||||||
|
throttled_time: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
precpu_stats: CPUStats {
|
||||||
|
cpu_usage: CPUUsage {
|
||||||
|
percpu_usage: Some(vec![
|
||||||
|
291_593_800,
|
||||||
|
182_192_900,
|
||||||
|
195_048_700,
|
||||||
|
23_032_300,
|
||||||
|
132_928_700,
|
||||||
|
235_555_600,
|
||||||
|
120_225_700,
|
||||||
|
175_752_000,
|
||||||
|
213_060_300,
|
||||||
|
95_321_600,
|
||||||
|
226_821_000,
|
||||||
|
0,
|
||||||
|
109_151_300,
|
||||||
|
0,
|
||||||
|
86_240_200,
|
||||||
|
1_884_400,
|
||||||
|
59_077_300,
|
||||||
|
23_224_900,
|
||||||
|
93_831_100,
|
||||||
|
144_987_400,
|
||||||
|
]),
|
||||||
|
total_usage: 200_000_000,
|
||||||
|
usage_in_usermode: 1_020_000_000,
|
||||||
|
usage_in_kernelmode: 1_020_000_000,
|
||||||
|
},
|
||||||
|
system_cpu_usage: Some(y),
|
||||||
|
online_cpus: Some(1),
|
||||||
|
throttling_data: ThrottlingData {
|
||||||
|
periods: 0,
|
||||||
|
throttled_periods: 0,
|
||||||
|
throttled_time: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storage_stats: StorageStats {
|
||||||
|
read_count_normalized: None,
|
||||||
|
read_size_bytes: None,
|
||||||
|
write_count_normalized: None,
|
||||||
|
write_size_bytes: None,
|
||||||
|
},
|
||||||
|
name: "/container_1".to_owned(),
|
||||||
|
id: "1".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[allow(clippy::float_cmp)]
|
||||||
|
/// Test the stats calculator, had to cheat here to get round input/outputs
|
||||||
|
fn test_calculate_usage_no_previous_cpu() {
|
||||||
|
let stats = gen_stats(1_000_000_000, 900_000_000);
|
||||||
|
let result = DockerData::calculate_usage(&stats);
|
||||||
|
assert_eq!(result, 50.0);
|
||||||
|
|
||||||
|
let stats = gen_stats(1_000_000_000, 800_000_000);
|
||||||
|
let result = DockerData::calculate_usage(&stats);
|
||||||
|
assert_eq!(result, 25.0);
|
||||||
|
|
||||||
|
let stats = gen_stats(1_000_000_000, 750_000_000);
|
||||||
|
let result = DockerData::calculate_usage(&stats);
|
||||||
|
assert_eq!(result, 20.00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -268,11 +268,11 @@ impl InputHandler {
|
|||||||
// This isn't great, just means you can't send docker commands before full initialization of the program
|
// This isn't great, just means you can't send docker commands before full initialization of the program
|
||||||
let panel = self.gui_state.lock().get_selected_panel();
|
let panel = self.gui_state.lock().get_selected_panel();
|
||||||
if panel == SelectablePanel::Commands {
|
if panel == SelectablePanel::Commands {
|
||||||
let option_command = self.app_data.lock().selected_docker_command();
|
let option_command = self.app_data.lock().selected_docker_controls();
|
||||||
|
|
||||||
if let Some(command) = option_command {
|
if let Some(command) = option_command {
|
||||||
// Poor way of disallowing commands to be sent to a containerised okxer
|
// Poor way of disallowing commands to be sent to a containerised okxer
|
||||||
if self.app_data.lock().is_oxker() {
|
if self.app_data.lock().is_oxker_in_container() {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let option_id = self.app_data.lock().get_selected_container_id();
|
let option_id = self.app_data.lock().get_selected_container_id();
|
||||||
@@ -286,8 +286,8 @@ impl InputHandler {
|
|||||||
DockerControls::Pause => {
|
DockerControls::Pause => {
|
||||||
self.docker_tx.send(DockerMessage::Pause(id)).await.ok()
|
self.docker_tx.send(DockerMessage::Pause(id)).await.ok()
|
||||||
}
|
}
|
||||||
DockerControls::Unpause => {
|
DockerControls::Resume => {
|
||||||
self.docker_tx.send(DockerMessage::Unpause(id)).await.ok()
|
self.docker_tx.send(DockerMessage::Resume(id)).await.ok()
|
||||||
}
|
}
|
||||||
DockerControls::Start => {
|
DockerControls::Start => {
|
||||||
self.docker_tx.send(DockerMessage::Start(id)).await.ok()
|
self.docker_tx.send(DockerMessage::Start(id)).await.ok()
|
||||||
@@ -337,7 +337,7 @@ impl InputHandler {
|
|||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => locked_data.containers_start(),
|
SelectablePanel::Containers => locked_data.containers_start(),
|
||||||
SelectablePanel::Logs => locked_data.log_start(),
|
SelectablePanel::Logs => locked_data.log_start(),
|
||||||
SelectablePanel::Commands => locked_data.docker_command_start(),
|
SelectablePanel::Commands => locked_data.docker_controls_start(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ impl InputHandler {
|
|||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => locked_data.containers_end(),
|
SelectablePanel::Containers => locked_data.containers_end(),
|
||||||
SelectablePanel::Logs => locked_data.log_end(),
|
SelectablePanel::Logs => locked_data.log_end(),
|
||||||
SelectablePanel::Commands => locked_data.docker_command_end(),
|
SelectablePanel::Commands => locked_data.docker_controls_end(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,7 +481,7 @@ impl InputHandler {
|
|||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => locked_data.containers_next(),
|
SelectablePanel::Containers => locked_data.containers_next(),
|
||||||
SelectablePanel::Logs => locked_data.log_next(),
|
SelectablePanel::Logs => locked_data.log_next(),
|
||||||
SelectablePanel::Commands => locked_data.docker_command_next(),
|
SelectablePanel::Commands => locked_data.docker_controls_next(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +492,7 @@ impl InputHandler {
|
|||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => locked_data.containers_previous(),
|
SelectablePanel::Containers => locked_data.containers_previous(),
|
||||||
SelectablePanel::Logs => locked_data.log_previous(),
|
SelectablePanel::Logs => locked_data.log_previous(),
|
||||||
SelectablePanel::Commands => locked_data.docker_command_previous(),
|
SelectablePanel::Commands => locked_data.docker_controls_previous(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+89
@@ -164,3 +164,92 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used, clippy::many_single_char_names, unused)]
|
||||||
|
mod tests {
|
||||||
|
use bollard::service::{ContainerSummary, Port};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
app_data::{AppData, ContainerId, ContainerItem, ContainerPorts, State, StatefulList},
|
||||||
|
parse_args::CliArgs,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const fn gen_args() -> CliArgs {
|
||||||
|
CliArgs {
|
||||||
|
color: false,
|
||||||
|
docker_interval: 1000,
|
||||||
|
gui: true,
|
||||||
|
host: None,
|
||||||
|
in_container: false,
|
||||||
|
save_dir: None,
|
||||||
|
raw: false,
|
||||||
|
show_self: false,
|
||||||
|
timestamp: false,
|
||||||
|
use_cli: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_item(id: &ContainerId, index: usize) -> ContainerItem {
|
||||||
|
ContainerItem::new(
|
||||||
|
u64::try_from(index).unwrap(),
|
||||||
|
id.clone(),
|
||||||
|
format!("image_{index}"),
|
||||||
|
false,
|
||||||
|
format!("container_{index}"),
|
||||||
|
vec![ContainerPorts {
|
||||||
|
ip: None,
|
||||||
|
private: u16::try_from(index).unwrap_or(1) + 8000,
|
||||||
|
public: None,
|
||||||
|
}],
|
||||||
|
State::Running,
|
||||||
|
format!("Up {index} hour"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_appdata(containers: &[ContainerItem]) -> AppData {
|
||||||
|
AppData {
|
||||||
|
containers: StatefulList::new(containers.to_vec()),
|
||||||
|
error: None,
|
||||||
|
sorted_by: None,
|
||||||
|
args: gen_args(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_containers() -> (Vec<ContainerId>, Vec<ContainerItem>) {
|
||||||
|
let ids = (1..=3)
|
||||||
|
.map(|i| ContainerId::from(format!("{i}").as_str()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let containers = ids
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, id)| gen_item(id, index + 1))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
(ids, containers)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_container_summary(index: usize, state: &str) -> ContainerSummary {
|
||||||
|
ContainerSummary {
|
||||||
|
id: Some(format!("{index}")),
|
||||||
|
names: Some(vec![format!("container_{}", index)]),
|
||||||
|
image: Some(format!("image_{index}")),
|
||||||
|
image_id: Some(format!("{index}")),
|
||||||
|
command: None,
|
||||||
|
created: Some(i64::try_from(index).unwrap()),
|
||||||
|
ports: Some(vec![Port {
|
||||||
|
ip: None,
|
||||||
|
private_port: u16::try_from(index).unwrap_or(1) + 8000,
|
||||||
|
public_port: None,
|
||||||
|
typ: None,
|
||||||
|
}]),
|
||||||
|
size_rw: None,
|
||||||
|
size_root_fs: None,
|
||||||
|
labels: None,
|
||||||
|
state: Some(state.to_owned()),
|
||||||
|
status: Some(format!("Up {index} hour")),
|
||||||
|
host_config: None,
|
||||||
|
network_settings: None,
|
||||||
|
mounts: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,3 +72,79 @@ pub mod log_sanitizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use ratatui::{
|
||||||
|
style::{Color, Style},
|
||||||
|
text::{Line, Span},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::log_sanitizer;
|
||||||
|
|
||||||
|
// This spells out "oxker", with each char having a foreground and background colour
|
||||||
|
const INPUT: &str = "\x1b[31;47mo\x1b[32;40mx\x1b[33;41mk\x1b[34;42me\x1b[35;43mr\x1b[0m";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Return test raw, as in show escape codes
|
||||||
|
fn color_match_raw() {
|
||||||
|
let result = log_sanitizer::raw(INPUT);
|
||||||
|
let expected = vec![Line {
|
||||||
|
spans: [Span {
|
||||||
|
content: std::borrow::Cow::Borrowed(
|
||||||
|
"\x1b[31;47mo\x1b[32;40mx\x1b[33;41mk\x1b[34;42me\x1b[35;43mr\x1b[0m",
|
||||||
|
),
|
||||||
|
style: Style::default(),
|
||||||
|
}]
|
||||||
|
.to_vec(),
|
||||||
|
alignment: None,
|
||||||
|
}];
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Use the escape codes to colorize the text
|
||||||
|
fn color_match_colorize() {
|
||||||
|
let result = log_sanitizer::colorize_logs(INPUT);
|
||||||
|
let expected = vec![Line {
|
||||||
|
spans: vec![
|
||||||
|
Span {
|
||||||
|
content: std::borrow::Cow::Borrowed("o"),
|
||||||
|
style: Style::default().fg(Color::Red).bg(Color::White),
|
||||||
|
},
|
||||||
|
Span {
|
||||||
|
content: std::borrow::Cow::Borrowed("x"),
|
||||||
|
style: Style::default().fg(Color::Green).bg(Color::Black),
|
||||||
|
},
|
||||||
|
Span {
|
||||||
|
content: std::borrow::Cow::Borrowed("k"),
|
||||||
|
style: Style::default().fg(Color::Yellow).bg(Color::Red),
|
||||||
|
},
|
||||||
|
Span {
|
||||||
|
content: std::borrow::Cow::Borrowed("e"),
|
||||||
|
style: Style::default().fg(Color::Blue).bg(Color::Green),
|
||||||
|
},
|
||||||
|
Span {
|
||||||
|
content: std::borrow::Cow::Borrowed("r"),
|
||||||
|
style: Style::default().fg(Color::Magenta).bg(Color::Yellow),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
alignment: None,
|
||||||
|
}];
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Remove all escape ansi codes from given input
|
||||||
|
fn color_match_remove_ansi() {
|
||||||
|
let result = log_sanitizer::remove_ansi(INPUT);
|
||||||
|
let expected = vec![Line {
|
||||||
|
spans: vec![Span {
|
||||||
|
content: std::borrow::Cow::Borrowed("oxker"),
|
||||||
|
style: Style::default(),
|
||||||
|
}],
|
||||||
|
alignment: None,
|
||||||
|
}];
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2149
-69
File diff suppressed because it is too large
Load Diff
+20
-30
@@ -217,22 +217,6 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
fn get_wholelayout(f: &Frame) -> std::rc::Rc<[ratatui::layout::Rect]> {
|
|
||||||
Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([Constraint::Min(1), Constraint::Min(100)].as_ref())
|
|
||||||
.split(f.size())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
fn get_wholelayout(f: &Frame) -> std::rc::Rc<[ratatui::layout::Rect]> {
|
|
||||||
Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints([Constraint::Min(1), Constraint::Min(1), Constraint::Min(100)].as_ref())
|
|
||||||
.split(f.size())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Frequent data required by multiple framde drawing functions, can reduce mutex reads by placing it all in here
|
/// Frequent data required by multiple framde drawing functions, can reduce mutex reads by placing it all in here
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FrameData {
|
pub struct FrameData {
|
||||||
@@ -279,21 +263,16 @@ impl From<(MutexGuard<'_, AppData>, MutexGuard<'_, GuiState>)> for FrameData {
|
|||||||
fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mutex<GuiState>>) {
|
fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mutex<GuiState>>) {
|
||||||
let fd = FrameData::from((app_data.lock(), gui_state.lock()));
|
let fd = FrameData::from((app_data.lock(), gui_state.lock()));
|
||||||
|
|
||||||
let whole_layout = get_wholelayout(f);
|
let whole_layout = Layout::default()
|
||||||
#[cfg(debug_assertions)]
|
.direction(Direction::Vertical)
|
||||||
draw_blocks::debug_bar(whole_layout[0], f, app_data.lock().get_debug_string());
|
.constraints([Constraint::Min(1), Constraint::Min(100)].as_ref())
|
||||||
|
.split(f.size());
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
let whole_layout_split = (1, 2);
|
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
let whole_layout_split = (0, 1);
|
|
||||||
|
|
||||||
// Split into 3, containers+controls, logs, then graphs
|
// Split into 3, containers+controls, logs, then graphs
|
||||||
let upper_main = Layout::default()
|
let upper_main = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([Constraint::Max(fd.height), Constraint::Percentage(50)].as_ref())
|
.constraints([Constraint::Max(fd.height), Constraint::Percentage(50)].as_ref())
|
||||||
.split(whole_layout[whole_layout_split.1]);
|
.split(whole_layout[1]);
|
||||||
|
|
||||||
let top_split = if fd.has_containers {
|
let top_split = if fd.has_containers {
|
||||||
vec![Constraint::Percentage(90), Constraint::Percentage(10)]
|
vec![Constraint::Percentage(90), Constraint::Percentage(10)]
|
||||||
@@ -307,7 +286,7 @@ fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mut
|
|||||||
.split(upper_main[0]);
|
.split(upper_main[0]);
|
||||||
|
|
||||||
let lower_split = if fd.has_containers {
|
let lower_split = if fd.has_containers {
|
||||||
vec![Constraint::Percentage(75), Constraint::Percentage(25)]
|
vec![Constraint::Percentage(70), Constraint::Percentage(20)]
|
||||||
} else {
|
} else {
|
||||||
vec![Constraint::Percentage(100)]
|
vec![Constraint::Percentage(100)]
|
||||||
};
|
};
|
||||||
@@ -318,11 +297,11 @@ fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mut
|
|||||||
.constraints(lower_split)
|
.constraints(lower_split)
|
||||||
.split(upper_main[1]);
|
.split(upper_main[1]);
|
||||||
|
|
||||||
draw_blocks::containers(app_data, top_panel[0], f, &fd, gui_state, &fd.columns);
|
draw_blocks::containers(app_data, top_panel[0], f, &fd, gui_state);
|
||||||
|
|
||||||
draw_blocks::logs(app_data, lower_main[0], f, &fd, gui_state);
|
draw_blocks::logs(app_data, lower_main[0], f, &fd, gui_state);
|
||||||
|
|
||||||
draw_blocks::heading_bar(whole_layout[whole_layout_split.0], f, &fd, gui_state);
|
draw_blocks::heading_bar(whole_layout[0], f, &fd, gui_state);
|
||||||
|
|
||||||
if let Some(id) = fd.delete_confirm.as_ref() {
|
if let Some(id) = fd.delete_confirm.as_ref() {
|
||||||
app_data.lock().get_container_name_by_id(id).map_or_else(
|
app_data.lock().get_container_name_by_id(id).map_or_else(
|
||||||
@@ -340,7 +319,18 @@ fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mut
|
|||||||
// only draw commands + charts if there are containers
|
// only draw commands + charts if there are containers
|
||||||
if fd.has_containers {
|
if fd.has_containers {
|
||||||
draw_blocks::commands(app_data, top_panel[1], f, &fd, gui_state);
|
draw_blocks::commands(app_data, top_panel[1], f, &fd, gui_state);
|
||||||
draw_blocks::chart(f, lower_main[1], app_data);
|
|
||||||
|
// Can calculate the max string length here, and then use that to keep the ports section as small as possible (+4 for some padding + border)
|
||||||
|
let max_lens = app_data.lock().get_longest_port();
|
||||||
|
let ports_len = u16::try_from(max_lens.0 + max_lens.1 + max_lens.2 + 2).unwrap_or(26);
|
||||||
|
|
||||||
|
let lower = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints([Constraint::Min(1), Constraint::Max(ports_len)])
|
||||||
|
.split(lower_main[1]);
|
||||||
|
|
||||||
|
draw_blocks::chart(f, lower[0], app_data);
|
||||||
|
draw_blocks::ports(f, lower[1], app_data, max_lens);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((text, instant)) = fd.info_text {
|
if let Some((text, instant)) = fd.info_text {
|
||||||
|
|||||||
Reference in New Issue
Block a user