mirror of
https://github.com/qwjyh/xdbm
synced 2024-11-22 06:40:12 +09:00
add for online, refactored bind
This commit is contained in:
parent
017e34d392
commit
5f81eccd2d
7 changed files with 175 additions and 57 deletions
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# TODO:
|
||||||
|
- [ ] reorganize cmd option for storage
|
||||||
|
- [ ] use subcommand
|
75
src/main.rs
75
src/main.rs
|
@ -31,6 +31,7 @@ use std::{fs, io::prelude::*};
|
||||||
use sysinfo::{Disk, DiskExt, SystemExt};
|
use sysinfo::{Disk, DiskExt, SystemExt};
|
||||||
|
|
||||||
use crate::inquire_filepath_completer::FilePathCompleter;
|
use crate::inquire_filepath_completer::FilePathCompleter;
|
||||||
|
use crate::storages::online_storage::OnlineStorage;
|
||||||
use crate::storages::{
|
use crate::storages::{
|
||||||
directory::Directory, get_storages, local_info, online_storage, physical_drive_partition::*,
|
directory::Directory, get_storages, local_info, online_storage, physical_drive_partition::*,
|
||||||
write_storages, Storage, StorageExt, StorageType, STORAGESFILE,
|
write_storages, Storage, StorageExt, StorageType, STORAGESFILE,
|
||||||
|
@ -89,9 +90,18 @@ enum StorageCommands {
|
||||||
},
|
},
|
||||||
/// List all storages.
|
/// List all storages.
|
||||||
List {},
|
List {},
|
||||||
/// Add new device-specific name to existing storage.
|
/// Make `storage` available for the current device.
|
||||||
/// For physical disk, the name is taken from system info automatically.
|
/// For physical disk, the name is taken from system info automatically.
|
||||||
Bind { storage: String },
|
Bind {
|
||||||
|
/// Name of the storage.
|
||||||
|
storage: String,
|
||||||
|
/// Device specific alias for the storage.
|
||||||
|
#[arg(short, long)]
|
||||||
|
alias: String,
|
||||||
|
/// Mount point on this device.
|
||||||
|
#[arg(short, long)]
|
||||||
|
path: path::PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
mod devices;
|
mod devices;
|
||||||
|
@ -296,7 +306,40 @@ fn main() -> Result<()> {
|
||||||
)?;
|
)?;
|
||||||
(key_name, Storage::SubDirectory(storage))
|
(key_name, Storage::SubDirectory(storage))
|
||||||
}
|
}
|
||||||
StorageType::Online => todo!(),
|
StorageType::Online => {
|
||||||
|
let path = path.unwrap_or_else(|| {
|
||||||
|
let mut cmd = Cli::command();
|
||||||
|
cmd.error(
|
||||||
|
ErrorKind::MissingRequiredArgument,
|
||||||
|
"<PATH> is required with sub-directory",
|
||||||
|
)
|
||||||
|
.exit();
|
||||||
|
});
|
||||||
|
let mut name = String::new();
|
||||||
|
loop {
|
||||||
|
name = Text::new("Name for the storage:")
|
||||||
|
.with_validator(min_length!(0, "At least 1 character"))
|
||||||
|
.prompt()
|
||||||
|
.context("Failed to get Name")?;
|
||||||
|
if storages.iter().all(|(k, _v)| k != &name) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
println!("The name {} is already used.", name);
|
||||||
|
}
|
||||||
|
let provider = Text::new("Provider:").prompt().context("Failed to get provider")?;
|
||||||
|
let capacity: u64 = CustomType::<u64>::new("Capacity (byte):")
|
||||||
|
.with_error_message("Please type number.")
|
||||||
|
.prompt()
|
||||||
|
.context("Failed to get capacity.")?;
|
||||||
|
let alias = Text::new("Alias:").prompt().context("Failed to get provider")?;
|
||||||
|
let storage = OnlineStorage::new(
|
||||||
|
name.clone(), provider, capacity, alias, path, &device,
|
||||||
|
);
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
Storage::Online(storage),
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// add to storages
|
// add to storages
|
||||||
|
@ -328,26 +371,26 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
StorageCommands::Bind {
|
StorageCommands::Bind {
|
||||||
storage: storage_name,
|
storage: storage_name,
|
||||||
|
alias: new_alias,
|
||||||
|
path: mount_point,
|
||||||
} => {
|
} => {
|
||||||
|
let device = get_device(&config_dir)?;
|
||||||
// get storages
|
// get storages
|
||||||
let mut storages: HashMap<String, Storage> = get_storages(&config_dir)?;
|
let mut storages: HashMap<String, Storage> = get_storages(&config_dir)?;
|
||||||
let commit_comment = {
|
let commit_comment = {
|
||||||
// find matching storage
|
// find matching storage
|
||||||
let storage = storages
|
let storage = &mut storages
|
||||||
.get_mut(&storage_name)
|
.get_mut(&storage_name)
|
||||||
.context(format!("No storage has name {}", storage_name))?;
|
.context(format!("No storage has name {}", storage_name))?;
|
||||||
// get disk from sysinfo
|
let old_alias = storage
|
||||||
let mut sysinfo = sysinfo::System::new_all();
|
.local_info(&device)
|
||||||
sysinfo.refresh_disks();
|
.context(format!("Failed to get LocalInfo for {}", storage.name()))?
|
||||||
let disk = select_sysinfo_disk(&sysinfo)?;
|
.alias()
|
||||||
let system_name = disk
|
.clone();
|
||||||
.name()
|
// TODO: get mount path for directory automatically?
|
||||||
.to_str()
|
storage.bound_on_device(new_alias, mount_point, &device)?;
|
||||||
.context("Failed to convert disk name to valid string")?;
|
// trace!("storage: {}", &storage);
|
||||||
// add to storages
|
format!("{} to {}", old_alias, storage.name())
|
||||||
storage.bind_device(disk, &config_dir)?;
|
|
||||||
trace!("storage: {}", storage);
|
|
||||||
format!("{} to {}", system_name, storage.name())
|
|
||||||
};
|
};
|
||||||
trace!("bound new system name to the storage");
|
trace!("bound new system name to the storage");
|
||||||
trace!("storages: {:#?}", storages);
|
trace!("storages: {:#?}", storages);
|
||||||
|
|
|
@ -27,20 +27,7 @@ pub enum Storage {
|
||||||
Online(OnlineStorage),
|
Online(OnlineStorage),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Storage {
|
impl Storage {}
|
||||||
/// Add or update alias of `disk` for current device.
|
|
||||||
pub fn bind_device(
|
|
||||||
&mut self,
|
|
||||||
disk: &sysinfo::Disk,
|
|
||||||
config_dir: &std::path::PathBuf,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
match self {
|
|
||||||
Self::PhysicalStorage(s) => s.bind_device(disk, config_dir),
|
|
||||||
Self::SubDirectory(_) => Err(anyhow!("SubDirectory doesn't have system alias.")),
|
|
||||||
Self::Online(_) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StorageExt for Storage {
|
impl StorageExt for Storage {
|
||||||
fn name(&self) -> &String {
|
fn name(&self) -> &String {
|
||||||
|
@ -51,11 +38,11 @@ impl StorageExt for Storage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_alias(&self, device: &devices::Device) -> bool {
|
fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo> {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(s) => s.has_alias(&device),
|
Self::PhysicalStorage(s) => s.local_info(device),
|
||||||
Self::SubDirectory(s) => s.has_alias(&device),
|
Self::SubDirectory(s) => s.local_info(device),
|
||||||
Self::Online(s) => s.has_alias(&device),
|
Self::Online(s) => s.local_info(device),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +57,19 @@ impl StorageExt for Storage {
|
||||||
Self::Online(s) => s.mount_path(&device, &storages),
|
Self::Online(s) => s.mount_path(&device, &storages),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bound_on_device(
|
||||||
|
&mut self,
|
||||||
|
alias: String,
|
||||||
|
mount_point: path::PathBuf,
|
||||||
|
device: &devices::Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Storage::PhysicalStorage(s) => s.bound_on_device(alias, mount_point, device),
|
||||||
|
Storage::SubDirectory(s) => s.bound_on_device(alias, mount_point, device),
|
||||||
|
Storage::Online(s) => s.bound_on_device(alias, mount_point, device),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Storage {
|
impl fmt::Display for Storage {
|
||||||
|
@ -85,13 +85,30 @@ impl fmt::Display for Storage {
|
||||||
/// Trait to manipulate all `Storage`s (Enums).
|
/// Trait to manipulate all `Storage`s (Enums).
|
||||||
pub trait StorageExt {
|
pub trait StorageExt {
|
||||||
fn name(&self) -> &String;
|
fn name(&self) -> &String;
|
||||||
fn has_alias(&self, device: &devices::Device) -> bool;
|
|
||||||
|
/// Return `true` if `self` has local info on the `device`.
|
||||||
|
/// Used to check if the storage is bound on the `device`.
|
||||||
|
fn has_alias(&self, device: &devices::Device) -> bool {
|
||||||
|
self.local_info(device).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get local info of `device`.
|
||||||
|
fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo>;
|
||||||
|
|
||||||
/// Get mount path of `self` on `device`.
|
/// Get mount path of `self` on `device`.
|
||||||
fn mount_path(
|
fn mount_path(
|
||||||
&self,
|
&self,
|
||||||
device: &devices::Device,
|
device: &devices::Device,
|
||||||
storages: &HashMap<String, Storage>,
|
storages: &HashMap<String, Storage>,
|
||||||
) -> Result<path::PathBuf>;
|
) -> Result<path::PathBuf>;
|
||||||
|
|
||||||
|
/// Add local info of `device` to `self`.
|
||||||
|
fn bound_on_device(
|
||||||
|
&mut self,
|
||||||
|
alias: String,
|
||||||
|
mount_point: path::PathBuf,
|
||||||
|
device: &devices::Device,
|
||||||
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod directory;
|
pub mod directory;
|
||||||
|
|
|
@ -104,16 +104,6 @@ impl Directory {
|
||||||
let parent_mount_path = parent.mount_path(&device, &storages)?;
|
let parent_mount_path = parent.mount_path(&device, &storages)?;
|
||||||
Ok(parent_mount_path.join(self.relative_path.clone()))
|
Ok(parent_mount_path.join(self.relative_path.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind_device(&mut self, alias: String, device: &devices::Device, storages: &HashMap<String, Storage>) -> Result<()> {
|
|
||||||
let mount_path = self.mount_path(&device, &storages)?;
|
|
||||||
let new_local_info = LocalInfo::new(alias, mount_path);
|
|
||||||
match self.local_info.insert(device.name(), new_local_info) {
|
|
||||||
Some(v) => println!("Value updated. old val is: {:?}", v),
|
|
||||||
None => println!("inserted new val"),
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StorageExt for Directory {
|
impl StorageExt for Directory {
|
||||||
|
@ -121,8 +111,8 @@ impl StorageExt for Directory {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_alias(&self, device: &devices::Device) -> bool {
|
fn local_info(&self, device: &devices::Device) -> Option<&LocalInfo> {
|
||||||
self.local_info.get(&device.name()).is_some()
|
self.local_info.get(&device.name())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mount_path(
|
fn mount_path(
|
||||||
|
@ -132,6 +122,21 @@ impl StorageExt for Directory {
|
||||||
) -> Result<path::PathBuf> {
|
) -> Result<path::PathBuf> {
|
||||||
Ok(self.mount_path(device, storages)?)
|
Ok(self.mount_path(device, storages)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method doesn't use `mount_path`.
|
||||||
|
fn bound_on_device(
|
||||||
|
&mut self,
|
||||||
|
alias: String,
|
||||||
|
mount_point: path::PathBuf,
|
||||||
|
device: &devices::Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
let new_local_info = LocalInfo::new(alias, mount_point);
|
||||||
|
match self.local_info.insert(device.name(), new_local_info) {
|
||||||
|
Some(v) => println!("Value updated. old val is: {:?}", v),
|
||||||
|
None => println!("inserted new val"),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Directory {
|
impl fmt::Display for Directory {
|
||||||
|
|
|
@ -18,6 +18,10 @@ impl LocalInfo {
|
||||||
LocalInfo { alias, mount_path }
|
LocalInfo { alias, mount_path }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn alias(&self) -> String {
|
||||||
|
self.alias.clone() // ?
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mount_path(&self) -> path::PathBuf {
|
pub fn mount_path(&self) -> path::PathBuf {
|
||||||
self.mount_path.clone()
|
self.mount_path.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Online storage which is not a children of any physical drive.
|
//! Online storage which is not a children of any physical drive.
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::{Context, Result};
|
||||||
use byte_unit::Byte;
|
use byte_unit::Byte;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -9,6 +9,7 @@ use std::path;
|
||||||
|
|
||||||
use crate::devices;
|
use crate::devices;
|
||||||
|
|
||||||
|
use super::local_info;
|
||||||
use super::local_info::LocalInfo;
|
use super::local_info::LocalInfo;
|
||||||
use super::StorageExt;
|
use super::StorageExt;
|
||||||
|
|
||||||
|
@ -16,13 +17,26 @@ use super::StorageExt;
|
||||||
pub struct OnlineStorage {
|
pub struct OnlineStorage {
|
||||||
name: String,
|
name: String,
|
||||||
provider: String,
|
provider: String,
|
||||||
capacity: u8,
|
capacity: u64,
|
||||||
local_info: HashMap<String, LocalInfo>,
|
local_info: HashMap<String, LocalInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OnlineStorage {
|
impl OnlineStorage {
|
||||||
fn new(name: String, provider: String, capacity: u8, path: path::PathBuf, device: &devices::Device) -> OnlineStorage {
|
pub fn new(
|
||||||
todo!()
|
name: String,
|
||||||
|
provider: String,
|
||||||
|
capacity: u64,
|
||||||
|
alias: String,
|
||||||
|
path: path::PathBuf,
|
||||||
|
device: &devices::Device,
|
||||||
|
) -> OnlineStorage {
|
||||||
|
let local_info = local_info::LocalInfo::new(alias, path);
|
||||||
|
OnlineStorage {
|
||||||
|
name,
|
||||||
|
provider,
|
||||||
|
capacity,
|
||||||
|
local_info: HashMap::from([(device.name(), local_info)]),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,8 +45,8 @@ impl StorageExt for OnlineStorage {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_alias(&self, device: &devices::Device) -> bool {
|
fn local_info(&self, device: &devices::Device) -> Option<&LocalInfo> {
|
||||||
self.local_info.get(&device.name()).is_some()
|
self.local_info.get(&device.name())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mount_path(
|
fn mount_path(
|
||||||
|
@ -46,6 +60,22 @@ impl StorageExt for OnlineStorage {
|
||||||
.context(format!("LocalInfo for storage: {} not found", &self.name()))?
|
.context(format!("LocalInfo for storage: {} not found", &self.name()))?
|
||||||
.mount_path())
|
.mount_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bound_on_device(
|
||||||
|
&mut self,
|
||||||
|
alias: String,
|
||||||
|
mount_point: path::PathBuf,
|
||||||
|
device: &devices::Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self
|
||||||
|
.local_info
|
||||||
|
.insert(device.name(), LocalInfo::new(alias, mount_point))
|
||||||
|
{
|
||||||
|
Some(old) => info!("Value replaced. Old value: {:?}", old),
|
||||||
|
None => info!("New value inserted."),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for OnlineStorage {
|
impl fmt::Display for OnlineStorage {
|
||||||
|
|
|
@ -36,7 +36,7 @@ impl PhysicalDrivePartition {
|
||||||
fs: String,
|
fs: String,
|
||||||
is_removable: bool,
|
is_removable: bool,
|
||||||
local_info: LocalInfo,
|
local_info: LocalInfo,
|
||||||
device: &Device
|
device: &Device,
|
||||||
) -> PhysicalDrivePartition {
|
) -> PhysicalDrivePartition {
|
||||||
PhysicalDrivePartition {
|
PhysicalDrivePartition {
|
||||||
name,
|
name,
|
||||||
|
@ -101,8 +101,8 @@ impl StorageExt for PhysicalDrivePartition {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_alias(&self, device: &devices::Device) -> bool {
|
fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo> {
|
||||||
self.local_info.get(&device.name()).is_some()
|
self.local_info.get(&device.name())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mount_path(
|
fn mount_path(
|
||||||
|
@ -116,6 +116,22 @@ impl StorageExt for PhysicalDrivePartition {
|
||||||
.context(format!("LocalInfo for storage: {} not found", &self.name()))?
|
.context(format!("LocalInfo for storage: {} not found", &self.name()))?
|
||||||
.mount_path())
|
.mount_path())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bound_on_device(
|
||||||
|
&mut self,
|
||||||
|
alias: String,
|
||||||
|
mount_point: path::PathBuf,
|
||||||
|
device: &devices::Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
match self
|
||||||
|
.local_info
|
||||||
|
.insert(device.name(), LocalInfo::new(alias, mount_point))
|
||||||
|
{
|
||||||
|
Some(old) => info!("Value replaced. Old value: {:?}", old),
|
||||||
|
None => info!("New value inserted."),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PhysicalDrivePartition {
|
impl fmt::Display for PhysicalDrivePartition {
|
||||||
|
@ -141,7 +157,7 @@ pub fn select_physical_storage(
|
||||||
) -> Result<(String, PhysicalDrivePartition)> {
|
) -> Result<(String, PhysicalDrivePartition)> {
|
||||||
trace!("select_physical_storage");
|
trace!("select_physical_storage");
|
||||||
// get disk info fron sysinfo
|
// get disk info fron sysinfo
|
||||||
let mut sys_disks =
|
let sys_disks =
|
||||||
sysinfo::System::new_with_specifics(sysinfo::RefreshKind::new().with_disks_list());
|
sysinfo::System::new_with_specifics(sysinfo::RefreshKind::new().with_disks_list());
|
||||||
trace!("refresh");
|
trace!("refresh");
|
||||||
// sys_disks.refresh_disks_list();
|
// sys_disks.refresh_disks_list();
|
||||||
|
|
Loading…
Reference in a new issue