Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flash command #24

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cli/src/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use dialoguer::{Confirm, Select};
use sys_mount::{Mount, UnmountDrop};

use hydrophonitor_lib::connect as connect_lib;
use hydrophonitor_lib::device_type::DeviceType;

//Runs the connect wizard to select and mount the hydrophonitor device. It returns a mount object that defines the lifetime of the mount.
pub fn connect() -> Result<UnmountDrop<Mount>> {
let devices = connect_lib::get_device_list().with_context(|| "Failed to get device list")?;
let devices = connect_lib::get_device_list(DeviceType::Part).with_context(|| "Failed to get device list")?;
let suitable_device = connect_lib::find_suitable_device(&devices).with_context(|| "Getting device failed")?;
let selected_device = match suitable_device {
Some(dev) => {
Expand All @@ -31,7 +32,7 @@ pub fn connect() -> Result<UnmountDrop<Mount>> {
Ok(mount)
}

fn manual_connect(devices: &[String]) -> &String {
pub(crate) fn manual_connect(devices: &[String]) -> &String {
let selection = Select::new()
.with_prompt("Please choose a device from the list:")
.items(devices)
Expand Down
53 changes: 53 additions & 0 deletions cli/src/flash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::path::PathBuf;

use anyhow::{Context, Result};
use clap::Parser;
use dialoguer::Confirm;

use hydrophonitor_lib::connect as connect_lib;
use hydrophonitor_lib::device_type::DeviceType;
use hydrophonitor_lib::flash as flash_lib;

#[derive(Parser, Debug)]
#[clap(about = "This command flashes a SD card or USB mass storage with the selected version of the Hydrophonitor system.")]
pub struct Flash {
///Path to USB mass storage or SD card where the NixOS image will be flashed.
#[clap(short, long)]
device: Option<PathBuf>,

/// Path to the image that will be flashed to the device.
#[clap(short, long, required = true)]
image: PathBuf,
}

impl Flash {
pub fn flash(&mut self) -> Result<()> {
let device_path = match &self.device {
Some(device) => device.clone(),
None => select_device().with_context(|| "Failed to select device")?
};

//Confirmation question
let use_device = Confirm::new()
.with_prompt(format!("Do you really want to flash the Hydrophonitor OS to the device {device_path:?}? All data on this device will be lost!"))
.default(true)
.interact()?;
if !use_device {
println!("Aborting!");
return Ok(());
}

//Flashing
println!("Flashing device {:?} with image {:?}, this may take a while...", &device_path, &self.image);
flash_lib::flash(&self.image, &device_path).with_context(|| "Flashing device failed")?;
Ok(())
}
}

fn select_device() -> Result<PathBuf> {
let devices = connect_lib::get_device_list(DeviceType::Disk).with_context(|| "Failed to get device list")?;
let selected_device = crate::connect::manual_connect(&devices);
Ok(PathBuf::from(format!("/dev/{selected_device}")))
}


4 changes: 4 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ use clap::{Parser, Subcommand};
use clap_verbosity_flag::Verbosity;

use crate::clean::Clean;
use crate::flash::Flash;
use crate::import::Import;

mod import;
mod clean;
mod connect;
mod flash;

#[derive(Subcommand)]
#[clap(about = "A tool to record audio on Linux using the command line.")]
pub enum Commands {
Import(Import),
Clean(Clean),
Flash(Flash),
}


Expand All @@ -36,6 +39,7 @@ fn main() {
let result = match commands {
Commands::Import(mut import) => import.import(),
Commands::Clean(mut clean) => clean.clean(),
Commands::Flash(mut flash) => flash.flash(),
};

if let Err(err) = result {
Expand Down
4 changes: 2 additions & 2 deletions lib/src/clean.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs;
use std::path::PathBuf;

use anyhow::{Context, Error};
use anyhow::{Context, Result};
use log::warn;

pub fn get_deployments_of_device(output_dir: &PathBuf) -> Option<Vec<String>> {
Expand All @@ -21,7 +21,7 @@ pub fn get_deployments_of_device(output_dir: &PathBuf) -> Option<Vec<String>> {
}
}

pub fn clear_directory(output_dir: &PathBuf) -> Result<(), Error> {
pub fn clear_directory(output_dir: &PathBuf) -> Result<()> {
fs::remove_dir_all(output_dir).with_context(|| format!("Removing everything in directory {:?} failed", &output_dir))?;
fs::create_dir(output_dir).with_context(|| format!("Creating new empty output directory in {:?} failed", &output_dir))?;
Ok(())
Expand Down
12 changes: 8 additions & 4 deletions lib/src/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,24 @@ use lazy_static::lazy_static;
use log::debug;
use sys_mount::{Mount, unmount, UnmountDrop, UnmountFlags};

use crate::device_type::DeviceType;

lazy_static! {
pub static ref MOUNT_PATH: PathBuf = PathBuf::from("/var/lib/hydrophonitor/device");
static ref TEMP_MOUNT_PATH: PathBuf = PathBuf::from("/var/lib/hydrophonitor/temp_device");
}

//gets all available devices with lsblk
pub fn get_device_list() -> Result<Vec<String>> {
pub fn get_device_list(device_type: DeviceType) -> Result<Vec<String>> {
let output = Command::new("lsblk").arg("-l").output().with_context(|| "Failed to run lsblk!")?;
let output = String::from_utf8_lossy(&output.stdout);
let devices: Vec<&str> = output.lines().collect();
let mut devices_cropped: Vec<String> = Vec::new();
for device in devices.iter() {
let mut device_columns = device.split_whitespace();
let cropped_device = device_columns.next().unwrap_or_default().to_string();
let device_type = device_columns.nth(4);
if device_type.unwrap_or_default() == "part" {
let actual_device_type = device_columns.nth(4);
if actual_device_type.unwrap_or_default() == device_type.as_str() {
devices_cropped.push(cropped_device);
}
}
Expand Down Expand Up @@ -57,7 +59,9 @@ pub fn find_suitable_device(devices: &[String]) -> Result<Option<&String>> {
}

pub fn mount_device(device: &String) -> Result<UnmountDrop<Mount>> {
if unmount(&*MOUNT_PATH, UnmountFlags::empty()).is_ok() { debug!("unmounting previously mounted device at {:?}", &*MOUNT_PATH) }
if unmount(&*MOUNT_PATH, UnmountFlags::empty()).is_ok() {
debug!("unmounting previously mounted device at {:?}", &*MOUNT_PATH)
}
create_dir_if_not_existing(&MOUNT_PATH).with_context(|| format!("Failed to create dir {:?}", &*MOUNT_PATH))?;

let device_path = format!("/dev/{device}");
Expand Down
14 changes: 14 additions & 0 deletions lib/src/device_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Is used to select which devices of which type should be shown in the connect wizard.
pub enum DeviceType {
Part,
Disk,
}

impl DeviceType {
pub fn as_str(&self) -> &str{
match self {
DeviceType::Disk => "disk",
DeviceType::Part => "part",
}
}
}
18 changes: 18 additions & 0 deletions lib/src/flash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;

use anyhow::Result;

pub fn flash(image_path: &PathBuf, device_path: &PathBuf) -> Result<()> {
let mut source_file = File::open(image_path).expect(&*format!("Failed to open image {:?}!", image_path));
let mut dest_file = File::create(device_path).expect(&*format!("Failed to open device file {:?}!", device_path));
let mut buffer = [0; 4096];
loop {
let bytes_read = source_file.read(&mut buffer).expect("Failed to read bytes from image!");
if bytes_read == 0 {
return Ok(());
}
dest_file.write_all(&buffer[..bytes_read]).expect("Failed to write bytes to device!");
}
}
4 changes: 3 additions & 1 deletion lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub mod import;
pub mod clean;
pub mod connect;
pub mod connect;
pub mod flash;
pub mod device_type;
Loading