Skip to content
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Commit 2bdbf6d

Browse files
committed
Rework automatic argument reversal with --reverse
The --reverse option, if specified, causes other arguments (the source and destination repository as well as the send and receive filters) to be swapped. In order to achieve this goal, it relies on a hidden helper option that is evaluated last and that acts upon the 'reverse' attribute (set when --reverse is encountered). Unfortunately, changes made to the argparse module with Python 3.4 modified the implementation in an incompatible way: the namespace containing the 'reverse' attribute is no longer passed to subparsers (which we use extensively). Rather, the returned namespace is merged into the final one (i.e., the one of the "main" parser). To cope with this incompatibility this patch reworks the handling of the --reverse option from using a hidden helper option to specifying a custom "action". This action now performs the argument reversal. The passing of the namespace of interest to actions was left unchanged between the Python versions 3.3 and 3.4.
1 parent 99ee152 commit 2bdbf6d

File tree

1 file changed

+31
-38
lines changed

1 file changed

+31
-38
lines changed

btrfs-backup/src/deso/btrfs/main.py

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# main.py
22

33
#/***************************************************************************
4-
# * Copyright (C) 2015 Daniel Mueller (deso@posteo.net) *
4+
# * Copyright (C) 2015-2016 Daniel Mueller (deso@posteo.net) *
55
# * *
66
# * This program is free software: you can redistribute it and/or modify *
77
# * it under the terms of the GNU General Public License as published by *
@@ -23,7 +23,6 @@
2323
alias,
2424
)
2525
from deso.btrfs.argv import (
26-
insert as insertArg,
2726
reorder as reorderArg,
2827
)
2928
from deso.btrfs.commands import (
@@ -46,11 +45,11 @@
4645
timedelta,
4746
)
4847
from argparse import (
48+
Action,
4949
ArgumentParser,
5050
ArgumentTypeError,
5151
HelpFormatter,
5252
Namespace,
53-
SUPPRESS,
5453
)
5554

5655

@@ -152,17 +151,24 @@ def checkSnapshotExtension(string, namespace, backup=True):
152151
return "%s%s" % (extsep, string)
153152

154153

155-
def reverse(_, namespace):
156-
"""Helper function to reverse arguments during parsing."""
157-
# In case the reverse option was given we swap the repositories and
158-
# the filters.
159-
with alias(namespace) as ns:
160-
if ns.reverse:
154+
class ReverseAction(Action):
155+
"""Action to reverse some source/destination arguments."""
156+
def __init__(self, option_strings, dest, const=None, default=None,
157+
required=False, help=None, metavar=None):
158+
"""Create a new ReverseAction object."""
159+
super().__init__(option_strings=option_strings, dest=dest, nargs=0,
160+
const=const, default=default, required=required,
161+
help=help)
162+
163+
164+
def __call__(self, parser, namespace, values, option_string=None):
165+
"""Helper function to reverse arguments during parsing."""
166+
# In case the reverse option was given we swap the repositories and
167+
# the filters.
168+
with alias(namespace) as ns:
161169
ns.src, ns.dst = ns.dst, ns.src
162170
ns.send_filters, ns.recv_filters = ns.recv_filters, ns.send_filters
163171

164-
return None
165-
166172

167173
def addStandardArgs(parser):
168174
"""Add the standard arguments --version and --help to an argument parser."""
@@ -179,11 +185,9 @@ def addStandardArgs(parser):
179185
def addOptionalArgs(parser, namespace, backup):
180186
"""Add the optional arguments to a parser."""
181187
parser.add_argument(
182-
# In order to implement the --join option we use a trick: Since we
183-
# cannot use a type field that performs an action for us as we do
184-
# for the reverse-hidden-helper option (because this option does not
185-
# accept an argument), we append the value 'None' to the
186-
# 'send_filters' array that stores all send filters.
188+
# In order to implement the --join option we use a trick: We append
189+
# the value 'None' to the 'send_filters' array that stores all send
190+
# filters.
187191
# TODO: Right now this option can be specified multiple times. That
188192
# is wrong and should not be allowed. However, it is tricky to
189193
# enforce that. Find a way.
@@ -216,17 +220,10 @@ def addOptionalArgs(parser, namespace, backup):
216220
"\"/usr/bin/ssh server\".",
217221
)
218222
parser.add_argument(
219-
"--reverse", action="store_true", dest="reverse", default=False,
223+
"--reverse", action=ReverseAction, dest="reverse",
220224
help="Reverse (i.e., swap) the source and destination repositories "
221225
"as well as the send and receive filters.",
222226
)
223-
# A helper option that is used to perform the argument reordering
224-
# during parsing.
225-
parser.add_argument(
226-
"--reverse-hidden-helper", action="store", default=None,
227-
dest="reverse_hidden_helper", help=SUPPRESS,
228-
type=lambda x: reverse(x, namespace),
229-
)
230227
parser.add_argument(
231228
"--send-filter", action="append", default=None, dest="send_filters",
232229
metavar="command", nargs=1,
@@ -426,7 +423,6 @@ def prepare(filters):
426423
del ns.dst
427424
del ns.command
428425
del ns.reverse
429-
del ns.reverse_hidden_helper
430426

431427
return command, subvolumes, src_repo, dst_repo
432428

@@ -456,20 +452,17 @@ def main(argv):
456452
# work the option has to be evaluated after all filter options. To
457453
# that end, we move it to the end of the options because the
458454
# ArgumentParser evaluates arguments in the order in which they are
459-
# provided in the argument vector. In order to have less branching in
460-
# various cases, we want to evaluate the --reverse option on the fly.
461-
# The problem there is that it does not accept an argument. So we
462-
# insert an artificial, undocumented option that performs the checking
463-
# (--reverse-hidden-helper). Because --snapshot-ext already requires
464-
# properly ordered arguments, the hidden reverse helper option has to
465-
# be evaluated before the former (it also has to be evaluated after
466-
# the actual --reverse option, but that is guaranteed since we insert
467-
# it at the end).
455+
# provided in the argument vector.
456+
# In order to have less branching in various cases, we want to
457+
# evaluate the --reverse option on the fly. This option has a special
458+
# action that reverses the source and destination repositories as well
459+
# as the send and receive filters. However, in order for it to work
460+
# correctly, it needs to be evaluated just before the --snapshot-ext
461+
# option (because the latter requires the reordered arguments) but
462+
# after all other options. Hence, we move it to the end right before
463+
# we do the same with the --snapshot-ext option.
468464
args = argv[1:].copy()
469-
470-
if "--reverse" in args:
471-
args = insertArg(args, ["--reverse-hidden-helper", "42"])
472-
465+
args = reorderArg(args, "--reverse")
473466
args = reorderArg(args, "--snapshot-ext")
474467
parser.parse_args(args, namespace)
475468

0 commit comments

Comments
 (0)