mirror of
https://github.com/qwjyh/xdbm
synced 2024-11-25 16:11:04 +09:00
refactoring: modularize devices
This commit is contained in:
parent
3648a190b7
commit
26a9d91297
1 changed files with 79 additions and 56 deletions
135
src/main.rs
135
src/main.rs
|
@ -14,10 +14,7 @@ use byte_unit::Byte;
|
||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
use clap_verbosity_flag::Verbosity;
|
use clap_verbosity_flag::Verbosity;
|
||||||
use git2::{Commit, IndexEntry, Oid, Repository};
|
use git2::{Commit, IndexEntry, Oid, Repository};
|
||||||
use inquire::{
|
use inquire::{validator::Validation, Text};
|
||||||
validator::Validation,
|
|
||||||
Text,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_yaml;
|
use serde_yaml;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -31,7 +28,9 @@ use std::{
|
||||||
io::{self, BufWriter},
|
io::{self, BufWriter},
|
||||||
};
|
};
|
||||||
use std::{fs, io::prelude::*};
|
use std::{fs, io::prelude::*};
|
||||||
use sysinfo::{DiskExt, System, SystemExt};
|
use sysinfo::{DiskExt, SystemExt};
|
||||||
|
|
||||||
|
use devices::{Device, DEVICESFILE};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
@ -75,37 +74,53 @@ enum StorageCommands {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
/// Manipulates each client device.
|
||||||
struct Device {
|
mod devices {
|
||||||
name: String,
|
|
||||||
os_name: String,
|
|
||||||
os_version: String,
|
|
||||||
hostname: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device {
|
use serde::{Deserialize, Serialize};
|
||||||
fn new(name: String) -> Device {
|
use sysinfo::{System, SystemExt};
|
||||||
let sys = System::new();
|
|
||||||
Device {
|
/// YAML file to store known devices.
|
||||||
name: name,
|
pub const DEVICESFILE: &str = "devices.yml";
|
||||||
os_name: sys.name().unwrap_or_else(|| {
|
|
||||||
warn!("Failed to get OS name. Saving as \"unknown\".");
|
/// Represents each devices.
|
||||||
"unknown".to_string()
|
/// Identified by name, which is accessible from `name()`.
|
||||||
}),
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
os_version: sys.os_version().unwrap_or_else(|| {
|
pub struct Device {
|
||||||
warn!("Failed to get OS version. Saving as \"unknown\".");
|
name: String,
|
||||||
"unknown".to_string()
|
os_name: String,
|
||||||
}),
|
os_version: String,
|
||||||
hostname: sys.host_name().unwrap_or_else(|| {
|
hostname: String,
|
||||||
warn!("Failed to get hostname. Saving as \"unknown\".");
|
}
|
||||||
"unknown".to_string()
|
|
||||||
}),
|
impl Device {
|
||||||
|
/// Create new `Device` of name `name`. Additional data is obtained via sysinfo.
|
||||||
|
pub fn new(name: String) -> Device {
|
||||||
|
let sys = System::new();
|
||||||
|
Device {
|
||||||
|
name: name,
|
||||||
|
os_name: sys.name().unwrap_or_else(|| {
|
||||||
|
warn!("Failed to get OS name. Saving as \"unknown\".");
|
||||||
|
"unknown".to_string()
|
||||||
|
}),
|
||||||
|
os_version: sys.os_version().unwrap_or_else(|| {
|
||||||
|
warn!("Failed to get OS version. Saving as \"unknown\".");
|
||||||
|
"unknown".to_string()
|
||||||
|
}),
|
||||||
|
hostname: sys.host_name().unwrap_or_else(|| {
|
||||||
|
warn!("Failed to get hostname. Saving as \"unknown\".");
|
||||||
|
"unknown".to_string()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get name.
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.name.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEVICESFILE: &str = "devices.yml";
|
|
||||||
|
|
||||||
#[derive(ValueEnum, Clone, Copy, Debug)]
|
#[derive(ValueEnum, Clone, Copy, Debug)]
|
||||||
enum StorageType {
|
enum StorageType {
|
||||||
Physical,
|
Physical,
|
||||||
|
@ -166,7 +181,7 @@ impl PhysicalDrivePartition {
|
||||||
capacity: disk.total_space(),
|
capacity: disk.total_space(),
|
||||||
fs: fs.to_string(),
|
fs: fs.to_string(),
|
||||||
is_removable: disk.is_removable(),
|
is_removable: disk.is_removable(),
|
||||||
system_names: HashMap::from([(device.name, alias)]),
|
system_names: HashMap::from([(device.name(), alias)]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +199,7 @@ impl PhysicalDrivePartition {
|
||||||
None => return Err("Failed to convert storage name to valid str.".to_string()),
|
None => return Err("Failed to convert storage name to valid str.".to_string()),
|
||||||
};
|
};
|
||||||
let mut aliases = self.system_names;
|
let mut aliases = self.system_names;
|
||||||
let _ = match aliases.insert(device.name, alias) {
|
let _ = match aliases.insert(device.name(), alias) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Err("Failed to insert alias".to_string()),
|
None => return Err("Failed to insert alias".to_string()),
|
||||||
};
|
};
|
||||||
|
@ -258,7 +273,7 @@ fn main() -> Result<()> {
|
||||||
{
|
{
|
||||||
let f = File::create(devname_path).context("Failed to create devname file")?;
|
let f = File::create(devname_path).context("Failed to create devname file")?;
|
||||||
let writer = BufWriter::new(f);
|
let writer = BufWriter::new(f);
|
||||||
serde_yaml::to_writer(writer, &device.name).unwrap();
|
serde_yaml::to_writer(writer, &device.name()).unwrap();
|
||||||
};
|
};
|
||||||
full_status(&repo)?;
|
full_status(&repo)?;
|
||||||
|
|
||||||
|
@ -269,7 +284,7 @@ fn main() -> Result<()> {
|
||||||
} else {
|
} else {
|
||||||
get_devices(&config_dir)?
|
get_devices(&config_dir)?
|
||||||
};
|
};
|
||||||
if devices.iter().any(|x| x.name == device.name) {
|
if devices.iter().any(|x| x.name() == device.name()) {
|
||||||
return Err(anyhow!("device name is already used."));
|
return Err(anyhow!("device name is already used."));
|
||||||
}
|
}
|
||||||
devices.push(device.clone());
|
devices.push(device.clone());
|
||||||
|
@ -282,10 +297,10 @@ fn main() -> Result<()> {
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
&Path::new(DEVICESFILE),
|
&Path::new(DEVICESFILE),
|
||||||
&format!("Add new devname: {}", &device.name),
|
&format!("Add new devname: {}", &device.name()),
|
||||||
)?;
|
)?;
|
||||||
full_status(&repo)?;
|
full_status(&repo)?;
|
||||||
},
|
}
|
||||||
Commands::Storage(storage) => match storage.command {
|
Commands::Storage(storage) => match storage.command {
|
||||||
StorageCommands::Add { storage_type } => {
|
StorageCommands::Add { storage_type } => {
|
||||||
trace!("Storage Add {:?}", storage_type);
|
trace!("Storage Add {:?}", storage_type);
|
||||||
|
@ -294,17 +309,18 @@ fn main() -> Result<()> {
|
||||||
match storage_type {
|
match storage_type {
|
||||||
StorageType::Physical => {
|
StorageType::Physical => {
|
||||||
// Get storages
|
// Get storages
|
||||||
let mut storages: Vec<Storage> = if let Some(storages_file) = fs::read_dir(&config_dir)?
|
let mut storages: Vec<Storage> = if let Some(storages_file) =
|
||||||
.filter(|f| {
|
fs::read_dir(&config_dir)?
|
||||||
f.as_ref().map_or_else(
|
.filter(|f| {
|
||||||
|_e| false,
|
f.as_ref().map_or_else(
|
||||||
|f| {
|
|_e| false,
|
||||||
let storagesfile: OsString = STORAGESFILE.into();
|
|f| {
|
||||||
f.path().file_name() == Some(&storagesfile)
|
let storagesfile: OsString = STORAGESFILE.into();
|
||||||
},
|
f.path().file_name() == Some(&storagesfile)
|
||||||
)
|
},
|
||||||
})
|
)
|
||||||
.next()
|
})
|
||||||
|
.next()
|
||||||
{
|
{
|
||||||
trace!("{} found: {:?}", STORAGESFILE, storages_file);
|
trace!("{} found: {:?}", STORAGESFILE, storages_file);
|
||||||
get_storages(&config_dir)?
|
get_storages(&config_dir)?
|
||||||
|
@ -328,7 +344,11 @@ fn main() -> Result<()> {
|
||||||
write_storages(&config_dir, storages)?;
|
write_storages(&config_dir, storages)?;
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
add_and_commit(&repo, &Path::new(STORAGESFILE), &format!("Add new storage(physical drive): {}", new_storage_name))?;
|
add_and_commit(
|
||||||
|
&repo,
|
||||||
|
&Path::new(STORAGESFILE),
|
||||||
|
&format!("Add new storage(physical drive): {}", new_storage_name),
|
||||||
|
)?;
|
||||||
|
|
||||||
println!("Added new storage.");
|
println!("Added new storage.");
|
||||||
trace!("Finished adding storage");
|
trace!("Finished adding storage");
|
||||||
|
@ -338,10 +358,10 @@ fn main() -> Result<()> {
|
||||||
},
|
},
|
||||||
Commands::Path {} => {
|
Commands::Path {} => {
|
||||||
println!("{}", &config_dir.display());
|
println!("{}", &config_dir.display());
|
||||||
},
|
}
|
||||||
Commands::Sync {} => {
|
Commands::Sync {} => {
|
||||||
unimplemented!("Sync is not implemented")
|
unimplemented!("Sync is not implemented")
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
full_status(&Repository::open(&config_dir)?)?;
|
full_status(&Repository::open(&config_dir)?)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -367,7 +387,7 @@ fn get_device(config_dir: &Path) -> Result<Device> {
|
||||||
trace!("devices: {:?}", devices);
|
trace!("devices: {:?}", devices);
|
||||||
devices
|
devices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|dev| dev.name == devname)
|
.filter(|dev| dev.name() == devname)
|
||||||
.next()
|
.next()
|
||||||
.context("Couldn't find Device in devices.yml")
|
.context("Couldn't find Device in devices.yml")
|
||||||
}
|
}
|
||||||
|
@ -426,7 +446,10 @@ fn write_devices(config_dir: &Path, devices: Vec<Device>) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interactively select physical storage from available disks in sysinfo.
|
/// Interactively select physical storage from available disks in sysinfo.
|
||||||
fn select_physical_storage(device: Device, storages: &Vec<Storage>) -> Result<PhysicalDrivePartition> {
|
fn select_physical_storage(
|
||||||
|
device: Device,
|
||||||
|
storages: &Vec<Storage>,
|
||||||
|
) -> Result<PhysicalDrivePartition> {
|
||||||
trace!("select_physical_storage");
|
trace!("select_physical_storage");
|
||||||
// get disk info fron sysinfo
|
// get disk info fron sysinfo
|
||||||
let mut sys_disks = sysinfo::System::new_all();
|
let mut sys_disks = sysinfo::System::new_all();
|
||||||
|
@ -477,16 +500,16 @@ fn select_physical_storage(device: Device, storages: &Vec<Storage>) -> Result<Ph
|
||||||
trace!("{}", disk_name);
|
trace!("{}", disk_name);
|
||||||
loop {
|
loop {
|
||||||
disk_name = Text::new("Name for the disk:").prompt()?;
|
disk_name = Text::new("Name for the disk:").prompt()?;
|
||||||
if storages.iter().all(|s| {s.name() != &disk_name}) {
|
if storages.iter().all(|s| s.name() != &disk_name) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
println!("The name {} is already used.", disk_name);
|
println!("The name {} is already used.", disk_name);
|
||||||
};
|
}
|
||||||
trace!("selected name: {}", disk_name);
|
trace!("selected name: {}", disk_name);
|
||||||
PhysicalDrivePartition::try_from_sysinfo_disk(disk, disk_name, device)
|
PhysicalDrivePartition::try_from_sysinfo_disk(disk, disk_name, device)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get Vec<Storage> from devices.yml([DEVICESFILE])
|
/// Get `Vec<Storage>` from devices.yml([DEVICESFILE])
|
||||||
fn get_storages(config_dir: &Path) -> Result<Vec<Storage>> {
|
fn get_storages(config_dir: &Path) -> Result<Vec<Storage>> {
|
||||||
let f = File::open(config_dir.join(STORAGESFILE))?;
|
let f = File::open(config_dir.join(STORAGESFILE))?;
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
|
|
Loading…
Reference in a new issue