To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit cc072f2e authored by Stefan Schindler's avatar Stefan Schindler
Browse files

Add colours, threading and tests for units

parent 95868f87
[root]
name = "whipe_buddy"
version = "0.1.0"
dependencies = [
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "threadpool"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc"
"checksum threadpool 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59f6d3eff89920113dac9db44dde461d71d01e88a5b57b258a0466c32b5d7fe1"
......@@ -4,3 +4,6 @@ version = "0.1.0"
authors = ["stefschi"]
[dependencies]
ansi_term = "0.9"
lazy_static = "0.2"
threadpool = "1.0"
extern crate ansi_term;
#[macro_use] extern crate lazy_static;
extern crate threadpool;
use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::{self, File};
use std::fs::{File};
use std::fmt::Display;
use std::sync::{Arc, Mutex};
use ansi_term::Style;
use ansi_term::Colour::*;
lazy_static! {
static ref BOLD: Style = Style::new().bold();
static ref UNDERLINE: Style = Style::new().underline();
static ref HEADING: Style = Yellow.bold();
}
fn main() {
let model = get_file_contents("/sys/devices/virtual/dmi/id/product_version");
println!("\n\n whipe buddy running on {}\n", model);
println!("\n\n {} running on {}\n", BOLD.paint("whipe buddy"), BOLD.paint(model));
let disks = parse_disks();
let pool = threadpool::ThreadPool::new(2);
list_disks(&disks);
// TODO interactive
return;
loop {
println!("\nPress q to exit");
println!("\nPress {} to exit, {} for a list of available commands", BOLD.paint("q"), BOLD.paint("h"));
let input = {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
input
};
let input = read_one_line_from_stdin();
match input.trim() {
"q" => return,
"l" => list_disks(&disks),
com => println!("unknown command: {}", com),
"h" => print_help(),
"w" => select_disk_to_whipe(&disks),
"" => {},
com => println!("unknown command: {}", com),
}
update_jobs(&disks, &pool);
}
}
fn list_disks(disks: &Vec<DiskInformation>) {
println!("Found following disks:");
fn list_disks(disks: &Vec<Arc<DiskInformation>>) {
println!("{}", HEADING.paint("Found following disks:") );
for disk in disks {
println!(" {}: {}", disk.name, disk.size);
println!(" {}) {}: {}", disk.id, BOLD.paint(&*disk.name), disk.size);
}
}
fn parse_disks() -> Vec<DiskInformation> {
fn parse_disks() -> Vec<Arc<DiskInformation>> {
let partitions = get_file_contents("/proc/partitions");
//println!("partitions: {:?}", partitions);
......@@ -48,6 +61,7 @@ fn parse_disks() -> Vec<DiskInformation> {
//println!("lines: {:?}", lines);
let mut disks = Vec::new();
let mut i = 0;
for line in lines {
let line = line.trim();
//println!("line: {:?}", line);
......@@ -59,10 +73,13 @@ fn parse_disks() -> Vec<DiskInformation> {
if minor == Some("0") && (name.starts_with("sd") || name.starts_with("nvme") || name.starts_with("xvd")) {
/// Contains the major and minor numbers of each partition as well as the number of 1024-byte blocks and the partition name.
let no_blocks: u64 = no_blocks.unwrap_or("0").parse().unwrap_or(0);
disks.push(DiskInformation {
i += 1;
disks.push(Arc::new(DiskInformation {
id: i,
name: name.into(),
size: KiloByte(no_blocks),
});
state: Mutex::new(Detected),
}));
}
}
}
......@@ -81,48 +98,184 @@ fn get_file_contents(path: &str) -> String {
let mut i = 0;
for line in reader.lines() {
i += 1;
buffer += &* line.unwrap_or( format!("<read error on line {} - {}>", i, path) );
buffer += &* line.unwrap_or( format!("<read error on line {} - {}>\n", i, path) );
buffer += "\n";
}
buffer
}
fn read_one_line_from_stdin() -> String {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap_or(0);
input
}
#[derive(Debug)]
struct DiskInformation {
id: u64,
size: ByteUnit,
name: String,
state: Mutex<DiskState>,
}
#[derive(Debug)]
#[derive(Debug,Eq)]
enum ByteUnit {
//Byte(u64),
Byte(u64),
KiloByte(u64),
}
use ByteUnit::*;
impl std::cmp::PartialEq<Self> for ByteUnit {
fn eq(&self, rhs: &Self) -> bool {
match self {
&Byte(l) => match rhs {
&Byte(r) => l == r,
&KiloByte(r) => l == 1024 * r,
},
&KiloByte(l) => match rhs {
&Byte(r) => 1024 * l == r,
&KiloByte(r) => l == r,
}
}
}
}
#[derive(Debug,PartialEq,Eq)]
enum DiskState {
Detected,
QueueForWhipe,
Whiping{ progress: ByteUnit, per_second: ByteUnit },
Whiped,
}
use DiskState::*;
impl Display for ByteUnit {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
&Byte(size) => {
if size < 1000 {
return write!(f, "{:>6.2} B ", size);
}
return KiloByte(size / 1024).fmt(f);
}
&KiloByte(size) => {
if size < 1600 {
return write!(f, "{:>7.2} KB", size);
if size < 1000 {
return write!(f, "{:>6.2} KB", size);
}
let size = size as f64;
let size: f64 = size / 1024.0;
if size < 1600.0 {
return write!(f, "{:>7.2} MB", size);
if size < 1000.0 {
return write!(f, "{:>6.2} MB", size);
}
let size: f64 = size / 1024.0;
if size < 1600.0 {
return write!(f, "{:>7.2} GB", size);
if size < 1000.0 {
return write!(f, "{:>6.2} GB", size);
}
let size: f64 = size / 1024.0;
write!(f, "{:>7.2} TB", size)
write!(f, "{:>6.2} TB", size)
}
}
}
}
fn print_help() {
println!("\n{}", HEADING.paint("Available Commands:"));
let options = [
("q", "quit"),
("h", "print this help"),
("l", "list found disks"),
("w", "start whiping a disk"),
("s", "show status updates"),
];
for option in options.iter() {
println!(" {} {}", BOLD.paint(option.0), option.1);
}
}
fn select_disk_to_whipe(disks: &Vec<Arc<DiskInformation>>) {
println!("{}", HEADING.paint("Enter the id of the disk you would like to be whiped:"));
match read_one_line_from_stdin().trim().parse() {
Ok(id) => {
if let Some(disk) = disks.iter().find(|ref e| e.id == id) {
while {
println!("\nWhiping is {}!\nDestroy any data on {} ({})\nEnter {} to continue or {} to abort?", UNDERLINE.paint("non-reversable"), BOLD.paint(&*disk.name), disk.size, BOLD.paint("y"), BOLD.paint("a"));
match read_one_line_from_stdin().trim() {
"y" | "Y" | "j" | "J" => { false },
"a" => { return }
_ => { println!("{}", Red.paint("invalid response")); true }
}
} {}
*disk.state.lock().unwrap() = QueueForWhipe;
return;
}
},
Err(e) => println!("parse_error: {:?}", e),
}
println!("{}", Red.paint("invalid selection"));
}
fn update_jobs(disks: &Vec<Arc<DiskInformation>>, pool: &threadpool::ThreadPool) {
for disk in disks {
if *disk.state.lock().unwrap() == QueueForWhipe {
println!("Queued {} for whipe", BOLD.paint(&*disk.name));
let disk = disk.clone();
pool.execute(move || {
*disk.state.lock().unwrap() = Whiping{ progress: Byte(0), per_second: Byte(0) };
let buf = [0; 4096];
})
}
}
}
#[cfg(test)]
mod test {
use ::ByteUnit::*;
#[test]
fn unit_eq() {
let one_k_bytes = Byte(1024);
let one_kilobyte = KiloByte(1);
assert_eq!(one_k_bytes, one_kilobyte);
assert_eq!(one_kilobyte, one_k_bytes);
}
#[test]
fn format_byte() {
assert_eq!(" 42 B ", format!("{}", Byte(42)));
}
#[test]
fn format_kilobyte() {
assert_eq!(" 42 KB", format!("{}", KiloByte(42)));
}
#[test]
fn format_megabyte() {
assert_eq!(" 42.00 MB", format!("{}", KiloByte(42 * 1024)));
}
#[test]
fn format_gigabyte() {
assert_eq!(" 42.00 GB", format!("{}", KiloByte(42 * 1024 * 1024)));
}
#[test]
fn format_terrabyte() {
assert_eq!(" 42.00 TB", format!("{}", KiloByte(42 * 1024 * 1024 * 1024)));
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment