Warn about failures loudly

Closes #47
This commit is contained in:
Olivier 'reivilibre' 2021-08-15 19:28:49 +01:00
parent 47eea11827
commit 6d24ccb248
3 changed files with 110 additions and 6 deletions

View File

@ -30,6 +30,13 @@ use datman::remote::backup_source_requester::backup_remote_source_to_destination
use datman::remote::backup_source_responder; use datman::remote::backup_source_responder;
use std::str::FromStr; use std::str::FromStr;
pub const FAILURE_SYMBOL_OBNOXIOUS_FLASHING: &str = "\x1b[5m\x1b[31m⚠ \x1b[25m\x1b[22m";
pub const BOLD: &str = "\x1b[1m";
pub const BOLD_OFF: &str = "\x1b[22m";
pub const WHITE: &str = "\x1b[37m";
pub const RED: &str = "\x1b[31m";
pub const GREEN: &str = "\x1b[32m";
#[derive(Clap)] #[derive(Clap)]
pub enum DatmanCommand { pub enum DatmanCommand {
/// Initialise a datman descriptor in this directory. /// Initialise a datman descriptor in this directory.
@ -127,6 +134,33 @@ impl FromStr for HumanDateTime {
} }
} }
fn with_obvious_successfail_message<R>(result: anyhow::Result<R>) -> anyhow::Result<R> {
match &result {
Ok(_) => {
eprintln!("Operation {}successful{}.", GREEN, WHITE);
}
Err(error) => {
eprintln!("{:?}", error);
eprintln!(
"{}{}Operation {}{}FAILED{}!{}",
FAILURE_SYMBOL_OBNOXIOUS_FLASHING, WHITE, RED, BOLD, WHITE, BOLD_OFF
);
}
};
result
}
fn with_exitcode<R>(result: anyhow::Result<R>) {
match &result {
Ok(_) => {
std::process::exit(0);
}
Err(_) => {
std::process::exit(5);
}
};
}
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
@ -168,7 +202,7 @@ fn main() -> anyhow::Result<()> {
} }
} }
if let Some(remote_name) = remote { let result = if let Some(remote_name) = remote {
let remote_host_descriptor = let remote_host_descriptor =
if let Some(rhd) = descriptor.remote_hosts.get(&remote_name) { if let Some(rhd) = descriptor.remote_hosts.get(&remote_name) {
rhd rhd
@ -185,7 +219,6 @@ fn main() -> anyhow::Result<()> {
remote_host_descriptor, remote_host_descriptor,
yama::utils::get_number_of_workers("YAMA_CHUNKERS"), yama::utils::get_number_of_workers("YAMA_CHUNKERS"),
) )
.unwrap();
} else { } else {
backup_source_to_destination( backup_source_to_destination(
source, source,
@ -196,8 +229,8 @@ fn main() -> anyhow::Result<()> {
&destination_name, &destination_name,
yama::utils::get_number_of_workers("YAMA_CHUNKERS"), yama::utils::get_number_of_workers("YAMA_CHUNKERS"),
) )
.unwrap(); };
} with_exitcode(with_obvious_successfail_message(result))
} }
DatmanCommand::BackupAll { destination_name } => { DatmanCommand::BackupAll { destination_name } => {
let descriptor = load_descriptor(Path::new(".")).unwrap(); let descriptor = load_descriptor(Path::new(".")).unwrap();

View File

@ -5,7 +5,7 @@ from tempfile import TemporaryDirectory
from unittest import TestCase from unittest import TestCase
from helpers import DirectoryDescriptor, generate_random_dir, scan_dir from helpers import DirectoryDescriptor, generate_random_dir, scan_dir
from helpers.datman_helpers import set_up_simple_datman from helpers.datman_helpers import get_hostname, set_up_simple_datman
from helpers.yama_helpers import set_up_simple_yama from helpers.yama_helpers import set_up_simple_yama
@ -59,3 +59,71 @@ class TestBackupAndExtract(TestCase):
self.assertEqual( self.assertEqual(
value.ignore_metadata(), later_expected_descriptor.ignore_metadata() value.ignore_metadata(), later_expected_descriptor.ignore_metadata()
) )
def test_backup_failure_is_loud(self):
"""
Tests that backup failure is noticeable.
"""
td = TemporaryDirectory("test_backup_failure_is_loud")
tdpath = Path(td.name)
datman_path = tdpath.joinpath("datman")
src_path = datman_path.joinpath("srca")
yama_path = datman_path.joinpath("main")
set_up_simple_datman(
datman_path,
f"""
[source.srcimpossible]
directory = "/path/to/absolutely/nowhere"
hostname = "{get_hostname()}"
[source.srcimpossible2]
directory = "/path/to/absolutely/nowhere"
hostname = "notmymachine"
[source.srcimpossible3]
helper = "failedhelper"
label = "precious"
kind = {{ stdout = "blahblah.txt" }}
""",
)
set_up_simple_yama(yama_path)
rng = Random()
seed = rng.randint(0, 9001)
print(f"seed: {seed}")
rng.seed(seed)
later_expected_descriptor, _ = generate_random_dir(rng, src_path, 32)
impossible_proc = subprocess.run(
("datman", "backup-one", "srcimpossible", "main"),
cwd=datman_path,
stderr=subprocess.PIPE,
)
self.assertNotEqual(impossible_proc.returncode, 0)
last_line = impossible_proc.stderr.decode().split("\n")[-2]
self.assertIn("\x1b[31m\x1b[1mFAILED", last_line)
# NOT YET SUPPORTED
print("TEST FOR REMOTE SRC LOUDNESS NOT YET SUPPORTED")
# impossible_proc = subprocess.run(("datman", "backup-one",
# "srcimpossible2", "main"),
# cwd=datman_path,
# stderr=subprocess.PIPE)
# self.assertNotEqual(impossible_proc.returncode, 0)
# last_line = impossible_proc.stderr.decode().split("\n")[-2]
# self.assertIn("\x1b[31m\x1b[1mFAILED", last_line)
impossible_proc = subprocess.run(
("datman", "backup-one", "srcimpossible3", "main"),
cwd=datman_path,
stderr=subprocess.PIPE,
)
self.assertNotEqual(impossible_proc.returncode, 0)
last_line = impossible_proc.stderr.decode().split("\n")[-2]
self.assertIn("\x1b[31m\x1b[1mFAILED", last_line)
td.cleanup()

View File

@ -1,12 +1,13 @@
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from typing import Optional
def get_hostname(): def get_hostname():
return subprocess.check_output("hostname").strip().decode() return subprocess.check_output("hostname").strip().decode()
def set_up_simple_datman(path: Path): def set_up_simple_datman(path: Path, custom_extra_test: Optional[str]):
path.mkdir(exist_ok=True) path.mkdir(exist_ok=True)
subprocess.check_call(("datman", "init"), cwd=path) subprocess.check_call(("datman", "init"), cwd=path)
@ -22,3 +23,5 @@ path = "main"
included_labels = ["precious"] included_labels = ["precious"]
""" """
) )
if custom_extra_test:
file.write(custom_extra_test)