other: aarch64 support (#217)

Adds theoretical aarch64 support.
This commit is contained in:
Clement Tsang 2020-09-02 02:59:51 -04:00 committed by GitHub
parent 663ae6c5c2
commit 22278d7d75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 513 additions and 192 deletions

View File

@ -1,4 +1,8 @@
[target.x86_64-pc-windows-msvc] [target.x86_64-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"] rustflags = ["-Ctarget-feature=+crt-static"]
[target.i686-pc-windows-msvc] [target.i686-pc-windows-msvc]
rustflags = ["-Ctarget-feature=+crt-static"] rustflags = ["-Ctarget-feature=+crt-static"]
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

View File

@ -1,16 +1,75 @@
language: rust language: rust
rust: cache: cargo
- stable notifications:
- beta email:
os: on_success: never
- linux
- osx matrix:
- windows include:
jobs: # Standard x86-64 stuff, stable and beta
- os: linux
env: TARGET=x86_64-unknown-linux-gnu
arch: amd64
rust: stable
- os: linux
env: TARGET=x86_64-unknown-linux-gnu
arch: amd64
rust: beta
- os: osx
env: TARGET=x86_64-apple-darwin
arch: amd64
rust: stable
- os: osx
env: TARGET=x86_64-apple-darwin
arch: amd64
rust: beta
- os: windows
env: TARGET=x86_64-pc-windows-msvc
arch: amd64
rust: stable
- os: windows
env: TARGET=x86_64-pc-windows-msvc
arch: amd64
rust: beta
# musl
- os: linux
env: TARGET=x86_64-unknown-linux-musl
arch: amd64
rust: stable
- os: linux
env: TARGET=x86_64-unknown-linux-musl
arch: amd64
rust: beta
# ARM stuff (skip beta for now, see https://github.com/rust-lang/rust/issues/62896)
- os: linux
env: TARGET=aarch64-unknown-linux-gnu
arch: arm64
rust: stable
- os: linux
env: TARGET=armv7-unknown-linux-gnueabihf
arch: amd64
rust: stable
addons:
apt:
packages: &armhf
- gcc-arm-linux-gnueabihf
- libc6-armhf-cross
- libc6-dev-armhf-cross
fast_finish: true fast_finish: true
exclude: exclude:
- if: tag IS present - if: tag IS present
rust: beta rust: beta
- if: tag IS present
arch: arm64
- if: tag IS present
env: TARGET=armv7-unknown-linux-gnueabihf
allow_failures:
- arch: arm64 # ARM will be run, but support is still gonna be limited for now... may change.
- env: TARGET=armv7-unknown-linux-gnueabihf
branches: branches:
only: only:
- master - master
@ -19,10 +78,7 @@ branches:
before_install: before_install:
- export RUST_BACKTRACE=1 - export RUST_BACKTRACE=1
- | - |
if [[ $TRAVIS_OS_NAME == "linux" ]]; then if [[ $TRAVIS_OS_NAME == "windows" ]]; then
export TARGET=x86_64-unknown-linux-gnu;
elif [[ $TRAVIS_OS_NAME == "windows" ]]; then
export TARGET=x86_64-pc-windows-msvc;
if [[ -n $TRAVIS_TAG ]]; then if [[ -n $TRAVIS_TAG ]]; then
powershell Install-WindowsFeature Net-Framework-Core; powershell Install-WindowsFeature Net-Framework-Core;
choco install -y wixtoolset; choco install -y wixtoolset;
@ -30,21 +86,29 @@ before_install:
choco install zip; choco install zip;
rustup target add i686-pc-windows-msvc; rustup target add i686-pc-windows-msvc;
fi fi
elif [[ $TRAVIS_OS_NAME == "osx" ]]; then
export TARGET=x86_64-apple-darwin;
fi fi
before_script: before_script:
- rustup target add $TARGET - rustup target add $TARGET
- rustup component add clippy - rustup update
- |
# Only check clippy if stable...
if [[ $TRAVIS_RUST_VERSION == "stable" ]]; then
rustup component add clippy
fi
script: script:
- cargo clippy -- -D clippy::all - |
- cargo test --verbose --target $TARGET # Only check clippy if stable...
if [[ $TRAVIS_RUST_VERSION == "stable" ]]; then
cache: cargo cargo clippy -- -D clippy::all
fi
notifications: - |
email: if [[ $TARGET = "armv7-unknown-linux-gnueabihf" ]]; then
on_success: never cargo build --verbose --target $TARGET
else
cargo test --verbose --target $TARGET
fi
before_deploy: before_deploy:
- | - |
@ -98,11 +162,10 @@ before_deploy:
strip btm; strip btm;
local target_dir=$(ls target/release/build/bottom-*/out/rg.bash | head -n1 | xargs dirname) local target_dir=$(ls target/release/build/bottom-*/out/rg.bash | head -n1 | xargs dirname)
cp -r $target_dir completions cp -r $target_dir completions
echo "Tar-ing macOS/Linux binary and completions..."
tar -czvf bottom_$TARGET.tar.gz btm completions;
if [[ $TRAVIS_OS_NAME == "linux" ]]; then if [[ $TRAVIS_OS_NAME == "linux" ]]; then
echo "Tar-ing Linux binary and completions..."
tar -czvf bottom_x86_64-unknown-linux-gnu.tar.gz btm completions;
echo "Generating AUR template..."; echo "Generating AUR template...";
python "./deployment/packager.py" $TRAVIS_TAG "./deployment/linux/arch/PKGBUILD_BIN.template" "./PKGBUILD_BIN" "SHA512" "./bottom_x86_64-unknown-linux-gnu.tar.gz"; python "./deployment/packager.py" $TRAVIS_TAG "./deployment/linux/arch/PKGBUILD_BIN.template" "./PKGBUILD_BIN" "SHA512" "./bottom_x86_64-unknown-linux-gnu.tar.gz";
curl -LO "https://github.com/ClementTsang/bottom/archive/$TRAVIS_TAG.tar.gz"; curl -LO "https://github.com/ClementTsang/bottom/archive/$TRAVIS_TAG.tar.gz";
@ -120,9 +183,6 @@ before_deploy:
cargo deb; cargo deb;
cp ./target/debian/bottom_*.deb .; cp ./target/debian/bottom_*.deb .;
elif [[ $TRAVIS_OS_NAME == "osx" ]]; then elif [[ $TRAVIS_OS_NAME == "osx" ]]; then
echo "Tar-ing macOS binary and completions..."
tar -czvf bottom_x86_64-apple-darwin.tar.gz btm completions;
# The bottom.rb file must be generated AFTER, since it relies on the Linux binary file. # The bottom.rb file must be generated AFTER, since it relies on the Linux binary file.
fi fi

View File

@ -19,6 +19,7 @@
"Mousebindings", "Mousebindings",
"Nonexhaustive", "Nonexhaustive",
"PKGBUILD", "PKGBUILD",
"PKGBUILDs",
"Polishchuk", "Polishchuk",
"Qudsi", "Qudsi",
"SIGTERM", "SIGTERM",
@ -30,6 +31,7 @@
"WASD", "WASD",
"Wojnarowski", "Wojnarowski",
"andys", "andys",
"armv",
"atim", "atim",
"choco", "choco",
"cmdline", "cmdline",
@ -39,6 +41,7 @@
"czvf", "czvf",
"fpath", "fpath",
"fract", "fract",
"gnueabihf",
"gotop", "gotop",
"gtop", "gtop",
"haase", "haase",
@ -48,6 +51,7 @@
"markdownlint", "markdownlint",
"memb", "memb",
"minwindef", "minwindef",
"musl",
"n'th", "n'th",
"noheader", "noheader",
"ntdef", "ntdef",
@ -81,6 +85,7 @@
"winget", "winget",
"winnt", "winnt",
"wixtoolset", "wixtoolset",
"xargs",
"xzvf", "xzvf",
"ytop" "ytop"
] ]

View File

@ -32,7 +32,6 @@ ctrlc = {version = "3.1", features = ["termination"]}
clap = "2.33" clap = "2.33"
dirs = "3.0.1" dirs = "3.0.1"
futures = "0.3.5" futures = "0.3.5"
heim = "0.0.10"
itertools = "0.9.0" itertools = "0.9.0"
libc = "0.2" libc = "0.2"
regex = "1.3" regex = "1.3"
@ -51,6 +50,9 @@ tui = {version = "0.9.5", features = ["crossterm"], default-features = false }
fern = "0.6.0" fern = "0.6.0"
log = "0.4.11" log = "0.4.11"
[target.'cfg(not(any(target_arch = "arm", target_arch = "aarch64")))'.dependencies]
heim = "0.0.10"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi = "0.3.9" winapi = "0.3.9"

View File

@ -62,7 +62,9 @@ Note that bottom is:
- Officially tested and released for only `x86_64` (and `i686` for Windows) - Officially tested and released for only `x86_64` (and `i686` for Windows)
- Developed mainly for macOS, Windows, and Linux - Developed mainly for macOS, Windows, and Linux
As such, support beyond that is not guaranteed. As such, support beyond that is not guaranteed. There is now _technically_ support for AArch64 builds,
and I do run them in Travis, but I am currently not guaranteeing their stability. In theory, they should
work fine, but I've had some troubles with building on ARM in some situations.
### Manually ### Manually

View File

@ -15,8 +15,9 @@ use lazy_static::lazy_static;
/// more points as this is used! /// more points as this is used!
use std::{time::Instant, vec::Vec}; use std::{time::Instant, vec::Vec};
use crate::data_harvester::{ use crate::{
battery_harvester, cpu, disks, mem, network, processes, temperature, Data, data_harvester::{battery_harvester, cpu, disks, mem, network, processes, temperature, Data},
utils::gen_util::get_simple_byte_values,
}; };
use regex::Regex; use regex::Regex;
@ -54,6 +55,7 @@ pub struct DataCollection {
pub disk_harvest: Vec<disks::DiskHarvest>, pub disk_harvest: Vec<disks::DiskHarvest>,
pub io_harvest: disks::IOHarvest, pub io_harvest: disks::IOHarvest,
pub io_labels_and_prev: Vec<((u64, u64), (u64, u64))>, pub io_labels_and_prev: Vec<((u64, u64), (u64, u64))>,
pub io_labels: Vec<(String, String)>,
pub temp_harvest: Vec<temperature::TempHarvest>, pub temp_harvest: Vec<temperature::TempHarvest>,
pub battery_harvest: Vec<battery_harvester::BatteryHarvest>, pub battery_harvest: Vec<battery_harvester::BatteryHarvest>,
} }
@ -72,6 +74,7 @@ impl Default for DataCollection {
disk_harvest: Vec::default(), disk_harvest: Vec::default(),
io_harvest: disks::IOHarvest::default(), io_harvest: disks::IOHarvest::default(),
io_labels_and_prev: Vec::default(), io_labels_and_prev: Vec::default(),
io_labels: Vec::default(),
temp_harvest: Vec::default(), temp_harvest: Vec::default(),
battery_harvest: Vec::default(), battery_harvest: Vec::default(),
} }
@ -232,7 +235,6 @@ impl DataCollection {
if let Some(trim) = device.name.split('/').last() { if let Some(trim) = device.name.split('/').last() {
let io_device = if cfg!(target_os = "macos") { let io_device = if cfg!(target_os = "macos") {
// Must trim one level further! // Must trim one level further!
lazy_static! { lazy_static! {
static ref DISK_REGEX: Regex = Regex::new(r"disk\d+").unwrap(); static ref DISK_REGEX: Regex = Regex::new(r"disk\d+").unwrap();
} }
@ -244,24 +246,50 @@ impl DataCollection {
} else { } else {
io.get(trim) io.get(trim)
}; };
let (io_r_pt, io_w_pt) = if let Some(io) = io_device {
(io.read_bytes, io.write_bytes) if let Some(io_device) = io_device {
let (io_r_pt, io_w_pt) = if let Some(io) = io_device {
(io.read_bytes, io.write_bytes)
} else {
(0, 0)
};
if self.io_labels.len() <= itx {
self.io_labels.push((String::default(), String::default()));
}
if self.io_labels_and_prev.len() <= itx {
self.io_labels_and_prev.push(((0, 0), (io_r_pt, io_w_pt)));
}
if let Some((io_curr, io_prev)) = self.io_labels_and_prev.get_mut(itx) {
let r_rate = ((io_r_pt.saturating_sub(io_prev.0)) as f64
/ time_since_last_harvest)
.round() as u64;
let w_rate = ((io_w_pt.saturating_sub(io_prev.1)) as f64
/ time_since_last_harvest)
.round() as u64;
*io_curr = (r_rate, w_rate);
*io_prev = (io_r_pt, io_w_pt);
if let Some(io_labels) = self.io_labels.get_mut(itx) {
let converted_read = get_simple_byte_values(r_rate, false);
let converted_write = get_simple_byte_values(w_rate, false);
*io_labels = (
format!("{:.*}{}/s", 0, converted_read.0, converted_read.1),
format!("{:.*}{}/s", 0, converted_write.0, converted_write.1),
);
}
}
} else { } else {
(0, 0) if self.io_labels.len() <= itx {
}; self.io_labels.push((String::default(), String::default()));
}
if self.io_labels_and_prev.len() <= itx { if let Some(io_labels) = self.io_labels.get_mut(itx) {
self.io_labels_and_prev.push(((0, 0), (io_r_pt, io_w_pt))); *io_labels = ("N/A".to_string(), "N/A".to_string());
} else if let Some((io_curr, io_prev)) = self.io_labels_and_prev.get_mut(itx) { }
let r_rate = ((io_r_pt.saturating_sub(io_prev.0)) as f64
/ time_since_last_harvest)
.round() as u64;
let w_rate = ((io_w_pt.saturating_sub(io_prev.1)) as f64
/ time_since_last_harvest)
.round() as u64;
*io_curr = (r_rate, w_rate);
*io_prev = (io_r_pt, io_w_pt);
} }
} }
} }

View File

@ -160,16 +160,32 @@ impl DataCollector {
self.sys.refresh_cpu(); self.sys.refresh_cpu();
} }
if cfg!(not(target_os = "linux")) { if cfg!(any(target_arch = "arm", target_arch = "aarch64")) {
// ARM stuff
if self.widgets_to_harvest.use_proc { if self.widgets_to_harvest.use_proc {
self.sys.refresh_processes(); self.sys.refresh_processes();
} }
if self.widgets_to_harvest.use_temp { if self.widgets_to_harvest.use_temp {
self.sys.refresh_components(); self.sys.refresh_components();
} }
} if self.widgets_to_harvest.use_net {
if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net { self.sys.refresh_networks();
self.sys.refresh_networks(); }
if self.widgets_to_harvest.use_mem {
self.sys.refresh_memory();
}
} else {
if cfg!(not(target_os = "linux")) {
if self.widgets_to_harvest.use_proc {
self.sys.refresh_processes();
}
if self.widgets_to_harvest.use_temp {
self.sys.refresh_components();
}
}
if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net {
self.sys.refresh_networks();
}
} }
let current_instant = std::time::Instant::now(); let current_instant = std::time::Instant::now();
@ -230,25 +246,96 @@ impl DataCollector {
} }
} }
// ASYNC // Async if Heim
let network_data_fut = network::get_network_data( let network_data_fut = {
&self.sys, #[cfg(any(target_os = "windows", target_arch = "aarch64", target_arch = "arm"))]
self.last_collection_time, {
&mut self.total_rx, network::get_sysinfo_network_data(
&mut self.total_tx, &self.sys,
current_instant, self.last_collection_time,
self.widgets_to_harvest.use_net, &mut self.total_rx,
); &mut self.total_tx,
current_instant,
self.widgets_to_harvest.use_net,
)
}
#[cfg(not(any(target_os = "windows", target_arch = "aarch64", target_arch = "arm")))]
{
network::get_heim_network_data(
self.last_collection_time,
&mut self.total_rx,
&mut self.total_tx,
current_instant,
self.widgets_to_harvest.use_net,
)
}
};
let mem_data_fut = {
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
{
mem::get_sysinfo_mem_data_list(&self.sys, self.widgets_to_harvest.use_mem)
}
let mem_data_fut = mem::get_mem_data_list(self.widgets_to_harvest.use_mem); #[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
let swap_data_fut = mem::get_swap_data_list(self.widgets_to_harvest.use_mem); {
let disk_data_fut = disks::get_disk_usage_list(self.widgets_to_harvest.use_disk); mem::get_heim_mem_data_list(self.widgets_to_harvest.use_mem)
let disk_io_usage_fut = disks::get_io_usage_list(false, self.widgets_to_harvest.use_disk); }
let temp_data_fut = temperature::get_temperature_data( };
&self.sys, let swap_data_fut = {
&self.temperature_type, #[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
self.widgets_to_harvest.use_temp, {
); mem::get_sysinfo_swap_data_list(&self.sys, self.widgets_to_harvest.use_mem)
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
{
mem::get_heim_swap_data_list(self.widgets_to_harvest.use_mem)
}
};
let disk_data_fut = {
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
{
disks::get_sysinfo_disk_usage_list(&self.sys, self.widgets_to_harvest.use_disk)
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
{
disks::get_heim_disk_usage_list(self.widgets_to_harvest.use_disk)
}
};
let disk_io_usage_fut = {
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
{
disks::get_sysinfo_io_usage_list(&self.sys, self.widgets_to_harvest.use_disk)
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
{
disks::get_heim_io_usage_list(false, self.widgets_to_harvest.use_disk)
}
};
let temp_data_fut = {
#[cfg(any(not(target_os = "linux"), target_arch = "aarch64", target_arch = "arm"))]
{
temperature::get_sysinfo_temperature_data(
&self.sys,
&self.temperature_type,
self.widgets_to_harvest.use_temp,
)
}
#[cfg(not(any(
not(target_os = "linux"),
target_arch = "aarch64",
target_arch = "arm"
)))]
{
temperature::get_heim_temperature_data(
&self.temperature_type,
self.widgets_to_harvest.use_temp,
)
}
};
let (net_data, mem_res, swap_res, disk_res, io_res, temp_res) = join!( let (net_data, mem_res, swap_res, disk_res, io_res, temp_res) = join!(
network_data_fut, network_data_fut,
@ -259,7 +346,6 @@ impl DataCollector {
temp_data_fut temp_data_fut
); );
// After async
if let Some(net_data) = net_data { if let Some(net_data) = net_data {
self.total_rx = net_data.total_rx; self.total_rx = net_data.total_rx;
self.total_tx = net_data.total_tx; self.total_tx = net_data.total_tx;

View File

@ -1,6 +1,3 @@
use futures::stream::StreamExt;
use heim::units::information;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct DiskHarvest { pub struct DiskHarvest {
pub name: String, pub name: String,
@ -16,16 +13,60 @@ pub struct IOData {
pub write_bytes: u64, pub write_bytes: u64,
} }
pub type IOHarvest = std::collections::HashMap<String, IOData>; pub type IOHarvest = std::collections::HashMap<String, Option<IOData>>;
pub async fn get_io_usage_list( /// Meant for ARM use.
get_physical: bool, actually_get: bool, #[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
pub async fn get_sysinfo_io_usage_list(
_sys: &sysinfo::System, _actually_get: bool,
) -> crate::utils::error::Result<Option<IOHarvest>> { ) -> crate::utils::error::Result<Option<IOHarvest>> {
let io_hash: std::collections::HashMap<String, Option<IOData>> =
std::collections::HashMap::new();
Ok(Some(io_hash))
// TODO: Sysinfo disk I/O usage.
// ...sadly, this cannot be done as of now (other than me writing my own), it requires further
// work. See https://github.com/GuillaumeGomez/sysinfo/issues/304.
}
/// Meant for ARM use.
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
pub async fn get_sysinfo_disk_usage_list(
sys: &sysinfo::System, actually_get: bool,
) -> crate::utils::error::Result<Option<Vec<DiskHarvest>>> {
use sysinfo::{DiskExt, SystemExt};
if !actually_get { if !actually_get {
return Ok(None); return Ok(None);
} }
let mut io_hash: std::collections::HashMap<String, IOData> = std::collections::HashMap::new(); let mut vec_disks = sys
.get_disks()
.iter()
.map(|disk| DiskHarvest {
name: disk.get_name().to_string_lossy().into(),
mount_point: disk.get_mount_point().to_string_lossy().into(),
free_space: disk.get_available_space(),
used_space: disk.get_total_space() - disk.get_available_space(),
total_space: disk.get_total_space(),
})
.collect::<Vec<DiskHarvest>>();
vec_disks.sort_by(|a, b| a.name.cmp(&b.name));
Ok(Some(vec_disks))
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
pub async fn get_heim_io_usage_list(
get_physical: bool, actually_get: bool,
) -> crate::utils::error::Result<Option<IOHarvest>> {
use futures::stream::StreamExt;
if !actually_get {
return Ok(None);
}
let mut io_hash: std::collections::HashMap<String, Option<IOData>> =
std::collections::HashMap::new();
if get_physical { if get_physical {
let mut physical_counter_stream = heim::disk::io_counters_physical(); let mut physical_counter_stream = heim::disk::io_counters_physical();
while let Some(io) = physical_counter_stream.next().await { while let Some(io) = physical_counter_stream.next().await {
@ -33,10 +74,10 @@ pub async fn get_io_usage_list(
let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable"); let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable");
io_hash.insert( io_hash.insert(
mount_point.to_string(), mount_point.to_string(),
IOData { Some(IOData {
read_bytes: io.read_bytes().get::<information::megabyte>(), read_bytes: io.read_bytes().get::<heim::units::information::megabyte>(),
write_bytes: io.write_bytes().get::<information::megabyte>(), write_bytes: io.write_bytes().get::<heim::units::information::megabyte>(),
}, }),
); );
} }
} else { } else {
@ -46,10 +87,10 @@ pub async fn get_io_usage_list(
let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable"); let mount_point = io.device_name().to_str().unwrap_or("Name Unavailable");
io_hash.insert( io_hash.insert(
mount_point.to_string(), mount_point.to_string(),
IOData { Some(IOData {
read_bytes: io.read_bytes().get::<information::byte>(), read_bytes: io.read_bytes().get::<heim::units::information::byte>(),
write_bytes: io.write_bytes().get::<information::byte>(), write_bytes: io.write_bytes().get::<heim::units::information::byte>(),
}, }),
); );
} }
} }
@ -57,9 +98,12 @@ pub async fn get_io_usage_list(
Ok(Some(io_hash)) Ok(Some(io_hash))
} }
pub async fn get_disk_usage_list( #[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
pub async fn get_heim_disk_usage_list(
actually_get: bool, actually_get: bool,
) -> crate::utils::error::Result<Option<Vec<DiskHarvest>>> { ) -> crate::utils::error::Result<Option<Vec<DiskHarvest>>> {
use futures::stream::StreamExt;
if !actually_get { if !actually_get {
return Ok(None); return Ok(None);
} }
@ -73,9 +117,9 @@ pub async fn get_disk_usage_list(
let usage = heim::disk::usage(partition.mount_point().to_path_buf()).await?; let usage = heim::disk::usage(partition.mount_point().to_path_buf()).await?;
vec_disks.push(DiskHarvest { vec_disks.push(DiskHarvest {
free_space: usage.free().get::<information::byte>(), free_space: usage.free().get::<heim::units::information::byte>(),
used_space: usage.used().get::<information::byte>(), used_space: usage.used().get::<heim::units::information::byte>(),
total_space: usage.total().get::<information::byte>(), total_space: usage.total().get::<heim::units::information::byte>(),
mount_point: (partition mount_point: (partition
.mount_point() .mount_point()
.to_str() .to_str()

View File

@ -1,5 +1,3 @@
use heim::units::information;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MemHarvest { pub struct MemHarvest {
pub mem_total_in_mb: u64, pub mem_total_in_mb: u64,
@ -15,7 +13,40 @@ impl Default for MemHarvest {
} }
} }
pub async fn get_mem_data_list( /// Meant for ARM use.
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
pub async fn get_sysinfo_mem_data_list(
sys: &sysinfo::System, actually_get: bool,
) -> crate::utils::error::Result<Option<MemHarvest>> {
use sysinfo::SystemExt;
if !actually_get {
return Ok(None);
}
Ok(Some(MemHarvest {
mem_total_in_mb: sys.get_total_memory() / 1024,
mem_used_in_mb: sys.get_used_memory() / 1024,
}))
}
/// Meant for ARM use.
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
pub async fn get_sysinfo_swap_data_list(
sys: &sysinfo::System, actually_get: bool,
) -> crate::utils::error::Result<Option<MemHarvest>> {
use sysinfo::SystemExt;
if !actually_get {
return Ok(None);
}
Ok(Some(MemHarvest {
mem_total_in_mb: sys.get_total_swap() / 1024,
mem_used_in_mb: sys.get_used_swap() / 1024,
}))
}
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
pub async fn get_heim_mem_data_list(
actually_get: bool, actually_get: bool,
) -> crate::utils::error::Result<Option<MemHarvest>> { ) -> crate::utils::error::Result<Option<MemHarvest>> {
if !actually_get { if !actually_get {
@ -25,13 +56,16 @@ pub async fn get_mem_data_list(
let memory = heim::memory::memory().await?; let memory = heim::memory::memory().await?;
Ok(Some(MemHarvest { Ok(Some(MemHarvest {
mem_total_in_mb: memory.total().get::<information::megabyte>(), mem_total_in_mb: memory.total().get::<heim::units::information::megabyte>(),
mem_used_in_mb: memory.total().get::<information::megabyte>() mem_used_in_mb: memory.total().get::<heim::units::information::megabyte>()
- memory.available().get::<information::megabyte>(), - memory
.available()
.get::<heim::units::information::megabyte>(),
})) }))
} }
pub async fn get_swap_data_list( #[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
pub async fn get_heim_swap_data_list(
actually_get: bool, actually_get: bool,
) -> crate::utils::error::Result<Option<MemHarvest>> { ) -> crate::utils::error::Result<Option<MemHarvest>> {
if !actually_get { if !actually_get {
@ -41,7 +75,7 @@ pub async fn get_swap_data_list(
let memory = heim::memory::swap().await?; let memory = heim::memory::swap().await?;
Ok(Some(MemHarvest { Ok(Some(MemHarvest {
mem_total_in_mb: memory.total().get::<information::megabyte>(), mem_total_in_mb: memory.total().get::<heim::units::information::megabyte>(),
mem_used_in_mb: memory.used().get::<information::megabyte>(), mem_used_in_mb: memory.used().get::<heim::units::information::megabyte>(),
})) }))
} }

View File

@ -1,10 +1,5 @@
use std::time::Instant; use std::time::Instant;
use futures::StreamExt;
use heim::net;
use heim::units::information::byte;
use sysinfo::{NetworkExt, System, SystemExt};
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
pub struct NetworkHarvest { pub struct NetworkHarvest {
pub rx: u64, pub rx: u64,
@ -20,30 +15,67 @@ impl NetworkHarvest {
} }
} }
pub async fn get_network_data( /// Meant for Windows and ARM use.
sys: &System, prev_net_access_time: Instant, prev_net_rx: &mut u64, prev_net_tx: &mut u64, #[cfg(any(target_os = "windows", target_arch = "aarch64", target_arch = "arm"))]
curr_time: Instant, actually_get: bool, pub async fn get_sysinfo_network_data(
sys: &sysinfo::System, prev_net_access_time: Instant, prev_net_rx: &mut u64,
prev_net_tx: &mut u64, curr_time: Instant, actually_get: bool,
) -> Option<NetworkHarvest> { ) -> Option<NetworkHarvest> {
use sysinfo::{NetworkExt, SystemExt};
if !actually_get { if !actually_get {
return None; return None;
} }
let mut io_data = net::io_counters();
let mut total_rx: u64 = 0; let mut total_rx: u64 = 0;
let mut total_tx: u64 = 0; let mut total_tx: u64 = 0;
if cfg!(target_os = "windows") { let networks = sys.get_networks();
let networks = sys.get_networks(); for (_, network) in networks {
for (_, network) in networks { total_rx += network.get_total_received();
total_rx += network.get_total_received(); total_tx += network.get_total_transmitted();
total_tx += network.get_total_transmitted(); }
}
let elapsed_time = curr_time.duration_since(prev_net_access_time).as_secs_f64();
let (rx, tx) = if elapsed_time == 0.0 {
(0, 0)
} else { } else {
while let Some(io) = io_data.next().await { (
if let Ok(io) = io { ((total_rx.saturating_sub(*prev_net_rx)) as f64 / elapsed_time) as u64,
total_rx += io.bytes_recv().get::<byte>(); ((total_tx.saturating_sub(*prev_net_tx)) as f64 / elapsed_time) as u64,
total_tx += io.bytes_sent().get::<byte>(); )
} };
*prev_net_rx = total_rx;
*prev_net_tx = total_tx;
Some(NetworkHarvest {
rx,
tx,
total_rx,
total_tx,
})
}
#[cfg(not(any(target_os = "windows", target_arch = "aarch64", target_arch = "arm")))]
pub async fn get_heim_network_data(
prev_net_access_time: Instant, prev_net_rx: &mut u64, prev_net_tx: &mut u64,
curr_time: Instant, actually_get: bool,
) -> Option<NetworkHarvest> {
use futures::StreamExt;
if !actually_get {
return None;
}
let mut io_data = heim::net::io_counters();
let mut total_rx: u64 = 0;
let mut total_tx: u64 = 0;
while let Some(io) = io_data.next().await {
if let Ok(io) = io {
total_rx += io.bytes_recv().get::<heim::units::information::byte>();
total_tx += io.bytes_sent().get::<heim::units::information::byte>();
} }
} }

View File

@ -1,9 +1,5 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use futures::StreamExt;
use heim::units::thermodynamic_temperature;
use sysinfo::{ComponentExt, System, SystemExt};
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct TempHarvest { pub struct TempHarvest {
pub component_name: Option<String>, pub component_name: Option<String>,
@ -24,61 +20,90 @@ impl Default for TemperatureType {
} }
} }
pub async fn get_temperature_data( /// Meant for ARM and non-Linux usage.
sys: &System, temp_type: &TemperatureType, actually_get: bool, #[cfg(any(not(target_os = "linux"), target_arch = "aarch64", target_arch = "arm"))]
pub async fn get_sysinfo_temperature_data(
sys: &sysinfo::System, temp_type: &TemperatureType, actually_get: bool,
) -> crate::utils::error::Result<Option<Vec<TempHarvest>>> { ) -> crate::utils::error::Result<Option<Vec<TempHarvest>>> {
use sysinfo::{ComponentExt, SystemExt};
fn convert_celsius_to_kelvin(celsius: f32) -> f32 {
celsius + 273.15
}
fn convert_celsius_to_fahrenheit(celsius: f32) -> f32 {
(celsius * (9.0 / 5.0)) + 32.0
}
if !actually_get { if !actually_get {
return Ok(None); return Ok(None);
} }
let mut temperature_vec: Vec<TempHarvest> = Vec::new(); let mut temperature_vec: Vec<TempHarvest> = Vec::new();
if cfg!(target_os = "linux") { let sensor_data = sys.get_components();
let mut sensor_data = heim::sensors::temperatures(); for component in sensor_data {
while let Some(sensor) = sensor_data.next().await { temperature_vec.push(TempHarvest {
if let Ok(sensor) = sensor { component_name: None,
temperature_vec.push(TempHarvest { component_label: Some(component.get_label().to_string()),
component_name: Some(sensor.unit().to_string()), temperature: match temp_type {
component_label: if let Some(label) = sensor.label() { TemperatureType::Celsius => component.get_temperature(),
Some(label.to_string()) TemperatureType::Kelvin => convert_celsius_to_kelvin(component.get_temperature()),
} else { TemperatureType::Fahrenheit => {
None convert_celsius_to_fahrenheit(component.get_temperature())
}, }
temperature: match temp_type { },
TemperatureType::Celsius => sensor });
.current() }
.get::<thermodynamic_temperature::degree_celsius>(
), temp_vec_sort(&mut temperature_vec);
TemperatureType::Kelvin => { Ok(Some(temperature_vec))
sensor.current().get::<thermodynamic_temperature::kelvin>() }
}
TemperatureType::Fahrenheit => sensor #[cfg(not(any(not(target_os = "linux"), target_arch = "aarch64", target_arch = "arm")))]
.current() pub async fn get_heim_temperature_data(
.get::<thermodynamic_temperature::degree_fahrenheit>( temp_type: &TemperatureType, actually_get: bool,
), ) -> crate::utils::error::Result<Option<Vec<TempHarvest>>> {
}, use futures::StreamExt;
});
} if !actually_get {
} return Ok(None);
} else { }
let sensor_data = sys.get_components();
for component in sensor_data { let mut temperature_vec: Vec<TempHarvest> = Vec::new();
use heim::units::thermodynamic_temperature;
let mut sensor_data = heim::sensors::temperatures();
while let Some(sensor) = sensor_data.next().await {
if let Ok(sensor) = sensor {
temperature_vec.push(TempHarvest { temperature_vec.push(TempHarvest {
component_name: None, component_name: Some(sensor.unit().to_string()),
component_label: Some(component.get_label().to_string()), component_label: if let Some(label) = sensor.label() {
Some(label.to_string())
} else {
None
},
temperature: match temp_type { temperature: match temp_type {
TemperatureType::Celsius => component.get_temperature(), TemperatureType::Celsius => sensor
.current()
.get::<thermodynamic_temperature::degree_celsius>(),
TemperatureType::Kelvin => { TemperatureType::Kelvin => {
convert_celsius_to_kelvin(component.get_temperature()) sensor.current().get::<thermodynamic_temperature::kelvin>()
}
TemperatureType::Fahrenheit => {
convert_celsius_to_fahrenheit(component.get_temperature())
} }
TemperatureType::Fahrenheit => sensor
.current()
.get::<thermodynamic_temperature::degree_fahrenheit>(
),
}, },
}); });
} }
} }
temp_vec_sort(&mut temperature_vec);
Ok(Some(temperature_vec))
}
fn temp_vec_sort(temperature_vec: &mut Vec<TempHarvest>) {
// By default, sort temperature, then by alphabetically! // By default, sort temperature, then by alphabetically!
// TODO: [TEMPS] Allow users to control this. // TODO: [TEMPS] Allow users to control this.
@ -97,14 +122,4 @@ pub async fn get_temperature_data(
.partial_cmp(&b.component_name) .partial_cmp(&b.component_name)
.unwrap_or(Ordering::Equal) .unwrap_or(Ordering::Equal)
}); });
Ok(Some(temperature_vec))
}
fn convert_celsius_to_kelvin(celsius: f32) -> f32 {
celsius + 273.15
}
fn convert_celsius_to_fahrenheit(celsius: f32) -> f32 {
(celsius * (9.0 / 5.0)) + 32.0
} }

View File

@ -117,15 +117,8 @@ pub fn convert_disk_row(current_data: &data_farmer::DataCollection) -> Vec<Vec<S
current_data current_data
.disk_harvest .disk_harvest
.iter() .iter()
.zip(&current_data.io_labels_and_prev) .zip(&current_data.io_labels)
.for_each(|(disk, (io_label, _io_prev))| { .for_each(|(disk, (io_read, io_write))| {
let converted_read = get_simple_byte_values(io_label.0, false);
let converted_write = get_simple_byte_values(io_label.1, false);
let io_activity = (
format!("{:.*}{}/s", 0, converted_read.0, converted_read.1),
format!("{:.*}{}/s", 0, converted_write.0, converted_write.1),
);
let converted_free_space = get_simple_byte_values(disk.free_space, false); let converted_free_space = get_simple_byte_values(disk.free_space, false);
let converted_total_space = get_simple_byte_values(disk.total_space, false); let converted_total_space = get_simple_byte_values(disk.total_space, false);
disk_vector.push(vec![ disk_vector.push(vec![
@ -140,8 +133,8 @@ pub fn convert_disk_row(current_data: &data_farmer::DataCollection) -> Vec<Vec<S
"{:.*}{}", "{:.*}{}",
0, converted_total_space.0, converted_total_space.1 0, converted_total_space.0, converted_total_space.1
), ),
io_activity.0, io_read.to_string(),
io_activity.1, io_write.to_string(),
]); ]);
}); });
@ -348,7 +341,7 @@ pub fn convert_network_data_points(
} }
} else { } else {
let rx_display = format!( let rx_display = format!(
"RX: {:<9} Total: {:<9}", "RX: {:<9} All: {:<9}",
format!("{:.1}{:3}", rx_converted_result.0, rx_converted_result.1), format!("{:.1}{:3}", rx_converted_result.0, rx_converted_result.1),
format!( format!(
"{:.1}{:3}", "{:.1}{:3}",
@ -356,7 +349,7 @@ pub fn convert_network_data_points(
) )
); );
let tx_display = format!( let tx_display = format!(
"TX: {:<9} Total: {:<9}", "TX: {:<9} All: {:<9}",
format!("{:.1}{:3}", tx_converted_result.0, tx_converted_result.1), format!("{:.1}{:3}", tx_converted_result.0, tx_converted_result.1),
format!( format!(
"{:.1}{:3}", "{:.1}{:3}",

View File

@ -42,6 +42,7 @@ impl From<std::io::Error> for BottomError {
} }
} }
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
impl From<heim::Error> for BottomError { impl From<heim::Error> for BottomError {
fn from(err: heim::Error) -> Self { fn from(err: heim::Error) -> Self {
BottomError::InvalidHeim(err.to_string()) BottomError::InvalidHeim(err.to_string())

View File

@ -148,6 +148,17 @@ fn test_empty_battery() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) Ok(())
} }
#[test]
fn test_lone_default_widget_count() -> Result<(), Box<dyn std::error::Error>> {
Command::new(get_binary_location())
.arg("-C")
.arg("./tests/invalid_configs/lone_default_widget_count.toml")
.assert()
.failure()
.stderr(predicate::str::contains("it must be used with"));
Ok(())
}
#[test] #[test]
fn test_invalid_default_widget_count() -> Result<(), Box<dyn std::error::Error>> { fn test_invalid_default_widget_count() -> Result<(), Box<dyn std::error::Error>> {
Command::new(get_binary_location()) Command::new(get_binary_location())
@ -155,6 +166,6 @@ fn test_invalid_default_widget_count() -> Result<(), Box<dyn std::error::Error>>
.arg("./tests/invalid_configs/invalid_default_widget_count.toml") .arg("./tests/invalid_configs/invalid_default_widget_count.toml")
.assert() .assert()
.failure() .failure()
.stderr(predicate::str::contains("it must be used with")); .stderr(predicate::str::contains("invalid number"));
Ok(()) Ok(())
} }

View File

@ -1,2 +1,3 @@
[flags] [flags]
default_widget_count = 3 default_widget_type="CPU"
default_widget_count=18446744073709551616

View File

@ -3,3 +3,4 @@
type="cpu" type="cpu"
[[row.child]] [[row.child]]
type="not_real" type="not_real"

View File

@ -0,0 +1,2 @@
[flags]
default_widget_count = 3