mirror of
https://github.com/qwjyh/xdbm
synced 2024-11-22 14:50:12 +09:00
new: storage add (git is not working)
This commit is contained in:
parent
2a1854c488
commit
db09897b5a
3 changed files with 264 additions and 92 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -59,6 +59,12 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.75"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -77,6 +83,16 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-unit"
|
||||||
|
version = "4.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da78b32057b8fdfc352504708feeba7216dcd65a2c9ab02978cbd288d1279b6c"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"utf8-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.83"
|
version = "1.0.83"
|
||||||
|
@ -931,6 +947,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-width"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1050,6 +1072,8 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
name = "xdbm"
|
name = "xdbm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"byte-unit",
|
||||||
"clap",
|
"clap",
|
||||||
"clap-verbosity-flag",
|
"clap-verbosity-flag",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
|
|
@ -16,3 +16,5 @@ git2 = "0.17.2"
|
||||||
dirs = "5.0"
|
dirs = "5.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
|
byte-unit = "4.0.19"
|
||||||
|
anyhow = "1.0"
|
||||||
|
|
324
src/main.rs
324
src/main.rs
|
@ -1,25 +1,36 @@
|
||||||
|
//! # Main variables
|
||||||
|
//! * [Device]: represents PC.
|
||||||
|
//! * [Storage]: all storages
|
||||||
|
//! * [PhysicalDrivePartition]: partition on a physical disk.
|
||||||
|
//!
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
extern crate dirs;
|
extern crate dirs;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
use byte_unit::Byte;
|
||||||
|
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::{StringValidator, Validation},
|
validator::Validation,
|
||||||
Text,
|
Text,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_yaml;
|
use serde_yaml;
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::io::{self, BufWriter};
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::RandomState, HashMap},
|
collections::{hash_map::RandomState, HashMap},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
};
|
};
|
||||||
use std::{env, io::BufReader, path::Path};
|
use std::{env, io::BufReader, path::Path};
|
||||||
|
use std::{
|
||||||
|
ffi::OsString,
|
||||||
|
io::{self, BufWriter},
|
||||||
|
};
|
||||||
|
use std::{fs, io::prelude::*};
|
||||||
use sysinfo::{DiskExt, System, SystemExt};
|
use sysinfo::{DiskExt, System, SystemExt};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
@ -39,6 +50,7 @@ enum Commands {
|
||||||
repo_url: Option<String>, // url?
|
repo_url: Option<String>, // url?
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Manage storages.
|
||||||
Storage(StorageArgs),
|
Storage(StorageArgs),
|
||||||
|
|
||||||
/// Print config dir.
|
/// Print config dir.
|
||||||
|
@ -57,7 +69,10 @@ struct StorageArgs {
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum StorageCommands {
|
enum StorageCommands {
|
||||||
Add {},
|
Add {
|
||||||
|
#[arg(value_enum)]
|
||||||
|
storage_type: StorageType,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
@ -91,6 +106,12 @@ impl Device {
|
||||||
|
|
||||||
const DEVICESFILE: &str = "devices.yml";
|
const DEVICESFILE: &str = "devices.yml";
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Clone, Copy, Debug)]
|
||||||
|
enum StorageType {
|
||||||
|
Physical,
|
||||||
|
// Online,
|
||||||
|
}
|
||||||
|
|
||||||
/// All storage types.
|
/// All storage types.
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
enum Storage {
|
enum Storage {
|
||||||
|
@ -103,6 +124,16 @@ enum Storage {
|
||||||
// },
|
// },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Storage {
|
||||||
|
fn name(&self) -> &String {
|
||||||
|
match self {
|
||||||
|
Self::PhysicalStorage(s) => s.name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const STORAGESFILE: &str = "storages.yml";
|
||||||
|
|
||||||
/// Partitoin of physical (on-premises) drive.
|
/// Partitoin of physical (on-premises) drive.
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct PhysicalDrivePartition {
|
struct PhysicalDrivePartition {
|
||||||
|
@ -111,33 +142,31 @@ struct PhysicalDrivePartition {
|
||||||
capacity: u64,
|
capacity: u64,
|
||||||
fs: String,
|
fs: String,
|
||||||
is_removable: bool,
|
is_removable: bool,
|
||||||
aliases: HashMap<String, String, RandomState>,
|
system_names: HashMap<String, String, RandomState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhysicalDrivePartition {
|
impl PhysicalDrivePartition {
|
||||||
/// Try to get Physical drive info from sysinfo.
|
/// Try to get Physical drive info from sysinfo.
|
||||||
fn try_from_sysinfo_disk(
|
fn try_from_sysinfo_disk(
|
||||||
disk: sysinfo::Disk,
|
disk: &sysinfo::Disk,
|
||||||
name: String,
|
name: String,
|
||||||
device: Device,
|
device: Device,
|
||||||
) -> Result<PhysicalDrivePartition, String> {
|
) -> Result<PhysicalDrivePartition> {
|
||||||
let alias = match disk.name().to_str() {
|
let alias = disk
|
||||||
Some(s) => s.to_string(),
|
.name()
|
||||||
None => return Err("Failed to convert storage name to valid str.".to_string()),
|
.to_str()
|
||||||
};
|
.context("Failed to convert storage name to valid str.")?
|
||||||
|
.to_string();
|
||||||
let fs = disk.file_system();
|
let fs = disk.file_system();
|
||||||
trace!("fs: {:?}", fs);
|
trace!("fs: {:?}", fs);
|
||||||
let fs = match std::str::from_utf8(fs) {
|
let fs = std::str::from_utf8(fs)?;
|
||||||
Ok(s) => s,
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
Ok(PhysicalDrivePartition {
|
Ok(PhysicalDrivePartition {
|
||||||
name: name,
|
name: name,
|
||||||
kind: format!("{:?}", disk.kind()),
|
kind: format!("{:?}", disk.kind()),
|
||||||
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(),
|
||||||
aliases: HashMap::from([(device.name, alias)]),
|
system_names: HashMap::from([(device.name, alias)]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,12 +174,16 @@ impl PhysicalDrivePartition {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_alias(self, disk: sysinfo::Disk, device: Device) -> Result<PhysicalDrivePartition, String> {
|
fn add_alias(
|
||||||
|
self,
|
||||||
|
disk: sysinfo::Disk,
|
||||||
|
device: Device,
|
||||||
|
) -> Result<PhysicalDrivePartition, String> {
|
||||||
let alias = match disk.name().to_str() {
|
let alias = match disk.name().to_str() {
|
||||||
Some(s) => s.to_string(),
|
Some(s) => s.to_string(),
|
||||||
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.aliases;
|
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()),
|
||||||
|
@ -161,24 +194,21 @@ impl PhysicalDrivePartition {
|
||||||
capacity: self.capacity,
|
capacity: self.capacity,
|
||||||
fs: self.fs,
|
fs: self.fs,
|
||||||
is_removable: self.is_removable,
|
is_removable: self.is_removable,
|
||||||
aliases,
|
system_names: aliases,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BackupLog {}
|
struct BackupLog {}
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<()> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
env_logger::Builder::new()
|
env_logger::Builder::new()
|
||||||
.filter_level(cli.verbose.log_level_filter())
|
.filter_level(cli.verbose.log_level_filter())
|
||||||
.init();
|
.init();
|
||||||
trace!("Start logging...");
|
trace!("Start logging...");
|
||||||
|
|
||||||
let mut config_dir = match dirs::config_local_dir() {
|
let mut config_dir = dirs::config_local_dir().context("Failed to get config dir.")?;
|
||||||
Some(dir) => dir,
|
|
||||||
None => return Err("Failed to get config dir.".to_string()),
|
|
||||||
};
|
|
||||||
config_dir.push("xdbm");
|
config_dir.push("xdbm");
|
||||||
trace!("Config dir: {:?}", config_dir);
|
trace!("Config dir: {:?}", config_dir);
|
||||||
|
|
||||||
|
@ -186,13 +216,10 @@ fn main() -> Result<(), String> {
|
||||||
Commands::Init { repo_url } => {
|
Commands::Init { repo_url } => {
|
||||||
let is_first_device: bool;
|
let is_first_device: bool;
|
||||||
// get repo or initialize it
|
// get repo or initialize it
|
||||||
let repo_url = match repo_url {
|
let repo = match repo_url {
|
||||||
Some(repo_url) => {
|
Some(repo_url) => {
|
||||||
trace!("repo: {}", repo_url);
|
trace!("repo: {}", repo_url);
|
||||||
let repo = match Repository::clone(&repo_url, &config_dir) {
|
let repo = Repository::clone(&repo_url, &config_dir)?;
|
||||||
Ok(repo) => repo,
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
is_first_device = false;
|
is_first_device = false;
|
||||||
repo
|
repo
|
||||||
}
|
}
|
||||||
|
@ -201,34 +228,20 @@ fn main() -> Result<(), String> {
|
||||||
println!("Initializing for the first device...");
|
println!("Initializing for the first device...");
|
||||||
|
|
||||||
// create repository
|
// create repository
|
||||||
let repo = match Repository::init(&config_dir) {
|
let repo = Repository::init(&config_dir)?;
|
||||||
Ok(repo) => repo,
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// set up gitignore
|
// set up gitignore
|
||||||
{
|
{
|
||||||
let f = match File::create(&config_dir.join(".gitignore")) {
|
let f = File::create(&config_dir.join(".gitignore"))?;
|
||||||
Ok(f) => f,
|
{
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
let mut buf = BufWriter::new(f);
|
let mut buf = BufWriter::new(f);
|
||||||
match buf.write("devname".as_bytes()) {
|
buf.write("devname".as_bytes())?;
|
||||||
Ok(_) => trace!("successfully created ignore file"),
|
}
|
||||||
Err(e) => return Err(e.to_string()),
|
add_and_commit(
|
||||||
};
|
|
||||||
match buf.flush() {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
match add_and_commit(
|
|
||||||
&repo,
|
&repo,
|
||||||
Path::new(".gitignore"),
|
Path::new(".gitignore"),
|
||||||
"Add devname to gitignore.",
|
"Add devname to gitignore.",
|
||||||
) {
|
)?;
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
is_first_device = true;
|
is_first_device = true;
|
||||||
repo
|
repo
|
||||||
|
@ -241,11 +254,8 @@ fn main() -> Result<(), String> {
|
||||||
// save devname
|
// save devname
|
||||||
let devname_path = &config_dir.join("devname");
|
let devname_path = &config_dir.join("devname");
|
||||||
{
|
{
|
||||||
let mut f = match File::create(devname_path) {
|
let f = File::create(devname_path).context("Failed to create devname file")?;
|
||||||
Ok(f) => f,
|
let writer = BufWriter::new(f);
|
||||||
Err(e) => panic!("Failed to create devname file: {}", e),
|
|
||||||
};
|
|
||||||
let mut writer = BufWriter::new(f);
|
|
||||||
serde_yaml::to_writer(writer, &device.name).unwrap();
|
serde_yaml::to_writer(writer, &device.name).unwrap();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -257,7 +267,7 @@ fn main() -> Result<(), String> {
|
||||||
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("device name is already used.".to_string());
|
return Err(anyhow!("device name is already used."));
|
||||||
}
|
}
|
||||||
devices.push(device.clone());
|
devices.push(device.clone());
|
||||||
trace!("Devices: {:?}", devices);
|
trace!("Devices: {:?}", devices);
|
||||||
|
@ -265,22 +275,61 @@ fn main() -> Result<(), String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
match add_and_commit(
|
add_and_commit(
|
||||||
&repo_url,
|
&repo,
|
||||||
&Path::new(DEVICESFILE),
|
&Path::new(DEVICESFILE),
|
||||||
&format!("Add new devname: {}", &device.name),
|
&format!("Add new devname: {}", &device.name),
|
||||||
) {
|
)?;
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
Commands::Storage(storage) => match storage.command {
|
||||||
Commands::Storage(storage) => {
|
StorageCommands::Add { storage_type } => {
|
||||||
match storage.command {
|
trace!("Storage Add {:?}", storage_type);
|
||||||
StorageCommands::Add {} => {
|
let repo = Repository::open(&config_dir)?;
|
||||||
|
trace!("repo state: {:?}", repo.state());
|
||||||
|
match storage_type {
|
||||||
|
StorageType::Physical => {
|
||||||
|
// Get storages
|
||||||
|
let mut storages: 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);
|
||||||
|
get_storages(&config_dir)?
|
||||||
|
} else {
|
||||||
|
trace!("No {} found", STORAGESFILE);
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
trace!("found storages: {:?}", storages);
|
||||||
|
|
||||||
|
// select storage
|
||||||
|
let device = get_device(&config_dir)?;
|
||||||
|
let storage = select_physical_storage(device, &storages)?;
|
||||||
|
trace!("storage: {:?}", storage);
|
||||||
|
let new_storage_name = storage.name().clone();
|
||||||
|
|
||||||
|
// add to storages
|
||||||
|
storages.push(Storage::PhysicalStorage(storage));
|
||||||
|
trace!("updated storages: {:?}", storages);
|
||||||
|
|
||||||
|
// write to file
|
||||||
|
write_storages(&config_dir, storages)?;
|
||||||
|
|
||||||
|
// commit
|
||||||
|
add_and_commit(&repo, &Path::new(STORAGESFILE), &format!("Add new storage(physical drive): {}", new_storage_name))?;
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
Commands::Path {} => {
|
Commands::Path {} => {
|
||||||
println!("{}", &config_dir.display());
|
println!("{}", &config_dir.display());
|
||||||
}
|
}
|
||||||
|
@ -291,8 +340,33 @@ fn main() -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get devname of the device.
|
||||||
|
fn get_devname(config_dir: &Path) -> Result<String> {
|
||||||
|
let f = File::open(config_dir.join("devname")).context("Failed to open devname file")?;
|
||||||
|
let bufreader = BufReader::new(f);
|
||||||
|
let devname = bufreader
|
||||||
|
.lines()
|
||||||
|
.next()
|
||||||
|
.context("Couldn't get devname.")??;
|
||||||
|
trace!("devname: {}", devname);
|
||||||
|
Ok(devname)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current device.
|
||||||
|
fn get_device(config_dir: &Path) -> Result<Device> {
|
||||||
|
let devname = get_devname(config_dir)?;
|
||||||
|
let devices = get_devices(config_dir)?;
|
||||||
|
trace!("devname: {}", devname);
|
||||||
|
trace!("devices: {:?}", devices);
|
||||||
|
devices
|
||||||
|
.into_iter()
|
||||||
|
.filter(|dev| dev.name == devname)
|
||||||
|
.next()
|
||||||
|
.context("Couldn't find Device in devices.yml")
|
||||||
|
}
|
||||||
|
|
||||||
/// Set device name interactively.
|
/// Set device name interactively.
|
||||||
fn set_device_name() -> Result<Device, String> {
|
fn set_device_name() -> Result<Device> {
|
||||||
let validator = |input: &str| {
|
let validator = |input: &str| {
|
||||||
if input.chars().count() == 0 {
|
if input.chars().count() == 0 {
|
||||||
Ok(Validation::Invalid("Need at least 1 character.".into()))
|
Ok(Validation::Invalid("Need at least 1 character.".into()))
|
||||||
|
@ -312,7 +386,7 @@ fn set_device_name() -> Result<Device, String> {
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error {}", err);
|
println!("Error {}", err);
|
||||||
return Err(err.to_string());
|
return Err(anyhow!(err));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -324,36 +398,105 @@ fn set_device_name() -> Result<Device, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get `Vec<Device>` from yaml file in `config_dir`.
|
/// Get `Vec<Device>` from yaml file in `config_dir`.
|
||||||
fn get_devices(config_dir: &Path) -> Result<Vec<Device>, String> {
|
fn get_devices(config_dir: &Path) -> Result<Vec<Device>> {
|
||||||
trace!("get_devices");
|
trace!("get_devices");
|
||||||
let f = match File::open(config_dir.join(DEVICESFILE)) {
|
let f = File::open(config_dir.join(DEVICESFILE))?;
|
||||||
Ok(f) => f,
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
let yaml: Vec<Device> = match serde_yaml::from_reader(reader) {
|
let yaml: Vec<Device> =
|
||||||
Ok(yaml) => yaml,
|
serde_yaml::from_reader(reader).context("Failed to parse devices.yml")?;
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
return Ok(yaml);
|
return Ok(yaml);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write `devices` to yaml file in `config_dir`.
|
/// Write `devices` to yaml file in `config_dir`.
|
||||||
fn write_devices(config_dir: &Path, devices: Vec<Device>) -> Result<(), String> {
|
fn write_devices(config_dir: &Path, devices: Vec<Device>) -> Result<()> {
|
||||||
trace!("write_devices");
|
trace!("write_devices");
|
||||||
let f = match OpenOptions::new()
|
let f = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(config_dir.join(DEVICESFILE))
|
.open(config_dir.join(DEVICESFILE))?;
|
||||||
{
|
|
||||||
Ok(f) => f,
|
|
||||||
Err(e) => return Err(e.to_string()),
|
|
||||||
};
|
|
||||||
let writer = BufWriter::new(f);
|
let writer = BufWriter::new(f);
|
||||||
match serde_yaml::to_writer(writer, &devices) {
|
serde_yaml::to_writer(writer, &devices).map_err(|e| anyhow!(e))
|
||||||
Ok(()) => Ok(()),
|
}
|
||||||
Err(e) => Err(e.to_string()),
|
|
||||||
|
/// 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 available_disks = sys_disks
|
||||||
|
.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) = sys_disks
|
||||||
|
.disks()
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(i, _)| i == &disk_num)
|
||||||
|
.unwrap();
|
||||||
|
trace!("selected disk: {:?}", disk);
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Vec<Storage> from devices.yml([DEVICESFILE])
|
||||||
|
fn get_storages(config_dir: &Path) -> Result<Vec<Storage>> {
|
||||||
|
let f = File::open(config_dir.join(STORAGESFILE))?;
|
||||||
|
let reader = BufReader::new(f);
|
||||||
|
// for line in reader.lines() {
|
||||||
|
// trace!("{:?}", line);
|
||||||
|
// }
|
||||||
|
// unimplemented!();
|
||||||
|
let yaml: Vec<Storage> =
|
||||||
|
serde_yaml::from_reader(reader).context("Failed to read devices.yml")?;
|
||||||
|
Ok(yaml)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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> {
|
||||||
|
@ -372,6 +515,7 @@ fn find_last_commit(repo: &Repository) -> Result<Option<Commit>, git2::Error> {
|
||||||
|
|
||||||
/// Add file and commit
|
/// Add file and commit
|
||||||
fn add_and_commit(repo: &Repository, path: &Path, message: &str) -> Result<Oid, git2::Error> {
|
fn add_and_commit(repo: &Repository, path: &Path, message: &str) -> Result<Oid, git2::Error> {
|
||||||
|
trace!("repo state: {:?}", repo.state());
|
||||||
let mut index = repo.index()?;
|
let mut index = repo.index()?;
|
||||||
index.add_path(path)?;
|
index.add_path(path)?;
|
||||||
let oid = index.write_tree()?;
|
let oid = index.write_tree()?;
|
||||||
|
@ -383,7 +527,7 @@ fn add_and_commit(repo: &Repository, path: &Path, message: &str) -> Result<Oid,
|
||||||
trace!("git signature: {}", signature);
|
trace!("git signature: {}", signature);
|
||||||
let parent_commit = find_last_commit(&repo)?;
|
let parent_commit = find_last_commit(&repo)?;
|
||||||
let tree = repo.find_tree(oid)?;
|
let tree = repo.find_tree(oid)?;
|
||||||
match parent_commit {
|
let result = match parent_commit {
|
||||||
Some(parent_commit) => repo.commit(
|
Some(parent_commit) => repo.commit(
|
||||||
Some("HEAD"),
|
Some("HEAD"),
|
||||||
&signature,
|
&signature,
|
||||||
|
@ -393,5 +537,7 @@ fn add_and_commit(repo: &Repository, path: &Path, message: &str) -> Result<Oid,
|
||||||
&[&parent_commit],
|
&[&parent_commit],
|
||||||
),
|
),
|
||||||
None => repo.commit(Some("HEAD"), &signature, &signature, message, &tree, &[]),
|
None => repo.commit(Some("HEAD"), &signature, &signature, message, &tree, &[]),
|
||||||
}
|
};
|
||||||
|
trace!("repo state: {:?}", repo.state());
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue