Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package borgmatic for openSUSE:Factory 
checked in at 2021-07-07 18:30:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/borgmatic (Old)
 and      /work/SRC/openSUSE:Factory/.borgmatic.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "borgmatic"

Wed Jul  7 18:30:39 2021 rev:28 rq:904550 version:1.5.15

Changes:
--------
--- /work/SRC/openSUSE:Factory/borgmatic/borgmatic.changes      2021-06-14 
23:11:33.476801685 +0200
+++ /work/SRC/openSUSE:Factory/.borgmatic.new.2625/borgmatic.changes    
2021-07-07 18:31:56.250304558 +0200
@@ -1,0 +2,8 @@
+Wed Jun 30 16:45:16 UTC 2021 - Ferdinand Thiessen <[email protected]>
+
+- Update to 1.5.15
+  * Document use case of running backups conditionally based on
+    laptop power level
+  * Run arbitrary Borg commands with new "borgmatic borg" action
+
+-------------------------------------------------------------------

Old:
----
  borgmatic-1.5.14.tar.gz

New:
----
  borgmatic-1.5.15.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ borgmatic.spec ++++++
--- /var/tmp/diff_new_pack.zm6SoR/_old  2021-07-07 18:31:56.610301734 +0200
+++ /var/tmp/diff_new_pack.zm6SoR/_new  2021-07-07 18:31:56.614301702 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           borgmatic
-Version:        1.5.14
+Version:        1.5.15
 Release:        0
 Summary:        Automation tool for borgbackup
 License:        GPL-3.0-only

++++++ borgmatic-1.5.14.tar.gz -> borgmatic-1.5.15.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/.gitignore 
new/borgmatic-1.5.15/.gitignore
--- old/borgmatic-1.5.14/.gitignore     2021-06-08 20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/.gitignore     2021-06-18 05:44:54.000000000 +0200
@@ -2,7 +2,7 @@
 *.pyc
 *.swp
 .cache
-.coverage
+.coverage*
 .pytest_cache
 .tox
 __pycache__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/NEWS new/borgmatic-1.5.15/NEWS
--- old/borgmatic-1.5.14/NEWS   2021-06-08 20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/NEWS   2021-06-18 05:44:54.000000000 +0200
@@ -1,3 +1,9 @@
+1.5.15
+ * #419: Document use case of running backups conditionally based on laptop 
power level:
+   
https://torsion.org/borgmatic/docs/how-to/backup-to-a-removable-drive-or-an-intermittent-server/
+ * #425: Run arbitrary Borg commands with new "borgmatic borg" action. See the 
documentation for
+   more information: 
https://torsion.org/borgmatic/docs/how-to/run-arbitrary-borg-commands/
+
 1.5.14
  * #390: Add link to Hetzner storage offering from the documentation.
  * #398: Clarify canonical home of borgmatic in documentation.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/borgmatic/borg/borg.py 
new/borgmatic-1.5.15/borgmatic/borg/borg.py
--- old/borgmatic-1.5.14/borgmatic/borg/borg.py 1970-01-01 01:00:00.000000000 
+0100
+++ new/borgmatic-1.5.15/borgmatic/borg/borg.py 2021-06-18 05:44:54.000000000 
+0200
@@ -0,0 +1,45 @@
+import logging
+
+from borgmatic.borg.flags import make_flags
+from borgmatic.execute import execute_command
+
+logger = logging.getLogger(__name__)
+
+
+REPOSITORYLESS_BORG_COMMANDS = {'serve', None}
+
+
+def run_arbitrary_borg(
+    repository, storage_config, options, archive=None, local_path='borg', 
remote_path=None
+):
+    '''
+    Given a local or remote repository path, a storage config dict, a sequence 
of arbitrary
+    command-line Borg options, and an optional archive name, run an arbitrary 
Borg command on the
+    given repository/archive.
+    '''
+    lock_wait = storage_config.get('lock_wait', None)
+
+    try:
+        options = options[1:] if options[0] == '--' else options
+        borg_command = options[0]
+        command_options = tuple(options[1:])
+    except IndexError:
+        borg_command = None
+        command_options = ()
+
+    repository_archive = '::'.join((repository, archive)) if repository and 
archive else repository
+
+    full_command = (
+        (local_path,)
+        + ((borg_command,) if borg_command else ())
+        + ((repository_archive,) if borg_command and repository_archive else 
())
+        + command_options
+        + (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+        + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else 
())
+        + make_flags('remote-path', remote_path)
+        + make_flags('lock-wait', lock_wait)
+    )
+
+    return execute_command(
+        full_command, output_log_level=logging.WARNING, 
borg_local_path=local_path,
+    )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/borgmatic/borg/create.py 
new/borgmatic-1.5.15/borgmatic/borg/create.py
--- old/borgmatic-1.5.14/borgmatic/borg/create.py       2021-06-08 
20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/borgmatic/borg/create.py       2021-06-18 
05:44:54.000000000 +0200
@@ -220,7 +220,8 @@
     extra_borg_options = storage_config.get('extra_borg_options', 
{}).get('create', '')
 
     full_command = (
-        (local_path, 'create')
+        tuple(local_path.split(' '))
+        + ('create',)
         + _make_pattern_flags(location_config, pattern_file.name if 
pattern_file else None)
         + _make_exclude_flags(location_config, exclude_file.name if 
exclude_file else None)
         + (('--checkpoint-interval', str(checkpoint_interval)) if 
checkpoint_interval else ())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/borgmatic/commands/arguments.py 
new/borgmatic-1.5.15/borgmatic/commands/arguments.py
--- old/borgmatic-1.5.14/borgmatic/commands/arguments.py        2021-06-08 
20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/borgmatic/commands/arguments.py        2021-06-18 
05:44:54.000000000 +0200
@@ -15,17 +15,18 @@
     'restore': ['--restore', '-r'],
     'list': ['--list', '-l'],
     'info': ['--info', '-i'],
+    'borg': [],
 }
 
 
 def parse_subparser_arguments(unparsed_arguments, subparsers):
     '''
-    Given a sequence of arguments, and a subparsers object as returned by
-    argparse.ArgumentParser().add_subparsers(), give each requested action's 
subparser a shot at
-    parsing all arguments. This allows common arguments like "--repository" to 
be shared across
-    multiple subparsers.
+    Given a sequence of arguments and a dict from subparser name to 
argparse.ArgumentParser
+    instance, give each requested action's subparser a shot at parsing all 
arguments. This allows
+    common arguments like "--repository" to be shared across multiple 
subparsers.
 
-    Return the result as a dict mapping from subparser name to a parsed 
namespace of arguments.
+    Return the result as a tuple of (a dict mapping from subparser name to a 
parsed namespace of
+    arguments, a list of remaining arguments not claimed by any subparser).
     '''
     arguments = collections.OrderedDict()
     remaining_arguments = list(unparsed_arguments)
@@ -35,7 +36,12 @@
         for alias in aliases
     }
 
-    for subparser_name, subparser in subparsers.choices.items():
+    # If the "borg" action is used, skip all other subparsers. This avoids 
confusion like
+    # "borg list" triggering borgmatic's own list action.
+    if 'borg' in unparsed_arguments:
+        subparsers = {'borg': subparsers['borg']}
+
+    for subparser_name, subparser in subparsers.items():
         if subparser_name not in remaining_arguments:
             continue
 
@@ -47,11 +53,11 @@
         parsed, unused_remaining = 
subparser.parse_known_args(unparsed_arguments)
         for value in vars(parsed).values():
             if isinstance(value, str):
-                if value in subparsers.choices:
+                if value in subparsers:
                     remaining_arguments.remove(value)
             elif isinstance(value, list):
                 for item in value:
-                    if item in subparsers.choices:
+                    if item in subparsers:
                         remaining_arguments.remove(item)
 
         arguments[canonical_name] = parsed
@@ -59,47 +65,33 @@
     # If no actions are explicitly requested, assume defaults: prune, create, 
and check.
     if not arguments and '--help' not in unparsed_arguments and '-h' not in 
unparsed_arguments:
         for subparser_name in ('prune', 'create', 'check'):
-            subparser = subparsers.choices[subparser_name]
+            subparser = subparsers[subparser_name]
             parsed, unused_remaining = 
subparser.parse_known_args(unparsed_arguments)
             arguments[subparser_name] = parsed
 
-    return arguments
-
-
-def parse_global_arguments(unparsed_arguments, top_level_parser, subparsers):
-    '''
-    Given a sequence of arguments, a top-level parser (containing subparsers), 
and a subparsers
-    object as returned by argparse.ArgumentParser().add_subparsers(), parse 
and return any global
-    arguments as a parsed argparse.Namespace instance.
-    '''
-    # Ask each subparser, one by one, to greedily consume arguments. Any 
arguments that remain
-    # are global arguments.
     remaining_arguments = list(unparsed_arguments)
-    present_subparser_names = set()
 
-    for subparser_name, subparser in subparsers.choices.items():
-        if subparser_name not in remaining_arguments:
+    # Now ask each subparser, one by one, to greedily consume arguments.
+    for subparser_name, subparser in subparsers.items():
+        if subparser_name not in arguments.keys():
             continue
 
-        present_subparser_names.add(subparser_name)
+        subparser = subparsers[subparser_name]
         unused_parsed, remaining_arguments = 
subparser.parse_known_args(remaining_arguments)
 
-    # If no actions are explicitly requested, assume defaults: prune, create, 
and check.
-    if (
-        not present_subparser_names
-        and '--help' not in unparsed_arguments
-        and '-h' not in unparsed_arguments
-    ):
-        for subparser_name in ('prune', 'create', 'check'):
-            subparser = subparsers.choices[subparser_name]
-            unused_parsed, remaining_arguments = 
subparser.parse_known_args(remaining_arguments)
+    # Special case: If "borg" is present in the arguments, consume all 
arguments after (+1) the
+    # "borg" action.
+    if 'borg' in arguments:
+        borg_options_index = remaining_arguments.index('borg') + 1
+        arguments['borg'].options = remaining_arguments[borg_options_index:]
+        remaining_arguments = remaining_arguments[:borg_options_index]
 
     # Remove the subparser names themselves.
-    for subparser_name in present_subparser_names:
+    for subparser_name, subparser in subparsers.items():
         if subparser_name in remaining_arguments:
             remaining_arguments.remove(subparser_name)
 
-    return top_level_parser.parse_args(remaining_arguments)
+    return (arguments, remaining_arguments)
 
 
 class Extend_action(Action):
@@ -510,8 +502,7 @@
     )
     list_group = list_parser.add_argument_group('list arguments')
     list_group.add_argument(
-        '--repository',
-        help='Path of repository to list, defaults to the configured 
repository if there is only one',
+        '--repository', help='Path of repository to list, defaults to the 
configured repositories',
     )
     list_group.add_argument('--archive', help='Name of archive to list (or 
"latest")')
     list_group.add_argument(
@@ -601,8 +592,32 @@
     )
     info_group.add_argument('-h', '--help', action='help', help='Show this 
help message and exit')
 
-    arguments = parse_subparser_arguments(unparsed_arguments, subparsers)
-    arguments['global'] = parse_global_arguments(unparsed_arguments, 
top_level_parser, subparsers)
+    borg_parser = subparsers.add_parser(
+        'borg',
+        aliases=SUBPARSER_ALIASES['borg'],
+        help='Run an arbitrary Borg command',
+        description='Run an arbitrary Borg command based on borgmatic\'s 
configuration',
+        add_help=False,
+    )
+    borg_group = borg_parser.add_argument_group('borg arguments')
+    borg_group.add_argument(
+        '--repository',
+        help='Path of repository to pass to Borg, defaults to the configured 
repositories',
+    )
+    borg_group.add_argument('--archive', help='Name of archive to pass to Borg 
(or "latest")')
+    borg_group.add_argument(
+        '--',
+        metavar='OPTION',
+        dest='options',
+        nargs='+',
+        help='Options to pass to Borg, command first ("create", "list", etc). 
"--" is optional. To specify the repository or the archive, you must use 
--repository or --archive instead of providing them here.',
+    )
+    borg_group.add_argument('-h', '--help', action='help', help='Show this 
help message and exit')
+
+    arguments, remaining_arguments = parse_subparser_arguments(
+        unparsed_arguments, subparsers.choices
+    )
+    arguments['global'] = top_level_parser.parse_args(remaining_arguments)
 
     if arguments['global'].excludes_filename:
         raise ValueError(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/borgmatic/commands/borgmatic.py 
new/borgmatic-1.5.15/borgmatic/commands/borgmatic.py
--- old/borgmatic-1.5.14/borgmatic/commands/borgmatic.py        2021-06-08 
20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/borgmatic/commands/borgmatic.py        2021-06-18 
05:44:54.000000000 +0200
@@ -9,6 +9,7 @@
 import colorama
 import pkg_resources
 
+from borgmatic.borg import borg as borg_borg
 from borgmatic.borg import check as borg_check
 from borgmatic.borg import create as borg_create
 from borgmatic.borg import environment as borg_environment
@@ -543,6 +544,22 @@
             )
             if json_output:
                 yield json.loads(json_output)
+    if 'borg' in arguments:
+        if arguments['borg'].repository is None or validate.repositories_match(
+            repository, arguments['borg'].repository
+        ):
+            logger.warning('{}: Running arbitrary Borg 
command'.format(repository))
+            archive_name = borg_list.resolve_archive_name(
+                repository, arguments['borg'].archive, storage, local_path, 
remote_path
+            )
+            borg_borg.run_arbitrary_borg(
+                repository,
+                storage,
+                options=arguments['borg'].options,
+                archive=archive_name,
+                local_path=local_path,
+                remote_path=remote_path,
+            )
 
 
 def load_configurations(config_filenames, overrides=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/docs/Dockerfile 
new/borgmatic-1.5.15/docs/Dockerfile
--- old/borgmatic-1.5.14/docs/Dockerfile        2021-06-08 20:44:53.000000000 
+0200
+++ new/borgmatic-1.5.15/docs/Dockerfile        2021-06-18 05:44:54.000000000 
+0200
@@ -3,7 +3,7 @@
 COPY . /app
 RUN pip install --no-cache /app && generate-borgmatic-config && chmod +r 
/etc/borgmatic/config.yaml
 RUN borgmatic --help > /command-line.txt \
-    && for action in init prune create check extract mount umount restore list 
info; do \
+    && for action in init prune create check extract export-tar mount umount 
restore list info borg; do \
            echo -e 
"\n--------------------------------------------------------------------------------\n"
 >> /command-line.txt \
            && borgmatic "$action" --help >> /command-line.txt; done
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/borgmatic-1.5.14/docs/how-to/backup-to-a-removable-drive-or-an-intermittent-server.md
 
new/borgmatic-1.5.15/docs/how-to/backup-to-a-removable-drive-or-an-intermittent-server.md
--- 
old/borgmatic-1.5.14/docs/how-to/backup-to-a-removable-drive-or-an-intermittent-server.md
   2021-06-08 20:44:53.000000000 +0200
+++ 
new/borgmatic-1.5.15/docs/how-to/backup-to-a-removable-drive-or-an-intermittent-server.md
   2021-06-18 05:44:54.000000000 +0200
@@ -16,9 +16,14 @@
 server is offline, then you'll get an annoying error message and the overall
 borgmatic run will fail (even if individual repositories still complete).
 
+Another variant is when the source machine is only sometimes available for
+backups, e.g. a laptop where you want to skip backups when the battery falls
+below a certain level.
+
 So what if you want borgmatic to swallow the error of a missing drive
-or an offline server, and continue trucking along? That's where the concept of
-"soft failure" come in.
+or an offline server or a low battery???and exit gracefully? That's where the
+concept of "soft failure" come in.
+
 
 ## Soft failure command hooks
 
@@ -78,6 +83,17 @@
       - ping -q -c 1 buddys-server.org > /dev/null || exit 75
 ```
 
+Or to only run backups if the battery level is high enough:
+
+```yaml
+hooks:
+    before_backup:
+      - is_battery_percent_at_least.sh 25
+```
+
+(Writing the battery script is left as an exercise to the reader.)
+
+
 ## Caveats and details
 
 There are some caveats you should be aware of with this feature.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/docs/how-to/develop-on-borgmatic.md 
new/borgmatic-1.5.15/docs/how-to/develop-on-borgmatic.md
--- old/borgmatic-1.5.14/docs/how-to/develop-on-borgmatic.md    2021-06-08 
20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/docs/how-to/develop-on-borgmatic.md    2021-06-18 
05:44:54.000000000 +0200
@@ -3,7 +3,7 @@
 eleventyNavigation:
   key: Develop on borgmatic
   parent: How-to guides
-  order: 11
+  order: 12
 ---
 ## Source code
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/borgmatic-1.5.14/docs/how-to/run-arbitrary-borg-commands.md 
new/borgmatic-1.5.15/docs/how-to/run-arbitrary-borg-commands.md
--- old/borgmatic-1.5.14/docs/how-to/run-arbitrary-borg-commands.md     
1970-01-01 01:00:00.000000000 +0100
+++ new/borgmatic-1.5.15/docs/how-to/run-arbitrary-borg-commands.md     
2021-06-18 05:44:54.000000000 +0200
@@ -0,0 +1,94 @@
+---
+title: How to run arbitrary Borg commands
+eleventyNavigation:
+  key: Run arbitrary Borg commands
+  parent: How-to guides
+  order: 10
+---
+## Running Borg with borgmatic
+
+Borg has several commands (and options) that borgmatic does not currently
+support. Sometimes though, as a borgmatic user, you may find yourself wanting
+to take advantage of these off-the-beaten-path Borg features. You could of
+course drop down to running Borg directly. But then you'd give up all the
+niceties of your borgmatic configuration. You could file a [borgmatic
+ticket](https://torsion.org/borgmatic/#issues) or even a [pull
+request](https://torsion.org/borgmatic/#contributing) to add the feature. But
+what if you need it *now*?
+
+That's where borgmatic's support for running "arbitrary" Borg commands comes
+in. Running Borg commands with borgmatic takes advantage of the following, all
+based on your borgmatic configuration files or command-line arguments:
+
+ * configured repositories (automatically runs your Borg command once for each
+   one)
+ * local and remote Borg binary paths
+ * SSH settings and Borg environment variables
+ * lock wait settings
+ * verbosity
+
+
+### borg action
+
+The way you run Borg with borgmatic is via the `borg` action. Here's a simple
+example:
+
+```bash
+borgmatic borg break-lock
+```
+
+(No `borg` action in borgmatic? Time to upgrade!)
+
+This runs Borg's `break-lock` command once on each configured borgmatic
+repository. Notice how the repository isn't present in the specified Borg
+options, as that part is provided by borgmatic.
+
+You can also specify Borg options for relevant commands:
+
+```bash
+borgmatic borg list --progress
+```
+
+This runs Borg's `list` command once on each configured borgmatic
+repository. However, the native `borgmatic list` action should be preferred
+for most use.
+
+What if you only want to run Borg on a single configured borgmatic repository
+when you've got several configured? Not a problem.
+
+```bash
+borgmatic borg --repository repo.borg break-lock
+```
+
+And what about a single archive?
+
+```bash
+borgmatic borg --archive your-archive-name list
+```
+
+### Limitations
+
+borgmatic's `borg` action is not without limitations:
+
+ * The Borg command you want to run (`create`, `list`, etc.) *must* come first
+   after the `borg` action. If you have any other Borg options to specify,
+   provide them after. For instance, `borgmatic borg list --progress` will 
work,
+   but `borgmatic borg --progress list` will not.
+ * borgmatic supplies the repository/archive name to Borg for you (based on
+   your borgmatic configuration or the `borgmatic borg 
--repository`/`--archive`
+   arguments), so do not specify the repository/archive otherwise.
+ * The `borg` action will not currently work for any Borg commands like `borg
+   serve` that do not accept a repository/archive name.
+ * Do not specify any global borgmatic arguments to the right of the `borg`
+   action. (They will be passed to Borg instead of borgmatic.) If you have
+   global borgmatic arguments, specify them *before* the `borg` action.
+ * Unlike other borgmatic actions, you cannot combine the `borg` action with
+   other borgmatic actions. This is to prevent ambiguity in commands like
+   `borgmatic borg list`, in which `list` is both a valid Borg command and a
+   borgmatic action. In this case, only the Borg command is run.
+ * Unlike normal borgmatic actions that support JSON, the `borg` action will
+   not disable certain borgmatic logs to avoid interfering with JSON output.
+
+In general, this `borgmatic borg` feature should be considered an escape
+valve???a feature of second resort. In the long run, it's preferable to wrap
+Borg commands with borgmatic actions that can support them fully.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/docs/how-to/upgrade.md 
new/borgmatic-1.5.15/docs/how-to/upgrade.md
--- old/borgmatic-1.5.14/docs/how-to/upgrade.md 2021-06-08 20:44:53.000000000 
+0200
+++ new/borgmatic-1.5.15/docs/how-to/upgrade.md 2021-06-18 05:44:54.000000000 
+0200
@@ -3,7 +3,7 @@
 eleventyNavigation:
   key: Upgrade borgmatic
   parent: How-to guides
-  order: 10
+  order: 11
 ---
 ## Upgrading
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/sample/systemd/borgmatic.service 
new/borgmatic-1.5.15/sample/systemd/borgmatic.service
--- old/borgmatic-1.5.14/sample/systemd/borgmatic.service       2021-06-08 
20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/sample/systemd/borgmatic.service       2021-06-18 
05:44:54.000000000 +0200
@@ -2,6 +2,8 @@
 Description=borgmatic backup
 Wants=network-online.target
 After=network-online.target
+# Prevent borgmatic from running unless the machine is plugged into power. 
Remove this line if you
+# want to allow borgmatic to run anytime.
 ConditionACPower=true
 
 [Service]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/setup.py 
new/borgmatic-1.5.15/setup.py
--- old/borgmatic-1.5.14/setup.py       2021-06-08 20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/setup.py       2021-06-18 05:44:54.000000000 +0200
@@ -1,6 +1,6 @@
 from setuptools import find_packages, setup
 
-VERSION = '1.5.14'
+VERSION = '1.5.15'
 
 
 setup(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/borgmatic-1.5.14/tests/integration/commands/test_arguments.py 
new/borgmatic-1.5.15/tests/integration/commands/test_arguments.py
--- old/borgmatic-1.5.14/tests/integration/commands/test_arguments.py   
2021-06-08 20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/tests/integration/commands/test_arguments.py   
2021-06-18 05:44:54.000000000 +0200
@@ -163,6 +163,24 @@
     assert 'create arguments:' in captured.out
 
 
+def test_parse_arguments_with_action_before_global_options_parses_options():
+    
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
+
+    arguments = module.parse_arguments('prune', '--verbosity', '2')
+
+    assert 'prune' in arguments
+    assert arguments['global'].verbosity == 2
+
+
+def test_parse_arguments_with_global_options_before_action_parses_options():
+    
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
+
+    arguments = module.parse_arguments('--verbosity', '2', 'prune')
+
+    assert 'prune' in arguments
+    assert arguments['global'].verbosity == 2
+
+
 def test_parse_arguments_with_prune_action_leaves_other_actions_disabled():
     
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/borgmatic-1.5.14/tests/unit/borg/test_borg.py 
new/borgmatic-1.5.15/tests/unit/borg/test_borg.py
--- old/borgmatic-1.5.14/tests/unit/borg/test_borg.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/borgmatic-1.5.15/tests/unit/borg/test_borg.py   2021-06-18 
05:44:54.000000000 +0200
@@ -0,0 +1,123 @@
+import logging
+
+from flexmock import flexmock
+
+from borgmatic.borg import borg as module
+
+from ..test_verbosity import insert_logging_mock
+
+
+def test_run_arbitrary_borg_calls_borg_with_parameters():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo'), output_log_level=logging.WARNING, 
borg_local_path='borg'
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['break-lock'],
+    )
+
+
+def test_run_arbitrary_borg_with_log_info_calls_borg_with_info_parameter():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo', '--info'),
+        output_log_level=logging.WARNING,
+        borg_local_path='borg',
+    )
+    insert_logging_mock(logging.INFO)
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['break-lock'],
+    )
+
+
+def test_run_arbitrary_borg_with_log_debug_calls_borg_with_debug_parameter():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo', '--debug', '--show-rc'),
+        output_log_level=logging.WARNING,
+        borg_local_path='borg',
+    )
+    insert_logging_mock(logging.DEBUG)
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['break-lock'],
+    )
+
+
+def 
test_run_arbitrary_borg_with_lock_wait_calls_borg_with_lock_wait_parameters():
+    storage_config = {'lock_wait': 5}
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo', '--lock-wait', '5'),
+        output_log_level=logging.WARNING,
+        borg_local_path='borg',
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config=storage_config, 
options=['break-lock'],
+    )
+
+
+def test_run_arbitrary_borg_with_archive_calls_borg_with_archive_parameter():
+    storage_config = {}
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo::archive'),
+        output_log_level=logging.WARNING,
+        borg_local_path='borg',
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config=storage_config, 
options=['break-lock'], archive='archive',
+    )
+
+
+def test_run_arbitrary_borg_with_local_path_calls_borg_via_local_path():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg1', 'break-lock', 'repo'), output_log_level=logging.WARNING, 
borg_local_path='borg1'
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['break-lock'], 
local_path='borg1',
+    )
+
+
+def 
test_run_arbitrary_borg_with_remote_path_calls_borg_with_remote_path_parameters():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo', '--remote-path', 'borg1'),
+        output_log_level=logging.WARNING,
+        borg_local_path='borg',
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['break-lock'], 
remote_path='borg1',
+    )
+
+
+def test_run_arbitrary_borg_passes_borg_specific_parameters_to_borg():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'list', 'repo', '--progress'),
+        output_log_level=logging.WARNING,
+        borg_local_path='borg',
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['list', '--progress'],
+    )
+
+
+def test_run_arbitrary_borg_omits_dash_dash_in_parameters_passed_to_borg():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'break-lock', 'repo'), output_log_level=logging.WARNING, 
borg_local_path='borg',
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=['--', 'break-lock'],
+    )
+
+
+def test_run_arbitrary_borg_without_borg_specific_parameters_does_not_raise():
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg',), output_log_level=logging.WARNING, borg_local_path='borg',
+    )
+
+    module.run_arbitrary_borg(
+        repository='repo', storage_config={}, options=[],
+    )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/borgmatic-1.5.14/tests/unit/commands/test_arguments.py 
new/borgmatic-1.5.15/tests/unit/commands/test_arguments.py
--- old/borgmatic-1.5.14/tests/unit/commands/test_arguments.py  2021-06-08 
20:44:53.000000000 +0200
+++ new/borgmatic-1.5.15/tests/unit/commands/test_arguments.py  2021-06-18 
05:44:54.000000000 +0200
@@ -5,146 +5,137 @@
 
 def 
test_parse_subparser_arguments_consumes_subparser_arguments_before_subparser_name():
     action_namespace = flexmock(foo=True)
-    subparsers = flexmock(
-        choices={
-            'action': flexmock(parse_known_args=lambda arguments: 
(action_namespace, [])),
-            'other': flexmock(),
-        }
-    )
+    subparsers = {
+        'action': flexmock(parse_known_args=lambda arguments: 
(action_namespace, ['action'])),
+        'other': flexmock(),
+    }
 
-    arguments = module.parse_subparser_arguments(('--foo', 'true', 'action'), 
subparsers)
+    arguments, remaining_arguments = module.parse_subparser_arguments(
+        ('--foo', 'true', 'action'), subparsers
+    )
 
     assert arguments == {'action': action_namespace}
+    assert remaining_arguments == []
 
 
 def 
test_parse_subparser_arguments_consumes_subparser_arguments_after_subparser_name():
     action_namespace = flexmock(foo=True)
-    subparsers = flexmock(
-        choices={
-            'action': flexmock(parse_known_args=lambda arguments: 
(action_namespace, [])),
-            'other': flexmock(),
-        }
-    )
+    subparsers = {
+        'action': flexmock(parse_known_args=lambda arguments: 
(action_namespace, ['action'])),
+        'other': flexmock(),
+    }
 
-    arguments = module.parse_subparser_arguments(('action', '--foo', 'true'), 
subparsers)
+    arguments, remaining_arguments = module.parse_subparser_arguments(
+        ('action', '--foo', 'true'), subparsers
+    )
 
     assert arguments == {'action': action_namespace}
+    assert remaining_arguments == []
 
 
 def test_parse_subparser_arguments_consumes_subparser_arguments_with_alias():
     action_namespace = flexmock(foo=True)
-    action_subparser = flexmock(parse_known_args=lambda arguments: 
(action_namespace, []))
-    subparsers = flexmock(
-        choices={
-            'action': action_subparser,
-            '-a': action_subparser,
-            'other': flexmock(),
-            '-o': flexmock(),
-        }
-    )
+    action_subparser = flexmock(parse_known_args=lambda arguments: 
(action_namespace, ['action']))
+    subparsers = {
+        'action': action_subparser,
+        '-a': action_subparser,
+        'other': flexmock(),
+        '-o': flexmock(),
+    }
     flexmock(module).SUBPARSER_ALIASES = {'action': ['-a'], 'other': ['-o']}
 
-    arguments = module.parse_subparser_arguments(('-a', '--foo', 'true'), 
subparsers)
+    arguments, remaining_arguments = module.parse_subparser_arguments(
+        ('-a', '--foo', 'true'), subparsers
+    )
 
     assert arguments == {'action': action_namespace}
+    assert remaining_arguments == []
 
 
 def test_parse_subparser_arguments_consumes_multiple_subparser_arguments():
     action_namespace = flexmock(foo=True)
     other_namespace = flexmock(bar=3)
-    subparsers = flexmock(
-        choices={
-            'action': flexmock(
-                parse_known_args=lambda arguments: (action_namespace, 
['--bar', '3'])
-            ),
-            'other': flexmock(parse_known_args=lambda arguments: 
(other_namespace, [])),
-        }
-    )
+    subparsers = {
+        'action': flexmock(
+            parse_known_args=lambda arguments: (action_namespace, ['action', 
'--bar', '3'])
+        ),
+        'other': flexmock(parse_known_args=lambda arguments: (other_namespace, 
[])),
+    }
 
-    arguments = module.parse_subparser_arguments(
+    arguments, remaining_arguments = module.parse_subparser_arguments(
         ('action', '--foo', 'true', 'other', '--bar', '3'), subparsers
     )
 
     assert arguments == {'action': action_namespace, 'other': other_namespace}
+    assert remaining_arguments == []
 
 
 def test_parse_subparser_arguments_applies_default_subparsers():
     prune_namespace = flexmock()
     create_namespace = flexmock(progress=True)
     check_namespace = flexmock()
-    subparsers = flexmock(
-        choices={
-            'prune': flexmock(parse_known_args=lambda arguments: 
(prune_namespace, ['--progress'])),
-            'create': flexmock(parse_known_args=lambda arguments: 
(create_namespace, [])),
-            'check': flexmock(parse_known_args=lambda arguments: 
(check_namespace, [])),
-            'other': flexmock(),
-        }
-    )
+    subparsers = {
+        'prune': flexmock(
+            parse_known_args=lambda arguments: (prune_namespace, ['prune', 
'--progress'])
+        ),
+        'create': flexmock(parse_known_args=lambda arguments: 
(create_namespace, [])),
+        'check': flexmock(parse_known_args=lambda arguments: (check_namespace, 
[])),
+        'other': flexmock(),
+    }
 
-    arguments = module.parse_subparser_arguments(('--progress'), subparsers)
+    arguments, remaining_arguments = 
module.parse_subparser_arguments(('--progress'), subparsers)
 
     assert arguments == {
         'prune': prune_namespace,
         'create': create_namespace,
         'check': check_namespace,
     }
+    assert remaining_arguments == []
 
 
-def test_parse_global_arguments_with_help_does_not_apply_default_subparsers():
-    global_namespace = flexmock(verbosity='lots')
+def 
test_parse_subparser_arguments_passes_through_unknown_arguments_before_subparser_name():
     action_namespace = flexmock()
-    top_level_parser = flexmock(parse_args=lambda arguments: global_namespace)
-    subparsers = flexmock(
-        choices={
-            'action': flexmock(
-                parse_known_args=lambda arguments: (action_namespace, 
['--verbosity', 'lots'])
-            ),
-            'other': flexmock(),
-        }
-    )
+    subparsers = {
+        'action': flexmock(
+            parse_known_args=lambda arguments: (action_namespace, ['action', 
'--verbosity', 'lots'])
+        ),
+        'other': flexmock(),
+    }
 
-    arguments = module.parse_global_arguments(
-        ('--verbosity', 'lots', '--help'), top_level_parser, subparsers
+    arguments, remaining_arguments = module.parse_subparser_arguments(
+        ('--verbosity', 'lots', 'action'), subparsers
     )
 
-    assert arguments == global_namespace
+    assert arguments == {'action': action_namespace}
+    assert remaining_arguments == ['--verbosity', 'lots']
 
 
-def 
test_parse_global_arguments_consumes_global_arguments_before_subparser_name():
-    global_namespace = flexmock(verbosity='lots')
+def 
test_parse_subparser_arguments_passes_through_unknown_arguments_after_subparser_name():
     action_namespace = flexmock()
-    top_level_parser = flexmock(parse_args=lambda arguments: global_namespace)
-    subparsers = flexmock(
-        choices={
-            'action': flexmock(
-                parse_known_args=lambda arguments: (action_namespace, 
['--verbosity', 'lots'])
-            ),
-            'other': flexmock(),
-        }
-    )
+    subparsers = {
+        'action': flexmock(
+            parse_known_args=lambda arguments: (action_namespace, ['action', 
'--verbosity', 'lots'])
+        ),
+        'other': flexmock(),
+    }
 
-    arguments = module.parse_global_arguments(
-        ('--verbosity', 'lots', 'action'), top_level_parser, subparsers
+    arguments, remaining_arguments = module.parse_subparser_arguments(
+        ('action', '--verbosity', 'lots'), subparsers
     )
 
-    assert arguments == global_namespace
+    assert arguments == {'action': action_namespace}
+    assert remaining_arguments == ['--verbosity', 'lots']
 
 
-def 
test_parse_global_arguments_consumes_global_arguments_after_subparser_name():
-    global_namespace = flexmock(verbosity='lots')
-    action_namespace = flexmock()
-    top_level_parser = flexmock(parse_args=lambda arguments: global_namespace)
-    subparsers = flexmock(
-        choices={
-            'action': flexmock(
-                parse_known_args=lambda arguments: (action_namespace, 
['--verbosity', 'lots'])
-            ),
-            'other': flexmock(),
-        }
-    )
+def 
test_parse_subparser_arguments_parses_borg_options_and_skips_other_subparsers():
+    action_namespace = flexmock(options=[])
+    subparsers = {
+        'borg': flexmock(parse_known_args=lambda arguments: (action_namespace, 
['borg', 'list'])),
+        'list': flexmock(),
+    }
 
-    arguments = module.parse_global_arguments(
-        ('action', '--verbosity', 'lots'), top_level_parser, subparsers
-    )
+    arguments, remaining_arguments = module.parse_subparser_arguments(('borg', 
'list'), subparsers)
 
-    assert arguments == global_namespace
+    assert arguments == {'borg': action_namespace}
+    assert arguments['borg'].options == ['list']
+    assert remaining_arguments == []

Reply via email to