From 811a78c19c48ae862faffeb24a061a4f8f932da3 Mon Sep 17 00:00:00 2001 From: aawsome <37850842+aawsome@users.noreply.github.com> Date: Tue, 12 Mar 2024 01:50:39 +0100 Subject: [PATCH 1/5] fix(rclone): Use semver for version checking (#188) rclone version checking required a version in form "major.minor.patch". Now it supports all semver-compatible versions. closes https://github.com/rustic-rs/rustic/issues/1097 fixes #6 --------- Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com> Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- Cargo.toml | 1 + crates/backend/Cargo.toml | 5 +- crates/backend/src/error.rs | 2 + crates/backend/src/rclone.rs | 96 ++++++++++++++++++++++++------------ crates/core/Cargo.toml | 2 +- 5 files changed, 71 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 922538160..91accdf1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ rustic_core = { path = "crates/core" } simplelog = "0.12.2" # dev-dependencies +rstest = "0.18.2" tempfile = "3.10.1" # see: https://nnethercote.github.io/perf-book/build-configuration.html diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index 099283f05..19dd94131 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -38,7 +38,7 @@ clap = ["dep:clap"] s3 = ["opendal"] opendal = ["dep:opendal", "dep:rayon", "dep:tokio", "tokio/rt-multi-thread"] rest = ["dep:reqwest", "dep:backoff"] -rclone = ["rest", "dep:rand"] +rclone = ["rest", "dep:rand", "dep:semver"] # Note: sftp is not yet supported on windows, see below sftp = ["opendal"] @@ -82,6 +82,7 @@ reqwest = { version = "0.11.25", default-features = false, features = ["json", " # rclone backend rand = { version = "0.8.5", optional = true } +semver = { version = "1.0.22", optional = true } # opendal backend rayon = { version = "1.9.0", optional = true } @@ -96,7 +97,7 @@ opendal = { version = "0.45", features = ["services-b2", "services-sftp", "servi opendal = { version = "0.45", features = ["services-b2", "services-swift", "layers-blocking"], optional = true } [dev-dependencies] -rstest = "0.18.2" +rstest = { workspace = true } [lints] workspace = true diff --git a/crates/backend/src/error.rs b/crates/backend/src/error.rs index 8bf364bc7..01bcfded8 100644 --- a/crates/backend/src/error.rs +++ b/crates/backend/src/error.rs @@ -54,6 +54,8 @@ pub enum RcloneErrorKind { FromUtf8Error(#[from] Utf8Error), /// error parsing verision number from `{0:?}` FromParseVersion(String), + /// Using rclone without authentication! Upgrade to rclone >= 1.52.2 (current version: `{0}`)! + RCloneWithoutAuthentication(String), } /// [`RestErrorKind`] describes the errors that can be returned while dealing with the REST API diff --git a/crates/backend/src/rclone.rs b/crates/backend/src/rclone.rs index 0fb536356..6dd5e76eb 100644 --- a/crates/backend/src/rclone.rs +++ b/crates/backend/src/rclone.rs @@ -7,12 +7,13 @@ use std::{ use anyhow::Result; use bytes::Bytes; -use itertools::Itertools; -use log::{debug, info, warn}; +use log::{debug, info}; use rand::{ distributions::{Alphanumeric, DistString}, thread_rng, }; + +use semver::{BuildMetadata, Prerelease, Version, VersionReq}; use shell_words::split; use crate::{error::RcloneErrorKind, rest::RestBackend}; @@ -47,7 +48,11 @@ impl Drop for RcloneBackend { } } -/// Get the rclone version. +/// Check the rclone version. +/// +/// # Arguments +/// +/// * `rclone_version_output` - The output of `rclone version`. /// /// # Errors /// @@ -58,31 +63,40 @@ impl Drop for RcloneBackend { /// /// # Returns /// -/// The rclone version as a tuple of (major, minor, patch). +/// * `Ok(())` - If the rclone version is supported. /// /// [`RcloneErrorKind::FromIoError`]: RcloneErrorKind::FromIoError /// [`RcloneErrorKind::FromUtf8Error`]: RcloneErrorKind::FromUtf8Error /// [`RcloneErrorKind::NoOutputForRcloneVersion`]: RcloneErrorKind::NoOutputForRcloneVersion /// [`RcloneErrorKind::FromParseVersion`]: RcloneErrorKind::FromParseVersion -fn rclone_version() -> Result<(i32, i32, i32)> { - let rclone_version_output = Command::new("rclone") - .arg("version") - .output() - .map_err(RcloneErrorKind::FromIoError)? - .stdout; - let rclone_version = std::str::from_utf8(&rclone_version_output) +fn check_clone_version(rclone_version_output: &[u8]) -> Result<()> { + let rclone_version = std::str::from_utf8(rclone_version_output) .map_err(RcloneErrorKind::FromUtf8Error)? .lines() .next() .ok_or_else(|| RcloneErrorKind::NoOutputForRcloneVersion)? .trim_start_matches(|c: char| !c.is_numeric()); - let versions = rclone_version - .split(&['.', '-', ' '][..]) - .filter_map(|v| v.parse().ok()) - .collect_tuple() - .ok_or_else(|| RcloneErrorKind::FromParseVersion(rclone_version.to_string()))?; - Ok(versions) + let mut parsed_version = Version::parse(rclone_version)?; + + // we need to set the pre and build fields to empty to make the comparison work + // otherwise the comparison will take the pre and build fields into account + // which would make beta versions pass the check + parsed_version.pre = Prerelease::EMPTY; + parsed_version.build = BuildMetadata::EMPTY; + + // for rclone < 1.52.2 setting user/password via env variable doesn't work. This means + // we are setting up an rclone without authentication which is a security issue! + // we hard fail here to prevent this, as we can't guarantee the security of the data + // also because 1.52.2 has been released on Jun 24, 2020, we can assume that this is a + // reasonable lower bound for the version + if VersionReq::parse("<1.52.2")?.matches(&parsed_version) { + return Err( + RcloneErrorKind::RCloneWithoutAuthentication(rclone_version.to_string()).into(), + ); + } + + Ok(()) } impl RcloneBackend { @@ -121,21 +135,16 @@ impl RcloneBackend { .unwrap_or(true); if use_password && rclone_command.is_none() { - // if we want to use a password and rclone_command is not explicitely set, we check for a rclone version supporting - // user/password via env variables - match rclone_version() { - Ok(v) => { - if v < (1, 52, 2) { - // TODO: This should be an error, and explicitly agreed to with a flag passed to `rustic`, - // check #812 for details - // for rclone < 1.52.2 setting user/password via env variable doesn't work. This means - // we are setting up an rclone without authentication which is a security issue! - // (however, it still works, so we give a warning) - warn!("Using rclone without authentication! Upgrade to rclone >= 1.52.2 (current version: {}.{}.{})!", v.0, v.1, v.2); - } - } - Err(err) => warn!("Could not determine rclone version: {err}"), - } + let rclone_version_output = Command::new("rclone") + .arg("version") + .output() + .map_err(RcloneErrorKind::FromIoError)? + .stdout; + + // if we want to use a password and rclone_command is not explicitly set, + // we check for a rclone version supporting user/password via env variables + // if the version is not supported, we return an error + check_clone_version(rclone_version_output.as_slice())?; } let user = Alphanumeric.sample_string(&mut thread_rng(), 12); @@ -308,3 +317,26 @@ impl WriteBackend for RcloneBackend { self.rest.remove(tpe, id, cacheable) } } + +#[cfg(test)] +mod tests { + use super::*; + + use rstest::rstest; + + #[rstest] + #[case(b"rclone v1.52.2\n- os/arch: linux/amd64\n- go version: go1.14.4\n")] + #[case(b"rclone v1.66.0\n- os/version: Microsoft Windows 11 Pro 23H2 (64 bit)\n- os/kernel: 10.0.22631.3155 (x86_64)\n- os/type: windows\n- os/arch: amd64\n- go/version: go1.22.1\n- go/linking: static\n- go/tags: cmount")] + #[case(b"rclone v1.63.0-beta.7022.e649cf4d5\n- os/arch: linux/amd64\n- go version: go1.14.4\n")] + fn test_check_clone_version_passes(#[case] rclone_version_output: &[u8]) { + assert!(check_clone_version(rclone_version_output).is_ok()); + } + + #[rstest] + #[case(b"")] + #[case(b"rclone v1.52.1\n- os/arch: linux/amd64\n- go version: go1.14.4\n")] + #[case(b"rclone v1.51.3-beta\n- os/arch: linux/amd64\n- go version: go1.14.4\n")] + fn test_check_clone_version_fails(#[case] rclone_version_output: &[u8]) { + assert!(check_clone_version(rclone_version_output).is_err()); + } +} diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index d6e03a2da..102427e5e 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -136,7 +136,7 @@ mockall = "0.12.1" pretty_assertions = "1.4.0" quickcheck = "1.0.3" quickcheck_macros = "1.0.0" -rstest = "0.18.2" +rstest = { workspace = true } rustdoc-json = "0.8.9" # We need to have rustic_backend here, because the doc-tests in lib.rs of rustic_core rustic_backend = { workspace = true } From c99e9a6747b814572cb1c5a69146a7eb000794ff Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 02:10:49 +0000 Subject: [PATCH 2/5] fix(deps): update rust crate serde_with to 3.7.0 (#189) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [serde_with](https://togithub.com/jonasbb/serde_with) | dependencies | minor | `3.6.1` -> `3.7.0` | --- ### Release Notes
jonasbb/serde_with (serde_with) ### [`v3.7.0`](https://togithub.com/jonasbb/serde_with/releases/tag/v3.7.0): serde_with v3.7.0 [Compare Source](https://togithub.com/jonasbb/serde_with/compare/v3.6.1...v3.7.0) ##### Added - Implement `JsonSchemaAs` for `EnumMap` by [@​swlynch99](https://togithub.com/swlynch99) ([#​697](https://togithub.com/jonasbb/serde_with/issues/697)) - Implement `JsonSchemaAs` for `IfIsHumanReadable` by [@​swlynch99](https://togithub.com/swlynch99) ([#​717](https://togithub.com/jonasbb/serde_with/issues/717)) - Implement `JsonSchemaAs` for `KeyValueMap` by [@​swlynch99](https://togithub.com/swlynch99) ([#​713](https://togithub.com/jonasbb/serde_with/issues/713)) - Implement `JsonSchemaAs` for `OneOrMany` by [@​swlynch99](https://togithub.com/swlynch99) ([#​719](https://togithub.com/jonasbb/serde_with/issues/719)) ##### Fixed - Detect conflicting `schema_with` attributes on fields with `schemars` annotations by [@​swlynch99](https://togithub.com/swlynch99) ([#​715](https://togithub.com/jonasbb/serde_with/issues/715)) This extends the existing avoidance mechanism to a new variant fixing [#​712](https://togithub.com/jonasbb/serde_with/issues/712).
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/rustic-rs/rustic_core). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- crates/core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 102427e5e..424d9b3d6 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -76,7 +76,7 @@ serde = { version = "1.0.197" } serde-aux = "4.5.0" serde_derive = "1.0.197" serde_json = "1.0.114" -serde_with = { version = "3.6.1", features = ["base64"] } +serde_with = { version = "3.7.0", features = ["base64"] } # local source/destination cached = { version = "0.49.2", default-features = false, features = ["proc_macro"] } From d06aca10cb3ec4849af62c0010e760eaaff911dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 05:49:29 +0100 Subject: [PATCH 3/5] fix(deps): update rust crate anyhow to 1.0.81 (#191) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [anyhow](https://togithub.com/dtolnay/anyhow) | dependencies | patch | `1.0.80` -> `1.0.81` | --- ### Release Notes
dtolnay/anyhow (anyhow) ### [`v1.0.81`](https://togithub.com/dtolnay/anyhow/compare/1.0.80...1.0.81) [Compare Source](https://togithub.com/dtolnay/anyhow/compare/1.0.80...1.0.81)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/rustic-rs/rustic_core). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- crates/backend/Cargo.toml | 2 +- crates/core/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index 19dd94131..617894992 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -47,7 +47,7 @@ sftp = ["opendal"] rustic_core = { workspace = true } # errors -anyhow = "1.0.80" +anyhow = "1.0.81" displaydoc = "0.2.4" thiserror = "1.0.57" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 424d9b3d6..39407df7c 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -102,7 +102,7 @@ futures = { version = "0.3", optional = true } runtime-format = "0.1.3" # other dependencies -anyhow = "1.0.80" +anyhow = "1.0.81" bitmask-enum = "2.2.3" bytes = "1.5.0" bytesize = "1.3.0" From 83131f9dfa76286ad361085262adf8ce17b87bde Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 05:51:38 +0100 Subject: [PATCH 4/5] fix(deps): update rust crate thiserror to 1.0.58 (#192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [thiserror](https://togithub.com/dtolnay/thiserror) | dependencies | patch | `1.0.57` -> `1.0.58` | --- ### Release Notes
dtolnay/thiserror (thiserror) ### [`v1.0.58`](https://togithub.com/dtolnay/thiserror/releases/tag/1.0.58) [Compare Source](https://togithub.com/dtolnay/thiserror/compare/1.0.57...1.0.58) - Make backtrace support available when using -Dwarnings ([#​292](https://togithub.com/dtolnay/thiserror/issues/292))
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/rustic-rs/rustic_core). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- crates/backend/Cargo.toml | 2 +- crates/core/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index 617894992..499eaae64 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -49,7 +49,7 @@ rustic_core = { workspace = true } # errors anyhow = "1.0.81" displaydoc = "0.2.4" -thiserror = "1.0.57" +thiserror = "1.0.58" # logging log = "0.4.21" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 39407df7c..35bf87d81 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -48,7 +48,7 @@ rustdoc-args = ["--document-private-items", "--generate-link-to-definition"] [dependencies] # errors displaydoc = "0.2.4" -thiserror = "1.0.57" +thiserror = "1.0.58" # macros derivative = "2.2.0" From bfd2c49ba3bfaec5f5b6020f8388991faa2da6ae Mon Sep 17 00:00:00 2001 From: aawsome <37850842+aawsome@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:02:43 +0100 Subject: [PATCH 5/5] refactor: replace dep bitmask-enum by enumset (#173) To support e.g. serialization --------- Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com> Co-authored-by: simonsan <14062932+simonsan@users.noreply.github.com> --- crates/core/Cargo.toml | 2 +- crates/core/src/commands/prune.rs | 66 ++++++++++++++++++------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 35bf87d81..82c21e5a3 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -103,12 +103,12 @@ runtime-format = "0.1.3" # other dependencies anyhow = "1.0.81" -bitmask-enum = "2.2.3" bytes = "1.5.0" bytesize = "1.3.0" chrono = { version = "0.4.35", default-features = false, features = ["clock", "serde"] } enum-map = "2.7.3" enum-map-derive = "0.17.0" +enumset = { version = "1.1.3", features = ["serde"] } gethostname = "0.4.3" humantime = "2.1.0" itertools = "0.12.1" diff --git a/crates/core/src/commands/prune.rs b/crates/core/src/commands/prune.rs index f1611c1cf..e670330b5 100644 --- a/crates/core/src/commands/prune.rs +++ b/crates/core/src/commands/prune.rs @@ -1,10 +1,7 @@ //! `prune` subcommand -use derive_setters::Setters; /// App-local prelude includes `app_reader()`/`app_writer()`/`app_config()` /// accessors along with logging macros. Customize as you see fit. -use log::{info, warn}; - use std::{ cmp::Ordering, collections::{BTreeMap, BTreeSet}, @@ -12,12 +9,15 @@ use std::{ sync::{Arc, Mutex}, }; -use bitmask_enum::bitmask; use bytesize::ByteSize; use chrono::{DateTime, Duration, Local}; use derive_more::Add; +use derive_setters::Setters; +use enumset::{EnumSet, EnumSetType}; use itertools::Itertools; +use log::{info, warn}; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; +use serde::{Deserialize, Serialize}; use crate::{ backend::{ @@ -269,8 +269,8 @@ impl FromStr for LimitOption { } } -#[bitmask(u8)] -#[bitmask_config(vec_debug)] +#[derive(EnumSetType, Debug, PartialOrd, Ord, Serialize, Deserialize)] +#[enumset(serialize_repr = "list")] pub enum PackStatus { NotCompressed, TooYoung, @@ -282,7 +282,7 @@ pub enum PackStatus { Marked, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize)] pub struct DebugDetailedStats { pub packs: u64, pub unused_blobs: u64, @@ -291,15 +291,26 @@ pub struct DebugDetailedStats { pub used_size: u64, } -#[derive(Debug, Default)] -pub struct DebugStats(pub BTreeMap<(PackToDo, BlobType, PackStatus), DebugDetailedStats>); +#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, PartialOrd, Ord)] +pub struct DebugStatsKey { + pub todo: PackToDo, + pub blob_type: BlobType, + pub status: EnumSet, +} + +#[derive(Debug, Default, Serialize)] +pub struct DebugStats(pub BTreeMap); impl DebugStats { - fn add(&mut self, pi: &PackInfo, todo: PackToDo, status: PackStatus) { + fn add(&mut self, pi: &PackInfo, todo: PackToDo, status: EnumSet) { let blob_type = pi.blob_type; let details = self .0 - .entry((todo, blob_type, status)) + .entry(DebugStatsKey { + todo, + blob_type, + status, + }) .or_insert(DebugDetailedStats { packs: 0, unused_blobs: 0, @@ -400,7 +411,7 @@ pub struct PruneStats { pub index_files: u64, /// Number of index files which will be rebuilt during the prune pub index_files_rebuild: u64, - /// Number of index files which will be rebuilt during the prune + /// Detailed debug statistics pub debug: DebugStats, } @@ -441,7 +452,7 @@ impl PruneIndex { } /// Task to be executed by a `PrunePlan` on Packs -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)] pub enum PackToDo { // TODO: Add documentation Undecided, @@ -559,7 +570,7 @@ impl PrunePack { &mut self, todo: PackToDo, pi: &PackInfo, - status: PackStatus, + status: EnumSet, stats: &mut PruneStats, ) { let tpe = self.blob_type; @@ -626,7 +637,7 @@ pub struct PrunePlan { /// The ids of the existing packs existing_packs: BTreeMap, /// The packs which should be repacked - repack_candidates: Vec<(PackInfo, PackStatus, RepackReason, usize, usize)>, + repack_candidates: Vec<(PackInfo, EnumSet, RepackReason, usize, usize)>, /// The index files index_files: Vec, /// `prune` statistics @@ -784,31 +795,31 @@ impl PrunePlan { self.stats.blobs[pi.blob_type].unused += u64::from(pi.unused_blobs); self.stats.size[pi.blob_type].used += u64::from(pi.used_size); self.stats.size[pi.blob_type].unused += u64::from(pi.unused_size); - let mut status = PackStatus::none(); + let mut status = EnumSet::empty(); // Various checks to determine if packs need to be kept let too_young = pack.time > Some(self.time - keep_pack); if too_young && !pack.delete_mark { - status |= PackStatus::TooYoung; + _ = status.insert(PackStatus::TooYoung); } let keep_uncacheable = repack_cacheable_only && !pack.blob_type.is_cacheable(); let to_compress = repack_uncompressed && !pack.is_compressed(); if to_compress { - status |= PackStatus::NotCompressed; + _ = status.insert(PackStatus::NotCompressed); } let size_mismatch = !pack_sizer[pack.blob_type].size_ok(pack.size); if pack_sizer[pack.blob_type].is_too_small(pack.size) { - status |= PackStatus::TooSmall; + _ = status.insert(PackStatus::TooSmall); } if pack_sizer[pack.blob_type].is_too_large(pack.size) { - status |= PackStatus::TooLarge; + _ = status.insert(PackStatus::TooLarge); } match (pack.delete_mark, pi.used_blobs, pi.unused_blobs) { (false, 0, _) => { // unused pack self.stats.packs.unused += 1; - status |= PackStatus::HasUnusedBlobs; + _ = status.insert(PackStatus::HasUnusedBlobs); if too_young { // keep packs which are too young pack.set_todo(PackToDo::Keep, &pi, status, &mut self.stats); @@ -819,7 +830,7 @@ impl PrunePlan { (false, 1.., 0) => { // used pack self.stats.packs.used += 1; - status |= PackStatus::HasUsedBlobs; + _ = status.insert(PackStatus::HasUsedBlobs); if too_young || keep_uncacheable { pack.set_todo(PackToDo::Keep, &pi, status, &mut self.stats); } else if to_compress || repack_all { @@ -846,7 +857,8 @@ impl PrunePlan { (false, 1.., 1..) => { // partly used pack self.stats.packs.partly_used += 1; - status |= PackStatus::HasUsedBlobs | PackStatus::HasUnusedBlobs; + status + .insert_all(PackStatus::HasUsedBlobs | PackStatus::HasUnusedBlobs); if too_young || keep_uncacheable { // keep packs which are too young and non-cacheable packs if requested @@ -863,18 +875,18 @@ impl PrunePlan { } } (true, 0, _) => { - status |= PackStatus::Marked; + _ = status.insert(PackStatus::Marked); match pack.time { // unneeded and marked pack => check if we can remove it. Some(local_date_time) if self.time - local_date_time >= keep_delete => { - status |= PackStatus::TooYoung; + _ = status.insert(PackStatus::TooYoung); pack.set_todo(PackToDo::Delete, &pi, status, &mut self.stats); } None => { warn!("pack to delete {}: no time set, this should not happen! Keeping this pack.", pack.id); - status |= PackStatus::TimeNotSet; + _ = status.insert(PackStatus::TimeNotSet); pack.set_todo( PackToDo::KeepMarkedAndCorrect, &pi, @@ -891,7 +903,7 @@ impl PrunePlan { } } (true, 1.., _) => { - status |= PackStatus::Marked | PackStatus::HasUsedBlobs; + status.insert_all(PackStatus::Marked | PackStatus::HasUsedBlobs); // needed blobs; mark this pack for recovery pack.set_todo(PackToDo::Recover, &pi, status, &mut self.stats); }