mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
commit
4390a85ebc
@ -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)?;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
76
src/commands/config.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
@ -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?;
|
||||
|
||||
|
||||
@ -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?,
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user