add stuff

This commit is contained in:
timeshifter
2026-05-06 19:14:50 +02:00
parent 8c55028574
commit a30e0f4a8c
7 changed files with 87 additions and 5 deletions
+2
View File
@@ -3,6 +3,8 @@ snapshot_interval = "monthly"
local_pool_name = "tank" local_pool_name = "tank"
do_not_backup_datasets = ["docker", "cache"]
[backup_pools] [backup_pools]
backup1 = 'a235c116-764f-4082-97fc-47ca31e11e53' backup1 = 'a235c116-764f-4082-97fc-47ca31e11e53'
backup2 = '200ced55-894c-4f70-b089-b140e60193fc' backup2 = '200ced55-894c-4f70-b089-b140e60193fc'
+1
View File
@@ -8,6 +8,7 @@ pub struct Config {
pub snapshot_tag: String, pub snapshot_tag: String,
pub snapshot_interval: String, pub snapshot_interval: String,
pub local_pool_name: String, pub local_pool_name: String,
pub do_not_backup_datasets: Vec<String>,
pub backup_pools: BackupPools, pub backup_pools: BackupPools,
} }
+1
View File
@@ -1,5 +1,6 @@
pub mod cmd; pub mod cmd;
pub mod config; pub mod config;
pub mod encryption; pub mod encryption;
pub mod pathbuf;
pub mod todo; pub mod todo;
pub mod zfs; pub mod zfs;
+10 -2
View File
@@ -26,6 +26,7 @@ fn main() -> Result<()> {
&backup_pool, &backup_pool,
config.snapshot_tag, config.snapshot_tag,
config.snapshot_interval, config.snapshot_interval,
config.do_not_backup_datasets,
)?; )?;
if something_was_done { if something_was_done {
@@ -56,9 +57,16 @@ fn do_backup(
backup_pool: &ZPool, backup_pool: &ZPool,
snapshot_tag: String, snapshot_tag: String,
snapshot_interval: String, snapshot_interval: String,
datasets: Vec<String>,
) -> Result<bool> { ) -> Result<bool> {
let todos = todo::Todo::plan(local_pool, backup_pool, snapshot_tag, snapshot_interval) let todos = todo::Todo::plan(
.context("planning todos")?; local_pool,
backup_pool,
datasets,
snapshot_tag,
snapshot_interval,
)
.context("planning todos")?;
if todos.is_empty() { if todos.is_empty() {
println!("nothing to do"); println!("nothing to do");
+58
View File
@@ -0,0 +1,58 @@
use crate::zfs::Dataset;
pub trait Relative {
fn is_child_of(&self, other: &Dataset) -> bool;
}
impl Relative for Dataset {
fn is_child_of(&self, other: &Dataset) -> bool {
let self_components: Vec<_> = self.0.components().collect();
let other_components: Vec<_> = other.0.components().collect();
if self_components.len() < other_components.len() {
return false;
}
other
.0
.iter()
.zip(self.0.iter())
.map(|(left, right)| left == right)
.reduce(|left, right| left && right)
.unwrap()
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
#[test]
fn base() {
let mut pb1 = PathBuf::new();
pb1.push("/a/b/c");
let ds1 = Dataset::new(pb1);
let mut pb2 = PathBuf::new();
pb2.push("/a/b/c/d");
let ds2 = Dataset::new(pb2);
assert!(ds2.is_child_of(&ds1));
assert!(!ds1.is_child_of(&ds2));
}
#[test]
fn not_related() {
let mut pb1 = PathBuf::new();
pb1.push("/a/z/c");
let ds1 = Dataset::new(pb1);
let mut pb2 = PathBuf::new();
pb2.push("/a/b/c");
let ds2 = Dataset::new(pb2);
assert!(!ds2.is_child_of(&ds1));
}
}
+13 -1
View File
@@ -1,8 +1,12 @@
use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use crate::zfs::Snapshot; use crate::zfs::Snapshot;
use crate::zfs::ZPool; use crate::zfs::ZPool;
use crate::pathbuf::Relative;
use crate::zfs::Dataset; use crate::zfs::Dataset;
pub enum Todo { pub enum Todo {
@@ -29,12 +33,20 @@ impl Todo {
pub fn plan( pub fn plan(
local: &ZPool, local: &ZPool,
remote: &ZPool, remote: &ZPool,
do_not_backup_datasets: Vec<String>,
snapshot_tag: String, snapshot_tag: String,
snapshot_interval: String, snapshot_interval: String,
) -> Result<Vec<Self>> { ) -> Result<Vec<Self>> {
let mut result = vec![]; let mut result = vec![];
for local_dataset in &local.datasets { 'outer: for local_dataset in &local.datasets {
for do_not_backup in &do_not_backup_datasets {
let ds = Dataset::new(PathBuf::from(do_not_backup));
if local_dataset.is_child_of(&ds) {
continue 'outer;
}
}
let last_snapshot_with_tag = let last_snapshot_with_tag =
local_dataset.find_last_snapshot_with_tag(&snapshot_tag, &snapshot_interval)?; local_dataset.find_last_snapshot_with_tag(&snapshot_tag, &snapshot_interval)?;
+2 -2
View File
@@ -120,10 +120,10 @@ impl ZPool {
/// E.g. if the name of the pool is `tank`, with the elements `ROOT` and `default` below it, this /// E.g. if the name of the pool is `tank`, with the elements `ROOT` and `default` below it, this
/// struct would contain `tank/ROOT/default`. /// struct would contain `tank/ROOT/default`.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Dataset(PathBuf); pub struct Dataset(pub(crate) PathBuf);
impl Dataset { impl Dataset {
fn new(path: PathBuf) -> Self { pub fn new(path: PathBuf) -> Self {
Self(path) Self(path)
} }