mirror of
https://github.com/qwjyh/xdbm
synced 2024-11-22 14:50:12 +09:00
lint with clippy
fix problems reported by clippy excepts about unused functions
This commit is contained in:
parent
01f959b666
commit
bac829c1f1
12 changed files with 296 additions and 313 deletions
|
@ -174,7 +174,7 @@ impl Backup {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn device<'a>(&'a self, devices: &'a Vec<Device>) -> Option<&Device> {
|
pub fn device<'a>(&'a self, devices: &'a [Device]) -> Option<&Device> {
|
||||||
devices.iter().find(|dev| dev.name() == self.device)
|
devices.iter().find(|dev| dev.name() == self.device)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ impl Backup {
|
||||||
&self.command
|
&self.command
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_log(&mut self, newlog: BackupLog) -> () {
|
pub fn add_log(&mut self, newlog: BackupLog) {
|
||||||
self.logs.push(newlog)
|
self.logs.push(newlog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::{self, stdout, Write},
|
io::{self, stdout, Write},
|
||||||
path::PathBuf,
|
path::{PathBuf, Path},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Ok, Result};
|
use anyhow::{anyhow, Context, Ok, Result};
|
||||||
|
@ -28,21 +28,21 @@ pub(crate) fn cmd_backup_add(
|
||||||
dest: PathBuf,
|
dest: PathBuf,
|
||||||
cmd: BackupAddCommands,
|
cmd: BackupAddCommands,
|
||||||
repo: Repository,
|
repo: Repository,
|
||||||
config_dir: &PathBuf,
|
config_dir: &Path,
|
||||||
storages: &Storages,
|
storages: &Storages,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
trace!("Canonicalize path: {:?}", src);
|
trace!("Canonicalize path: {:?}", src);
|
||||||
let src = canonicalize(util::expand_tilde(src)?)?;
|
let src = canonicalize(util::expand_tilde(src)?)?;
|
||||||
trace!("Canonicalize path: {:?}", dest);
|
trace!("Canonicalize path: {:?}", dest);
|
||||||
let dest = canonicalize(util::expand_tilde(dest)?)?;
|
let dest = canonicalize(util::expand_tilde(dest)?)?;
|
||||||
let device = devices::get_device(&config_dir)?;
|
let device = devices::get_device(config_dir)?;
|
||||||
let new_backup = new_backup(name, src, dest, cmd, &device, storages)?;
|
let new_backup = new_backup(name, src, dest, cmd, &device, storages)?;
|
||||||
let new_backup_name = new_backup.name().clone();
|
let new_backup_name = new_backup.name().clone();
|
||||||
let mut backups = Backups::read(&config_dir, &device)?;
|
let mut backups = Backups::read(config_dir, &device)?;
|
||||||
println!("Backup config:");
|
println!("Backup config:");
|
||||||
serde_yaml::to_writer(stdout(), &new_backup)?;
|
serde_yaml::to_writer(stdout(), &new_backup)?;
|
||||||
backups.add(new_backup)?;
|
backups.add(new_backup)?;
|
||||||
backups.write(&config_dir, &device)?;
|
backups.write(config_dir, &device)?;
|
||||||
|
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
|
@ -64,12 +64,12 @@ fn new_backup(
|
||||||
storages: &Storages,
|
storages: &Storages,
|
||||||
) -> Result<Backup> {
|
) -> Result<Backup> {
|
||||||
let (src_parent, src_diff) =
|
let (src_parent, src_diff) =
|
||||||
util::min_parent_storage(&src, &storages, &device).context(format!(
|
util::min_parent_storage(&src, storages, device).context(format!(
|
||||||
"Coundn't find parent storage for src directory {}",
|
"Coundn't find parent storage for src directory {}",
|
||||||
src.display()
|
src.display()
|
||||||
))?;
|
))?;
|
||||||
let (dest_parent, dest_diff) =
|
let (dest_parent, dest_diff) =
|
||||||
util::min_parent_storage(&dest, &storages, &device).context(format!(
|
util::min_parent_storage(&dest, storages, device).context(format!(
|
||||||
"Couldn't find parent storage for dest directory: {}",
|
"Couldn't find parent storage for dest directory: {}",
|
||||||
dest.display()
|
dest.display()
|
||||||
))?;
|
))?;
|
||||||
|
@ -94,6 +94,166 @@ fn new_backup(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cmd_backup_list(
|
||||||
|
src_storage: Option<String>,
|
||||||
|
dest_storage: Option<String>,
|
||||||
|
device_name: Option<String>,
|
||||||
|
longprint: bool,
|
||||||
|
config_dir: &Path,
|
||||||
|
storages: &Storages,
|
||||||
|
) -> Result<()> {
|
||||||
|
let devices = devices::get_devices(config_dir)?;
|
||||||
|
let backups: HashMap<(String, String), Backup> = match device_name {
|
||||||
|
Some(device_name) => {
|
||||||
|
let device = devices
|
||||||
|
.iter()
|
||||||
|
.find(|dev| dev.name() == device_name)
|
||||||
|
.context(format!("Device with name {} doesn't exist", device_name))?;
|
||||||
|
let backups = Backups::read(config_dir, device)?;
|
||||||
|
let mut allbackups = HashMap::new();
|
||||||
|
for (name, backup) in backups.list {
|
||||||
|
if allbackups.insert((device.name(), name), backup).is_some() {
|
||||||
|
return Err(anyhow!("unexpected duplication in backups hashmap"));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
allbackups
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let mut allbackups = HashMap::new();
|
||||||
|
for device in &devices {
|
||||||
|
let backups = Backups::read(config_dir, device)?;
|
||||||
|
for (name, backup) in backups.list {
|
||||||
|
if allbackups.insert((device.name(), name), backup).is_some() {
|
||||||
|
return Err(anyhow!("unexpected duplication in backups hashmap"));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allbackups
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// source/destination filtering
|
||||||
|
let backups: HashMap<(String, String), Backup> = backups
|
||||||
|
.into_iter()
|
||||||
|
.filter(|((_dev, _name), backup)| {
|
||||||
|
let src_matched = match &src_storage {
|
||||||
|
Some(src_storage) => &backup.source().storage == src_storage,
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
let dest_matched = match &dest_storage {
|
||||||
|
Some(dest_storage) => &backup.destination().storage == dest_storage,
|
||||||
|
None => true,
|
||||||
|
};
|
||||||
|
src_matched && dest_matched
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut stdout = io::BufWriter::new(io::stdout());
|
||||||
|
write_backups_list(&mut stdout, backups, longprint, storages, &devices)?;
|
||||||
|
stdout.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO: status printing
|
||||||
|
fn write_backups_list(
|
||||||
|
mut writer: impl io::Write,
|
||||||
|
backups: HashMap<(String, String), Backup>,
|
||||||
|
longprint: bool,
|
||||||
|
storages: &Storages,
|
||||||
|
devices: &[Device],
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut name_width = 0;
|
||||||
|
let mut dev_width = 0;
|
||||||
|
let mut src_width = 0;
|
||||||
|
let mut src_storage_width = 0;
|
||||||
|
let mut dest_width = 0;
|
||||||
|
let mut dest_storage_width = 0;
|
||||||
|
let mut cmd_name_width = 0;
|
||||||
|
// get widths
|
||||||
|
for ((dev, _name), backup) in &backups {
|
||||||
|
let device = backup.device(devices).context(format!(
|
||||||
|
"Couldn't find device specified in backup config {}",
|
||||||
|
backup.name()
|
||||||
|
))?;
|
||||||
|
name_width = name_width.max(backup.name().width());
|
||||||
|
dev_width = dev_width.max(dev.width());
|
||||||
|
let src = backup.source().path(storages, device)?;
|
||||||
|
src_width = src_width.max(format!("{}", src.display()).width());
|
||||||
|
src_storage_width = src_storage_width.max(backup.source().storage.width());
|
||||||
|
let dest = backup.destination().path(storages, device)?;
|
||||||
|
dest_width = dest_width.max(format!("{}", dest.display()).width());
|
||||||
|
dest_storage_width = dest_storage_width.max(backup.destination().storage.width());
|
||||||
|
let cmd_name = backup.command().name();
|
||||||
|
cmd_name_width = cmd_name_width.max(cmd_name.width());
|
||||||
|
}
|
||||||
|
// main printing
|
||||||
|
for ((dev, _name), backup) in &backups {
|
||||||
|
let device = backup.device(devices).context(format!(
|
||||||
|
"Couldn't find device specified in backup config {}",
|
||||||
|
backup.name()
|
||||||
|
))?;
|
||||||
|
let src = backup.source().path(storages, device)?;
|
||||||
|
let dest = backup.destination().path(storages, device)?;
|
||||||
|
let cmd_name = backup.command().name();
|
||||||
|
let last_backup_elapsed = match backup.last_backup() {
|
||||||
|
Some(log) => {
|
||||||
|
let time = Local::now() - log.datetime;
|
||||||
|
util::format_summarized_duration(time)
|
||||||
|
}
|
||||||
|
None => "---".to_string(),
|
||||||
|
};
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
"{name:<name_width$} [{dev:<dev_width$}] {src:<src_storage_width$} → {dest:<dest_storage_width$} {last_backup_elapsed}",
|
||||||
|
name = backup.name(),
|
||||||
|
src = backup.source().storage,
|
||||||
|
dest = backup.destination().storage,
|
||||||
|
)?;
|
||||||
|
if longprint {
|
||||||
|
let cmd_note = backup.command().note();
|
||||||
|
writeln!(writer, " src : {src:<src_width$}", src = src.display())?;
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
" dest: {dest:<dest_width$}",
|
||||||
|
dest = dest.display()
|
||||||
|
)?;
|
||||||
|
writeln!(
|
||||||
|
writer,
|
||||||
|
" {cmd_name:<cmd_name_width$}({note})",
|
||||||
|
note = cmd_note,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmd_backup_done(
|
||||||
|
name: String,
|
||||||
|
exit_status: u64,
|
||||||
|
log: Option<String>,
|
||||||
|
repo: Repository,
|
||||||
|
config_dir: &Path,
|
||||||
|
) -> Result<()> {
|
||||||
|
let device = devices::get_device(config_dir)?;
|
||||||
|
let mut backups = Backups::read(config_dir, &device)?;
|
||||||
|
let backup = backups
|
||||||
|
.get_mut(&name)
|
||||||
|
.context(format!("Failed to get backup with name {}", name))?;
|
||||||
|
trace!("Got backup: {:?}", backup);
|
||||||
|
let backup_name = backup.name().clone();
|
||||||
|
let status = BackupResult::from_exit_code(exit_status);
|
||||||
|
let new_log = BackupLog::new_with_current_time(status, log.unwrap_or("".to_string()));
|
||||||
|
trace!("New backup log: {:?}", new_log);
|
||||||
|
backup.add_log(new_log);
|
||||||
|
trace!("Added");
|
||||||
|
backups.write(config_dir, &device)?;
|
||||||
|
add_and_commit(
|
||||||
|
&repo,
|
||||||
|
&backups::backups_file(&device),
|
||||||
|
&format!("Done backup: {}", backup_name),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::path::{Component, PathBuf};
|
use std::path::{Component, PathBuf};
|
||||||
|
@ -162,166 +322,3 @@ mod test {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cmd_backup_list(
|
|
||||||
src_storage: Option<String>,
|
|
||||||
dest_storage: Option<String>,
|
|
||||||
device_name: Option<String>,
|
|
||||||
longprint: bool,
|
|
||||||
config_dir: &PathBuf,
|
|
||||||
storages: &Storages,
|
|
||||||
) -> Result<()> {
|
|
||||||
let devices = devices::get_devices(&config_dir)?;
|
|
||||||
let backups: HashMap<(String, String), Backup> = match device_name {
|
|
||||||
Some(device_name) => {
|
|
||||||
let device = devices
|
|
||||||
.iter()
|
|
||||||
.find(|dev| dev.name() == device_name)
|
|
||||||
.context(format!("Device with name {} doesn't exist", device_name))?;
|
|
||||||
let backups = Backups::read(&config_dir, device)?;
|
|
||||||
let mut allbackups = HashMap::new();
|
|
||||||
for (name, backup) in backups.list {
|
|
||||||
if allbackups.insert((device.name(), name), backup).is_some() {
|
|
||||||
return Err(anyhow!("unexpected duplication in backups hashmap"));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
allbackups
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let mut allbackups = HashMap::new();
|
|
||||||
for device in &devices {
|
|
||||||
let backups = Backups::read(&config_dir, &device)?;
|
|
||||||
for (name, backup) in backups.list {
|
|
||||||
if allbackups.insert((device.name(), name), backup).is_some() {
|
|
||||||
return Err(anyhow!("unexpected duplication in backups hashmap"));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allbackups
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// source/destination filtering
|
|
||||||
let backups: HashMap<(String, String), Backup> = backups
|
|
||||||
.into_iter()
|
|
||||||
.filter(|((_dev, _name), backup)| {
|
|
||||||
let src_matched = match &src_storage {
|
|
||||||
Some(src_storage) => &backup.source().storage == src_storage,
|
|
||||||
None => true,
|
|
||||||
};
|
|
||||||
let dest_matched = match &dest_storage {
|
|
||||||
Some(dest_storage) => &backup.destination().storage == dest_storage,
|
|
||||||
None => true,
|
|
||||||
};
|
|
||||||
src_matched && dest_matched
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut stdout = io::BufWriter::new(io::stdout());
|
|
||||||
write_backups_list(&mut stdout, backups, longprint, storages, &devices)?;
|
|
||||||
stdout.flush()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO: status printing
|
|
||||||
fn write_backups_list(
|
|
||||||
mut writer: impl io::Write,
|
|
||||||
backups: HashMap<(String, String), Backup>,
|
|
||||||
longprint: bool,
|
|
||||||
storages: &Storages,
|
|
||||||
devices: &Vec<Device>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut name_width = 0;
|
|
||||||
let mut dev_width = 0;
|
|
||||||
let mut src_width = 0;
|
|
||||||
let mut src_storage_width = 0;
|
|
||||||
let mut dest_width = 0;
|
|
||||||
let mut dest_storage_width = 0;
|
|
||||||
let mut cmd_name_width = 0;
|
|
||||||
// get widths
|
|
||||||
for ((dev, _name), backup) in &backups {
|
|
||||||
let device = backup.device(devices).context(format!(
|
|
||||||
"Couldn't find device specified in backup config {}",
|
|
||||||
backup.name()
|
|
||||||
))?;
|
|
||||||
name_width = name_width.max(backup.name().width());
|
|
||||||
dev_width = dev_width.max(dev.width());
|
|
||||||
let src = backup.source().path(&storages, &device)?;
|
|
||||||
src_width = src_width.max(format!("{}", src.display()).width());
|
|
||||||
src_storage_width = src_storage_width.max(backup.source().storage.width());
|
|
||||||
let dest = backup.destination().path(&storages, &device)?;
|
|
||||||
dest_width = dest_width.max(format!("{}", dest.display()).width());
|
|
||||||
dest_storage_width = dest_storage_width.max(backup.destination().storage.width());
|
|
||||||
let cmd_name = backup.command().name();
|
|
||||||
cmd_name_width = cmd_name_width.max(cmd_name.width());
|
|
||||||
}
|
|
||||||
// main printing
|
|
||||||
for ((dev, _name), backup) in &backups {
|
|
||||||
let device = backup.device(devices).context(format!(
|
|
||||||
"Couldn't find device specified in backup config {}",
|
|
||||||
backup.name()
|
|
||||||
))?;
|
|
||||||
let src = backup.source().path(&storages, &device)?;
|
|
||||||
let dest = backup.destination().path(&storages, &device)?;
|
|
||||||
let cmd_name = backup.command().name();
|
|
||||||
let last_backup_elapsed = match backup.last_backup() {
|
|
||||||
Some(log) => {
|
|
||||||
let time = Local::now() - log.datetime;
|
|
||||||
util::format_summarized_duration(time)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
format!("---")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
"{name:<name_width$} [{dev:<dev_width$}] {src:<src_storage_width$} → {dest:<dest_storage_width$} {last_backup_elapsed}",
|
|
||||||
name = backup.name(),
|
|
||||||
src = backup.source().storage,
|
|
||||||
dest = backup.destination().storage,
|
|
||||||
)?;
|
|
||||||
if longprint {
|
|
||||||
let cmd_note = backup.command().note();
|
|
||||||
writeln!(writer, " src : {src:<src_width$}", src = src.display())?;
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
" dest: {dest:<dest_width$}",
|
|
||||||
dest = dest.display()
|
|
||||||
)?;
|
|
||||||
writeln!(
|
|
||||||
writer,
|
|
||||||
" {cmd_name:<cmd_name_width$}({note})",
|
|
||||||
note = cmd_note,
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cmd_backup_done(
|
|
||||||
name: String,
|
|
||||||
exit_status: u64,
|
|
||||||
log: Option<String>,
|
|
||||||
repo: Repository,
|
|
||||||
config_dir: &PathBuf,
|
|
||||||
) -> Result<()> {
|
|
||||||
let device = devices::get_device(&config_dir)?;
|
|
||||||
let mut backups = Backups::read(&config_dir, &device)?;
|
|
||||||
let backup = backups
|
|
||||||
.get_mut(&name)
|
|
||||||
.context(format!("Failed to get backup with name {}", name))?;
|
|
||||||
trace!("Got backup: {:?}", backup);
|
|
||||||
let backup_name = backup.name().clone();
|
|
||||||
let status = BackupResult::from_exit_code(exit_status);
|
|
||||||
let new_log = BackupLog::new_with_current_time(status, log.unwrap_or("".to_string()));
|
|
||||||
trace!("New backup log: {:?}", new_log);
|
|
||||||
backup.add_log(new_log);
|
|
||||||
trace!("Added");
|
|
||||||
backups.write(&config_dir, &device)?;
|
|
||||||
add_and_commit(
|
|
||||||
&repo,
|
|
||||||
&backups::backups_file(&device),
|
|
||||||
&format!("Done backup: {}", backup_name),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::path::PathBuf;
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
|
||||||
|
@ -8,16 +8,16 @@ use crate::{
|
||||||
storages::{Storage, StorageExt, Storages},
|
storages::{Storage, StorageExt, Storages},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn cmd_check(config_dir: &PathBuf) -> Result<()> {
|
pub(crate) fn cmd_check(config_dir: &Path) -> Result<()> {
|
||||||
info!("Config dir: {}", &config_dir.display());
|
info!("Config dir: {}", &config_dir.display());
|
||||||
|
|
||||||
let device = devices::get_device(&config_dir)?;
|
let device = devices::get_device(config_dir)?;
|
||||||
info!("Current device: {:?}", device);
|
info!("Current device: {:?}", device);
|
||||||
|
|
||||||
let devices = devices::get_devices(&config_dir)?;
|
let devices = devices::get_devices(config_dir)?;
|
||||||
info!("Configured devices: {:?}", devices);
|
info!("Configured devices: {:?}", devices);
|
||||||
|
|
||||||
let storages = Storages::read(&config_dir)?;
|
let storages = Storages::read(config_dir)?;
|
||||||
info!("Storages: {:?}", storages);
|
info!("Storages: {:?}", storages);
|
||||||
if !(storages.list.iter().all(|(_name, storage)| match storage {
|
if !(storages.list.iter().all(|(_name, storage)| match storage {
|
||||||
Storage::SubDirectory(storage) => storage.parent(&storages).is_some(),
|
Storage::SubDirectory(storage) => storage.parent(&storages).is_some(),
|
||||||
|
@ -30,7 +30,7 @@ pub(crate) fn cmd_check(config_dir: &PathBuf) -> Result<()> {
|
||||||
info!("All SubDirectory's parent exists.");
|
info!("All SubDirectory's parent exists.");
|
||||||
|
|
||||||
for device in &devices {
|
for device in &devices {
|
||||||
let backups = Backups::read(&config_dir, &device)?;
|
let backups = Backups::read(config_dir, device)?;
|
||||||
for (name, backup) in &backups.list {
|
for (name, backup) in &backups.list {
|
||||||
if name != backup.name() {
|
if name != backup.name() {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
|
|
|
@ -15,7 +15,7 @@ use std::io::{BufWriter, Write};
|
||||||
use std::path::{self, Path, PathBuf};
|
use std::path::{self, Path, PathBuf};
|
||||||
|
|
||||||
fn clone_repo(
|
fn clone_repo(
|
||||||
repo_url: &String,
|
repo_url: &str,
|
||||||
use_sshagent: bool,
|
use_sshagent: bool,
|
||||||
ssh_key: Option<PathBuf>,
|
ssh_key: Option<PathBuf>,
|
||||||
config_dir: &path::PathBuf,
|
config_dir: &path::PathBuf,
|
||||||
|
@ -24,7 +24,7 @@ fn clone_repo(
|
||||||
if ssh_key.is_none() && !use_sshagent {
|
if ssh_key.is_none() && !use_sshagent {
|
||||||
info!("No authentication will be used.");
|
info!("No authentication will be used.");
|
||||||
info!("Use either ssh_key or ssh-agent to access private repository");
|
info!("Use either ssh_key or ssh-agent to access private repository");
|
||||||
return Ok(Repository::clone(&repo_url, &config_dir)?);
|
return Ok(Repository::clone(repo_url, config_dir)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
// using credentials
|
// using credentials
|
||||||
|
@ -68,7 +68,7 @@ fn clone_repo(
|
||||||
let mut builder = git2::build::RepoBuilder::new();
|
let mut builder = git2::build::RepoBuilder::new();
|
||||||
builder.fetch_options(fo);
|
builder.fetch_options(fo);
|
||||||
|
|
||||||
Ok(builder.clone(&repo_url, config_dir)?)
|
Ok(builder.clone(repo_url, config_dir)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn cmd_init(
|
pub(crate) fn cmd_init(
|
||||||
|
@ -91,22 +91,21 @@ pub(crate) fn cmd_init(
|
||||||
let repo = match repo_url {
|
let repo = match repo_url {
|
||||||
Some(repo_url) => {
|
Some(repo_url) => {
|
||||||
trace!("repo: {}", repo_url);
|
trace!("repo: {}", repo_url);
|
||||||
let repo = clone_repo(&repo_url, use_sshagent, ssh_key, config_dir)?;
|
clone_repo(&repo_url, use_sshagent, ssh_key, config_dir)?
|
||||||
repo
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
trace!("No repo provided");
|
trace!("No repo provided");
|
||||||
println!("Initializing for the first device...");
|
println!("Initializing for the first device...");
|
||||||
|
|
||||||
// create repository
|
// create repository
|
||||||
let repo = Repository::init(&config_dir)?;
|
let repo = Repository::init(config_dir)?;
|
||||||
|
|
||||||
// set up gitignore
|
// set up gitignore
|
||||||
{
|
{
|
||||||
let f = File::create(&config_dir.join(".gitignore"))?;
|
let f = File::create(config_dir.join(".gitignore"))?;
|
||||||
{
|
{
|
||||||
let mut buf = BufWriter::new(f);
|
let mut buf = BufWriter::new(f);
|
||||||
buf.write("devname".as_bytes())?;
|
buf.write_all("devname".as_bytes())?;
|
||||||
}
|
}
|
||||||
add_and_commit(&repo, Path::new(".gitignore"), "Add devname to gitignore.")?;
|
add_and_commit(&repo, Path::new(".gitignore"), "Add devname to gitignore.")?;
|
||||||
full_status(&repo)?;
|
full_status(&repo)?;
|
||||||
|
@ -115,7 +114,7 @@ pub(crate) fn cmd_init(
|
||||||
// TDOO: wrap up below into one commit?
|
// TDOO: wrap up below into one commit?
|
||||||
// set up devices.yml
|
// set up devices.yml
|
||||||
let devices: Vec<Device> = vec![];
|
let devices: Vec<Device> = vec![];
|
||||||
write_devices(&config_dir, devices)?;
|
write_devices(config_dir, devices)?;
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
Path::new(DEVICESFILE),
|
Path::new(DEVICESFILE),
|
||||||
|
@ -123,7 +122,7 @@ pub(crate) fn cmd_init(
|
||||||
)?;
|
)?;
|
||||||
// set up storages.yml
|
// set up storages.yml
|
||||||
let storages = Storages::new();
|
let storages = Storages::new();
|
||||||
storages.write(&config_dir)?;
|
storages.write(config_dir)?;
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
Path::new(STORAGESFILE),
|
Path::new(STORAGESFILE),
|
||||||
|
@ -131,7 +130,7 @@ pub(crate) fn cmd_init(
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// set up directory for backups
|
// set up directory for backups
|
||||||
DirBuilder::new().create(&config_dir.join(backups::BACKUPSDIR))?;
|
DirBuilder::new().create(config_dir.join(backups::BACKUPSDIR))?;
|
||||||
|
|
||||||
repo
|
repo
|
||||||
}
|
}
|
||||||
|
@ -155,7 +154,7 @@ pub(crate) fn cmd_init(
|
||||||
|
|
||||||
// Add new device to devices.yml
|
// Add new device to devices.yml
|
||||||
{
|
{
|
||||||
let mut devices: Vec<Device> = get_devices(&config_dir)?;
|
let mut devices: Vec<Device> = get_devices(config_dir)?;
|
||||||
trace!("devices: {:?}", devices);
|
trace!("devices: {:?}", devices);
|
||||||
if devices.iter().any(|x| x.name() == device.name()) {
|
if devices.iter().any(|x| x.name() == device.name()) {
|
||||||
error!("Device name `{}` is already used.", device.name());
|
error!("Device name `{}` is already used.", device.name());
|
||||||
|
@ -164,21 +163,21 @@ pub(crate) fn cmd_init(
|
||||||
}
|
}
|
||||||
devices.push(device.clone());
|
devices.push(device.clone());
|
||||||
trace!("Devices: {:?}", devices);
|
trace!("Devices: {:?}", devices);
|
||||||
write_devices(&config_dir, devices)?;
|
write_devices(config_dir, devices)?;
|
||||||
}
|
}
|
||||||
full_status(&repo)?;
|
full_status(&repo)?;
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
&Path::new(DEVICESFILE),
|
Path::new(DEVICESFILE),
|
||||||
&format!("Add new device: {}", &device.name()),
|
&format!("Add new device: {}", &device.name()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// backups/[device].yml
|
// backups/[device].yml
|
||||||
{
|
{
|
||||||
let backups = Backups::new();
|
let backups = Backups::new();
|
||||||
backups.write(&config_dir, &device)?;
|
backups.write(config_dir, &device)?;
|
||||||
}
|
}
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
|
|
|
@ -27,14 +27,14 @@ use crate::{
|
||||||
pub(crate) fn cmd_storage_add(
|
pub(crate) fn cmd_storage_add(
|
||||||
args: StorageAddCommands,
|
args: StorageAddCommands,
|
||||||
repo: Repository,
|
repo: Repository,
|
||||||
config_dir: &PathBuf,
|
config_dir: &Path,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
trace!("Storage Add with args: {:?}", args);
|
trace!("Storage Add with args: {:?}", args);
|
||||||
// Get storages
|
// Get storages
|
||||||
let mut storages = Storages::read(&config_dir)?;
|
let mut storages = Storages::read(config_dir)?;
|
||||||
trace!("found storages: {:?}", storages);
|
trace!("found storages: {:?}", storages);
|
||||||
|
|
||||||
let device = devices::get_device(&config_dir)?;
|
let device = devices::get_device(config_dir)?;
|
||||||
let storage = match args {
|
let storage = match args {
|
||||||
StorageAddCommands::Physical { name, path } => {
|
StorageAddCommands::Physical { name, path } => {
|
||||||
if !is_unique_name(&name, &storages) {
|
if !is_unique_name(&name, &storages) {
|
||||||
|
@ -54,7 +54,7 @@ pub(crate) fn cmd_storage_add(
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
println!("storage: {}: {:?}", storage.name(), storage);
|
println!("storage: {}: {:?}", storage.name(), storage);
|
||||||
Storage::PhysicalStorage(storage)
|
Storage::Physical(storage)
|
||||||
}
|
}
|
||||||
StorageAddCommands::Directory {
|
StorageAddCommands::Directory {
|
||||||
name,
|
name,
|
||||||
|
@ -113,12 +113,12 @@ pub(crate) fn cmd_storage_add(
|
||||||
trace!("updated storages: {:?}", storages);
|
trace!("updated storages: {:?}", storages);
|
||||||
|
|
||||||
// write to file
|
// write to file
|
||||||
storages.write(&config_dir)?;
|
storages.write(config_dir)?;
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
&Path::new(storages::STORAGESFILE),
|
Path::new(storages::STORAGESFILE),
|
||||||
&format!(
|
&format!(
|
||||||
"Add new storage({}): {}",
|
"Add new storage({}): {}",
|
||||||
new_storage_type, new_storage_name
|
new_storage_type, new_storage_name
|
||||||
|
@ -163,19 +163,19 @@ fn manually_construct_physical_drive_partition(
|
||||||
fs,
|
fs,
|
||||||
is_removable,
|
is_removable,
|
||||||
local_info,
|
local_info,
|
||||||
&device,
|
device,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn cmd_storage_list(config_dir: &PathBuf, with_note: bool) -> Result<()> {
|
pub(crate) fn cmd_storage_list(config_dir: &Path, with_note: bool) -> Result<()> {
|
||||||
// Get storages
|
// Get storages
|
||||||
let storages = Storages::read(&config_dir)?;
|
let storages = Storages::read(config_dir)?;
|
||||||
trace!("found storages: {:?}", storages);
|
trace!("found storages: {:?}", storages);
|
||||||
if storages.list.is_empty() {
|
if storages.list.is_empty() {
|
||||||
println!("No storages found");
|
println!("No storages found");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let device = devices::get_device(&config_dir)?;
|
let device = devices::get_device(config_dir)?;
|
||||||
let mut stdout = io::BufWriter::new(io::stdout());
|
let mut stdout = io::BufWriter::new(io::stdout());
|
||||||
write_storages_list(&mut stdout, &storages, &device, with_note)?;
|
write_storages_list(&mut stdout, &storages, &device, with_note)?;
|
||||||
stdout.flush()?;
|
stdout.flush()?;
|
||||||
|
@ -190,12 +190,12 @@ fn write_storages_list(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let name_width = storages
|
let name_width = storages
|
||||||
.list
|
.list
|
||||||
.iter()
|
.values()
|
||||||
.map(|(_k, v)| v.name().width())
|
.map(|v| v.name().width())
|
||||||
.max()
|
.max()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
trace!("name widths: {}", name_width);
|
trace!("name widths: {}", name_width);
|
||||||
for (_k, storage) in &storages.list {
|
for storage in storages.list.values() {
|
||||||
let size_str = match storage.capacity() {
|
let size_str = match storage.capacity() {
|
||||||
Some(b) => Byte::from_bytes(b.into())
|
Some(b) => Byte::from_bytes(b.into())
|
||||||
.get_appropriate_unit(true)
|
.get_appropriate_unit(true)
|
||||||
|
@ -203,7 +203,7 @@ fn write_storages_list(
|
||||||
.to_string(),
|
.to_string(),
|
||||||
None => "".to_string(),
|
None => "".to_string(),
|
||||||
};
|
};
|
||||||
let isremovable = if let Storage::PhysicalStorage(s) = storage {
|
let isremovable = if let Storage::Physical(s) = storage {
|
||||||
if s.is_removable() {
|
if s.is_removable() {
|
||||||
"+"
|
"+"
|
||||||
} else {
|
} else {
|
||||||
|
@ -212,7 +212,7 @@ fn write_storages_list(
|
||||||
} else {
|
} else {
|
||||||
" "
|
" "
|
||||||
};
|
};
|
||||||
let path = storage.mount_path(&device).map_or_else(
|
let path = storage.mount_path(device).map_or_else(
|
||||||
|e| {
|
|e| {
|
||||||
info!("Not found: {}", e);
|
info!("Not found: {}", e);
|
||||||
"".to_string()
|
"".to_string()
|
||||||
|
@ -220,7 +220,7 @@ fn write_storages_list(
|
||||||
|v| v.display().to_string(),
|
|v| v.display().to_string(),
|
||||||
);
|
);
|
||||||
let parent_name = if let Storage::SubDirectory(s) = storage {
|
let parent_name = if let Storage::SubDirectory(s) = storage {
|
||||||
s.parent(&storages)
|
s.parent(storages)
|
||||||
.context(format!("Failed to get parent of storage {}", s))?
|
.context(format!("Failed to get parent of storage {}", s))?
|
||||||
.name()
|
.name()
|
||||||
} else {
|
} else {
|
||||||
|
@ -238,7 +238,7 @@ fn write_storages_list(
|
||||||
)?;
|
)?;
|
||||||
if long_display {
|
if long_display {
|
||||||
let note = match storage {
|
let note = match storage {
|
||||||
Storage::PhysicalStorage(s) => s.kind(),
|
Storage::Physical(s) => s.kind(),
|
||||||
Storage::SubDirectory(s) => &s.notes,
|
Storage::SubDirectory(s) => &s.notes,
|
||||||
Storage::Online(s) => &s.provider,
|
Storage::Online(s) => &s.provider,
|
||||||
};
|
};
|
||||||
|
@ -253,11 +253,11 @@ pub(crate) fn cmd_storage_bind(
|
||||||
new_alias: String,
|
new_alias: String,
|
||||||
mount_point: PathBuf,
|
mount_point: PathBuf,
|
||||||
repo: Repository,
|
repo: Repository,
|
||||||
config_dir: &PathBuf,
|
config_dir: &Path,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let device = devices::get_device(&config_dir)?;
|
let device = devices::get_device(config_dir)?;
|
||||||
// get storages
|
// get storages
|
||||||
let mut storages = Storages::read(&config_dir)?;
|
let mut storages = Storages::read(config_dir)?;
|
||||||
let commit_comment = {
|
let commit_comment = {
|
||||||
// find matching storage
|
// find matching storage
|
||||||
let storage = &mut storages
|
let storage = &mut storages
|
||||||
|
@ -284,11 +284,11 @@ pub(crate) fn cmd_storage_bind(
|
||||||
trace!("bound new system name to the storage");
|
trace!("bound new system name to the storage");
|
||||||
trace!("storages: {:#?}", storages);
|
trace!("storages: {:#?}", storages);
|
||||||
|
|
||||||
storages.write(&config_dir)?;
|
storages.write(config_dir)?;
|
||||||
// commit
|
// commit
|
||||||
add_and_commit(
|
add_and_commit(
|
||||||
&repo,
|
&repo,
|
||||||
&Path::new(storages::STORAGESFILE),
|
Path::new(storages::STORAGESFILE),
|
||||||
&format!("Bound new storage name to storage ({})", commit_comment),
|
&format!("Bound new storage name to storage ({})", commit_comment),
|
||||||
)?;
|
)?;
|
||||||
println!("Bound new storage name to storage ({})", commit_comment);
|
println!("Bound new storage name to storage ({})", commit_comment);
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl Device {
|
||||||
pub fn new(name: String) -> Device {
|
pub fn new(name: String) -> Device {
|
||||||
let sys = System::new();
|
let sys = System::new();
|
||||||
Device {
|
Device {
|
||||||
name: name,
|
name,
|
||||||
os_name: sys.name().unwrap_or_else(|| {
|
os_name: sys.name().unwrap_or_else(|| {
|
||||||
warn!("Failed to get OS name. Saving as \"unknown\".");
|
warn!("Failed to get OS name. Saving as \"unknown\".");
|
||||||
"unknown".to_string()
|
"unknown".to_string()
|
||||||
|
@ -49,17 +49,6 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::Device;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn get_name() {
|
|
||||||
let device = Device::new("test".to_string());
|
|
||||||
assert_eq!("test".to_string(), device.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get devname of the device from file `devname`.
|
/// Get devname of the device from file `devname`.
|
||||||
fn get_devname(config_dir: &Path) -> Result<String> {
|
fn get_devname(config_dir: &Path) -> Result<String> {
|
||||||
let f = File::open(config_dir.join("devname")).context("Failed to open devname file")?;
|
let f = File::open(config_dir.join("devname")).context("Failed to open devname file")?;
|
||||||
|
@ -80,8 +69,7 @@ pub 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)
|
.find(|dev| dev.name() == devname)
|
||||||
.next()
|
|
||||||
.context("Couldn't find Device in devices.yml")
|
.context("Couldn't find Device in devices.yml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +81,7 @@ pub fn get_devices(config_dir: &Path) -> Result<Vec<Device>> {
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
let yaml: Vec<Device> =
|
let yaml: Vec<Device> =
|
||||||
serde_yaml::from_reader(reader).context("Failed to parse devices.yml")?;
|
serde_yaml::from_reader(reader).context("Failed to parse devices.yml")?;
|
||||||
return Ok(yaml);
|
Ok(yaml)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write `devices` to yaml file in `config_dir`.
|
/// Write `devices` to yaml file in `config_dir`.
|
||||||
|
@ -106,3 +94,14 @@ pub fn write_devices(config_dir: &Path, devices: Vec<Device>) -> Result<()> {
|
||||||
let writer = BufWriter::new(f);
|
let writer = BufWriter::new(f);
|
||||||
serde_yaml::to_writer(writer, &devices).map_err(|e| anyhow!(e))
|
serde_yaml::to_writer(writer, &devices).map_err(|e| anyhow!(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::Device;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_name() {
|
||||||
|
let device = Device::new("test".to_string());
|
||||||
|
assert_eq!("test".to_string(), device.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@ fn add_and_commit(repo: &Repository, path: &Path, message: &str) -> Result<Oid,
|
||||||
config.get_entry("user.email")?.value().unwrap(),
|
config.get_entry("user.email")?.value().unwrap(),
|
||||||
)?;
|
)?;
|
||||||
trace!("git signature: {}", signature);
|
trace!("git signature: {}", signature);
|
||||||
let parent_commit = find_last_commit(&repo)?;
|
let parent_commit = find_last_commit(repo)?;
|
||||||
let result = match parent_commit {
|
let result = match parent_commit {
|
||||||
Some(parent_commit) => repo.commit(
|
Some(parent_commit) => repo.commit(
|
||||||
Some("HEAD"),
|
Some("HEAD"),
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub enum StorageType {
|
||||||
/// All storage types.
|
/// All storage types.
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum Storage {
|
pub enum Storage {
|
||||||
PhysicalStorage(PhysicalDrivePartition),
|
Physical(PhysicalDrivePartition),
|
||||||
SubDirectory(Directory),
|
SubDirectory(Directory),
|
||||||
Online(OnlineStorage),
|
Online(OnlineStorage),
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ impl Storage {
|
||||||
/// Full type name like "PhysicalStorage".
|
/// Full type name like "PhysicalStorage".
|
||||||
pub fn typename(&self) -> &str {
|
pub fn typename(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(_) => "PhysicalStorage",
|
Self::Physical(_) => "PhysicalStorage",
|
||||||
Self::SubDirectory(_) => "SubDirectory",
|
Self::SubDirectory(_) => "SubDirectory",
|
||||||
Self::Online(_) => "OnlineStorage",
|
Self::Online(_) => "OnlineStorage",
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ impl Storage {
|
||||||
/// Short type name with one letter like "P".
|
/// Short type name with one letter like "P".
|
||||||
pub fn shorttypename(&self) -> &str {
|
pub fn shorttypename(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(_) => "P",
|
Self::Physical(_) => "P",
|
||||||
Self::SubDirectory(_) => "S",
|
Self::SubDirectory(_) => "S",
|
||||||
Self::Online(_) => "O",
|
Self::Online(_) => "O",
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ impl Storage {
|
||||||
impl StorageExt for Storage {
|
impl StorageExt for Storage {
|
||||||
fn name(&self) -> &String {
|
fn name(&self) -> &String {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(s) => s.name(),
|
Self::Physical(s) => s.name(),
|
||||||
Self::SubDirectory(s) => s.name(),
|
Self::SubDirectory(s) => s.name(),
|
||||||
Self::Online(s) => s.name(),
|
Self::Online(s) => s.name(),
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ impl StorageExt for Storage {
|
||||||
|
|
||||||
fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo> {
|
fn local_info(&self, device: &devices::Device) -> Option<&local_info::LocalInfo> {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(s) => s.local_info(device),
|
Self::Physical(s) => s.local_info(device),
|
||||||
Self::SubDirectory(s) => s.local_info(device),
|
Self::SubDirectory(s) => s.local_info(device),
|
||||||
Self::Online(s) => s.local_info(device),
|
Self::Online(s) => s.local_info(device),
|
||||||
}
|
}
|
||||||
|
@ -71,9 +71,9 @@ impl StorageExt for Storage {
|
||||||
|
|
||||||
fn mount_path(&self, device: &devices::Device) -> Result<path::PathBuf> {
|
fn mount_path(&self, device: &devices::Device) -> Result<path::PathBuf> {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(s) => s.mount_path(&device),
|
Self::Physical(s) => s.mount_path(device),
|
||||||
Self::SubDirectory(s) => s.mount_path(&device),
|
Self::SubDirectory(s) => s.mount_path(device),
|
||||||
Self::Online(s) => s.mount_path(&device),
|
Self::Online(s) => s.mount_path(device),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ impl StorageExt for Storage {
|
||||||
device: &devices::Device,
|
device: &devices::Device,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Storage::PhysicalStorage(s) => s.bound_on_device(alias, mount_point, device),
|
Storage::Physical(s) => s.bound_on_device(alias, mount_point, device),
|
||||||
Storage::SubDirectory(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),
|
Storage::Online(s) => s.bound_on_device(alias, mount_point, device),
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ impl StorageExt for Storage {
|
||||||
|
|
||||||
fn capacity(&self) -> Option<u64> {
|
fn capacity(&self) -> Option<u64> {
|
||||||
match self {
|
match self {
|
||||||
Storage::PhysicalStorage(s) => s.capacity(),
|
Storage::Physical(s) => s.capacity(),
|
||||||
Storage::SubDirectory(s) => s.capacity(),
|
Storage::SubDirectory(s) => s.capacity(),
|
||||||
Storage::Online(s) => s.capacity(),
|
Storage::Online(s) => s.capacity(),
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ impl StorageExt for Storage {
|
||||||
|
|
||||||
fn parent<'a>(&'a self, storages: &'a Storages) -> Option<&'a Storage> {
|
fn parent<'a>(&'a self, storages: &'a Storages) -> Option<&'a Storage> {
|
||||||
match self {
|
match self {
|
||||||
Storage::PhysicalStorage(s) => s.parent(storages),
|
Storage::Physical(s) => s.parent(storages),
|
||||||
Storage::SubDirectory(s) => s.parent(storages),
|
Storage::SubDirectory(s) => s.parent(storages),
|
||||||
Storage::Online(s) => s.parent(storages),
|
Storage::Online(s) => s.parent(storages),
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ impl StorageExt for Storage {
|
||||||
impl fmt::Display for Storage {
|
impl fmt::Display for Storage {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::PhysicalStorage(s) => s.fmt(f),
|
Self::Physical(s) => s.fmt(f),
|
||||||
Self::SubDirectory(s) => s.fmt(f),
|
Self::SubDirectory(s) => s.fmt(f),
|
||||||
Self::Online(s) => s.fmt(f),
|
Self::Online(s) => s.fmt(f),
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl Directory {
|
||||||
device: &devices::Device,
|
device: &devices::Device,
|
||||||
storages: &Storages,
|
storages: &Storages,
|
||||||
) -> Result<Directory> {
|
) -> Result<Directory> {
|
||||||
let (parent, diff_path) = util::min_parent_storage(&path, storages, &device)
|
let (parent, diff_path) = util::min_parent_storage(&path, storages, device)
|
||||||
.context("Failed to compare diff of paths")?;
|
.context("Failed to compare diff of paths")?;
|
||||||
trace!("Selected parent: {}", parent.name());
|
trace!("Selected parent: {}", parent.name());
|
||||||
let local_info = LocalInfo::new(alias, path);
|
let local_info = LocalInfo::new(alias, path);
|
||||||
|
@ -78,9 +78,9 @@ impl Directory {
|
||||||
/// Resolve mount path of directory with current device.
|
/// Resolve mount path of directory with current device.
|
||||||
fn mount_path(&self, device: &devices::Device, storages: &Storages) -> Result<path::PathBuf> {
|
fn mount_path(&self, device: &devices::Device, storages: &Storages) -> Result<path::PathBuf> {
|
||||||
let parent_mount_path = self
|
let parent_mount_path = self
|
||||||
.parent(&storages)
|
.parent(storages)
|
||||||
.context("Can't find parent storage")?
|
.context("Can't find parent storage")?
|
||||||
.mount_path(&device)?;
|
.mount_path(device)?;
|
||||||
Ok(parent_mount_path.join(self.relative_path.clone()))
|
Ok(parent_mount_path.join(self.relative_path.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ mod test {
|
||||||
);
|
);
|
||||||
let mut storages = Storages::new();
|
let mut storages = Storages::new();
|
||||||
storages
|
storages
|
||||||
.add(storages::Storage::PhysicalStorage(physical))
|
.add(storages::Storage::Physical(physical))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
storages.add(Storage::SubDirectory(directory)).unwrap();
|
storages.add(Storage::SubDirectory(directory)).unwrap();
|
||||||
// assert_eq!(directory.name(), "test_name");
|
// assert_eq!(directory.name(), "test_name");
|
||||||
|
|
|
@ -5,9 +5,8 @@ use crate::devices::Device;
|
||||||
use crate::storages::{Storage, StorageExt, Storages};
|
use crate::storages::{Storage, StorageExt, Storages};
|
||||||
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::path;
|
use std::path::{self, Path};
|
||||||
use std::{collections::HashMap, fmt};
|
use std::{collections::HashMap, fmt};
|
||||||
use sysinfo::{Disk, DiskExt, SystemExt};
|
use sysinfo::{Disk, DiskExt, SystemExt};
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ impl PhysicalDrivePartition {
|
||||||
let fs = std::str::from_utf8(fs)?;
|
let fs = std::str::from_utf8(fs)?;
|
||||||
let local_info = LocalInfo::new(alias, disk.mount_point().to_path_buf());
|
let local_info = LocalInfo::new(alias, disk.mount_point().to_path_buf());
|
||||||
Ok(PhysicalDrivePartition {
|
Ok(PhysicalDrivePartition {
|
||||||
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(),
|
||||||
|
@ -71,12 +70,8 @@ impl PhysicalDrivePartition {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_device(
|
pub fn bind_device(&mut self, disk: &sysinfo::Disk, config_dir: &Path) -> Result<()> {
|
||||||
&mut self,
|
let device = devices::get_device(config_dir)?;
|
||||||
disk: &sysinfo::Disk,
|
|
||||||
config_dir: &std::path::PathBuf,
|
|
||||||
) -> Result<()> {
|
|
||||||
let device = devices::get_device(&config_dir)?;
|
|
||||||
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(anyhow!("Failed to convert storage name to valid str.")),
|
None => return Err(anyhow!("Failed to convert storage name to valid str.")),
|
||||||
|
@ -101,33 +96,6 @@ impl PhysicalDrivePartition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use crate::{
|
|
||||||
devices::Device,
|
|
||||||
storages::{local_info::LocalInfo, StorageExt},
|
|
||||||
};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use super::PhysicalDrivePartition;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_new() {
|
|
||||||
let localinfo = LocalInfo::new("alias".to_string(), PathBuf::from("/mnt/sample"));
|
|
||||||
let storage = PhysicalDrivePartition::new(
|
|
||||||
"name".to_string(),
|
|
||||||
"SSD".to_string(),
|
|
||||||
100,
|
|
||||||
"ext_4".to_string(),
|
|
||||||
true,
|
|
||||||
localinfo,
|
|
||||||
&Device::new("test_device".to_string()),
|
|
||||||
);
|
|
||||||
assert_eq!(storage.name(), "name");
|
|
||||||
assert_eq!(storage.capacity(), Some(100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StorageExt for PhysicalDrivePartition {
|
impl StorageExt for PhysicalDrivePartition {
|
||||||
fn name(&self) -> &String {
|
fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
|
@ -203,7 +171,7 @@ pub fn select_physical_storage(
|
||||||
trace!("{:?}", disk)
|
trace!("{:?}", disk)
|
||||||
}
|
}
|
||||||
let disk = select_sysinfo_disk(&sys_disks)?;
|
let disk = select_sysinfo_disk(&sys_disks)?;
|
||||||
let storage = PhysicalDrivePartition::try_from_sysinfo_disk(&disk, disk_name, device)?;
|
let storage = PhysicalDrivePartition::try_from_sysinfo_disk(disk, disk_name, device)?;
|
||||||
Ok(storage)
|
Ok(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,10 +181,7 @@ fn select_sysinfo_disk(sysinfo: &sysinfo::System) -> Result<&Disk> {
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, disk)| {
|
.map(|(i, disk)| {
|
||||||
let name = match disk.name().to_str() {
|
let name = disk.name().to_str().unwrap_or("");
|
||||||
Some(s) => s,
|
|
||||||
None => "",
|
|
||||||
};
|
|
||||||
let fs: &str = std::str::from_utf8(disk.file_system()).unwrap_or("unknown");
|
let fs: &str = std::str::from_utf8(disk.file_system()).unwrap_or("unknown");
|
||||||
let kind = format!("{:?}", disk.kind());
|
let kind = format!("{:?}", disk.kind());
|
||||||
let mount_path = disk.mount_point();
|
let mount_path = disk.mount_point();
|
||||||
|
@ -246,3 +211,30 @@ fn select_sysinfo_disk(sysinfo: &sysinfo::System) -> Result<&Disk> {
|
||||||
trace!("selected disk: {:?}", disk);
|
trace!("selected disk: {:?}", disk);
|
||||||
Ok(disk)
|
Ok(disk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::{
|
||||||
|
devices::Device,
|
||||||
|
storages::{local_info::LocalInfo, StorageExt},
|
||||||
|
};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use super::PhysicalDrivePartition;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new() {
|
||||||
|
let localinfo = LocalInfo::new("alias".to_string(), PathBuf::from("/mnt/sample"));
|
||||||
|
let storage = PhysicalDrivePartition::new(
|
||||||
|
"name".to_string(),
|
||||||
|
"SSD".to_string(),
|
||||||
|
100,
|
||||||
|
"ext_4".to_string(),
|
||||||
|
true,
|
||||||
|
localinfo,
|
||||||
|
&Device::new("test_device".to_string()),
|
||||||
|
);
|
||||||
|
assert_eq!(storage.name(), "name");
|
||||||
|
assert_eq!(storage.capacity(), Some(100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
src/util.rs
12
src/util.rs
|
@ -21,7 +21,7 @@ pub fn min_parent_storage<'a>(
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
};
|
};
|
||||||
let diff = pathdiff::diff_paths(&path, storage_path)?;
|
let diff = pathdiff::diff_paths(path, storage_path)?;
|
||||||
if diff.components().any(|c| c == path::Component::ParentDir) {
|
if diff.components().any(|c| c == path::Component::ParentDir) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,14 +115,12 @@ mod test {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.eq(&PathBuf::from("/aaa/bbb/ccc")));
|
.eq(&PathBuf::from("/aaa/bbb/ccc")));
|
||||||
let expanded = expand_tilde(PathBuf::from("~/aaa/bbb/ccc"));
|
let expanded = expand_tilde(PathBuf::from("~/aaa/bbb/ccc"));
|
||||||
match expanded {
|
if let Ok(path) = expanded {
|
||||||
Ok(path) => assert!(path.eq(&dirs::home_dir().unwrap().join("aaa/bbb/ccc"))),
|
assert!(path.eq(&dirs::home_dir().unwrap().join("aaa/bbb/ccc")))
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
let expanded = expand_tilde(PathBuf::from("aaa/~/bbb"));
|
let expanded = expand_tilde(PathBuf::from("aaa/~/bbb"));
|
||||||
match expanded {
|
if let Ok(path) = expanded {
|
||||||
Ok(path) => assert_eq!(path, PathBuf::from("aaa/~/bbb")),
|
assert_eq!(path, PathBuf::from("aaa/~/bbb"))
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
34
tests/cli.rs
34
tests/cli.rs
|
@ -41,7 +41,7 @@ mod cmd_init {
|
||||||
let repo_1 = Repository::open(&config_dir_1)?;
|
let repo_1 = Repository::open(&config_dir_1)?;
|
||||||
let upstream_name = "remote";
|
let upstream_name = "remote";
|
||||||
let mut repo_1_remote =
|
let mut repo_1_remote =
|
||||||
repo_1.remote(upstream_name, &bare_repo_dir.path().to_str().unwrap())?;
|
repo_1.remote(upstream_name, bare_repo_dir.path().to_str().unwrap())?;
|
||||||
repo_1_remote.push(&["refs/heads/main"], None)?;
|
repo_1_remote.push(&["refs/heads/main"], None)?;
|
||||||
trace!("bare repo {:?}", bare_repo_dir.display());
|
trace!("bare repo {:?}", bare_repo_dir.display());
|
||||||
println!("{:?}", bare_repo_dir.read_dir()?);
|
println!("{:?}", bare_repo_dir.read_dir()?);
|
||||||
|
@ -112,7 +112,7 @@ mod cmd_init {
|
||||||
let repo_1 = Repository::open(&config_dir_1)?;
|
let repo_1 = Repository::open(&config_dir_1)?;
|
||||||
let upstream_name = "remote";
|
let upstream_name = "remote";
|
||||||
let mut repo_1_remote =
|
let mut repo_1_remote =
|
||||||
repo_1.remote(upstream_name, &bare_repo_dir.path().to_str().unwrap())?;
|
repo_1.remote(upstream_name, bare_repo_dir.path().to_str().unwrap())?;
|
||||||
repo_1_remote.push(&["refs/heads/main"], None)?;
|
repo_1_remote.push(&["refs/heads/main"], None)?;
|
||||||
trace!("bare repo {:?}", bare_repo_dir.display());
|
trace!("bare repo {:?}", bare_repo_dir.display());
|
||||||
println!("{:?}", bare_repo_dir.read_dir()?);
|
println!("{:?}", bare_repo_dir.read_dir()?);
|
||||||
|
@ -182,9 +182,7 @@ mod cmd_init {
|
||||||
.stdout(predicate::str::contains(""));
|
.stdout(predicate::str::contains(""));
|
||||||
// Add storage (directory)
|
// Add storage (directory)
|
||||||
let sample_directory = &sample_storage.join("foo").join("bar");
|
let sample_directory = &sample_storage.join("foo").join("bar");
|
||||||
DirBuilder::new()
|
DirBuilder::new().recursive(true).create(sample_directory)?;
|
||||||
.recursive(true)
|
|
||||||
.create(&sample_directory)?;
|
|
||||||
Command::cargo_bin("xdbm")?
|
Command::cargo_bin("xdbm")?
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(config_dir_1.path())
|
.arg(config_dir_1.path())
|
||||||
|
@ -194,7 +192,7 @@ mod cmd_init {
|
||||||
.arg("--alias")
|
.arg("--alias")
|
||||||
.arg("docs")
|
.arg("docs")
|
||||||
.arg("gdrive_docs")
|
.arg("gdrive_docs")
|
||||||
.arg(&sample_directory)
|
.arg(sample_directory)
|
||||||
.assert()
|
.assert()
|
||||||
.success()
|
.success()
|
||||||
.stdout(predicate::str::contains(""));
|
.stdout(predicate::str::contains(""));
|
||||||
|
@ -222,7 +220,7 @@ mod cmd_init {
|
||||||
.arg("--alias")
|
.arg("--alias")
|
||||||
.arg("gdocs")
|
.arg("gdocs")
|
||||||
.arg("--path")
|
.arg("--path")
|
||||||
.arg(&sample_directory)
|
.arg(sample_directory)
|
||||||
.arg("gdrive_docs")
|
.arg("gdrive_docs")
|
||||||
.assert()
|
.assert()
|
||||||
.success()
|
.success()
|
||||||
|
@ -232,7 +230,7 @@ mod cmd_init {
|
||||||
let sample_storage_2 = assert_fs::TempDir::new()?;
|
let sample_storage_2 = assert_fs::TempDir::new()?;
|
||||||
Command::cargo_bin("xdbm")?
|
Command::cargo_bin("xdbm")?
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&config_dir_2.path())
|
.arg(config_dir_2.path())
|
||||||
.arg("storage")
|
.arg("storage")
|
||||||
.arg("add")
|
.arg("add")
|
||||||
.arg("online")
|
.arg("online")
|
||||||
|
@ -243,13 +241,13 @@ mod cmd_init {
|
||||||
.arg("--alias")
|
.arg("--alias")
|
||||||
.arg("nas")
|
.arg("nas")
|
||||||
.arg("nas")
|
.arg("nas")
|
||||||
.arg(&sample_storage_2.path())
|
.arg(sample_storage_2.path())
|
||||||
.assert()
|
.assert()
|
||||||
.success();
|
.success();
|
||||||
|
|
||||||
Command::cargo_bin("xdbm")?
|
Command::cargo_bin("xdbm")?
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&config_dir_2.path())
|
.arg(config_dir_2.path())
|
||||||
.arg("storage")
|
.arg("storage")
|
||||||
.arg("list")
|
.arg("list")
|
||||||
.arg("-l")
|
.arg("-l")
|
||||||
|
@ -257,18 +255,18 @@ mod cmd_init {
|
||||||
.success();
|
.success();
|
||||||
// backup add
|
// backup add
|
||||||
let backup_src = &sample_storage_2.join("foo").join("bar");
|
let backup_src = &sample_storage_2.join("foo").join("bar");
|
||||||
DirBuilder::new().recursive(true).create(&backup_src)?;
|
DirBuilder::new().recursive(true).create(backup_src)?;
|
||||||
let backup_dest = &sample_directory.join("docs");
|
let backup_dest = &sample_directory.join("docs");
|
||||||
DirBuilder::new().recursive(true).create(&backup_dest)?;
|
DirBuilder::new().recursive(true).create(backup_dest)?;
|
||||||
Command::cargo_bin("xdbm")?
|
Command::cargo_bin("xdbm")?
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&config_dir_2.path())
|
.arg(config_dir_2.path())
|
||||||
.arg("backup")
|
.arg("backup")
|
||||||
.arg("add")
|
.arg("add")
|
||||||
.arg("--src")
|
.arg("--src")
|
||||||
.arg(&backup_src)
|
.arg(backup_src)
|
||||||
.arg("--dest")
|
.arg("--dest")
|
||||||
.arg(&backup_dest)
|
.arg(backup_dest)
|
||||||
.arg("foodoc")
|
.arg("foodoc")
|
||||||
.arg("external")
|
.arg("external")
|
||||||
.arg("rsync")
|
.arg("rsync")
|
||||||
|
@ -278,13 +276,13 @@ mod cmd_init {
|
||||||
|
|
||||||
Command::cargo_bin("xdbm")?
|
Command::cargo_bin("xdbm")?
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&config_dir_2.path())
|
.arg(config_dir_2.path())
|
||||||
.arg("backup")
|
.arg("backup")
|
||||||
.arg("add")
|
.arg("add")
|
||||||
.arg("--src")
|
.arg("--src")
|
||||||
.arg(&backup_src)
|
.arg(backup_src)
|
||||||
.arg("--dest")
|
.arg("--dest")
|
||||||
.arg(&backup_dest)
|
.arg(backup_dest)
|
||||||
.arg("foodoc")
|
.arg("foodoc")
|
||||||
.arg("external")
|
.arg("external")
|
||||||
.arg("rsync")
|
.arg("rsync")
|
||||||
|
|
Loading…
Reference in a new issue