Don't pass the --stats flag to borg prune when using Borg 2.0 #1010

Closed
opened 2025-02-27 00:44:00 +00:00 by witten · 9 comments
Owner

What I'm trying to do and why

When using Borg 2.0 and running borgmatic with --stats (which implicitly runs prune), the user receives an error because Borg 2.0 no longer supports prune --stats: https://borgbackup.readthedocs.io/en/latest/usage/prune.html

It appears to have been removed in this commit, which suggests using compact for stats instead: git.zknt.org/mirror/borg@4c052cd65d (diff-a08f625915)

Also see: https://github.com/borgmatic-collective/docker-borgmatic/issues/395

Steps to reproduce

Use Borg 2.0 and run borgmatic --stats or a variant thereof.

Actual behavior

borg: error: unrecognized arguments: --stats

Expected behavior

borgmatic runs the default actions and doesn't pass --stats to prune (when using Borg 2).

Other notes / implementation ideas

Probably the thing to do here is add a feature toggle such that --stats gets passed to prune on Borg 1 but not 2.

It'd also be a good idea to update the CLI docs to say "Borg 1 only" on prune --stats.

borgmatic version

1.9.12

borgmatic installation method

No response

Borg version

2.0.0.b13

Python version

No response

Database version (if applicable)

No response

Operating system and version

No response

### What I'm trying to do and why When using Borg 2.0 and running `borgmatic` with `--stats` (which implicitly runs `prune`), the user receives an error because Borg 2.0 no longer supports `prune --stats`: https://borgbackup.readthedocs.io/en/latest/usage/prune.html It appears to have been removed in this commit, which suggests using compact for stats instead: https://git.zknt.org/mirror/borg/commit/4c052cd65d6f9e98ab6cae45ae15849e59dea686#diff-a08f625915d1815ca2a9b7d06a60630aeecc4695 Also see: https://github.com/borgmatic-collective/docker-borgmatic/issues/395 ### Steps to reproduce Use Borg 2.0 and run `borgmatic --stats` or a variant thereof. ### Actual behavior ``` borg: error: unrecognized arguments: --stats ``` ### Expected behavior borgmatic runs the default actions and doesn't pass `--stats` to `prune` (when using Borg 2). ### Other notes / implementation ideas Probably the thing to do here is add a feature toggle such that `--stats` gets passed to `prune` on Borg 1 but not 2. It'd also be a good idea to update the CLI docs to say "Borg 1 only" on `prune --stats`. ### borgmatic version 1.9.12 ### borgmatic installation method _No response_ ### Borg version 2.0.0.b13 ### Python version _No response_ ### Database version (if applicable) _No response_ ### Operating system and version _No response_

Additional Info :
Please Pass --stats to borg compact in-case borg compact allows it. (I am a little confused here whether it supports it or not since at one place it is mentioned it supports it but in the official documents it is not there.)

Additional Info : Please Pass --stats to `borg compact` in-case `borg compact` allows it. (I am a little confused here whether it supports it or not since at one place it is mentioned it supports it but in the official documents it is not there.)
Author
Owner

Yeah, unfortunately it doesn't appear that Borg 2 implements compact --stats: https://borgbackup.readthedocs.io/en/2.0.0b14/usage/compact.html ... That changelog might just be indicating that compact displays some stats by default without actually having a formal --stats flag. For instance, these "stats" are what I get when running Borg 2 just with compact --info (equivalent to borgmatic's --verbosity 1):

# ./borg2.0.0b14 compact --repo tmp/test2.borg --info
Enter passphrase for key /root/tmp/test2.borg: 
Starting compaction / garbage collection...
Getting object IDs present in the repository...
Computing object IDs used by archives...
Cleaning archives directory from soft-deleted archives...
Determining unused objects...
Deleting 0 unused objects...
Overall statistics, considering all 0 archives in this repository:
Source data size was 0 B in 0 files.
Repository size is 0 B in 0 objects.
Compaction saved 0 B.
Finished compaction / garbage collection...
Yeah, unfortunately it doesn't appear that Borg 2 implements `compact --stats`: https://borgbackup.readthedocs.io/en/2.0.0b14/usage/compact.html ... That changelog might just be indicating that compact displays some stats by default without actually having a formal `--stats` flag. For instance, these "stats" are what I get when running Borg 2 just with `compact --info` (equivalent to borgmatic's `--verbosity 1`): ``` # ./borg2.0.0b14 compact --repo tmp/test2.borg --info Enter passphrase for key /root/tmp/test2.borg: Starting compaction / garbage collection... Getting object IDs present in the repository... Computing object IDs used by archives... Cleaning archives directory from soft-deleted archives... Determining unused objects... Deleting 0 unused objects... Overall statistics, considering all 0 archives in this repository: Source data size was 0 B in 0 files. Repository size is 0 B in 0 objects. Compaction saved 0 B. Finished compaction / garbage collection... ```
Contributor

I want to work on this issue.

I want to work on this issue.
Author
Owner

Awesome, please have a look at the docs on how to get started with development! It might also save you time if you wanted to outline your approach to the ticket here to get feedback before you start writing code. But it's also small enough that you could probably just submit a PR if you don't mind the risk of re-work.

One thing that may be useful for this particular ticket is the existing feature flag support. That's how borgmatic typically provides different behavior for different versions of Borg. And here's an example of that in action.

Let me know if you have any questions!

Awesome, please have a look at the [docs on how to get started with development](https://torsion.org/borgmatic/docs/how-to/develop-on-borgmatic/)! It might also save you time if you wanted to outline your approach to the ticket here to get feedback before you start writing code. But it's also small enough that you could probably just submit a PR if you don't mind the risk of re-work. One thing that may be useful for this particular ticket is the existing [feature flag](https://projects.torsion.org/borgmatic-collective/borgmatic/src/branch/main/borgmatic/borg/feature.py) support. That's how borgmatic typically provides different behavior for different versions of Borg. And [here's an example](https://projects.torsion.org/borgmatic-collective/borgmatic/src/commit/901e668c760f6a17e4f02ef418ff65285bbca5ed/borgmatic/actions/compact.py#L30) of that in action. Let me know if you have any questions!
Contributor

Yes I have few things to say:

  1. In feature flag support, FEATURE_TO_MINIMUM_BORG_VERSION is meant for when a feature is introduced, so I would like add new dictionary FEATURE_REMOVAL_BORG_VERSION to store PRUNE_STATS feature and its removal version 2.0.0b10(will add corresponding logic in available)(considering --stats is available since 1.1.0 - I guess there is no need of minimum version check)
  2. This is where implementation goes as
    (('--stats',) if prune_arguments.stats and not dry_run and borgmatic.borg.feature.available(borgmatic.borg.feature.Feature.PRUNE_STATS, local_borg_version) else ())
Yes I have few things to say: 1. In [feature flag](https://projects.torsion.org/borgmatic-collective/borgmatic/src/branch/main/borgmatic/borg/feature.py) support, [FEATURE_TO_MINIMUM_BORG_VERSION](https://projects.torsion.org/borgmatic-collective/borgmatic/src/commit/901e668c760f6a17e4f02ef418ff65285bbca5ed/borgmatic/borg/feature.py#L22) is meant for when a feature is introduced, so I would like add new dictionary FEATURE_REMOVAL_BORG_VERSION to store PRUNE_STATS feature and its removal version 2.0.0b10(will add corresponding logic in [available](https://projects.torsion.org/borgmatic-collective/borgmatic/src/commit/901e668c760f6a17e4f02ef418ff65285bbca5ed/borgmatic/borg/feature.py#L39))(considering --stats is available since 1.1.0 - I guess there is no need of minimum version check) 2. [This](https://projects.torsion.org/borgmatic-collective/borgmatic/src/commit/901e668c760f6a17e4f02ef418ff65285bbca5ed/borgmatic/borg/prune.py#L78) is where implementation goes as `(('--stats',) if prune_arguments.stats and not dry_run and borgmatic.borg.feature.available(borgmatic.borg.feature.Feature.PRUNE_STATS, local_borg_version) else ())`
Author
Owner

That makes sense to me! For point number one though, I think you can simplify even further. Rather than introducing the concept of a "feature removal", you can continue using FEATURE_TO_MINIMUM_BORG_VERSION and add an entry to it called something like Feature.STATLESS_PRUNE or Feature.NO_PRUNE_STATS or whatever. The idea being that a Borg feature removal is really a feature change or addition just like anything else. Then you wouldn't have to update available() either.

Also, don't forget the automated tests piece of this (I'm think mostly for point number two), which should hopefully be pretty straight-forward. Thank you!

That makes sense to me! For point number one though, I think you can simplify even further. Rather than introducing the concept of a "feature removal", you can continue using `FEATURE_TO_MINIMUM_BORG_VERSION` and add an entry to it called something like `Feature.STATLESS_PRUNE` or `Feature.NO_PRUNE_STATS` or whatever. The idea being that a Borg feature removal is really a feature change or addition just like anything else. Then you wouldn't have to update `available()` either. Also, don't forget the automated tests piece of this (I'm think mostly for point number two), which should hopefully be pretty straight-forward. Thank you!
Contributor

Also, don't forget the automated tests piece of this (I'm think mostly for point number two), which should hopefully be pretty straight-forward. Thank you!

Is it about adding
flexmock(module.feature).should_receive('available').with_args( module.feature.Feature.NO_PRUNE_STATS, '1.2.3' ).and_return(True/False)
to all tests(in test_prune.py)(True/False based on test) with stats such as.Or is it required to write new tests? Please correct me if I am wrong(I am new to testing)

> Also, don't forget the automated tests piece of this (I'm think mostly for point number two), which should hopefully be pretty straight-forward. Thank you! Is it about adding `flexmock(module.feature).should_receive('available').with_args( module.feature.Feature.NO_PRUNE_STATS, '1.2.3' ).and_return(True/False)` to all tests(in test_prune.py)(True/False based on test) with stats [such as](https://projects.torsion.org/borgmatic-collective/borgmatic/src/commit/901e668c760f6a17e4f02ef418ff65285bbca5ed/tests/unit/borg/test_prune.py#L208).Or is it required to write new tests? Please correct me if I am wrong(I am new to testing)
Author
Owner

Adding that mock to the existing tests seems like a good idea, but you might need to add a single new test—since presumably the existing tests wouldn't vary the available(NO_PRUNE_STATS, ...) return value. For instance, the mock you add to all the existing tests might all return True, and then you could just add one more test that has the False return value mock and the corresponding expectation. (Or the other way around.)

Adding that mock to the existing tests seems like a good idea, but you might need to add a single new test—since presumably the existing tests wouldn't vary the `available(NO_PRUNE_STATS, ...)` return value. For instance, the mock you add to all the existing tests might all return `True`, and then you could just add one more test that has the `False` return value mock and the corresponding expectation. (Or the other way around.)
Author
Owner

Released in borgmatic 2.0.0!

Released in borgmatic 2.0.0!
Sign in to join this conversation.
No milestone
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
borgmatic-collective/borgmatic#1010
No description provided.