Merge pull request #76 from rustic-rs/add-config

Add config command
This commit is contained in:
aawsome 2022-07-22 23:44:35 +02:00 committed by GitHub
commit 4390a85ebc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 119 additions and 22 deletions

View File

@ -139,7 +139,7 @@ impl WriteBackend for LocalBackend {
v3!("writing tpe: {:?}, id: {}", &tpe, &id);
let filename = self.path(tpe, id);
let mut file = fs::OpenOptions::new()
.create_new(true)
.create(true)
.write(true)
.open(&filename)?;
copy(&mut f, &mut file)?;
@ -151,7 +151,7 @@ impl WriteBackend for LocalBackend {
v3!("writing tpe: {:?}, id: {}", &tpe, &id);
let filename = self.path(tpe, id);
let mut file = fs::OpenOptions::new()
.create_new(true)
.create(true)
.write(true)
.open(&filename)?;
file.write_all(&buf)?;

View File

@ -1,6 +1,6 @@
use std::path::PathBuf;
use anyhow::{anyhow, bail, Result};
use anyhow::{anyhow, Result};
use chrono::{Duration, Local};
use clap::Parser;
use gethostname::gethostname;
@ -57,11 +57,7 @@ pub(super) async fn execute(
) -> Result<()> {
let time = Local::now();
let poly = config.poly()?;
let zstd = match config.version {
1 => None,
2 => Some(0),
_ => bail!("config version not supported!"),
};
let zstd = config.zstd()?;
let mut be = DryRunBackend::new(be.clone(), opts.dry_run);
be.set_zstd(zstd);

View File

@ -21,14 +21,14 @@ pub(super) struct Opts {
enum Command {
TreeBlob(IdOpt),
DataBlob(IdOpt),
Config(IdOpt),
Config,
Index(IdOpt),
Snapshot(IdOpt),
/// display a tree within a snapshot
Tree(TreeOpts),
}
#[derive(Parser)]
#[derive(Default, Parser)]
struct IdOpt {
/// id to cat
id: String,
@ -45,7 +45,7 @@ struct TreeOpts {
pub(super) async fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> {
match opts.command {
Command::Config(opt) => cat_file(be, FileType::Config, opt).await,
Command::Config => cat_file(be, FileType::Config, IdOpt::default()).await,
Command::Index(opt) => cat_file(be, FileType::Index, opt).await,
Command::Snapshot(opt) => cat_file(be, FileType::Snapshot, opt).await,
// special treatment for catingg blobs: read the index and use it to locate the blob

76
src/commands/config.rs Normal file
View File

@ -0,0 +1,76 @@
use anyhow::{bail, Result};
use clap::Parser;
use crate::backend::DecryptFullBackend;
use crate::repo::ConfigFile;
#[derive(Parser)]
pub(super) struct Opts {
#[clap(flatten)]
config_opts: ConfigOpts,
}
pub(super) async fn execute(
be: &impl DecryptFullBackend,
opts: Opts,
config: ConfigFile,
) -> Result<()> {
let mut new_config = config.clone();
opts.config_opts.apply(&mut new_config)?;
if new_config != config {
be.save_file(&new_config).await?;
println!("saved new config");
} else {
println!("config is unchanged");
}
Ok(())
}
#[derive(Parser)]
pub(super) struct ConfigOpts {
/// set compression level, 0 equals no compression
#[clap(long, value_name = "LEVEL")]
pub set_compression: Option<i32>,
/// set repository version
#[clap(long, value_name = "VERSION")]
pub set_version: Option<u32>,
}
impl ConfigOpts {
pub fn apply(&self, config: &mut ConfigFile) -> Result<()> {
if let Some(version) = self.set_version {
let range = 1..=2;
if !range.contains(&version) {
bail!(
"version {version} is not supported. Allowed values: {}..{}",
range.start(),
range.end()
);
} else if version < config.version {
bail!(
"cannot downgrade version from {} to {version}",
config.version
);
}
config.version = version;
}
if let Some(compression) = self.set_compression {
if config.version == 1 && compression != 0 {
bail!("compression level {compression} is not supported for repo v1");
}
let range = zstd::compression_level_range();
if !range.contains(&compression) {
bail!(
"compression level {compression} is not supported. Allowed values: 0..{}",
range.end()
);
}
config.compression = Some(compression);
}
Ok(())
}
}

View File

@ -5,6 +5,7 @@ use anyhow::{bail, Result};
use clap::Parser;
use rpassword::{prompt_password, read_password_from_bufread};
use super::config::ConfigOpts;
use super::key::AddOpts;
use crate::backend::{DecryptBackend, DecryptWriteBackend, FileType, WriteBackend};
use crate::chunker;
@ -16,6 +17,9 @@ use crate::repo::{ConfigFile, KeyFile};
pub(super) struct Opts {
#[clap(flatten)]
key_opts: AddOpts,
#[clap(flatten)]
config_opts: ConfigOpts,
}
pub(super) async fn execute(
@ -28,6 +32,17 @@ pub(super) async fn execute(
bail!("Config file already exists. Aborting.");
}
// Create config first to allow catching errors from here without writing anything
let repo_id = Id::random();
let chunker_poly = chunker::random_poly()?;
let version = match opts.config_opts.set_version {
None => 2,
Some(_) => 1, // will be changed later
};
let mut config = ConfigFile::new(version, repo_id, chunker_poly);
opts.config_opts.apply(&mut config)?;
// generate key
let key = Key::new();
let key_opts = opts.key_opts;
@ -56,10 +71,7 @@ pub(super) async fn execute(
}
println!("key {} successfully added.", id);
let repo_id = Id::random();
let chunker_poly = chunker::random_poly()?;
let mut config = ConfigFile::new(2, repo_id, chunker_poly);
// save config
let dbe = DecryptBackend::new(be, key.clone());
dbe.save_file(&config).await?;

View File

@ -12,6 +12,7 @@ use crate::repo::ConfigFile;
mod backup;
mod cat;
mod check;
mod config;
mod diff;
mod forget;
mod helpers;
@ -76,6 +77,9 @@ enum Command {
/// Cat repository files and blobs
Cat(cat::Opts),
/// Change repo configuration
Config(config::Opts),
/// Check repository
Check(check::Opts),
@ -171,6 +175,7 @@ pub async fn execute() -> Result<()> {
match cmd {
Command::Backup(opts) => backup::execute(&dbe, opts, config, command).await?,
Command::Config(opts) => config::execute(&dbe, opts, config).await?,
Command::Cat(opts) => cat::execute(&dbe, opts).await?,
Command::Check(opts) => check::execute(&dbe, &cache, &be_hot, &be, opts).await?,
Command::Diff(opts) => diff::execute(&dbe, opts).await?,

View File

@ -715,11 +715,7 @@ impl Pruner {
opts: Opts,
config: ConfigFile,
) -> Result<()> {
let zstd = match config.version {
1 => None,
2 => Some(0),
_ => bail!("config version not supported!"),
};
let zstd = config.zstd()?;
let mut be = be.clone();
be.set_zstd(zstd);

View File

@ -1,16 +1,18 @@
use anyhow::Result;
use anyhow::{bail, Result};
use serde::{Deserialize, Serialize};
use crate::backend::{FileType, RepoFile};
use crate::id::Id;
#[derive(Debug, Default, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConfigFile {
pub version: u32,
pub id: Id,
pub chunker_polynomial: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub is_hot: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub compression: Option<i32>, // note that Some(0) means no compression.
}
impl RepoFile for ConfigFile {
@ -24,10 +26,20 @@ impl ConfigFile {
id,
chunker_polynomial: format!("{:x}", poly),
is_hot: None,
compression: None,
}
}
pub fn poly(&self) -> Result<u64> {
Ok(u64::from_str_radix(&self.chunker_polynomial, 16)?)
}
pub fn zstd(&self) -> Result<Option<i32>> {
match (self.version, self.compression) {
(1, _) | (2, Some(0)) => Ok(None),
(2, None) => Ok(Some(0)), // use default (=0) zstd compression
(2, Some(c)) => Ok(Some(c)),
_ => bail!("config version not supported!"),
}
}
}