From dfdc5af0f896f1b47e11269b7ace49624b077470 Mon Sep 17 00:00:00 2001 From: mxwt Date: Mon, 13 Nov 2023 14:58:02 +0100 Subject: [PATCH 01/22] added .idea folder to .gitignore Signed-off-by: Max Winter --- .gitignore | 2 ++ Cargo.lock | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 73fab07..345b19a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ target/ # MSVC Windows builds of rustc generate these, which store debugging information *.pdb + +.idea/ diff --git a/Cargo.lock b/Cargo.lock index f8a3bff..88a4003 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -122,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1" [[package]] -name = "hp-cli" +name = "hydrophonitor-cli" version = "0.1.0" dependencies = [ "anyhow", From ebc7a0b2f3b61638d1e44c9bb3f3f995e4d2cc28 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 13 Nov 2023 15:44:00 +0100 Subject: [PATCH 02/22] moved logic into separate files Signed-off-by: Max Winter --- src/clean.rs | 0 src/import.rs | 108 +++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 126 +++++--------------------------------------------- 3 files changed, 119 insertions(+), 115 deletions(-) create mode 100644 src/clean.rs create mode 100644 src/import.rs diff --git a/src/clean.rs b/src/clean.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/import.rs b/src/import.rs new file mode 100644 index 0000000..4d69b9e --- /dev/null +++ b/src/import.rs @@ -0,0 +1,108 @@ +use std::error::Error; +use std::fs; +use std::path::PathBuf; + +use clap::Parser; +use hound::{WavReader, WavWriter}; +use indicatif::ProgressBar; +use walkdir::WalkDir; + +const DATA_FOLDER: &str = "home/pi/data"; + +#[derive(Parser, Debug)] +#[clap(about = "Import audio from an SD card.")] +pub struct Import { + /// Path to the SD card. You can find the path to the SD card by running + /// `lsblk` in the terminal. + #[clap(short, long, required = true)] + pub device: PathBuf, + + /// Path to the output folder. If not specified, the output folder will be + /// the current directory. + #[clap(short, long)] + pub output: Option, + + ///Increases the CLI verbosity + #[clap(short, long, action)] + pub verbose: bool, +} + +pub fn import_from_sd(sd_card: &mut PathBuf, output_folder: Option) -> Result<(), Box> { + let output_folder = match output_folder { + Some(output_folder) => output_folder, + None => std::env::current_dir().unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }) + }; + + sd_card.push(DATA_FOLDER); + + let count = WalkDir::new(sd_card.clone()).into_iter().count(); + let progress_bar = ProgressBar::new(count as u64); + + for entry in WalkDir::new(sd_card.clone()) { + let entry = entry?; + let from = entry.path(); + let to = output_folder.join(from.strip_prefix(sd_card.clone())?); + + if entry.file_type().is_dir() { + fs::create_dir_all(to)?; + } else if entry.file_type().is_file() { + fs::copy(from, to)?; + } + progress_bar.inc(1); + } + progress_bar.finish(); + Ok(()) +} + +pub fn merge_wavs(input: &std::path::PathBuf, output: &std::path::PathBuf) -> Result<(), Box> { + // Read files from input directory + let mut files = std::fs::read_dir(input)? + .filter_map(|entry| entry.ok()) + .filter(|entry| entry.file_type().ok().map(|t| t.is_file()).unwrap_or(false)) + .filter(|entry| entry.path().extension().unwrap_or_default() == "wav") + .collect::>(); + + // If there are no wav files, return + if files.is_empty() { + println!("No wav files found in {:?}", input); + return Ok(()); + } + // Sort files by name + files.sort_by(|a, b| a.file_name().cmp(&b.file_name())); + + let output_name = files.first().unwrap().file_name(); + let output_name = output_name.to_str().unwrap(); + + // Get wav spec from file + let spec = WavReader::open(files.first().unwrap().path())?.spec(); + let mut writer = WavWriter::create(output.join(output_name), spec)?; + + let progress_bar = ProgressBar::new(files.len() as u64); + match spec.sample_format { + hound::SampleFormat::Float => { + for file in files { + let mut reader = WavReader::open(file.path())?; + for sample in reader.samples::() { + writer.write_sample(sample?)?; + } + progress_bar.inc(1); + } + } + hound::SampleFormat::Int => { + for file in files { + let mut reader = WavReader::open(file.path())?; + for sample in reader.samples::() { + writer.write_sample(sample?)?; + } + progress_bar.inc(1); + } + } + } + progress_bar.finish(); + writer.finalize()?; + Ok(()) +} + diff --git a/src/main.rs b/src/main.rs index eabbdb7..6d133cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,20 @@ -use clap::{Parser, Subcommand}; -use std::error::Error; use std::fs; use std::path::PathBuf; + +use clap::{Parser, Subcommand}; use walkdir::WalkDir; -use indicatif::ProgressBar; -use hound::{WavReader, WavWriter}; -const DATA_FOLDER: &str = "home/pi/data"; +use crate::import::{Import, import_from_sd, merge_wavs}; + +mod import; +mod clean; #[derive(Subcommand)] #[clap(about = "A tool to record audio on Linux using the command line.")] pub enum Commands { - Install(Install), Import(Import), } -#[derive(Parser, Debug)] -#[clap(about = "Install hydrophonitor on an SD card.")] -pub struct Install { - /// Path to the SD card. You can find the path to the SD card by running - /// `lsblk` in the terminal. - #[clap(short, long, required = true)] - pub sd_card: PathBuf, -} - -#[derive(Parser, Debug)] -#[clap(about = "Import audio from an SD card.")] -pub struct Import { - /// Path to the SD card. You can find the path to the SD card by running - /// `lsblk` in the terminal. - #[clap(short, long, required = true)] - pub sd_card: PathBuf, - - /// Path to the output folder. If not specified, the output folder will be - /// the current directory. - #[clap(short, long)] - pub output_folder: Option, -} #[derive(Parser)] #[clap(author, version, about, long_about = None)] @@ -46,105 +24,23 @@ pub struct Cli { pub commands: Commands, } -fn import_from_sd(sd_card: &mut PathBuf, output_folder: Option) -> Result<(), Box>{ - let output_folder = match output_folder { - Some(output_folder) => output_folder, - None => std::env::current_dir().unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }) - }; - - sd_card.push(DATA_FOLDER); - - let count = WalkDir::new(sd_card.clone()).into_iter().count(); - let progress_bar = ProgressBar::new(count as u64); - - for entry in WalkDir::new(sd_card.clone()) { - let entry = entry?; - let from = entry.path(); - let to = output_folder.join(from.strip_prefix(sd_card.clone())?); - - if entry.file_type().is_dir() { - fs::create_dir_all(to)?; - } else if entry.file_type().is_file() { - fs::copy(from, to)?; - } - progress_bar.inc(1); - } - progress_bar.finish(); - Ok(()) -} - - -pub fn merge_wavs(input: &std::path::PathBuf, output: &std::path::PathBuf) -> Result<(), Box> { - // Read files from input directory - let mut files = std::fs::read_dir(input)? - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.file_type().ok().map(|t| t.is_file()).unwrap_or(false)) - .filter(|entry| entry.path().extension().unwrap_or_default() == "wav") - .collect::>(); - - // If there are no wav files, return - if files.is_empty() { - println!("No wav files found in {:?}", input); - return Ok(()); - } - // Sort files by name - files.sort_by(|a, b| a.file_name().cmp(&b.file_name())); - - let output_name = files.first().unwrap().file_name(); - let output_name = output_name.to_str().unwrap(); - - // Get wav spec from file - let spec = WavReader::open(files.first().unwrap().path())?.spec(); - let mut writer = WavWriter::create(output.join(output_name), spec)?; - - let progress_bar = ProgressBar::new(files.len() as u64); - match spec.sample_format { - hound::SampleFormat::Float => { - for file in files { - let mut reader = WavReader::open(file.path())?; - for sample in reader.samples::() { - writer.write_sample(sample?)?; - } - progress_bar.inc(1); - } - }, - hound::SampleFormat::Int => { - for file in files { - let mut reader = WavReader::open(file.path())?; - for sample in reader.samples::() { - writer.write_sample(sample?)?; - } - progress_bar.inc(1); - } - }, - } - progress_bar.finish(); - writer.finalize()?; - Ok(()) -} fn main() { let commands = Cli::parse(); match commands.commands { - Commands::Install(install) => { - println!("Installing hydrophonitor on SD card at {:?}", install.sd_card); - } Commands::Import(mut import) => { - println!("Importing audio from SD card at {:?}", import.sd_card); + println!("Importing audio from SD card at {:?}", import.device); - if let Some(output_folder) = &import.output_folder { + if let Some(output_folder) = &import.output { println!("Output folder: {:?}", output_folder); - import_from_sd(&mut import.sd_card, Some(output_folder.clone())).unwrap_or_else(|err| { + import_from_sd(&mut import.device, Some(output_folder.clone())).unwrap_or_else(|err| { eprintln!("Error: {}", err); std::process::exit(1); }); } else { println!("Output folder: current directory"); - import_from_sd(&mut import.sd_card, None).unwrap_or_else(|err| { + import_from_sd(&mut import.device, None).unwrap_or_else(|err| { eprintln!("Error: {}", err); std::process::exit(1); }); @@ -153,7 +49,7 @@ fn main() { // Iterate folders inside output folder. Inside each iterated folder there is // a folder called "audio" which contains the wav files. Merge them into a single // wav file and delete the "audio" folder. - let output_folder = match import.output_folder { + let output_folder = match import.output { Some(output_folder) => output_folder, None => std::env::current_dir().unwrap_or_else(|err| { eprintln!("Error: {}", err); From d88a3279e27df377b83ddd643d88c34e591b16a7 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 13 Nov 2023 15:48:09 +0100 Subject: [PATCH 03/22] added import command arguments Signed-off-by: Max Winter --- src/import.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/import.rs b/src/import.rs index 4d69b9e..238052d 100644 --- a/src/import.rs +++ b/src/import.rs @@ -22,6 +22,14 @@ pub struct Import { #[clap(short, long)] pub output: Option, + ///Runs a clean after import is complete + #[clap(long, action)] + pub clean_imported: bool, + + ///Generates compressed previews of audio files. + #[clap(long, action)] + pub audio_previews: bool, + ///Increases the CLI verbosity #[clap(short, long, action)] pub verbose: bool, From d5b222793e396e46a28f5687be184cc5d903af82 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 13 Nov 2023 16:14:52 +0100 Subject: [PATCH 04/22] moved paramter execution of import command into method of Import struct Signed-off-by: Max Winter --- src/import.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 56 ++------------------------------------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/import.rs b/src/import.rs index 238052d..c3bd423 100644 --- a/src/import.rs +++ b/src/import.rs @@ -35,6 +35,58 @@ pub struct Import { pub verbose: bool, } +impl Import { + pub fn import(&mut self) { + println!("Importing audio from SD card at {:?}", self.device); + + if let Some(output_folder) = &self.output { + println!("Output folder: {:?}", output_folder); + import_from_sd(&mut self.device, Some(output_folder.clone())).unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }); + } else { + println!("Output folder: current directory"); + import_from_sd(&mut self.device, None).unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }); + } + + // Iterate folders inside output folder. Inside each iterated folder there is + // a folder called "audio" which contains the wav files. Merge them into a single + // wav file and delete the "audio" folder. + let output_folder = match &self.output { + Some(output_folder) => output_folder, + None => std::env::current_dir().unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }) + }; + + for entry in WalkDir::new(output_folder.clone()) { + let entry = entry.unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }); + let path = entry.path(); + if path.is_dir() { + let audio_folder = path.join("audio"); + if audio_folder.exists() { + merge_wavs(&audio_folder, &PathBuf::from(path)).unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }); + fs::remove_dir_all(audio_folder).unwrap_or_else(|err| { + eprintln!("Error: {}", err); + std::process::exit(1); + }); + } + } + } + } +} + pub fn import_from_sd(sd_card: &mut PathBuf, output_folder: Option) -> Result<(), Box> { let output_folder = match output_folder { Some(output_folder) => output_folder, diff --git a/src/main.rs b/src/main.rs index 6d133cb..e630fb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,6 @@ -use std::fs; -use std::path::PathBuf; - use clap::{Parser, Subcommand}; -use walkdir::WalkDir; -use crate::import::{Import, import_from_sd, merge_wavs}; +use crate::import::Import; mod import; mod clean; @@ -29,54 +25,6 @@ fn main() { let commands = Cli::parse(); match commands.commands { - Commands::Import(mut import) => { - println!("Importing audio from SD card at {:?}", import.device); - - if let Some(output_folder) = &import.output { - println!("Output folder: {:?}", output_folder); - import_from_sd(&mut import.device, Some(output_folder.clone())).unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }); - } else { - println!("Output folder: current directory"); - import_from_sd(&mut import.device, None).unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }); - } - - // Iterate folders inside output folder. Inside each iterated folder there is - // a folder called "audio" which contains the wav files. Merge them into a single - // wav file and delete the "audio" folder. - let output_folder = match import.output { - Some(output_folder) => output_folder, - None => std::env::current_dir().unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }) - }; - - for entry in WalkDir::new(output_folder.clone()) { - let entry = entry.unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }); - let path = entry.path(); - if path.is_dir() { - let audio_folder = path.join("audio"); - if audio_folder.exists() { - merge_wavs(&audio_folder, &PathBuf::from(path)).unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }); - fs::remove_dir_all(audio_folder).unwrap_or_else(|err| { - eprintln!("Error: {}", err); - std::process::exit(1); - }); - } - } - } - } + Commands::Import(mut import) => { import.import() } } } From 7bd329c8ead2e3bf2cdaa381ae97372995144d59 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 13 Nov 2023 16:28:39 +0100 Subject: [PATCH 05/22] added clean command dummy implementation Signed-off-by: Max Winter --- src/clean.rs | 21 +++++++++++++++++++++ src/import.rs | 8 ++++---- src/main.rs | 3 +++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/clean.rs b/src/clean.rs index e69de29..4bbed32 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -0,0 +1,21 @@ +use std::path::PathBuf; + +use clap::Parser; + +#[derive(Parser, Debug)] +#[clap(about = "This command removes all deployment data from the given device's /output path")] +pub struct Clean { + ///Path to USB mass storage or SD card where data will be deleted from. + #[clap(short, long, required = True)] + pub device: PathBuf, + + ///Increases the CLI verbosity. + #[clap(short, long, action)] + pub verbose: bool, +} + +impl Clean { + pub fn clean(&self) { + println!("Cleaning device at {:?}", self.device); + } +} \ No newline at end of file diff --git a/src/import.rs b/src/import.rs index c3bd423..5865a0e 100644 --- a/src/import.rs +++ b/src/import.rs @@ -12,8 +12,8 @@ const DATA_FOLDER: &str = "home/pi/data"; #[derive(Parser, Debug)] #[clap(about = "Import audio from an SD card.")] pub struct Import { - /// Path to the SD card. You can find the path to the SD card by running - /// `lsblk` in the terminal. + /// Path to USB mass storage or SD where data will be imported from. You can find the path to + /// the SD card by running `lsblk` in the terminal. #[clap(short, long, required = true)] pub device: PathBuf, @@ -22,7 +22,7 @@ pub struct Import { #[clap(short, long)] pub output: Option, - ///Runs a clean after import is complete + ///Runs a clean after import is complete. #[clap(long, action)] pub clean_imported: bool, @@ -30,7 +30,7 @@ pub struct Import { #[clap(long, action)] pub audio_previews: bool, - ///Increases the CLI verbosity + ///Increases the CLI verbosity. #[clap(short, long, action)] pub verbose: bool, } diff --git a/src/main.rs b/src/main.rs index e630fb0..c72660c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use clap::{Parser, Subcommand}; +use crate::clean::Clean; use crate::import::Import; mod import; @@ -9,6 +10,7 @@ mod clean; #[clap(about = "A tool to record audio on Linux using the command line.")] pub enum Commands { Import(Import), + Clean(Clean), } @@ -26,5 +28,6 @@ fn main() { match commands.commands { Commands::Import(mut import) => { import.import() } + Commands::Clean(mut clean) => { clean.clean() } } } From 571868e8051036fe057ca2943c70344396bfb897 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 20 Nov 2023 14:21:37 +0100 Subject: [PATCH 06/22] added todos to mark old code Signed-off-by: Max Winter --- src/import.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/import.rs b/src/import.rs index 5865a0e..52fd940 100644 --- a/src/import.rs +++ b/src/import.rs @@ -36,6 +36,7 @@ pub struct Import { } impl Import { + //TODO old logic; has to be changed to match new commands pub fn import(&mut self) { println!("Importing audio from SD card at {:?}", self.device); @@ -87,6 +88,7 @@ impl Import { } } +//TODO old logic pub fn import_from_sd(sd_card: &mut PathBuf, output_folder: Option) -> Result<(), Box> { let output_folder = match output_folder { Some(output_folder) => output_folder, @@ -117,6 +119,7 @@ pub fn import_from_sd(sd_card: &mut PathBuf, output_folder: Option) -> Ok(()) } +//TODO old logic pub fn merge_wavs(input: &std::path::PathBuf, output: &std::path::PathBuf) -> Result<(), Box> { // Read files from input directory let mut files = std::fs::read_dir(input)? From f365e2f6fd439c4141890cc6c7ba503c8ac519ff Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 20 Nov 2023 15:11:55 +0100 Subject: [PATCH 07/22] fixed errors Signed-off-by: Max Winter --- src/clean.rs | 2 +- src/import.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clean.rs b/src/clean.rs index 4bbed32..298cb9c 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -6,7 +6,7 @@ use clap::Parser; #[clap(about = "This command removes all deployment data from the given device's /output path")] pub struct Clean { ///Path to USB mass storage or SD card where data will be deleted from. - #[clap(short, long, required = True)] + #[clap(short, long, required = true)] pub device: PathBuf, ///Increases the CLI verbosity. diff --git a/src/import.rs b/src/import.rs index 52fd940..0a970ee 100644 --- a/src/import.rs +++ b/src/import.rs @@ -57,7 +57,7 @@ impl Import { // Iterate folders inside output folder. Inside each iterated folder there is // a folder called "audio" which contains the wav files. Merge them into a single // wav file and delete the "audio" folder. - let output_folder = match &self.output { + let output_folder = match self.output.clone() { Some(output_folder) => output_folder, None => std::env::current_dir().unwrap_or_else(|err| { eprintln!("Error: {}", err); From b201f2b7e23957a7cc8aa3ef719c12da6603e730 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 20 Nov 2023 15:28:19 +0100 Subject: [PATCH 08/22] imported log crate Signed-off-by: Max Winter --- Cargo.lock | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/clean.rs | 3 ++- src/main.rs | 6 +++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 88a4003..7302a94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.70" @@ -82,6 +91,19 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "errno" version = "0.2.8" @@ -121,14 +143,22 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hydrophonitor-cli" version = "0.1.0" dependencies = [ "anyhow", "clap", + "env_logger", "hound", "indicatif", + "log", "walkdir", ] @@ -185,6 +215,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + [[package]] name = "number_prefix" version = "0.4.0" @@ -251,6 +293,35 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rustix" version = "0.36.10" diff --git a/Cargo.toml b/Cargo.toml index 7757dd3..9c05caa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,5 @@ clap = { version = "4.1.11", features = ["derive"] } hound = "3.5.0" indicatif = "0.17.3" walkdir = "2.3.3" +log = "0.4" +env_logger = "0.10.1" diff --git a/src/clean.rs b/src/clean.rs index 298cb9c..f8aaad1 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use clap::Parser; +use log::{error, info, trace, warn}; #[derive(Parser, Debug)] #[clap(about = "This command removes all deployment data from the given device's /output path")] @@ -16,6 +17,6 @@ pub struct Clean { impl Clean { pub fn clean(&self) { - println!("Cleaning device at {:?}", self.device); + trace!("Cleaning device at {:?}", self.device); } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c72660c..dd904c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use clap::{Parser, Subcommand}; +use log::{info, LevelFilter}; use crate::clean::Clean; use crate::import::Import; @@ -22,8 +23,13 @@ pub struct Cli { pub commands: Commands, } +fn init_logging() { + env_logger::builder().filter_level(LevelFilter::Trace).init(); + info!("Initialized logging!") +} fn main() { + init_logging(); let commands = Cli::parse(); match commands.commands { From 9f642d12dccbe2496cf889a2f6c7beb7440beed7 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 20 Nov 2023 16:20:45 +0100 Subject: [PATCH 09/22] implemented verbose command Signed-off-by: Max Winter --- src/clean.rs | 7 +++++-- src/import.rs | 4 +++- src/logging.rs | 11 +++++++++++ src/main.rs | 9 +++------ 4 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 src/logging.rs diff --git a/src/clean.rs b/src/clean.rs index f8aaad1..131b933 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -1,7 +1,9 @@ use std::path::PathBuf; use clap::Parser; -use log::{error, info, trace, warn}; +use log::trace; + +use crate::logging::init_logging; #[derive(Parser, Debug)] #[clap(about = "This command removes all deployment data from the given device's /output path")] @@ -17,6 +19,7 @@ pub struct Clean { impl Clean { pub fn clean(&self) { + init_logging(self.verbose); trace!("Cleaning device at {:?}", self.device); } -} \ No newline at end of file +} diff --git a/src/import.rs b/src/import.rs index 0a970ee..244ac0f 100644 --- a/src/import.rs +++ b/src/import.rs @@ -7,6 +7,8 @@ use hound::{WavReader, WavWriter}; use indicatif::ProgressBar; use walkdir::WalkDir; +use crate::logging::init_logging; + const DATA_FOLDER: &str = "home/pi/data"; #[derive(Parser, Debug)] @@ -38,6 +40,7 @@ pub struct Import { impl Import { //TODO old logic; has to be changed to match new commands pub fn import(&mut self) { + init_logging(self.verbose); println!("Importing audio from SD card at {:?}", self.device); if let Some(output_folder) = &self.output { @@ -168,4 +171,3 @@ pub fn merge_wavs(input: &std::path::PathBuf, output: &std::path::PathBuf) -> Re writer.finalize()?; Ok(()) } - diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..1e0646c --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,11 @@ +use log::{info, LevelFilter}; + +pub fn init_logging(verbose: bool) { + let mut level = LevelFilter::Error; + if verbose { + level = LevelFilter::Trace; + } + env_logger::builder().filter_level(level).init(); + info!("Initialized logging with log level {}", level) +} + diff --git a/src/main.rs b/src/main.rs index dd904c3..6961b54 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ use clap::{Parser, Subcommand}; -use log::{info, LevelFilter}; use crate::clean::Clean; use crate::import::Import; mod import; mod clean; +mod logging; #[derive(Subcommand)] #[clap(about = "A tool to record audio on Linux using the command line.")] @@ -23,17 +23,14 @@ pub struct Cli { pub commands: Commands, } -fn init_logging() { - env_logger::builder().filter_level(LevelFilter::Trace).init(); - info!("Initialized logging!") -} fn main() { - init_logging(); let commands = Cli::parse(); + match commands.commands { Commands::Import(mut import) => { import.import() } Commands::Clean(mut clean) => { clean.clean() } } } + From 9553614b272a490b6767571b82818acdd0be069a Mon Sep 17 00:00:00 2001 From: Max Winter Date: Mon, 20 Nov 2023 16:24:02 +0100 Subject: [PATCH 10/22] changed print statements to logging in old import logic Signed-off-by: Max Winter --- src/import.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/import.rs b/src/import.rs index 244ac0f..dfc2daa 100644 --- a/src/import.rs +++ b/src/import.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use clap::Parser; use hound::{WavReader, WavWriter}; use indicatif::ProgressBar; +use log::{error, info}; use walkdir::WalkDir; use crate::logging::init_logging; @@ -41,18 +42,18 @@ impl Import { //TODO old logic; has to be changed to match new commands pub fn import(&mut self) { init_logging(self.verbose); - println!("Importing audio from SD card at {:?}", self.device); + info!("Importing audio from SD card at {:?}", self.device); if let Some(output_folder) = &self.output { - println!("Output folder: {:?}", output_folder); + info!("Output folder: {:?}", output_folder); import_from_sd(&mut self.device, Some(output_folder.clone())).unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }); } else { - println!("Output folder: current directory"); + info!("Output folder: current directory"); import_from_sd(&mut self.device, None).unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }); } @@ -63,14 +64,14 @@ impl Import { let output_folder = match self.output.clone() { Some(output_folder) => output_folder, None => std::env::current_dir().unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }) }; for entry in WalkDir::new(output_folder.clone()) { let entry = entry.unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }); let path = entry.path(); @@ -78,11 +79,11 @@ impl Import { let audio_folder = path.join("audio"); if audio_folder.exists() { merge_wavs(&audio_folder, &PathBuf::from(path)).unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }); fs::remove_dir_all(audio_folder).unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }); } @@ -96,7 +97,7 @@ pub fn import_from_sd(sd_card: &mut PathBuf, output_folder: Option) -> let output_folder = match output_folder { Some(output_folder) => output_folder, None => std::env::current_dir().unwrap_or_else(|err| { - eprintln!("Error: {}", err); + error!("Error: {}", err); std::process::exit(1); }) }; From 55c5edbbfe2ae571cb37a4ce4579c7ebf753bde9 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 10:24:31 +0100 Subject: [PATCH 11/22] wip: --verbose option --- src/clean.rs | 8 ++++---- src/import.rs | 5 +++-- src/logging.rs | 14 +++++++++----- src/main.rs | 3 ++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/clean.rs b/src/clean.rs index 131b933..6d946db 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use clap::Parser; -use log::trace; +use log::info; use crate::logging::init_logging; @@ -13,13 +13,13 @@ pub struct Clean { pub device: PathBuf, ///Increases the CLI verbosity. - #[clap(short, long, action)] - pub verbose: bool, + #[clap(short, long, parse(from_occurrences))] + pub verbose: usize, } impl Clean { pub fn clean(&self) { init_logging(self.verbose); - trace!("Cleaning device at {:?}", self.device); + info!("Cleaning device at {:?}", self.device); } } diff --git a/src/import.rs b/src/import.rs index dfc2daa..389b601 100644 --- a/src/import.rs +++ b/src/import.rs @@ -7,6 +7,7 @@ use hound::{WavReader, WavWriter}; use indicatif::ProgressBar; use log::{error, info}; use walkdir::WalkDir; +use crate::Commands::Import; use crate::logging::init_logging; @@ -34,8 +35,8 @@ pub struct Import { pub audio_previews: bool, ///Increases the CLI verbosity. - #[clap(short, long, action)] - pub verbose: bool, + #[clap(short, long, parse(from_occurrences))] + pub verbose: usize, } impl Import { diff --git a/src/logging.rs b/src/logging.rs index 1e0646c..bc320f3 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,10 +1,14 @@ use log::{info, LevelFilter}; -pub fn init_logging(verbose: bool) { - let mut level = LevelFilter::Error; - if verbose { - level = LevelFilter::Trace; - } +pub fn init_logging(verbose: usize) { + let level = match verbose { + 0 => LevelFilter::Error, + 1 => LevelFilter::Warn, + 2 => LevelFilter::Info, + 3 => LevelFilter::Debug, + 4 => LevelFilter::Trace, + _ => LevelFilter::Error + }; env_logger::builder().filter_level(level).init(); info!("Initialized logging with log level {}", level) } diff --git a/src/main.rs b/src/main.rs index 6961b54..3b41651 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,8 @@ fn main() { match commands.commands { - Commands::Import(mut import) => { import.import() } + Commands::Import(mut import) => { + import.import() } Commands::Clean(mut clean) => { clean.clean() } } } From 7e0582e57a846bf42563c23f110ac058318ee919 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 10:58:39 +0100 Subject: [PATCH 12/22] verbosity can now be specified with a string Signed-off-by: Max Winter --- src/clean.rs | 6 +++--- src/import.rs | 7 +++---- src/logging.rs | 16 ++++++++-------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/clean.rs b/src/clean.rs index 6d946db..d971822 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -13,13 +13,13 @@ pub struct Clean { pub device: PathBuf, ///Increases the CLI verbosity. - #[clap(short, long, parse(from_occurrences))] - pub verbose: usize, + #[clap(short, long, default_value = "error")] + pub verbose: String, } impl Clean { pub fn clean(&self) { - init_logging(self.verbose); + init_logging(&self.verbose); info!("Cleaning device at {:?}", self.device); } } diff --git a/src/import.rs b/src/import.rs index 389b601..2ae0b55 100644 --- a/src/import.rs +++ b/src/import.rs @@ -7,7 +7,6 @@ use hound::{WavReader, WavWriter}; use indicatif::ProgressBar; use log::{error, info}; use walkdir::WalkDir; -use crate::Commands::Import; use crate::logging::init_logging; @@ -35,14 +34,14 @@ pub struct Import { pub audio_previews: bool, ///Increases the CLI verbosity. - #[clap(short, long, parse(from_occurrences))] - pub verbose: usize, + #[clap(short, long)] + pub verbose: String, } impl Import { //TODO old logic; has to be changed to match new commands pub fn import(&mut self) { - init_logging(self.verbose); + init_logging(&self.verbose); info!("Importing audio from SD card at {:?}", self.device); if let Some(output_folder) = &self.output { diff --git a/src/logging.rs b/src/logging.rs index bc320f3..636e369 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,13 +1,13 @@ use log::{info, LevelFilter}; -pub fn init_logging(verbose: usize) { - let level = match verbose { - 0 => LevelFilter::Error, - 1 => LevelFilter::Warn, - 2 => LevelFilter::Info, - 3 => LevelFilter::Debug, - 4 => LevelFilter::Trace, - _ => LevelFilter::Error +pub fn init_logging(verbose: &String) { + let level = match verbose.as_str() { + "error" => LevelFilter::Error, + "warn" => LevelFilter::Warn, + "info" => LevelFilter::Info, + "debug" => LevelFilter::Debug, + "trace" => LevelFilter::Trace, + _ => LevelFilter::Error //TODO throw an error }; env_logger::builder().filter_level(level).init(); info!("Initialized logging with log level {}", level) From 4a6eabc8b33256adca24686f2aec8decd6cc7951 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 12:29:00 +0100 Subject: [PATCH 13/22] updated requirements.md to match new verbose command --- Cargo.lock | 404 ++++++++++++++++++++++++++++--------------- docs/requirements.md | 225 ++++++++++++++++++++++++ 2 files changed, 486 insertions(+), 143 deletions(-) create mode 100644 docs/requirements.md diff --git a/Cargo.lock b/Cargo.lock index 7302a94..dac9cbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,52 +12,100 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.70" +name = "anstream" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] [[package]] -name = "bitflags" -version = "1.3.2" +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "bitflags" -version = "2.0.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] -name = "cc" -version = "1.0.79" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.1.11" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ - "bitflags 2.0.2", + "clap_builder", "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "is-terminal", - "once_cell", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.9" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", "syn", @@ -65,24 +113,27 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" -dependencies = [ - "os_str_bytes", -] +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" -version = "0.15.5" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -106,23 +157,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.2.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.48.0", ] [[package]] @@ -133,15 +173,15 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hound" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1" +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" [[package]] name = "humantime" @@ -164,37 +204,35 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.3" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", + "instant", "number_prefix", "portable-atomic", "unicode-width", ] [[package]] -name = "io-lifetimes" -version = "1.0.8" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd6da19f25979c7270e70fa95ab371ec3b701cd0eefc47667a09785b3c59155" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.45.0", + "cfg-if", ] [[package]] name = "is-terminal" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "io-lifetimes", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -205,15 +243,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "log" @@ -233,62 +271,26 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "portable-atomic" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -324,16 +326,15 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustix" -version = "0.36.10" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe885c3a125aa45213b68cc1472a49880cb5923dc23f522ad2791b882228778" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -353,9 +354,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -364,36 +365,36 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] -name = "version_check" -version = "0.9.4" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", @@ -417,9 +418,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -432,26 +433,29 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets 0.42.2", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] @@ -460,13 +464,43 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -475,38 +509,122 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/docs/requirements.md b/docs/requirements.md new file mode 100644 index 0000000..40bade9 --- /dev/null +++ b/docs/requirements.md @@ -0,0 +1,225 @@ +# Hydrophonitor CLI + +Introduces a command line utility called `hp-cli` which interfaces with a Hydrophonitor, a Raspberry Pi based hydrophone passive acoustic monitoring system. + +``` +Usage: hp-cli + +Commands: + import Import data from a hydrophonitor device. + clean Clean a hydrophonitor device. + update Update a hydrophonitor device. + flash Flash a new hydrophonitor device or overwrite an old + installation. + info Get information about the device. + debug DIfferent debugging options for the device. + help Print this message or the help of the given subcommand(s). + +Options: + -h, --help Print help. + --version Print version. +``` + +Example: + +``` +hp-cli import ~/brygga-1 ~/Deployments --clean-imported +[SUCCESS] Import deployment 2023-11-09_11:20:00.097196552+02:00 from brygga-1 to /home/kaskelotti/Deployments/2023-11-09_11:20:00.097196552+02:00 +[SUCCESS] Import deployment 2023-11-09_11:20:00.097196552+02:00 from brygga-1 to /home/kaskelotti/Deployments/2023-11-09_11:20:00.097196552+02:00 +[SUCCESS] Clean device brygga-1 +``` + +## Timestamp + +Timestamp is represented with the following formatting: + +``` +const TIMESTAMP: &str = "%Y-%m-%d_%H:%M:%S.%f%Z"; +``` + +Which will result in the following representation: + +``` +2023-11-09_11:20:00.097196552+02:00 +``` + +- This timestamp is unique because of fractional seconds (the `%f` format qualifier) in case of spurious power cycles which restart the deployment. +- Timestamp is in local time with timezone offset appended to the string. + +How to correctly obtain the time in Rust: + +```rust +use chrono::prelude::*; + +const TIMESTAMP: &str = "%Y-%m-%d_%H:%M:%S.%f%Z"; + +fn main() { + let dt = Local::now(); + println!("{}", dt.format(TIMESTAMP)); +} +``` + +## Supported commands + +### 1. Import + +Introduces the following command: + +``` +Usage: hp-cli import [Options] --device --output + +Options: + -d, --device Path to USB mass storage or SD card where data will be imported from. + -o, --output Path to where the directory for imported data will be created and data will be imported. + --clean-imported Runs a clean after import is complete. + --audio-previews Generates compressed previews of audio + files. + -h, --help Displays help for available commands, all other arguments are ignored. + -v, --verbose Increase CLI verbosity. +``` + +This command imports data from the given device, creating a new directory for each imported deployment at the specified output path. This command does not remove files from the device. + +At the beginning of the import, the CLI lists the deployments it has detected. For each deployment, the size of the deployment folder is printed. A progress bar shows the progress of the import. + +Upon successful import of a single deployment, a metadata file is created. CLI prompts user to fill in optional information. + +The device is attached to the host computer as USB mass storage. It is assumed that the output data is located in `/output` directory at the root of the device file system. This directory contains a timestamp-named directory for each deployment (one boot from startup to shut down). + +``` +/output/ + / + audio/ + _audio.wav + ... + gps/ + _gps.json + ... + depth/ + _depth.csv + log/ + _journalctl.txt + / + ... +``` + +All deployments are imported. The idea is that each deployment would be followed by an import and a cleanup that deletes that deployment from the device. However, one outing with the Hydrophonitor could result in several device restart cycles, so we need to support importing several deployments. + +Imported files are processed as described below, unless option `--debug-import` is given. In that case, all files and directories will be imported from `/output` directory as such. + +An error message will be printed and non-zero exit code returned in case of an error. + +#### Data Formats + +##### Audio + +The audio is recorded in batches (this is done to avoid data corruption in case of an ungraceful shutdown) as wav files in `/output//audio` directory and are merged upon import into one .wav file. + +##### GPS Data + +At the moment of writing, hydrophonitor-gps module records all available data points introduced by gpsd in json files in ``/output//gps` directory. All json files are merged into one json file upon import. + +##### Depth Data + +At the moment of writing, depth-recorder module records depth measurements in a csv file in `/output//depth` directory. If there are multiple csv files, those are merged into one file upon import. + +##### Logs + +During the deployment, journalctl logs are periodically exported to a text file in `/output//log` directory. + +##### Metadata + +When importing a dataset from a deployment, the CLI interface asks the user to fill out optional deployment info. Some of the fields are inferred from the data itself. This data will be saved as `meta.json` file. + +```rust +struct DeploymentInfo { + name: Option, + tags: Option>, + notes: Option, + start: chrono::DateTime, // Inferred from the timestamp of first audio file. + end: chrono::DateTime, // Inferred from the timestamp of last audio file. +} +``` + +#### Imported Data Directory Structure + +``` +/ + metadata.json + audio--.wav + gps--.csv + depth--.csv + journalctl-.log +``` + +### 2. Clean + +Introduces the following command: + +``` +Usage: hp-cli clean [OPTIONS] --device + +Options: + -d, --device Path to USB mass storage or SD card where data will be deleted from. + -h, --help Displays help for available commands. All other arguments are ignored. + -v, --verbose Increase CLI verbosity. +``` + +This command removes all deployment data from the given device's `/output` path. Before starting the removal, the CLI displays all deployments it has detected and prompts the user to confirm that these deployments will be deleted. + +An error message will be printed and non-zero exit code returned in case of an error. + +### 3. Update + +``` +Usage: hp-cli update [OPTIONS] --device + +Options: + -d, --device Path to USB mass storage or SD card where data will be deleted from. + -h, --help Displays help for available commands. All other arguments are ignored. + -v, --verbose Increase CLI verbosity. +``` + +### 4. Flash + +``` +Usage: hp-cli flash [OPTIONS] --device + +Options: + -d, --device Path to USB mass storage or SD card where data will be deleted from. + -h, --help Displays help for available commands. All other arguments are ignored. + -v, --verbose Increase CLI verbosity. +``` + +### 5. Info + +``` +Usage: hp-cli flash [OPTIONS] --device + +Options: + -d, --device Path to USB mass storage or SD card where data will be deleted from. + -h, --help Displays help for available commands. All other arguments are ignored. + -v, --verbose Increase CLI verbosity. +``` + +Example: + +``` +hp info ~/brygga-1 +MODEL: Raspberry Pi 4 +SOUND_CARD: Scarlett USB 2i2 +DEPLOYMENTS: 2023-11-09_11:55:43.007232607+02:00, 2023-11-09_11:55:53.892493975+02:00 +``` + +### 6. Debug + +``` +Usage: hp-cli flash [OPTIONS] --device + +Options: + --import-raw Import output folder from the device as is. + -d, --device Path to USB mass storage or SD card where data will be deleted from. + -h, --help Displays help for available commands. All other arguments are ignored. + -v, --verbose Increase CLI verbosity. +``` + From 290ad25d7eb0299f4dca5138e61ff5067faf6189 Mon Sep 17 00:00:00 2001 From: Satu Koskinen Date: Fri, 17 Nov 2023 21:41:43 +0200 Subject: [PATCH 14/22] Update timestamp format for hydrophonitor files and directories (#3) Signed-off-by: Satu Koskinen --- docs/requirements.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/requirements.md b/docs/requirements.md index 40bade9..f530c90 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -12,7 +12,7 @@ Commands: flash Flash a new hydrophonitor device or overwrite an old installation. info Get information about the device. - debug DIfferent debugging options for the device. + debug Different debugging options for the device. help Print this message or the help of the given subcommand(s). Options: @@ -24,8 +24,8 @@ Example: ``` hp-cli import ~/brygga-1 ~/Deployments --clean-imported -[SUCCESS] Import deployment 2023-11-09_11:20:00.097196552+02:00 from brygga-1 to /home/kaskelotti/Deployments/2023-11-09_11:20:00.097196552+02:00 -[SUCCESS] Import deployment 2023-11-09_11:20:00.097196552+02:00 from brygga-1 to /home/kaskelotti/Deployments/2023-11-09_11:20:00.097196552+02:00 +[SUCCESS] Import deployment 2023-11-09T10_20_01.041+0200 from brygga-1 to /home/kaskelotti/Deployments/2023-11-09T10_20_01.041+0200 +[SUCCESS] Import deployment 2023-11-09T11_20_00.097+0200 from brygga-1 to /home/kaskelotti/Deployments/2023-11-09T11_20_00.097+0200 [SUCCESS] Clean device brygga-1 ``` @@ -34,16 +34,16 @@ hp-cli import ~/brygga-1 ~/Deployments --clean-imported Timestamp is represented with the following formatting: ``` -const TIMESTAMP: &str = "%Y-%m-%d_%H:%M:%S.%f%Z"; +const TIMESTAMP: &str = "%Y-%m-%dT%H_%M_%S%.3f%z"; ``` Which will result in the following representation: ``` -2023-11-09_11:20:00.097196552+02:00 +2023-11-09T11_20_00.097+0200 ``` -- This timestamp is unique because of fractional seconds (the `%f` format qualifier) in case of spurious power cycles which restart the deployment. +- This timestamp is unique because of fractional seconds (the `%.3f` format qualifier, decimal fraction of a second with fixed length of 3 digits) in case of spurious power cycles which restart the deployment. - Timestamp is in local time with timezone offset appended to the string. How to correctly obtain the time in Rust: @@ -51,7 +51,7 @@ How to correctly obtain the time in Rust: ```rust use chrono::prelude::*; -const TIMESTAMP: &str = "%Y-%m-%d_%H:%M:%S.%f%Z"; +const TIMESTAMP: &str = "%Y-%m-%dT%H_%M_%S%.3f%z"; fn main() { let dt = Local::now(); @@ -59,12 +59,16 @@ fn main() { } ``` +How to obtain the time with the `date` command line utility: + +```sh +date +%Y-%m-%dT%H_%M_%S.%3N%z +``` + ## Supported commands ### 1. Import -Introduces the following command: - ``` Usage: hp-cli import [Options] --device --output @@ -105,8 +109,6 @@ The device is attached to the host computer as USB mass storage. It is assumed t All deployments are imported. The idea is that each deployment would be followed by an import and a cleanup that deletes that deployment from the device. However, one outing with the Hydrophonitor could result in several device restart cycles, so we need to support importing several deployments. -Imported files are processed as described below, unless option `--debug-import` is given. In that case, all files and directories will be imported from `/output` directory as such. - An error message will be printed and non-zero exit code returned in case of an error. #### Data Formats @@ -137,7 +139,7 @@ struct DeploymentInfo { tags: Option>, notes: Option, start: chrono::DateTime, // Inferred from the timestamp of first audio file. - end: chrono::DateTime, // Inferred from the timestamp of last audio file. + end: chrono::DateTime, // Inferred from the timestamp and duration of last audio file. } ``` @@ -154,8 +156,6 @@ struct DeploymentInfo { ### 2. Clean -Introduces the following command: - ``` Usage: hp-cli clean [OPTIONS] --device @@ -194,7 +194,7 @@ Options: ### 5. Info ``` -Usage: hp-cli flash [OPTIONS] --device +Usage: hp-cli info [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. @@ -208,13 +208,13 @@ Example: hp info ~/brygga-1 MODEL: Raspberry Pi 4 SOUND_CARD: Scarlett USB 2i2 -DEPLOYMENTS: 2023-11-09_11:55:43.007232607+02:00, 2023-11-09_11:55:53.892493975+02:00 +DEPLOYMENTS: 2023-11-09T11_55_43.007+0200, 2023-11-09T11_55_53.892+0200 ``` ### 6. Debug ``` -Usage: hp-cli flash [OPTIONS] --device +Usage: hp-cli debug [OPTIONS] --device Options: --import-raw Import output folder from the device as is. From df8c2c8cf7e1abb28ad5726d97b3f3515b2ec1b1 Mon Sep 17 00:00:00 2001 From: Julius Koskela <61438579+juliuskoskela@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:34:32 +0200 Subject: [PATCH 15/22] Rust build action for PR checks --- .github/workflows/rust.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..31000a2 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,22 @@ +name: Rust + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose From b856bd4ab707b0c1c49e4a26918a6a032199df58 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 12:19:13 +0100 Subject: [PATCH 16/22] changed verbose command description Signed-off-by: Max Winter --- src/clean.rs | 2 +- src/import.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clean.rs b/src/clean.rs index d971822..78af9c4 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -12,7 +12,7 @@ pub struct Clean { #[clap(short, long, required = true)] pub device: PathBuf, - ///Increases the CLI verbosity. + ///Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. #[clap(short, long, default_value = "error")] pub verbose: String, } diff --git a/src/import.rs b/src/import.rs index 2ae0b55..90e2f03 100644 --- a/src/import.rs +++ b/src/import.rs @@ -33,8 +33,8 @@ pub struct Import { #[clap(long, action)] pub audio_previews: bool, - ///Increases the CLI verbosity. - #[clap(short, long)] + ///Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + #[clap(short, long, default_value = "error")] pub verbose: String, } From 89fbb6965ba37df833ed82cd0d06a1c852c44016 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 12:21:54 +0100 Subject: [PATCH 17/22] updated requirements.md to match new verbose command --- docs/requirements.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/requirements.md b/docs/requirements.md index f530c90..66795f6 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -79,7 +79,7 @@ Options: --audio-previews Generates compressed previews of audio files. -h, --help Displays help for available commands, all other arguments are ignored. - -v, --verbose Increase CLI verbosity. + -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. ``` This command imports data from the given device, creating a new directory for each imported deployment at the specified output path. This command does not remove files from the device. @@ -162,7 +162,7 @@ Usage: hp-cli clean [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Increase CLI verbosity. + -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. ``` This command removes all deployment data from the given device's `/output` path. Before starting the removal, the CLI displays all deployments it has detected and prompts the user to confirm that these deployments will be deleted. @@ -177,7 +177,7 @@ Usage: hp-cli update [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Increase CLI verbosity. + -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. ``` ### 4. Flash @@ -188,7 +188,7 @@ Usage: hp-cli flash [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Increase CLI verbosity. + -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. ``` ### 5. Info @@ -199,7 +199,7 @@ Usage: hp-cli info [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Increase CLI verbosity. + -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. ``` Example: @@ -220,6 +220,6 @@ Options: --import-raw Import output folder from the device as is. -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Increase CLI verbosity. + -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. ``` From 3a33e6159aada1a2047b67d6e191d52f2c6e9af9 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 12:53:41 +0100 Subject: [PATCH 18/22] fixed Cargo.lock file Signed-off-by: Max Winter --- Cargo.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6d05cac..dac9cbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,7 +148,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ - "humantime",parse(from_occurrences) + "humantime", "is-terminal", "log", "regex", @@ -493,6 +493,7 @@ name = "windows-targets" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ "windows_aarch64_gnullvm 0.52.0", "windows_aarch64_msvc 0.52.0", "windows_i686_gnu 0.52.0", From 9b8290a4373afe57116f3e86293e4b179217b4b2 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Tue, 5 Dec 2023 14:46:46 +0100 Subject: [PATCH 19/22] implemented error message for invalid verbose level Signed-off-by: Max Winter --- src/logging.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/logging.rs b/src/logging.rs index 636e369..3cbcace 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,15 +1,23 @@ -use log::{info, LevelFilter}; +use log::{error, info, LevelFilter}; pub fn init_logging(verbose: &String) { + let mut invalid_verbosity = false; let level = match verbose.as_str() { "error" => LevelFilter::Error, "warn" => LevelFilter::Warn, "info" => LevelFilter::Info, "debug" => LevelFilter::Debug, "trace" => LevelFilter::Trace, - _ => LevelFilter::Error //TODO throw an error + _ => { + invalid_verbosity = true; + LevelFilter::Error + } }; env_logger::builder().filter_level(level).init(); - info!("Initialized logging with log level {}", level) + if invalid_verbosity { + error!("Invalid verbosity {verbose}! Using log level 'error' as fallback!") + } else { + info!("Initialized logging with log level {}", level) + } } From 0e7a9ca74eb166a0296d06d36e3ff3446db1281f Mon Sep 17 00:00:00 2001 From: Max Winter Date: Thu, 7 Dec 2023 14:13:25 +0100 Subject: [PATCH 20/22] changed verbose command to use the crate clap_verbosity_flag Signed-off-by: Max Winter --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + src/clean.rs | 7 ------- src/import.rs | 7 ------- src/logging.rs | 23 ----------------------- src/main.rs | 14 ++++++++++---- 6 files changed, 22 insertions(+), 41 deletions(-) delete mode 100644 src/logging.rs diff --git a/Cargo.lock b/Cargo.lock index dac9cbe..0eef580 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,6 +87,16 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-verbosity-flag" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fdbb015d790cfb378aca82caf9cc52a38be96a7eecdb92f31b4366a8afc019" +dependencies = [ + "clap", + "log", +] + [[package]] name = "clap_builder" version = "4.4.7" @@ -195,6 +205,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "clap-verbosity-flag", "env_logger", "hound", "indicatif", diff --git a/Cargo.toml b/Cargo.toml index 9c05caa..ad3ae6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,4 @@ indicatif = "0.17.3" walkdir = "2.3.3" log = "0.4" env_logger = "0.10.1" +clap-verbosity-flag = "2.1.0" \ No newline at end of file diff --git a/src/clean.rs b/src/clean.rs index 78af9c4..eb3ef5a 100644 --- a/src/clean.rs +++ b/src/clean.rs @@ -3,23 +3,16 @@ use std::path::PathBuf; use clap::Parser; use log::info; -use crate::logging::init_logging; - #[derive(Parser, Debug)] #[clap(about = "This command removes all deployment data from the given device's /output path")] pub struct Clean { ///Path to USB mass storage or SD card where data will be deleted from. #[clap(short, long, required = true)] pub device: PathBuf, - - ///Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. - #[clap(short, long, default_value = "error")] - pub verbose: String, } impl Clean { pub fn clean(&self) { - init_logging(&self.verbose); info!("Cleaning device at {:?}", self.device); } } diff --git a/src/import.rs b/src/import.rs index 90e2f03..2d6a141 100644 --- a/src/import.rs +++ b/src/import.rs @@ -8,8 +8,6 @@ use indicatif::ProgressBar; use log::{error, info}; use walkdir::WalkDir; -use crate::logging::init_logging; - const DATA_FOLDER: &str = "home/pi/data"; #[derive(Parser, Debug)] @@ -32,16 +30,11 @@ pub struct Import { ///Generates compressed previews of audio files. #[clap(long, action)] pub audio_previews: bool, - - ///Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. - #[clap(short, long, default_value = "error")] - pub verbose: String, } impl Import { //TODO old logic; has to be changed to match new commands pub fn import(&mut self) { - init_logging(&self.verbose); info!("Importing audio from SD card at {:?}", self.device); if let Some(output_folder) = &self.output { diff --git a/src/logging.rs b/src/logging.rs deleted file mode 100644 index 3cbcace..0000000 --- a/src/logging.rs +++ /dev/null @@ -1,23 +0,0 @@ -use log::{error, info, LevelFilter}; - -pub fn init_logging(verbose: &String) { - let mut invalid_verbosity = false; - let level = match verbose.as_str() { - "error" => LevelFilter::Error, - "warn" => LevelFilter::Warn, - "info" => LevelFilter::Info, - "debug" => LevelFilter::Debug, - "trace" => LevelFilter::Trace, - _ => { - invalid_verbosity = true; - LevelFilter::Error - } - }; - env_logger::builder().filter_level(level).init(); - if invalid_verbosity { - error!("Invalid verbosity {verbose}! Using log level 'error' as fallback!") - } else { - info!("Initialized logging with log level {}", level) - } -} - diff --git a/src/main.rs b/src/main.rs index 3b41651..a65adbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ use clap::{Parser, Subcommand}; +use clap_verbosity_flag::Verbosity; use crate::clean::Clean; use crate::import::Import; mod import; mod clean; -mod logging; #[derive(Subcommand)] #[clap(about = "A tool to record audio on Linux using the command line.")] @@ -21,16 +21,22 @@ pub enum Commands { pub struct Cli { #[clap(subcommand)] pub commands: Commands, + + #[command(flatten)] + pub verbose: Verbosity, } fn main() { - let commands = Cli::parse(); + let commands = Cli::parse().commands; + let verbose = Cli::parse().verbose; + env_logger::builder().filter_level(verbose.log_level_filter()).init(); - match commands.commands { + match commands { Commands::Import(mut import) => { - import.import() } + import.import() + } Commands::Clean(mut clean) => { clean.clean() } } } From b54793d379f7bb6a659fec9a59c4d8135b60effc Mon Sep 17 00:00:00 2001 From: Max Winter Date: Thu, 7 Dec 2023 14:22:50 +0100 Subject: [PATCH 21/22] updated requirements.md to match usage of clap_verbosity_flag --- docs/requirements.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/requirements.md b/docs/requirements.md index ddec406..7988d4a 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -79,7 +79,7 @@ Options: --audio-previews Generates compressed previews of audio files. -h, --help Displays help for available commands, all other arguments are ignored. - -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + -v, --verbose Increase CLI verbosity. ``` @@ -163,7 +163,7 @@ Usage: hp-cli clean [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + -v, --verbose Increase CLI verbosity. ``` This command removes all deployment data from the given device's `/output` path. Before starting the removal, the CLI displays all deployments it has detected and prompts the user to confirm that these deployments will be deleted. @@ -178,7 +178,7 @@ Usage: hp-cli update [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + -v, --verbose Increase CLI verbosity. ``` ### 4. Flash @@ -189,7 +189,7 @@ Usage: hp-cli flash [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + -v, --verbose Increase CLI verbosity. ``` ### 5. Info @@ -200,7 +200,7 @@ Usage: hp-cli info [OPTIONS] --device Options: -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + -v, --verbose Increase CLI verbosity. ``` Example: @@ -221,6 +221,6 @@ Options: --import-raw Import output folder from the device as is. -d, --device Path to USB mass storage or SD card where data will be deleted from. -h, --help Displays help for available commands. All other arguments are ignored. - -v, --verbose Sets the CLI verbosity. Allowed values are 'error', 'warn', 'info', 'debug' and 'trace'. + -v, --verbose Increase CLI verbosity. ``` From 6e1951bdad09b4a7c8445bca615c192513415cc2 Mon Sep 17 00:00:00 2001 From: Max Winter Date: Thu, 7 Dec 2023 17:47:06 +0100 Subject: [PATCH 22/22] refactoring Signed-off-by: Max Winter --- src/main.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index a65adbf..5d6c07f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,16 +28,13 @@ pub struct Cli { fn main() { - let commands = Cli::parse().commands; - let verbose = Cli::parse().verbose; + let Cli { commands, verbose } = Cli::parse(); env_logger::builder().filter_level(verbose.log_level_filter()).init(); match commands { - Commands::Import(mut import) => { - import.import() - } - Commands::Clean(mut clean) => { clean.clean() } + Commands::Import(mut import) => import.import(), + Commands::Clean(mut clean) => clean.clean(), } }