Ejemplo n.º 1
0
def args_to_path_backend(arg1, arg2):
    """
    Given exactly two arguments, arg1 and arg2, figure out which one
    is the backend URL and which one is a local path, and return
    (local, backend).
    """
    arg1_is_backend, arg2_is_backend = backend.is_backend_url(arg1), backend.is_backend_url(arg2)

    if not arg1_is_backend and not arg2_is_backend:
        command_line_error("""\
One of the arguments must be an URL.  Examples of URL strings are
"scp://[email protected]:1234/path" and "file:///usr/local".  See the man
page for more information.""")
    if arg1_is_backend and arg2_is_backend:
        command_line_error("Two URLs specified.  "
                           "One argument should be a path.")
    if arg1_is_backend:
        return (arg2, arg1)
    elif arg2_is_backend:
        return (arg1, arg2)
    else:
        raise AssertionError('should not be reached')
Ejemplo n.º 2
0
def args_to_path_backend(arg1, arg2):
    """
    Given exactly two arguments, arg1 and arg2, figure out which one
    is the backend URL and which one is a local path, and return
    (local, backend).
    """
    arg1_is_backend, arg2_is_backend = backend.is_backend_url(arg1), backend.is_backend_url(arg2)

    if not arg1_is_backend and not arg2_is_backend:
        command_line_error(
"""One of the arguments must be an URL.  Examples of URL strings are
"scp://[email protected]:1234/path" and "file:///usr/local".  See the man
page for more information.""")
    if arg1_is_backend and arg2_is_backend:
        command_line_error("Two URLs specified.  "
                           "One argument should be a path.")
    if arg1_is_backend:
        return (arg2, arg1)
    elif arg2_is_backend:
        return (arg1, arg2)
    else:
        raise AssertionError('should not be reached')
Ejemplo n.º 3
0
def parse_cmdline_options(arglist):
    """Parse argument list"""
    global select_opts, select_files, full_backup
    global list_current, collection_status, cleanup, remove_time, verify, replicate

    def set_log_fd(fd):
        if fd < 1:
            raise optparse.OptionValueError("log-fd must be greater than zero.")
        log.add_fd(fd)

    def set_time_sep(sep, opt):
        if sep == '-':
            raise optparse.OptionValueError("Dash ('-') not valid for time-separator.")
        globals.time_separator = sep
        old_fn_deprecation(opt)

    def add_selection(o, option, additional_arg, p):
        select_opts.append((util.fsdecode(option), util.fsdecode(additional_arg)))

    def add_filelist(o, s, filename, p):
        select_opts.append((util.fsdecode(s), util.fsdecode(filename)))
        try:
            select_files.append(io.open(filename, "rt", encoding="UTF-8"))
        except IOError:
            log.FatalError(_("Error opening file %s") % filename,
                           log.ErrorCode.cant_open_filelist)

    def print_ver(o, s, v, p):
        print("duplicity %s" % (globals.version))
        sys.exit(0)

    def add_rename(o, s, v, p):
        globals.rename[os.path.normcase(os.path.normpath(v[0]))] = v[1]

    parser = OPHelpFix(option_class=DupOption, usage=usage())

    # If this is true, only warn and don't raise fatal error when backup
    # source directory doesn't match previous backup source directory.
    parser.add_option("--allow-source-mismatch", action="store_true")

    # Set to the path of the archive directory (the directory which
    # contains the signatures and manifests of the relevent backup
    # collection), and for checkpoint state between volumes.
    # TRANSL: Used in usage help to represent a Unix-style path name. Example:
    # --archive-dir <path>
    parser.add_option("--archive-dir", type="file", metavar=_("path"))

    # Asynchronous put/get concurrency limit
    # (default of 0 disables asynchronicity).
    parser.add_option("--asynchronous-upload", action="store_const", const=1,
                      dest="async_concurrency")

    parser.add_option("--compare-data", action="store_true")

    # config dir for future use
    parser.add_option("--config-dir", type="file", metavar=_("path"),
                      help=optparse.SUPPRESS_HELP)

    # When symlinks are encountered, the item they point to is copied rather than
    # the symlink.
    parser.add_option("--copy-links", action="store_true")

    # for testing -- set current time
    parser.add_option("--current-time", type="int",
                      dest="current_time", help=optparse.SUPPRESS_HELP)

    # Don't actually do anything, but still report what would be done
    parser.add_option("--dry-run", action="store_true")

    # TRANSL: Used in usage help to represent an ID for a GnuPG key. Example:
    # --encrypt-key <gpg_key_id>
    parser.add_option("--encrypt-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: globals.gpg_profile.recipients.append(v))  # @UndefinedVariable

    # secret keyring in which the private encrypt key can be found
    parser.add_option("--encrypt-secret-keyring", type="string", metavar=_("path"))

    parser.add_option("--encrypt-sign-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: (globals.gpg_profile.recipients.append(v), set_sign_key(v)))

    # TRANSL: Used in usage help to represent a "glob" style pattern for
    # matching one or more files, as described in the documentation.
    # Example:
    # --exclude <shell_pattern>
    parser.add_option("--exclude", action="callback", metavar=_("shell_pattern"),
                      dest="", type="string", callback=add_selection)

    parser.add_option("--exclude-device-files", action="callback",
                      dest="", callback=add_selection)

    parser.add_option("--exclude-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=add_filelist)

    parser.add_option("--exclude-filelist-stdin", action="callback", dest="",
                      callback=lambda o, s, v, p: (select_opts.append(("--exclude-filelist", "standard input")),
                                                   select_files.append(sys.stdin),
                                                   stdin_deprecation(o)),
                      help=optparse.SUPPRESS_HELP)

    parser.add_option("--exclude-globbing-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=lambda o, s, v, p: (add_filelist(o, s, v, p),
                                                                               old_globbing_filelist_deprecation(s)),
                      help=optparse.SUPPRESS_HELP)

    # TRANSL: Used in usage help to represent the name of a file. Example:
    # --log-file <filename>
    parser.add_option("--exclude-if-present", metavar=_("filename"), dest="",
                      type="file", action="callback", callback=add_selection)

    parser.add_option("--exclude-other-filesystems", action="callback",
                      dest="", callback=add_selection)

    # TRANSL: Used in usage help to represent a regular expression (regexp).
    parser.add_option("--exclude-regexp", metavar=_("regular_expression"),
                      dest="", type="string", action="callback", callback=add_selection)

    # Exclude any files with modification dates older than this from the backup
    parser.add_option("--exclude-older-than", type="time", metavar=_("time"),
                      dest="", action="callback", callback=add_selection)

    # Whether we should be particularly aggressive when cleaning up
    parser.add_option("--extra-clean", action="store_true")

    # used in testing only - raises exception after volume
    parser.add_option("--fail-on-volume", type="int",
                      help=optparse.SUPPRESS_HELP)

    # used to provide a prefix on top of the defaul tar file name
    parser.add_option("--file-prefix", type="string", dest="file_prefix", action="store")

    # used to provide a suffix for manifest files only
    parser.add_option("--file-prefix-manifest", type="string", dest="file_prefix_manifest", action="store")

    # used to provide a suffix for archive files only
    parser.add_option("--file-prefix-archive", type="string", dest="file_prefix_archive", action="store")

    # used to provide a suffix for sigature files only
    parser.add_option("--file-prefix-signature", type="string", dest="file_prefix_signature", action="store")

    # used in testing only - skips upload for a given volume
    parser.add_option("--skip-volume", type="int",
                      help=optparse.SUPPRESS_HELP)

    # If set, restore only the subdirectory or file specified, not the
    # whole root.
    # TRANSL: Used in usage help to represent a Unix-style path name. Example:
    # --archive-dir <path>
    parser.add_option("--file-to-restore", "-r", action="callback", type="file",
                      metavar=_("path"), dest="restore_dir",
                      callback=lambda o, s, v, p: setattr(p.values, "restore_dir", v.strip('/')))

    # Used to confirm certain destructive operations like deleting old files.
    parser.add_option("--force", action="store_true")

    # FTP data connection type
    parser.add_option("--ftp-passive", action="store_const", const="passive", dest="ftp_connection")
    parser.add_option("--ftp-regular", action="store_const", const="regular", dest="ftp_connection")

    # If set, forces a full backup if the last full backup is older than
    # the time specified
    parser.add_option("--full-if-older-than", type="time", dest="full_force_time", metavar=_("time"))

    parser.add_option("--gio", action="callback", dest="use_gio",
                      callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                   old_fn_deprecation(s)))

    parser.add_option("--gpg-binary", type="file", metavar=_("path"))

    parser.add_option("--gpg-options", action="extend", metavar=_("options"))

    # TRANSL: Used in usage help to represent an ID for a hidden GnuPG key. Example:
    # --hidden-encrypt-key <gpg_key_id>
    parser.add_option("--hidden-encrypt-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: globals.gpg_profile.hidden_recipients.append(v))  # @UndefinedVariable

    # ignore (some) errors during operations; supposed to make it more
    # likely that you are able to restore data under problematic
    # circumstances. the default should absolutely always be False unless
    # you know what you are doing.
    parser.add_option("--ignore-errors", action="callback",
                      dest="ignore_errors",
                      callback=lambda o, s, v, p: (log.Warn(
                          _("Running in 'ignore errors' mode due to %s; please "
                            "re-consider if this was not intended") % s),
                          setattr(p.values, "ignore_errors", True)))

    # Whether to use the full email address as the user name when
    # logging into an imap server. If false just the user name
    # part of the email address is used.
    parser.add_option("--imap-full-address", action="store_true")

    # Name of the imap folder where we want to store backups.
    # Can be changed with a command line argument.
    # TRANSL: Used in usage help to represent an imap mailbox
    parser.add_option("--imap-mailbox", metavar=_("imap_mailbox"))

    parser.add_option("--include", action="callback", metavar=_("shell_pattern"),
                      dest="", type="string", callback=add_selection)
    parser.add_option("--include-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=add_filelist)
    parser.add_option("--include-filelist-stdin", action="callback", dest="",
                      callback=lambda o, s, v, p: (select_opts.append(("--include-filelist", "standard input")),
                                                   select_files.append(sys.stdin),
                                                   stdin_deprecation(o)),
                      help=optparse.SUPPRESS_HELP)
    parser.add_option("--include-globbing-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=lambda o, s, v, p: (add_filelist(o, s, v, p),
                                                                               old_globbing_filelist_deprecation(s)),
                      help=optparse.SUPPRESS_HELP)
    parser.add_option("--include-regexp", metavar=_("regular_expression"), dest="",
                      type="string", action="callback", callback=add_selection)

    parser.add_option("--log-fd", type="int", metavar=_("file_descriptor"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: set_log_fd(v))

    # TRANSL: Used in usage help to represent the name of a file. Example:
    # --log-file <filename>
    parser.add_option("--log-file", type="file", metavar=_("filename"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: log.add_file(v))

    # Maximum block size for large files
    parser.add_option("--max-blocksize", type="int", metavar=_("number"))

    # TRANSL: Used in usage help (noun)
    parser.add_option("--name", dest="backup_name", metavar=_("backup name"))

    # If set to false, then do not encrypt files on remote system
    parser.add_option("--no-encryption", action="store_false", dest="encryption")

    # If set to false, then do not compress files on remote system
    parser.add_option("--no-compression", action="store_false", dest="compression")

    # If set, print the statistics after every backup session
    parser.add_option("--no-print-statistics", action="store_false", dest="print_statistics")

    # If true, filelists and directory statistics will be split on
    # nulls instead of newlines.
    parser.add_option("--null-separator", action="store_true")

    # number of retries on network operations
    # TRANSL: Used in usage help to represent a desired number of
    # something. Example:
    # --num-retries <number>
    parser.add_option("--num-retries", type="int", metavar=_("number"))

    # File owner uid keeps number from tar file. Like same option in GNU tar.
    parser.add_option("--numeric-owner", action="store_true")

    # Whether the old filename format is in effect.
    parser.add_option("--old-filenames", action="callback",
                      dest="old_filenames",
                      callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                   old_fn_deprecation(s)))

    # Level of Redundancy in % for Par2 files
    parser.add_option("--par2-redundancy", type="int", metavar=_("number"))

    # Verbatim par2 options
    parser.add_option("--par2-options", action="extend", metavar=_("options"))

    # Used to display the progress for the full and incremental backup operations
    parser.add_option("--progress", action="store_true")

    # Used to control the progress option update rate in seconds. Default: prompts each 3 seconds
    parser.add_option("--progress-rate", type="int", metavar=_("number"))

    # option to trigger Pydev debugger
    parser.add_option("--pydevd", action="store_true")

    # option to rename files during restore
    parser.add_option("--rename", type="file", action="callback", nargs=2,
                      callback=add_rename)

    # Restores will try to bring back the state as of the following time.
    # If it is None, default to current time.
    # TRANSL: Used in usage help to represent a time spec for a previous
    # point in time, as described in the documentation. Example:
    # duplicity remove-older-than time [options] target_url
    parser.add_option("--restore-time", "--time", "-t", type="time", metavar=_("time"))

    # user added rsync options
    parser.add_option("--rsync-options", action="extend", metavar=_("options"))

    # Whether to create European buckets (sorry, hard-coded to only
    # support european for now).
    parser.add_option("--s3-european-buckets", action="store_true")

    # Whether to use S3 Reduced Redudancy Storage
    parser.add_option("--s3-use-rrs", action="store_true")

    # Whether to use S3 Infrequent Access Storage
    parser.add_option("--s3-use-ia", action="store_true")

    # Whether to use "new-style" subdomain addressing for S3 buckets. Such
    # use is not backwards-compatible with upper-case buckets, or buckets
    # that are otherwise not expressable in a valid hostname.
    parser.add_option("--s3-use-new-style", action="store_true")

    # Whether to use plain HTTP (without SSL) to send data to S3
    # See <https://bugs.launchpad.net/duplicity/+bug/433970>.
    parser.add_option("--s3-unencrypted-connection", action="store_true")

    # Chunk size used for S3 multipart uploads.The number of parallel uploads to
    # S3 be given by chunk size / volume size. Use this to maximize the use of
    # your bandwidth. Defaults to 25MB
    parser.add_option("--s3-multipart-chunk-size", type="int", action="callback", metavar=_("number"),
                      callback=lambda o, s, v, p: setattr(p.values, "s3_multipart_chunk_size", v * 1024 * 1024))

    # Number of processes to set the Processor Pool to when uploading multipart
    # uploads to S3. Use this to control the maximum simultaneous uploads to S3.
    parser.add_option("--s3-multipart-max-procs", type="int", metavar=_("number"))

    # Number of seconds to wait for each part of a multipart upload to S3. Use this
    # to prevent hangups when doing a multipart upload to S3.
    parser.add_option("--s3-multipart-max-timeout", type="int", metavar=_("number"))

    # Option to allow the s3/boto backend use the multiprocessing version.
    parser.add_option("--s3-use-multiprocessing", action="store_true")

    # Option to allow use of server side encryption in s3
    parser.add_option("--s3-use-server-side-encryption", action="store_true", dest="s3_use_sse")

    # Option to specify a Swift container storage policy.
    parser.add_option("--swift-storage-policy", type="string", metavar=_("policy"))

    # Number of the largest supported upload size where the Azure library makes only one put call.
    # This is used to upload a single block if the content length is known and is less than this value.
    # The default is 67108864 (64MiB)
    parser.add_option("--azure-max-single-put-size", type="int", metavar=_("number"))

    # Number for the block size used by the Azure library to upload a blob if the length is unknown
    # or is larger than the value set by --azure-max-single-put-size".
    # The maximum block size the service supports is 100MiB.
    # The default is 4 * 1024 * 1024 (4MiB)
    parser.add_option("--azure-max-block-size", type="int", metavar=_("number"))

    # The number for the maximum parallel connections to use when the blob size exceeds 64MB.
    # max_connections (int) - Maximum number of parallel connections to use when the blob size exceeds 64MB.
    parser.add_option("--azure-max-connections", type="int", metavar=_("number"))

    # scp command to use (ssh pexpect backend)
    parser.add_option("--scp-command", metavar=_("command"))

    # sftp command to use (ssh pexpect backend)
    parser.add_option("--sftp-command", metavar=_("command"))

    # allow the user to switch cloudfiles backend
    parser.add_option("--cf-backend", metavar=_("pyrax|cloudfiles"))

    # If set, use short (< 30 char) filenames for all the remote files.
    parser.add_option("--short-filenames", action="callback",
                      dest="short_filenames",
                      callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                   old_fn_deprecation(s)))

    # TRANSL: Used in usage help to represent an ID for a GnuPG key. Example:
    # --encrypt-key <gpg_key_id>
    parser.add_option("--sign-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: set_sign_key(v))

    # default to batch mode using public-key encryption
    parser.add_option("--ssh-askpass", action="store_true")

    # user added ssh options
    parser.add_option("--ssh-options", action="extend", metavar=_("options"))

    # user added ssl options (used by webdav, lftp backend)
    parser.add_option("--ssl-cacert-file", metavar=_("pem formatted bundle of certificate authorities"))
    parser.add_option("--ssl-cacert-path", metavar=_("path to a folder with certificate authority files"))
    parser.add_option("--ssl-no-check-certificate", action="store_true")

    # Working directory for the tempfile module. Defaults to /tmp on most systems.
    parser.add_option("--tempdir", dest="temproot", type="file", metavar=_("path"))

    # network timeout value
    # TRANSL: Used in usage help. Example:
    # --timeout <seconds>
    parser.add_option("--timeout", type="int", metavar=_("seconds"))

    # Character used like the ":" in time strings like
    # 2002-08-06T04:22:00-07:00.  The colon isn't good for filenames on
    # windows machines.
    # TRANSL: abbreviation for "character" (noun)
    parser.add_option("--time-separator", type="string", metavar=_("char"),
                      action="callback",
                      callback=lambda o, s, v, p: set_time_sep(v, s))

    # Whether to specify --use-agent in GnuPG options
    parser.add_option("--use-agent", action="store_true")

    parser.add_option("--verbosity", "-v", type="verbosity", metavar="[0-9]",
                      dest="", action="callback",
                      callback=lambda o, s, v, p: log.setverbosity(v))

    parser.add_option("-V", "--version", action="callback", callback=print_ver)

    # volume size
    # TRANSL: Used in usage help to represent a desired number of
    # something. Example:
    # --num-retries <number>
    parser.add_option("--volsize", type="int", action="callback", metavar=_("number"),
                      callback=lambda o, s, v, p: setattr(p.values, "volsize", v * 1024 * 1024))

    # If set, collect only the file status, not the whole root.
    parser.add_option("--file-changed", action="callback", type="file",
                      metavar=_("path"), dest="file_changed",
                      callback=lambda o, s, v, p: setattr(p.values, "file_changed", v.rstrip('/')))

    # delay time before next try after a failure of a backend operation
    # TRANSL: Used in usage help. Example:
    # --backend-retry-delay <seconds>
    parser.add_option("--backend-retry-delay", type="int", metavar=_("seconds"))

    # parse the options
    (options, args) = parser.parse_args(arglist)

    # Copy all arguments and their values to the globals module.  Don't copy
    # attributes that are 'hidden' (start with an underscore) or whose name is
    # the empty string (used for arguments that don't directly store a value
    # by using dest="")
    for f in filter(lambda x: x and not x.startswith("_"), dir(options)):
        v = getattr(options, f)
        # Only set if v is not None because None is the default for all the
        # variables.  If user didn't set it, we'll use defaults in globals.py
        if v is not None:
            setattr(globals, f, v)

    socket.setdefaulttimeout(globals.timeout)

    # expect no cmd and two positional args
    cmd = ""
    num_expect = 2

    # process first arg as command
    if args:
        cmd = args.pop(0)
        possible = [c for c in commands if c.startswith(cmd)]
        # no unique match, that's an error
        if len(possible) > 1:
            command_line_error("command '%s' not unique, could be %s" % (cmd, possible))
        # only one match, that's a keeper
        elif len(possible) == 1:
            cmd = possible[0]
        # no matches, assume no cmd
        elif not possible:
            args.insert(0, cmd)

    if cmd == "cleanup":
        cleanup = True
        num_expect = 1
    elif cmd == "collection-status":
        collection_status = True
        num_expect = 1
    elif cmd == "full":
        full_backup = True
        num_expect = 2
    elif cmd == "incremental":
        globals.incremental = True
        num_expect = 2
    elif cmd == "list-current-files":
        list_current = True
        num_expect = 1
    elif cmd == "remove-older-than":
        try:
            arg = args.pop(0)
        except Exception:
            command_line_error("Missing time string for remove-older-than")
        globals.remove_time = dup_time.genstrtotime(arg)
        num_expect = 1
    elif cmd == "remove-all-but-n-full" or cmd == "remove-all-inc-of-but-n-full":
        if cmd == "remove-all-but-n-full":
            globals.remove_all_but_n_full_mode = True
        if cmd == "remove-all-inc-of-but-n-full":
            globals.remove_all_inc_of_but_n_full_mode = True
        try:
            arg = args.pop(0)
        except Exception:
            command_line_error("Missing count for " + cmd)
        globals.keep_chains = int(arg)
        if not globals.keep_chains > 0:
            command_line_error(cmd + " count must be > 0")
        num_expect = 1
    elif cmd == "verify":
        verify = True
    elif cmd == "replicate":
        replicate = True
        num_expect = 2

    if len(args) != num_expect:
        command_line_error("Expected %d args, got %d" % (num_expect, len(args)))

    # expand pathname args, but not URL
    for loc in range(len(args)):
        if '://' not in args[loc]:
            args[loc] = expand_fn(args[loc])

    # Note that ProcessCommandLine depends on us verifying the arg
    # count here; do not remove without fixing it. We must make the
    # checks here in order to make enough sense of args to identify
    # the backend URL/lpath for args_to_path_backend().
    if len(args) < 1:
        command_line_error("Too few arguments")
    elif len(args) == 1:
        backend_url = args[0]
    elif len(args) == 2:
        if replicate:
            if not backend.is_backend_url(args[0]) or not backend.is_backend_url(args[1]):
                command_line_error("Two URLs expected for replicate.")
            src_backend_url, backend_url = args[0], args[1]
        else:
            lpath, backend_url = args_to_path_backend(args[0], args[1])  # @UnusedVariable
    else:
        command_line_error("Too many arguments")

    if globals.backup_name is None:
        globals.backup_name = generate_default_backup_name(backend_url)

    # set and expand archive dir
    set_archive_dir(expand_archive_dir(globals.archive_dir,
                                       globals.backup_name))

    log.Info(_("Using archive dir: %s") % (util.ufn(globals.archive_dir_path.name),))
    log.Info(_("Using backup name: %s") % (globals.backup_name,))

    return args
Ejemplo n.º 4
0
def parse_cmdline_options(arglist):
    """Parse argument list"""
    global select_opts, select_files, full_backup
    global list_current, collection_status, cleanup, remove_time, verify, replicate

    def set_log_fd(fd):
        if fd < 1:
            raise optparse.OptionValueError("log-fd must be greater than zero.")
        log.add_fd(fd)

    def set_time_sep(sep, opt):
        if sep == '-':
            raise optparse.OptionValueError("Dash ('-') not valid for time-separator.")
        globals.time_separator = sep
        old_fn_deprecation(opt)

    def add_selection(o, option, additional_arg, p):
        select_opts.append((util.fsdecode(option), util.fsdecode(additional_arg)))

    def add_filelist(o, s, filename, p):
        select_opts.append((util.fsdecode(s), util.fsdecode(filename)))
        try:
            select_files.append(io.open(filename, "rt", encoding="UTF-8"))
        except IOError:
            log.FatalError(_("Error opening file %s") % filename,
                           log.ErrorCode.cant_open_filelist)

    def print_ver(o, s, v, p):
        print("duplicity %s" % (globals.version))
        sys.exit(0)

    def add_rename(o, s, v, p):
        globals.rename[os.path.normcase(os.path.normpath(v[0]))] = v[1]

    parser = OPHelpFix(option_class=DupOption, usage=usage())

    # If this is true, only warn and don't raise fatal error when backup
    # source directory doesn't match previous backup source directory.
    parser.add_option("--allow-source-mismatch", action="store_true")

    # Set to the path of the archive directory (the directory which
    # contains the signatures and manifests of the relevent backup
    # collection), and for checkpoint state between volumes.
    # TRANSL: Used in usage help to represent a Unix-style path name. Example:
    # --archive-dir <path>
    parser.add_option("--archive-dir", type="file", metavar=_("path"))

    # Asynchronous put/get concurrency limit
    # (default of 0 disables asynchronicity).
    parser.add_option("--asynchronous-upload", action="store_const", const=1,
                      dest="async_concurrency")

    parser.add_option("--compare-data", action="store_true")

    # config dir for future use
    parser.add_option("--config-dir", type="file", metavar=_("path"),
                      help=optparse.SUPPRESS_HELP)

    # When symlinks are encountered, the item they point to is copied rather than
    # the symlink.
    parser.add_option("--copy-links", action="store_true")

    # for testing -- set current time
    parser.add_option("--current-time", type="int",
                      dest="current_time", help=optparse.SUPPRESS_HELP)

    # Don't actually do anything, but still report what would be done
    parser.add_option("--dry-run", action="store_true")

    # TRANSL: Used in usage help to represent an ID for a GnuPG key. Example:
    # --encrypt-key <gpg_key_id>
    parser.add_option("--encrypt-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: globals.gpg_profile.recipients.append(v))  # @UndefinedVariable

    # secret keyring in which the private encrypt key can be found
    parser.add_option("--encrypt-secret-keyring", type="string", metavar=_("path"))

    parser.add_option("--encrypt-sign-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: (globals.gpg_profile.recipients.append(v), set_sign_key(v)))

    # TRANSL: Used in usage help to represent a "glob" style pattern for
    # matching one or more files, as described in the documentation.
    # Example:
    # --exclude <shell_pattern>
    parser.add_option("--exclude", action="callback", metavar=_("shell_pattern"),
                      dest="", type="string", callback=add_selection)

    parser.add_option("--exclude-device-files", action="callback",
                      dest="", callback=add_selection)

    parser.add_option("--exclude-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=add_filelist)

    parser.add_option("--exclude-filelist-stdin", action="callback", dest="",
                      callback=lambda o, s, v, p: (select_opts.append(("--exclude-filelist", "standard input")),
                                                   select_files.append(sys.stdin),
                                                   stdin_deprecation(o)),
                      help=optparse.SUPPRESS_HELP)

    parser.add_option("--exclude-globbing-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=lambda o, s, v, p: (add_filelist(o, s, v, p),
                                                                               old_globbing_filelist_deprecation(s)),
                      help=optparse.SUPPRESS_HELP)

    # TRANSL: Used in usage help to represent the name of a file. Example:
    # --log-file <filename>
    parser.add_option("--exclude-if-present", metavar=_("filename"), dest="",
                      type="file", action="callback", callback=add_selection)

    parser.add_option("--exclude-other-filesystems", action="callback",
                      dest="", callback=add_selection)

    # TRANSL: Used in usage help to represent a regular expression (regexp).
    parser.add_option("--exclude-regexp", metavar=_("regular_expression"),
                      dest="", type="string", action="callback", callback=add_selection)

    # Exclude any files with modification dates older than this from the backup
    parser.add_option("--exclude-older-than", type="time", metavar=_("time"),
                      dest="", action="callback", callback=add_selection)

    # Whether we should be particularly aggressive when cleaning up
    parser.add_option("--extra-clean", action="store_true")

    # used in testing only - raises exception after volume
    parser.add_option("--fail-on-volume", type="int",
                      help=optparse.SUPPRESS_HELP)

    # used to provide a prefix on top of the defaul tar file name
    parser.add_option("--file-prefix", type="string", dest="file_prefix", action="store")

    # used to provide a suffix for manifest files only
    parser.add_option("--file-prefix-manifest", type="string", dest="file_prefix_manifest", action="store")

    # used to provide a suffix for archive files only
    parser.add_option("--file-prefix-archive", type="string", dest="file_prefix_archive", action="store")

    # used to provide a suffix for sigature files only
    parser.add_option("--file-prefix-signature", type="string", dest="file_prefix_signature", action="store")

    # used in testing only - skips upload for a given volume
    parser.add_option("--skip-volume", type="int",
                      help=optparse.SUPPRESS_HELP)

    # If set, restore only the subdirectory or file specified, not the
    # whole root.
    # TRANSL: Used in usage help to represent a Unix-style path name. Example:
    # --archive-dir <path>
    parser.add_option("--file-to-restore", "-r", action="callback", type="file",
                      metavar=_("path"), dest="restore_dir",
                      callback=lambda o, s, v, p: setattr(p.values, "restore_dir", v.strip('/')))

    # Used to confirm certain destructive operations like deleting old files.
    parser.add_option("--force", action="store_true")

    # FTP data connection type
    parser.add_option("--ftp-passive", action="store_const", const="passive", dest="ftp_connection")
    parser.add_option("--ftp-regular", action="store_const", const="regular", dest="ftp_connection")

    # If set, forces a full backup if the last full backup is older than
    # the time specified
    parser.add_option("--full-if-older-than", type="time", dest="full_force_time", metavar=_("time"))

    parser.add_option("--gio", action="callback", dest="use_gio",
                      callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                   old_fn_deprecation(s)))

    parser.add_option("--gpg-binary", type="file", metavar=_("path"))

    parser.add_option("--gpg-options", action="extend", metavar=_("options"))

    # TRANSL: Used in usage help to represent an ID for a hidden GnuPG key. Example:
    # --hidden-encrypt-key <gpg_key_id>
    parser.add_option("--hidden-encrypt-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: globals.gpg_profile.hidden_recipients.append(v))  # @UndefinedVariable

    # ignore (some) errors during operations; supposed to make it more
    # likely that you are able to restore data under problematic
    # circumstances. the default should absolutely always be False unless
    # you know what you are doing.
    parser.add_option("--ignore-errors", action="callback",
                      dest="ignore_errors",
                      callback=lambda o, s, v, p: (log.Warn(
                          _("Running in 'ignore errors' mode due to %s; please "
                            "re-consider if this was not intended") % s),
                          setattr(p.values, "ignore_errors", True)))

    # Whether to use the full email address as the user name when
    # logging into an imap server. If false just the user name
    # part of the email address is used.
    parser.add_option("--imap-full-address", action="store_true")

    # Name of the imap folder where we want to store backups.
    # Can be changed with a command line argument.
    # TRANSL: Used in usage help to represent an imap mailbox
    parser.add_option("--imap-mailbox", metavar=_("imap_mailbox"))

    parser.add_option("--include", action="callback", metavar=_("shell_pattern"),
                      dest="", type="string", callback=add_selection)
    parser.add_option("--include-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=add_filelist)
    parser.add_option("--include-filelist-stdin", action="callback", dest="",
                      callback=lambda o, s, v, p: (select_opts.append(("--include-filelist", "standard input")),
                                                   select_files.append(sys.stdin),
                                                   stdin_deprecation(o)),
                      help=optparse.SUPPRESS_HELP)
    parser.add_option("--include-globbing-filelist", type="file", metavar=_("filename"),
                      dest="", action="callback", callback=lambda o, s, v, p: (add_filelist(o, s, v, p),
                                                                               old_globbing_filelist_deprecation(s)),
                      help=optparse.SUPPRESS_HELP)
    parser.add_option("--include-regexp", metavar=_("regular_expression"), dest="",
                      type="string", action="callback", callback=add_selection)

    parser.add_option("--log-fd", type="int", metavar=_("file_descriptor"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: set_log_fd(v))

    # TRANSL: Used in usage help to represent the name of a file. Example:
    # --log-file <filename>
    parser.add_option("--log-file", type="file", metavar=_("filename"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: log.add_file(v))

    # Maximum block size for large files
    parser.add_option("--max-blocksize", type="int", metavar=_("number"))

    # TRANSL: Used in usage help (noun)
    parser.add_option("--name", dest="backup_name", metavar=_("backup name"))

    # If set to false, then do not encrypt files on remote system
    parser.add_option("--no-encryption", action="store_false", dest="encryption")

    # If set to false, then do not compress files on remote system
    parser.add_option("--no-compression", action="store_false", dest="compression")

    # If set, print the statistics after every backup session
    parser.add_option("--no-print-statistics", action="store_false", dest="print_statistics")

    # If true, filelists and directory statistics will be split on
    # nulls instead of newlines.
    parser.add_option("--null-separator", action="store_true")

    # number of retries on network operations
    # TRANSL: Used in usage help to represent a desired number of
    # something. Example:
    # --num-retries <number>
    parser.add_option("--num-retries", type="int", metavar=_("number"))

    # File owner uid keeps number from tar file. Like same option in GNU tar.
    parser.add_option("--numeric-owner", action="store_true")

    # Whether the old filename format is in effect.
    parser.add_option("--old-filenames", action="callback",
                      dest="old_filenames",
                      callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                   old_fn_deprecation(s)))

    # Level of Redundancy in % for Par2 files
    parser.add_option("--par2-redundancy", type="int", metavar=_("number"))

    # Verbatim par2 options
    parser.add_option("--par2-options", action="extend", metavar=_("options"))

    # Used to display the progress for the full and incremental backup operations
    parser.add_option("--progress", action="store_true")

    # Used to control the progress option update rate in seconds. Default: prompts each 3 seconds
    parser.add_option("--progress-rate", type="int", metavar=_("number"))

    # option to trigger Pydev debugger
    parser.add_option("--pydevd", action="store_true")

    # option to rename files during restore
    parser.add_option("--rename", type="file", action="callback", nargs=2,
                      callback=add_rename)

    # Restores will try to bring back the state as of the following time.
    # If it is None, default to current time.
    # TRANSL: Used in usage help to represent a time spec for a previous
    # point in time, as described in the documentation. Example:
    # duplicity remove-older-than time [options] target_url
    parser.add_option("--restore-time", "--time", "-t", type="time", metavar=_("time"))

    # user added rsync options
    parser.add_option("--rsync-options", action="extend", metavar=_("options"))

    # Whether to create European buckets (sorry, hard-coded to only
    # support european for now).
    parser.add_option("--s3-european-buckets", action="store_true")

    # Whether to use S3 Reduced Redudancy Storage
    parser.add_option("--s3-use-rrs", action="store_true")

    # Whether to use S3 Infrequent Access Storage
    parser.add_option("--s3-use-ia", action="store_true")

    # Whether to use S3 One Zone Infrequent Access Storage
    parser.add_option("--s3-use-onezone-ia", action="store_true")

    # Whether to use "new-style" subdomain addressing for S3 buckets. Such
    # use is not backwards-compatible with upper-case buckets, or buckets
    # that are otherwise not expressable in a valid hostname.
    parser.add_option("--s3-use-new-style", action="store_true")

    # Whether to use plain HTTP (without SSL) to send data to S3
    # See <https://bugs.launchpad.net/duplicity/+bug/433970>.
    parser.add_option("--s3-unencrypted-connection", action="store_true")

    # Chunk size used for S3 multipart uploads.The number of parallel uploads to
    # S3 be given by chunk size / volume size. Use this to maximize the use of
    # your bandwidth. Defaults to 25MB
    parser.add_option("--s3-multipart-chunk-size", type="int", action="callback", metavar=_("number"),
                      callback=lambda o, s, v, p: setattr(p.values, "s3_multipart_chunk_size", v * 1024 * 1024))

    # Number of processes to set the Processor Pool to when uploading multipart
    # uploads to S3. Use this to control the maximum simultaneous uploads to S3.
    parser.add_option("--s3-multipart-max-procs", type="int", metavar=_("number"))

    # Number of seconds to wait for each part of a multipart upload to S3. Use this
    # to prevent hangups when doing a multipart upload to S3.
    parser.add_option("--s3-multipart-max-timeout", type="int", metavar=_("number"))

    # Option to allow the s3/boto backend use the multiprocessing version.
    parser.add_option("--s3-use-multiprocessing", action="store_true")

    # Option to allow use of server side encryption in s3
    parser.add_option("--s3-use-server-side-encryption", action="store_true", dest="s3_use_sse")

    # Option to specify a Swift container storage policy.
    parser.add_option("--swift-storage-policy", type="string", metavar=_("policy"))

    # Number of the largest supported upload size where the Azure library makes only one put call.
    # This is used to upload a single block if the content length is known and is less than this value.
    # The default is 67108864 (64MiB)
    parser.add_option("--azure-max-single-put-size", type="int", metavar=_("number"))

    # Number for the block size used by the Azure library to upload a blob if the length is unknown
    # or is larger than the value set by --azure-max-single-put-size".
    # The maximum block size the service supports is 100MiB.
    # The default is 4 * 1024 * 1024 (4MiB)
    parser.add_option("--azure-max-block-size", type="int", metavar=_("number"))

    # The number for the maximum parallel connections to use when the blob size exceeds 64MB.
    # max_connections (int) - Maximum number of parallel connections to use when the blob size exceeds 64MB.
    parser.add_option("--azure-max-connections", type="int", metavar=_("number"))

    # scp command to use (ssh pexpect backend)
    parser.add_option("--scp-command", metavar=_("command"))

    # sftp command to use (ssh pexpect backend)
    parser.add_option("--sftp-command", metavar=_("command"))

    # allow the user to switch cloudfiles backend
    parser.add_option("--cf-backend", metavar=_("pyrax|cloudfiles"))

    # If set, use short (< 30 char) filenames for all the remote files.
    parser.add_option("--short-filenames", action="callback",
                      dest="short_filenames",
                      callback=lambda o, s, v, p: (setattr(p.values, o.dest, True),
                                                   old_fn_deprecation(s)))

    # TRANSL: Used in usage help to represent an ID for a GnuPG key. Example:
    # --encrypt-key <gpg_key_id>
    parser.add_option("--sign-key", type="string", metavar=_("gpg-key-id"),
                      dest="", action="callback",
                      callback=lambda o, s, v, p: set_sign_key(v))

    # default to batch mode using public-key encryption
    parser.add_option("--ssh-askpass", action="store_true")

    # user added ssh options
    parser.add_option("--ssh-options", action="extend", metavar=_("options"))

    # user added ssl options (used by webdav, lftp backend)
    parser.add_option("--ssl-cacert-file", metavar=_("pem formatted bundle of certificate authorities"))
    parser.add_option("--ssl-cacert-path", metavar=_("path to a folder with certificate authority files"))
    parser.add_option("--ssl-no-check-certificate", action="store_true")

    # Working directory for the tempfile module. Defaults to /tmp on most systems.
    parser.add_option("--tempdir", dest="temproot", type="file", metavar=_("path"))

    # network timeout value
    # TRANSL: Used in usage help. Example:
    # --timeout <seconds>
    parser.add_option("--timeout", type="int", metavar=_("seconds"))

    # Character used like the ":" in time strings like
    # 2002-08-06T04:22:00-07:00.  The colon isn't good for filenames on
    # windows machines.
    # TRANSL: abbreviation for "character" (noun)
    parser.add_option("--time-separator", type="string", metavar=_("char"),
                      action="callback",
                      callback=lambda o, s, v, p: set_time_sep(v, s))

    # Whether to specify --use-agent in GnuPG options
    parser.add_option("--use-agent", action="store_true")

    parser.add_option("--verbosity", "-v", type="verbosity", metavar="[0-9]",
                      dest="", action="callback",
                      callback=lambda o, s, v, p: log.setverbosity(v))

    parser.add_option("-V", "--version", action="callback", callback=print_ver)

    # volume size
    # TRANSL: Used in usage help to represent a desired number of
    # something. Example:
    # --num-retries <number>
    parser.add_option("--volsize", type="int", action="callback", metavar=_("number"),
                      callback=lambda o, s, v, p: setattr(p.values, "volsize", v * 1024 * 1024))

    # If set, collect only the file status, not the whole root.
    parser.add_option("--file-changed", action="callback", type="file",
                      metavar=_("path"), dest="file_changed",
                      callback=lambda o, s, v, p: setattr(p.values, "file_changed", v.rstrip('/')))

    # delay time before next try after a failure of a backend operation
    # TRANSL: Used in usage help. Example:
    # --backend-retry-delay <seconds>
    parser.add_option("--backend-retry-delay", type="int", metavar=_("seconds"))

    # parse the options
    (options, args) = parser.parse_args(arglist)

    # Copy all arguments and their values to the globals module.  Don't copy
    # attributes that are 'hidden' (start with an underscore) or whose name is
    # the empty string (used for arguments that don't directly store a value
    # by using dest="")
    for f in filter(lambda x: x and not x.startswith("_"), dir(options)):
        v = getattr(options, f)
        # Only set if v is not None because None is the default for all the
        # variables.  If user didn't set it, we'll use defaults in globals.py
        if v is not None:
            setattr(globals, f, v)

    socket.setdefaulttimeout(globals.timeout)

    # expect no cmd and two positional args
    cmd = ""
    num_expect = 2

    # process first arg as command
    if args:
        cmd = args.pop(0)
        possible = [c for c in commands if c.startswith(cmd)]
        # no unique match, that's an error
        if len(possible) > 1:
            command_line_error("command '%s' not unique, could be %s" % (cmd, possible))
        # only one match, that's a keeper
        elif len(possible) == 1:
            cmd = possible[0]
        # no matches, assume no cmd
        elif not possible:
            args.insert(0, cmd)

    if cmd == "cleanup":
        cleanup = True
        num_expect = 1
    elif cmd == "collection-status":
        collection_status = True
        num_expect = 1
    elif cmd == "full":
        full_backup = True
        num_expect = 2
    elif cmd == "incremental":
        globals.incremental = True
        num_expect = 2
    elif cmd == "list-current-files":
        list_current = True
        num_expect = 1
    elif cmd == "remove-older-than":
        try:
            arg = args.pop(0)
        except Exception:
            command_line_error("Missing time string for remove-older-than")
        globals.remove_time = dup_time.genstrtotime(arg)
        num_expect = 1
    elif cmd == "remove-all-but-n-full" or cmd == "remove-all-inc-of-but-n-full":
        if cmd == "remove-all-but-n-full":
            globals.remove_all_but_n_full_mode = True
        if cmd == "remove-all-inc-of-but-n-full":
            globals.remove_all_inc_of_but_n_full_mode = True
        try:
            arg = args.pop(0)
        except Exception:
            command_line_error("Missing count for " + cmd)
        globals.keep_chains = int(arg)
        if not globals.keep_chains > 0:
            command_line_error(cmd + " count must be > 0")
        num_expect = 1
    elif cmd == "verify":
        verify = True
    elif cmd == "replicate":
        replicate = True
        num_expect = 2

    if len(args) != num_expect:
        command_line_error("Expected %d args, got %d" % (num_expect, len(args)))

    # expand pathname args, but not URL
    for loc in range(len(args)):
        if '://' not in args[loc]:
            args[loc] = expand_fn(args[loc])

    # Note that ProcessCommandLine depends on us verifying the arg
    # count here; do not remove without fixing it. We must make the
    # checks here in order to make enough sense of args to identify
    # the backend URL/lpath for args_to_path_backend().
    if len(args) < 1:
        command_line_error("Too few arguments")
    elif len(args) == 1:
        backend_url = args[0]
    elif len(args) == 2:
        if replicate:
            if not backend.is_backend_url(args[0]) or not backend.is_backend_url(args[1]):
                command_line_error("Two URLs expected for replicate.")
            src_backend_url, backend_url = args[0], args[1]
        else:
            lpath, backend_url = args_to_path_backend(args[0], args[1])  # @UnusedVariable
    else:
        command_line_error("Too many arguments")

    if globals.backup_name is None:
        globals.backup_name = generate_default_backup_name(backend_url)

    # set and expand archive dir
    set_archive_dir(expand_archive_dir(globals.archive_dir,
                                       globals.backup_name))

    log.Info(_("Using archive dir: %s") % (globals.archive_dir_path.uc_name,))
    log.Info(_("Using backup name: %s") % (globals.backup_name,))

    return args