refactoring: moved storage related functions to crate storage

This commit is contained in:
qwjyh 2023-08-30 03:05:26 +09:00
parent 78b2d956a7
commit 33e1a9aba7
3 changed files with 124 additions and 109 deletions

View file

@ -30,8 +30,11 @@ use std::{
use std::{fs, io::prelude::*}; use std::{fs, io::prelude::*};
use sysinfo::{Disk, DiskExt, SystemExt}; use sysinfo::{Disk, DiskExt, SystemExt};
use crate::storages::{
get_storages, physical_drive_partition::*, write_storages, Storage, StorageExt, StorageType,
STORAGESFILE,
};
use devices::{Device, DEVICESFILE}; use devices::{Device, DEVICESFILE};
use storages::{physical_drive_partition::*, Storage, StorageExt, StorageType, STORAGESFILE};
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
@ -235,7 +238,10 @@ fn main() -> Result<()> {
let mut sysinfo = sysinfo::System::new_all(); let mut sysinfo = sysinfo::System::new_all();
sysinfo.refresh_disks(); sysinfo.refresh_disks();
let disk = select_sysinfo_disk(&sysinfo)?; let disk = select_sysinfo_disk(&sysinfo)?;
let system_name = disk.name().to_str().context("Failed to convert disk name to valid string")?; let system_name = disk
.name()
.to_str()
.context("Failed to convert disk name to valid string")?;
// add to storages // add to storages
storage.add_alias(disk, &config_dir)?; storage.add_alias(disk, &config_dir)?;
trace!("storage: {}", storage); trace!("storage: {}", storage);
@ -249,9 +255,15 @@ fn main() -> Result<()> {
add_and_commit( add_and_commit(
&repo, &repo,
&Path::new(STORAGESFILE), &Path::new(STORAGESFILE),
&format!("Bound new storage name to physical drive ({})", commit_comment), &format!(
"Bound new storage name to physical drive ({})",
commit_comment
),
)?; )?;
println!("Bound new storage name to physical drive ({})", commit_comment); println!(
"Bound new storage name to physical drive ({})",
commit_comment
);
} }
} }
} }
@ -344,108 +356,6 @@ fn write_devices(config_dir: &Path, devices: Vec<Device>) -> Result<()> {
serde_yaml::to_writer(writer, &devices).map_err(|e| anyhow!(e)) serde_yaml::to_writer(writer, &devices).map_err(|e| anyhow!(e))
} }
/// Interactively select physical storage from available disks in sysinfo.
fn select_physical_storage(
device: Device,
storages: &Vec<Storage>,
) -> Result<PhysicalDrivePartition> {
trace!("select_physical_storage");
// get disk info fron sysinfo
let mut sys_disks = sysinfo::System::new_all();
sys_disks.refresh_disks();
trace!("Available disks");
for disk in sys_disks.disks() {
trace!("{:?}", disk)
}
let disk = select_sysinfo_disk(&sys_disks)?;
// name the disk
let mut disk_name = String::new();
trace!("{}", disk_name);
loop {
disk_name = Text::new("Name for the disk:").prompt()?;
if storages.iter().all(|s| s.name() != &disk_name) {
break;
}
println!("The name {} is already used.", disk_name);
}
trace!("selected name: {}", disk_name);
PhysicalDrivePartition::try_from_sysinfo_disk(&disk, disk_name, device)
}
fn select_sysinfo_disk(sysinfo: &sysinfo::System) -> Result<&Disk> {
let available_disks = sysinfo
.disks()
.iter()
.enumerate()
.map(|(i, disk)| {
let name = match disk.name().to_str() {
Some(s) => s,
None => "",
};
let fs: &str = std::str::from_utf8(disk.file_system()).unwrap_or("unknown");
let kind = format!("{:?}", disk.kind());
let mount_path = disk.mount_point();
let total_space = Byte::from_bytes(disk.total_space().into())
.get_appropriate_unit(true)
.to_string();
format!(
"{}: {} {} ({}, {}) {}",
i,
name,
total_space,
fs,
kind,
mount_path.display()
)
})
.collect();
// select from list
let disk = inquire::Select::new("Select drive:", available_disks).prompt()?;
let disk_num: usize = disk.split(':').next().unwrap().parse().unwrap();
trace!("disk_num: {}", disk_num);
let disk = sysinfo
.disks()
.iter()
.nth(disk_num)
.context("no disk matched with selected one.")?;
trace!("selected disk: {:?}", disk);
Ok(disk)
}
/// Get `Vec<Storage>` from devices.yml([DEVICESFILE]).
/// If [DEVICESFILE] isn't found, return empty vec.
fn get_storages(config_dir: &Path) -> Result<Vec<Storage>> {
if let Some(storages_file) = fs::read_dir(&config_dir)?
.filter(|f| {
f.as_ref().map_or_else(
|_e| false,
|f| {
let storagesfile: OsString = STORAGESFILE.into();
f.path().file_name() == Some(&storagesfile)
},
)
})
.next()
{
trace!("{} found: {:?}", STORAGESFILE, storages_file);
let f = File::open(config_dir.join(STORAGESFILE))?;
let reader = BufReader::new(f);
let yaml: Vec<Storage> =
serde_yaml::from_reader(reader).context("Failed to read devices.yml")?;
Ok(yaml)
} else {
trace!("No {} found", STORAGESFILE);
Ok(vec![])
}
}
/// Write `storages` to yaml file in `config_dir`.
fn write_storages(config_dir: &Path, storages: Vec<Storage>) -> Result<()> {
let f = File::create(config_dir.join(STORAGESFILE))?;
let writer = BufWriter::new(f);
serde_yaml::to_writer(writer, &storages).map_err(|e| anyhow!(e))
}
fn find_last_commit(repo: &Repository) -> Result<Option<Commit>, git2::Error> { fn find_last_commit(repo: &Repository) -> Result<Option<Commit>, git2::Error> {
if repo.is_empty()? { if repo.is_empty()? {
Ok(None) Ok(None)

View file

@ -1,9 +1,10 @@
//! Manipulates storages. //! Manipulates storages.
use anyhow::{anyhow, Context, Result};
use clap::ValueEnum; use clap::ValueEnum;
use physical_drive_partition::PhysicalDrivePartition; use physical_drive_partition::PhysicalDrivePartition;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::{ffi, fmt, fs, path::Path, io};
/// YAML file to store known storages.. /// YAML file to store known storages..
pub const STORAGESFILE: &str = "storages.yml"; pub const STORAGESFILE: &str = "storages.yml";
@ -57,3 +58,37 @@ pub trait StorageExt {
} }
pub mod physical_drive_partition; pub mod physical_drive_partition;
/// Get `Vec<Storage>` from devices.yml([DEVICESFILE]).
/// If [DEVICESFILE] isn't found, return empty vec.
pub fn get_storages(config_dir: &Path) -> Result<Vec<Storage>> {
if let Some(storages_file) = fs::read_dir(&config_dir)?
.filter(|f| {
f.as_ref().map_or_else(
|_e| false,
|f| {
let storagesfile: ffi::OsString = STORAGESFILE.into();
f.path().file_name() == Some(&storagesfile)
},
)
})
.next()
{
trace!("{} found: {:?}", STORAGESFILE, storages_file);
let f = fs::File::open(config_dir.join(STORAGESFILE))?;
let reader = io::BufReader::new(f);
let yaml: Vec<Storage> =
serde_yaml::from_reader(reader).context("Failed to read devices.yml")?;
Ok(yaml)
} else {
trace!("No {} found", STORAGESFILE);
Ok(vec![])
}
}
/// Write `storages` to yaml file in `config_dir`.
pub fn write_storages(config_dir: &Path, storages: Vec<Storage>) -> Result<()> {
let f = fs::File::create(config_dir.join(STORAGESFILE))?;
let writer = io::BufWriter::new(f);
serde_yaml::to_writer(writer, &storages).map_err(|e| anyhow!(e))
}

View file

@ -1,15 +1,16 @@
//! Manipulate partition of physical drive (both removable and unremovable). //! Manipulate partition of physical drive (both removable and unremovable).
use crate::{devices::Device, get_device}; use crate::{devices::Device, get_device};
use crate::storages::StorageExt; use crate::storages::{Storage, StorageExt};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use byte_unit::Byte; use byte_unit::Byte;
use inquire::Text;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{
collections::{hash_map::RandomState, HashMap}, collections::{hash_map::RandomState, HashMap},
fmt, fmt,
}; };
use sysinfo::DiskExt; use sysinfo::{Disk, DiskExt, SystemExt};
/// Partitoin of physical (on-premises) drive. /// Partitoin of physical (on-premises) drive.
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -89,3 +90,72 @@ impl fmt::Display for PhysicalDrivePartition {
) )
} }
} }
/// Interactively select physical storage from available disks in sysinfo.
pub fn select_physical_storage(
device: Device,
storages: &Vec<Storage>,
) -> Result<PhysicalDrivePartition> {
trace!("select_physical_storage");
// get disk info fron sysinfo
let mut sys_disks = sysinfo::System::new_all();
sys_disks.refresh_disks();
trace!("Available disks");
for disk in sys_disks.disks() {
trace!("{:?}", disk)
}
let disk = select_sysinfo_disk(&sys_disks)?;
// name the disk
let mut disk_name = String::new();
trace!("{}", disk_name);
loop {
disk_name = Text::new("Name for the disk:").prompt()?;
if storages.iter().all(|s| s.name() != &disk_name) {
break;
}
println!("The name {} is already used.", disk_name);
}
trace!("selected name: {}", disk_name);
PhysicalDrivePartition::try_from_sysinfo_disk(&disk, disk_name, device)
}
pub fn select_sysinfo_disk(sysinfo: &sysinfo::System) -> Result<&Disk> {
let available_disks = sysinfo
.disks()
.iter()
.enumerate()
.map(|(i, disk)| {
let name = match disk.name().to_str() {
Some(s) => s,
None => "",
};
let fs: &str = std::str::from_utf8(disk.file_system()).unwrap_or("unknown");
let kind = format!("{:?}", disk.kind());
let mount_path = disk.mount_point();
let total_space = byte_unit::Byte::from_bytes(disk.total_space().into())
.get_appropriate_unit(true)
.to_string();
format!(
"{}: {} {} ({}, {}) {}",
i,
name,
total_space,
fs,
kind,
mount_path.display()
)
})
.collect();
// select from list
let disk = inquire::Select::new("Select drive:", available_disks).prompt()?;
let disk_num: usize = disk.split(':').next().unwrap().parse().unwrap();
trace!("disk_num: {}", disk_num);
let disk = sysinfo
.disks()
.iter()
.nth(disk_num)
.context("no disk matched with selected one.")?;
trace!("selected disk: {:?}", disk);
Ok(disk)
}