|
@@ -2304,35 +2304,91 @@ class Archiver:
|
|
|
add_common_option('--debug', dest='log_level',
|
|
|
action='store_const', const='debug', default='warning',
|
|
|
help='enable debug output, work on log level DEBUG')
|
|
|
- add_common_option('--debug-topic', dest='debug_topics',
|
|
|
- action='append', metavar='TOPIC', default=[],
|
|
|
+ add_common_option('--debug-topic', metavar='TOPIC', dest='debug_topics', action='append', default=[],
|
|
|
help='enable TOPIC debugging (can be specified multiple times). '
|
|
|
'The logger path is borg.debug.<TOPIC> if TOPIC is not fully qualified.')
|
|
|
add_common_option('-p', '--progress', dest='progress', action='store_true',
|
|
|
help='show progress information')
|
|
|
add_common_option('--log-json', dest='log_json', action='store_true',
|
|
|
help='Output one JSON object per log line instead of formatted text.')
|
|
|
- add_common_option('--lock-wait', dest='lock_wait', type=int, metavar='N', default=1,
|
|
|
- help='wait for the lock, but max. N seconds (default: %(default)d).')
|
|
|
+ add_common_option('--lock-wait', metavar='SECONDS', dest='lock_wait', type=int, default=1,
|
|
|
+ help='wait at most SECONDS for acquiring a repository/cache lock (default: %(default)d).')
|
|
|
add_common_option('--show-version', dest='show_version', action='store_true',
|
|
|
help='show/log the borg version')
|
|
|
add_common_option('--show-rc', dest='show_rc', action='store_true',
|
|
|
help='show/log the return code (rc)')
|
|
|
add_common_option('--no-files-cache', dest='cache_files', action='store_false',
|
|
|
help='do not load/update the file metadata cache used to detect unchanged files')
|
|
|
- add_common_option('--umask', dest='umask', type=lambda s: int(s, 8), default=UMASK_DEFAULT, metavar='M',
|
|
|
+ add_common_option('--umask', metavar='M', dest='umask', type=lambda s: int(s, 8), default=UMASK_DEFAULT,
|
|
|
help='set umask to M (local and remote, default: %(default)04o)')
|
|
|
- add_common_option('--remote-path', dest='remote_path', metavar='PATH',
|
|
|
+ add_common_option('--remote-path', metavar='PATH', dest='remote_path',
|
|
|
help='use PATH as borg executable on the remote (default: "borg")')
|
|
|
- add_common_option('--remote-ratelimit', dest='remote_ratelimit', type=int, metavar='rate',
|
|
|
+ add_common_option('--remote-ratelimit', metavar='RATE', dest='remote_ratelimit', type=int,
|
|
|
help='set remote network upload rate limit in kiByte/s (default: 0=unlimited)')
|
|
|
- add_common_option('--consider-part-files', dest='consider_part_files',
|
|
|
- action='store_true',
|
|
|
+ add_common_option('--consider-part-files', dest='consider_part_files', action='store_true',
|
|
|
help='treat part files like normal files (e.g. to list/extract them)')
|
|
|
- add_common_option('--debug-profile', dest='debug_profile', default=None, metavar='FILE',
|
|
|
+ add_common_option('--debug-profile', metavar='FILE', dest='debug_profile', default=None,
|
|
|
help='Write execution profile in Borg format into FILE. For local use a Python-'
|
|
|
'compatible file can be generated by suffixing FILE with ".pyprof".')
|
|
|
|
|
|
+ def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False):
|
|
|
+ add_option('-e', '--exclude', metavar='PATTERN', dest='patterns',
|
|
|
+ type=parse_exclude_pattern, action='append',
|
|
|
+ help='exclude paths matching PATTERN')
|
|
|
+ add_option('--exclude-from', metavar='EXCLUDEFILE', action=ArgparseExcludeFileAction,
|
|
|
+ help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
+ add_option('--pattern', metavar='PATTERN', action=ArgparsePatternAction,
|
|
|
+ help='experimental: include/exclude paths matching PATTERN')
|
|
|
+ add_option('--patterns-from', metavar='PATTERNFILE', action=ArgparsePatternFileAction,
|
|
|
+ help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
+
|
|
|
+ if tag_files:
|
|
|
+ add_option('--exclude-caches', dest='exclude_caches', action='store_true',
|
|
|
+ help='exclude directories that contain a CACHEDIR.TAG file '
|
|
|
+ '(http://www.brynosaurus.com/cachedir/spec.html)')
|
|
|
+ add_option('--exclude-if-present', metavar='NAME', dest='exclude_if_present',
|
|
|
+ action='append', type=str,
|
|
|
+ help='exclude directories that are tagged by containing a filesystem object with '
|
|
|
+ 'the given NAME')
|
|
|
+ add_option('--keep-exclude-tags', '--keep-tag-files', dest='keep_exclude_tags',
|
|
|
+ action='store_true',
|
|
|
+ help='if tag objects are specified with ``--exclude-if-present``, '
|
|
|
+ 'don\'t omit the tag objects themselves from the backup archive')
|
|
|
+
|
|
|
+ if strip_components:
|
|
|
+ add_option('--strip-components', metavar='NUMBER', dest='strip_components', type=int, default=0,
|
|
|
+ help='Remove the specified number of leading path elements. '
|
|
|
+ 'Paths with fewer elements will be silently skipped.')
|
|
|
+
|
|
|
+ def define_exclusion_group(subparser, **kwargs):
|
|
|
+ exclude_group = subparser.add_argument_group('Exclusion options')
|
|
|
+ define_exclude_and_patterns(exclude_group.add_argument, **kwargs)
|
|
|
+
|
|
|
+ def define_archive_filters_group(subparser, *, sort_by=True, first_last=True):
|
|
|
+ filters_group = subparser.add_argument_group('Archive filters',
|
|
|
+ 'Archive filters can be applied to repository targets.')
|
|
|
+ group = filters_group.add_mutually_exclusive_group()
|
|
|
+ group.add_argument('-P', '--prefix', metavar='PREFIX', dest='prefix', type=PrefixSpec, default='',
|
|
|
+ help='only consider archive names starting with this prefix.')
|
|
|
+ group.add_argument('-a', '--glob-archives', metavar='GLOB', dest='glob_archives', default=None,
|
|
|
+ help='only consider archive names matching the glob. '
|
|
|
+ 'sh: rules apply, see "borg help patterns". '
|
|
|
+ '``--prefix`` and ``--glob-archives`` are mutually exclusive.')
|
|
|
+
|
|
|
+ if sort_by:
|
|
|
+ sort_by_default = 'timestamp'
|
|
|
+ filters_group.add_argument('--sort-by', metavar='KEYS', dest='sort_by',
|
|
|
+ type=SortBySpec, default=sort_by_default,
|
|
|
+ help='Comma-separated list of sorting keys; valid keys are: {}; default is: {}'
|
|
|
+ .format(', '.join(HUMAN_SORT_KEYS), sort_by_default))
|
|
|
+
|
|
|
+ if first_last:
|
|
|
+ group = filters_group.add_mutually_exclusive_group()
|
|
|
+ group.add_argument('--first', metavar='N', dest='first', default=0, type=int,
|
|
|
+ help='consider first N archives after other filters were applied')
|
|
|
+ group.add_argument('--last', metavar='N', dest='last', default=0, type=int,
|
|
|
+ help='consider last N archives after other filters were applied')
|
|
|
+
|
|
|
parser = argparse.ArgumentParser(prog=self.prog, description='Borg - Deduplicated Backups',
|
|
|
add_help=False)
|
|
|
parser.common_options = self.CommonOptions(define_common_options,
|
|
@@ -2360,22 +2416,22 @@ class Archiver:
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
help='start repository server process')
|
|
|
subparser.set_defaults(func=self.do_serve)
|
|
|
- subparser.add_argument('--restrict-to-path', dest='restrict_to_paths', action='append',
|
|
|
- metavar='PATH', help='restrict repository access to PATH. '
|
|
|
- 'Can be specified multiple times to allow the client access to several directories. '
|
|
|
- 'Access to all sub-directories is granted implicitly; PATH doesn\'t need to directly point to a repository.')
|
|
|
- subparser.add_argument('--restrict-to-repository', dest='restrict_to_repositories', action='append',
|
|
|
- metavar='PATH', help='restrict repository access. Only the repository located at PATH (no sub-directories are considered) '
|
|
|
- 'is accessible. '
|
|
|
- 'Can be specified multiple times to allow the client access to several repositories. '
|
|
|
- 'Unlike ``--restrict-to-path`` sub-directories are not accessible; '
|
|
|
- 'PATH needs to directly point at a repository location. '
|
|
|
- 'PATH may be an empty directory or the last element of PATH may not exist, in which case '
|
|
|
- 'the client may initialize a repository there.')
|
|
|
+ subparser.add_argument('--restrict-to-path', metavar='PATH', dest='restrict_to_paths', action='append',
|
|
|
+ help='restrict repository access to PATH. '
|
|
|
+ 'Can be specified multiple times to allow the client access to several directories. '
|
|
|
+ 'Access to all sub-directories is granted implicitly; PATH doesn\'t need to directly point to a repository.')
|
|
|
+ subparser.add_argument('--restrict-to-repository', metavar='PATH', dest='restrict_to_repositories', action='append',
|
|
|
+ help='restrict repository access. Only the repository located at PATH '
|
|
|
+ '(no sub-directories are considered) is accessible. '
|
|
|
+ 'Can be specified multiple times to allow the client access to several repositories. '
|
|
|
+ 'Unlike ``--restrict-to-path`` sub-directories are not accessible; '
|
|
|
+ 'PATH needs to directly point at a repository location. '
|
|
|
+ 'PATH may be an empty directory or the last element of PATH may not exist, in which case '
|
|
|
+ 'the client may initialize a repository there.')
|
|
|
subparser.add_argument('--append-only', dest='append_only', action='store_true',
|
|
|
help='only allow appending to repository segment files')
|
|
|
- subparser.add_argument('--storage-quota', dest='storage_quota', default=None,
|
|
|
- type=parse_storage_quota,
|
|
|
+ subparser.add_argument('--storage-quota', metavar='QUOTA', dest='storage_quota',
|
|
|
+ type=parse_storage_quota, default=None,
|
|
|
help='Override storage quota of the repository (e.g. 5G, 1.5T). '
|
|
|
'When a new repository is initialized, sets the storage quota on the new '
|
|
|
'repository as well. Default: no quota.')
|
|
@@ -2491,12 +2547,12 @@ class Archiver:
|
|
|
subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
|
type=location_validator(archive=False),
|
|
|
help='repository to create')
|
|
|
- subparser.add_argument('-e', '--encryption', dest='encryption', required=True,
|
|
|
+ subparser.add_argument('-e', '--encryption', metavar='MODE', dest='encryption', required=True,
|
|
|
choices=('none', 'keyfile', 'repokey', 'keyfile-blake2', 'repokey-blake2', 'authenticated'),
|
|
|
help='select encryption key mode **(required)**')
|
|
|
subparser.add_argument('--append-only', dest='append_only', action='store_true',
|
|
|
help='create an append-only mode repository')
|
|
|
- subparser.add_argument('--storage-quota', dest='storage_quota', default=None,
|
|
|
+ subparser.add_argument('--storage-quota', metavar='QUOTA', dest='storage_quota', default=None,
|
|
|
type=parse_storage_quota,
|
|
|
help='Set storage quota of the new repository (e.g. 5G, 1.5T). Default: no quota.')
|
|
|
|
|
@@ -2557,22 +2613,17 @@ class Archiver:
|
|
|
type=location_validator(),
|
|
|
help='repository or archive to check consistency of')
|
|
|
subparser.add_argument('--repository-only', dest='repo_only', action='store_true',
|
|
|
- default=False,
|
|
|
help='only perform repository checks')
|
|
|
subparser.add_argument('--archives-only', dest='archives_only', action='store_true',
|
|
|
- default=False,
|
|
|
help='only perform archives checks')
|
|
|
subparser.add_argument('--verify-data', dest='verify_data', action='store_true',
|
|
|
- default=False,
|
|
|
help='perform cryptographic archive data integrity verification '
|
|
|
'(conflicts with ``--repository-only``)')
|
|
|
subparser.add_argument('--repair', dest='repair', action='store_true',
|
|
|
- default=False,
|
|
|
help='attempt to repair any inconsistencies found')
|
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
|
- default=False,
|
|
|
help='work slower, but using less space')
|
|
|
- self.add_archives_filters_args(subparser)
|
|
|
+ define_archive_filters_group(subparser)
|
|
|
|
|
|
subparser = subparsers.add_parser('key', parents=[mid_common_parser], add_help=False,
|
|
|
description="Manage a keyfile or repokey of a repository",
|
|
@@ -2613,10 +2664,8 @@ class Archiver:
|
|
|
subparser.add_argument('path', metavar='PATH', nargs='?', type=str,
|
|
|
help='where to store the backup')
|
|
|
subparser.add_argument('--paper', dest='paper', action='store_true',
|
|
|
- default=False,
|
|
|
help='Create an export suitable for printing and later type-in')
|
|
|
subparser.add_argument('--qr-html', dest='qr', action='store_true',
|
|
|
- default=False,
|
|
|
help='Create an html file suitable for printing and later type-in or qr scan')
|
|
|
|
|
|
key_import_epilog = process_epilog("""
|
|
@@ -2638,7 +2687,6 @@ class Archiver:
|
|
|
subparser.add_argument('path', metavar='PATH', nargs='?', type=str,
|
|
|
help='path to the backup')
|
|
|
subparser.add_argument('--paper', dest='paper', action='store_true',
|
|
|
- default=False,
|
|
|
help='interactively import from a backup done with ``--paper``')
|
|
|
|
|
|
change_passphrase_epilog = process_epilog("""
|
|
@@ -2790,86 +2838,52 @@ class Archiver:
|
|
|
help='create backup')
|
|
|
subparser.set_defaults(func=self.do_create)
|
|
|
|
|
|
- subparser.add_argument('-n', '--dry-run', dest='dry_run',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true',
|
|
|
help='do not create a backup archive')
|
|
|
-
|
|
|
- subparser.add_argument('-s', '--stats', dest='stats',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('-s', '--stats', dest='stats', action='store_true',
|
|
|
help='print statistics for the created archive')
|
|
|
- subparser.add_argument('--list', dest='output_list',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--list', dest='output_list', action='store_true',
|
|
|
help='output verbose list of items (files, dirs, ...)')
|
|
|
- subparser.add_argument('--filter', dest='output_filter', metavar='STATUSCHARS',
|
|
|
- help='only display items with the given status characters')
|
|
|
+ subparser.add_argument('--filter', metavar='STATUSCHARS', dest='output_filter',
|
|
|
+ help='only display items with the given status characters (see description)')
|
|
|
subparser.add_argument('--json', action='store_true',
|
|
|
help='output stats as JSON. Implies ``--stats``.')
|
|
|
subparser.add_argument('--no-cache-sync', dest='no_cache_sync', action='store_true',
|
|
|
help='experimental: do not synchronize the cache. Implies ``--no-files-cache``.')
|
|
|
|
|
|
- exclude_group = subparser.add_argument_group('Exclusion options')
|
|
|
- exclude_group.add_argument('-e', '--exclude', dest='patterns',
|
|
|
- type=parse_exclude_pattern, action='append',
|
|
|
- metavar="PATTERN", help='exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--exclude-from', action=ArgparseExcludeFileAction,
|
|
|
- metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
- exclude_group.add_argument('--exclude-caches', dest='exclude_caches',
|
|
|
- action='store_true', default=False,
|
|
|
- help='exclude directories that contain a CACHEDIR.TAG file ('
|
|
|
- 'http://www.brynosaurus.com/cachedir/spec.html)')
|
|
|
- exclude_group.add_argument('--exclude-if-present', dest='exclude_if_present',
|
|
|
- metavar='NAME', action='append', type=str,
|
|
|
- help='exclude directories that are tagged by containing a filesystem object with '
|
|
|
- 'the given NAME')
|
|
|
- exclude_group.add_argument('--keep-exclude-tags', '--keep-tag-files', dest='keep_exclude_tags',
|
|
|
- action='store_true', default=False,
|
|
|
- help='if tag objects are specified with ``--exclude-if-present``, '
|
|
|
- 'don\'t omit the tag objects themselves from the backup archive')
|
|
|
- exclude_group.add_argument('--pattern',
|
|
|
- action=ArgparsePatternAction,
|
|
|
- metavar="PATTERN", help='experimental: include/exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--patterns-from', action=ArgparsePatternFileAction,
|
|
|
- metavar='PATTERNFILE', help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
+ define_exclusion_group(subparser, tag_files=True)
|
|
|
|
|
|
fs_group = subparser.add_argument_group('Filesystem options')
|
|
|
- fs_group.add_argument('-x', '--one-file-system', dest='one_file_system',
|
|
|
- action='store_true', default=False,
|
|
|
+ fs_group.add_argument('-x', '--one-file-system', dest='one_file_system', action='store_true',
|
|
|
help='stay in the same file system and do not store mount points of other file systems')
|
|
|
- fs_group.add_argument('--numeric-owner', dest='numeric_owner',
|
|
|
- action='store_true', default=False,
|
|
|
+ fs_group.add_argument('--numeric-owner', dest='numeric_owner', action='store_true',
|
|
|
help='only store numeric user and group identifiers')
|
|
|
- fs_group.add_argument('--noatime', dest='noatime',
|
|
|
- action='store_true', default=False,
|
|
|
+ fs_group.add_argument('--noatime', dest='noatime', action='store_true',
|
|
|
help='do not store atime into archive')
|
|
|
- fs_group.add_argument('--noctime', dest='noctime',
|
|
|
- action='store_true', default=False,
|
|
|
+ fs_group.add_argument('--noctime', dest='noctime', action='store_true',
|
|
|
help='do not store ctime into archive')
|
|
|
- fs_group.add_argument('--ignore-inode', dest='ignore_inode',
|
|
|
- action='store_true', default=False,
|
|
|
+ fs_group.add_argument('--ignore-inode', dest='ignore_inode', action='store_true',
|
|
|
help='ignore inode data in the file metadata cache used to detect unchanged files.')
|
|
|
- fs_group.add_argument('--read-special', dest='read_special',
|
|
|
- action='store_true', default=False,
|
|
|
+ fs_group.add_argument('--read-special', dest='read_special', action='store_true',
|
|
|
help='open and read block and char device files as well as FIFOs as if they were '
|
|
|
'regular files. Also follows symlinks pointing to these kinds of files.')
|
|
|
|
|
|
archive_group = subparser.add_argument_group('Archive options')
|
|
|
archive_group.add_argument('--comment', dest='comment', metavar='COMMENT', default='',
|
|
|
help='add a comment text to the archive')
|
|
|
- archive_group.add_argument('--timestamp', dest='timestamp',
|
|
|
+ archive_group.add_argument('--timestamp', metavar='TIMESTAMP', dest='timestamp',
|
|
|
type=timestamp, default=None,
|
|
|
- metavar='TIMESTAMP',
|
|
|
help='manually specify the archive creation date/time (UTC, yyyy-mm-ddThh:mm:ss format). '
|
|
|
- 'alternatively, give a reference file/directory.')
|
|
|
- archive_group.add_argument('-c', '--checkpoint-interval', dest='checkpoint_interval',
|
|
|
- type=int, default=1800, metavar='SECONDS',
|
|
|
+ 'Alternatively, give a reference file/directory.')
|
|
|
+ archive_group.add_argument('-c', '--checkpoint-interval', metavar='SECONDS', dest='checkpoint_interval',
|
|
|
+ type=int, default=1800,
|
|
|
help='write checkpoint every SECONDS seconds (Default: 1800)')
|
|
|
- archive_group.add_argument('--chunker-params', dest='chunker_params',
|
|
|
+ archive_group.add_argument('--chunker-params', metavar='PARAMS', dest='chunker_params',
|
|
|
type=ChunkerParams, default=CHUNKER_PARAMS,
|
|
|
- metavar='PARAMS',
|
|
|
help='specify the chunker parameters (CHUNK_MIN_EXP, CHUNK_MAX_EXP, '
|
|
|
'HASH_MASK_BITS, HASH_WINDOW_SIZE). default: %d,%d,%d,%d' % CHUNKER_PARAMS)
|
|
|
- archive_group.add_argument('-C', '--compression', dest='compression',
|
|
|
- type=CompressionSpec, default=CompressionSpec('lz4'), metavar='COMPRESSION',
|
|
|
+ archive_group.add_argument('-C', '--compression', metavar='COMPRESSION', dest='compression',
|
|
|
+ type=CompressionSpec, default=CompressionSpec('lz4'),
|
|
|
help='select compression algorithm, see the output of the '
|
|
|
'"borg help compression" command for details.')
|
|
|
|
|
@@ -2905,38 +2919,22 @@ class Archiver:
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
help='extract archive contents')
|
|
|
subparser.set_defaults(func=self.do_extract)
|
|
|
- subparser.add_argument('--list', dest='output_list',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--list', dest='output_list', action='store_true',
|
|
|
help='output verbose list of items (files, dirs, ...)')
|
|
|
- subparser.add_argument('-n', '--dry-run', dest='dry_run',
|
|
|
- default=False, action='store_true',
|
|
|
+ subparser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true',
|
|
|
help='do not actually change any files')
|
|
|
- subparser.add_argument('-e', '--exclude', dest='patterns',
|
|
|
- type=parse_exclude_pattern, action='append',
|
|
|
- metavar="PATTERN", help='exclude paths matching PATTERN')
|
|
|
- subparser.add_argument('--exclude-from', action=ArgparseExcludeFileAction,
|
|
|
- metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
- subparser.add_argument('--pattern', action=ArgparsePatternAction,
|
|
|
- metavar="PATTERN", help='experimental: include/exclude paths matching PATTERN')
|
|
|
- subparser.add_argument('--patterns-from', action=ArgparsePatternFileAction,
|
|
|
- metavar='PATTERNFILE', help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
- subparser.add_argument('--numeric-owner', dest='numeric_owner',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--numeric-owner', dest='numeric_owner', action='store_true',
|
|
|
help='only obey numeric user and group identifiers')
|
|
|
- subparser.add_argument('--strip-components', dest='strip_components',
|
|
|
- type=int, default=0, metavar='NUMBER',
|
|
|
- help='Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped.')
|
|
|
- subparser.add_argument('--stdout', dest='stdout',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--stdout', dest='stdout', action='store_true',
|
|
|
help='write all extracted data to stdout')
|
|
|
- subparser.add_argument('--sparse', dest='sparse',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--sparse', dest='sparse', action='store_true',
|
|
|
help='create holes in output sparse file from all-zero chunks')
|
|
|
subparser.add_argument('location', metavar='ARCHIVE',
|
|
|
type=location_validator(archive=True),
|
|
|
help='archive to extract')
|
|
|
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
|
|
help='paths to extract; patterns are supported')
|
|
|
+ define_exclusion_group(subparser, strip_components=True)
|
|
|
|
|
|
export_tar_epilog = process_epilog("""
|
|
|
This command creates a tarball from an archive.
|
|
@@ -2981,21 +2979,8 @@ class Archiver:
|
|
|
subparser.set_defaults(func=self.do_export_tar)
|
|
|
subparser.add_argument('--tar-filter', dest='tar_filter', default='auto',
|
|
|
help='filter program to pipe data through')
|
|
|
- subparser.add_argument('--list', dest='output_list',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--list', dest='output_list', action='store_true',
|
|
|
help='output verbose list of items (files, dirs, ...)')
|
|
|
- subparser.add_argument('-e', '--exclude', dest='patterns',
|
|
|
- type=parse_exclude_pattern, action='append',
|
|
|
- metavar="PATTERN", help='exclude paths matching PATTERN')
|
|
|
- subparser.add_argument('--exclude-from', action=ArgparseExcludeFileAction,
|
|
|
- metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
- subparser.add_argument('--pattern', action=ArgparsePatternAction,
|
|
|
- metavar="PATTERN", help='experimental: include/exclude paths matching PATTERN')
|
|
|
- subparser.add_argument('--patterns-from', action=ArgparsePatternFileAction,
|
|
|
- metavar='PATTERNFILE', help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
- subparser.add_argument('--strip-components', dest='strip_components',
|
|
|
- type=int, default=0, metavar='NUMBER',
|
|
|
- help='Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped.')
|
|
|
subparser.add_argument('location', metavar='ARCHIVE',
|
|
|
type=location_validator(archive=True),
|
|
|
help='archive to export')
|
|
@@ -3003,6 +2988,7 @@ class Archiver:
|
|
|
help='output tar file. "-" to write to stdout instead.')
|
|
|
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
|
|
help='paths to extract; patterns are supported')
|
|
|
+ define_exclusion_group(subparser, strip_components=True)
|
|
|
|
|
|
diff_epilog = process_epilog("""
|
|
|
This command finds differences (file contents, user/group/mode) between archives.
|
|
@@ -3028,14 +3014,11 @@ class Archiver:
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
|
help='find differences in archive contents')
|
|
|
subparser.set_defaults(func=self.do_diff)
|
|
|
- subparser.add_argument('--numeric-owner', dest='numeric_owner',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--numeric-owner', dest='numeric_owner', action='store_true',
|
|
|
help='only consider numeric user and group identifiers')
|
|
|
- subparser.add_argument('--same-chunker-params', dest='same_chunker_params',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--same-chunker-params', dest='same_chunker_params', action='store_true',
|
|
|
help='Override check of chunker parameters.')
|
|
|
- subparser.add_argument('--sort', dest='sort',
|
|
|
- action='store_true', default=False,
|
|
|
+ subparser.add_argument('--sort', dest='sort', action='store_true',
|
|
|
help='Sort the output lines by file path.')
|
|
|
subparser.add_argument('location', metavar='REPO_ARCHIVE1',
|
|
|
type=location_validator(archive=True),
|
|
@@ -3045,30 +3028,7 @@ class Archiver:
|
|
|
help='ARCHIVE2 name (no repository location allowed)')
|
|
|
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
|
|
help='paths of items inside the archives to compare; patterns are supported')
|
|
|
-
|
|
|
- exclude_group = subparser.add_argument_group('Exclusion options')
|
|
|
- exclude_group.add_argument('-e', '--exclude', dest='patterns',
|
|
|
- type=parse_exclude_pattern, action='append',
|
|
|
- metavar="PATTERN", help='exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--exclude-from', action=ArgparseExcludeFileAction,
|
|
|
- metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
- exclude_group.add_argument('--exclude-caches', dest='exclude_caches',
|
|
|
- action='store_true', default=False,
|
|
|
- help='exclude directories that contain a CACHEDIR.TAG file ('
|
|
|
- 'http://www.brynosaurus.com/cachedir/spec.html)')
|
|
|
- exclude_group.add_argument('--exclude-if-present', dest='exclude_if_present',
|
|
|
- metavar='NAME', action='append', type=str,
|
|
|
- help='exclude directories that are tagged by containing a filesystem object with '
|
|
|
- 'the given NAME')
|
|
|
- exclude_group.add_argument('--keep-exclude-tags', '--keep-tag-files', dest='keep_exclude_tags',
|
|
|
- action='store_true', default=False,
|
|
|
- help='if tag objects are specified with ``--exclude-if-present``, '
|
|
|
- 'don\'t omit the tag objects themselves from the backup archive')
|
|
|
- exclude_group.add_argument('--pattern',
|
|
|
- action=ArgparsePatternAction,
|
|
|
- metavar="PATTERN", help='experimental: include/exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--patterns-from', action=ArgparsePatternFileAction,
|
|
|
- metavar='PATTERNFILE', help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
+ define_exclusion_group(subparser, tag_files=True)
|
|
|
|
|
|
rename_epilog = process_epilog("""
|
|
|
This command renames an archive in the repository.
|
|
@@ -3108,12 +3068,11 @@ class Archiver:
|
|
|
help='force deletion of corrupted archives, '
|
|
|
'use ``--force --force`` in case ``--force`` does not work.')
|
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
|
- default=False,
|
|
|
help='work slower, but using less space')
|
|
|
subparser.add_argument('location', metavar='TARGET', nargs='?', default='',
|
|
|
type=location_validator(),
|
|
|
help='archive or repository to delete')
|
|
|
- self.add_archives_filters_args(subparser)
|
|
|
+ define_archive_filters_group(subparser)
|
|
|
|
|
|
list_epilog = process_epilog("""
|
|
|
This command lists the contents of a repository or an archive.
|
|
@@ -3142,7 +3101,7 @@ class Archiver:
|
|
|
subparser.set_defaults(func=self.do_list)
|
|
|
subparser.add_argument('--short', dest='short', action='store_true',
|
|
|
help='only print file/directory names, nothing else')
|
|
|
- subparser.add_argument('--format', '--list-format', dest='format', type=str, metavar='FORMAT',
|
|
|
+ subparser.add_argument('--format', '--list-format', metavar='FORMAT', dest='format',
|
|
|
help='specify format for file listing '
|
|
|
'(default: "{mode} {user:6} {group:6} {size:8d} {isomtime} {path}{extra}{NL}")')
|
|
|
subparser.add_argument('--json', action='store_true',
|
|
@@ -3162,30 +3121,8 @@ class Archiver:
|
|
|
help='repository/archive to list contents of')
|
|
|
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
|
|
help='paths to list; patterns are supported')
|
|
|
- self.add_archives_filters_args(subparser)
|
|
|
-
|
|
|
- exclude_group = subparser.add_argument_group('Exclusion options')
|
|
|
- exclude_group.add_argument('-e', '--exclude', dest='patterns',
|
|
|
- type=parse_exclude_pattern, action='append',
|
|
|
- metavar="PATTERN", help='exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--exclude-from', action=ArgparseExcludeFileAction,
|
|
|
- metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
- exclude_group.add_argument('--exclude-caches', dest='exclude_caches', action='store_true',
|
|
|
- help='exclude directories that contain a CACHEDIR.TAG file ('
|
|
|
- 'http://www.brynosaurus.com/cachedir/spec.html)')
|
|
|
- exclude_group.add_argument('--exclude-if-present', dest='exclude_if_present',
|
|
|
- metavar='NAME', action='append', type=str,
|
|
|
- help='exclude directories that are tagged by containing a filesystem object with '
|
|
|
- 'the given NAME')
|
|
|
- exclude_group.add_argument('--keep-exclude-tags', '--keep-tag-files', dest='keep_exclude_tags',
|
|
|
- action='store_true',
|
|
|
- help='if tag objects are specified with ``--exclude-if-present``, don\'t omit the tag '
|
|
|
- 'objects themselves from the backup archive')
|
|
|
- exclude_group.add_argument('--pattern',
|
|
|
- action=ArgparsePatternAction,
|
|
|
- metavar="PATTERN", help='experimental: include/exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--patterns-from', action=ArgparsePatternFileAction,
|
|
|
- metavar='PATTERNFILE', help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
+ define_archive_filters_group(subparser)
|
|
|
+ define_exclusion_group(subparser, tag_files=True)
|
|
|
|
|
|
mount_epilog = process_epilog("""
|
|
|
This command mounts an archive as a FUSE filesystem. This can be useful for
|
|
@@ -3236,7 +3173,7 @@ class Archiver:
|
|
|
help='stay in foreground, do not daemonize')
|
|
|
subparser.add_argument('-o', dest='options', type=str,
|
|
|
help='Extra mount options')
|
|
|
- self.add_archives_filters_args(subparser)
|
|
|
+ define_archive_filters_group(subparser)
|
|
|
|
|
|
umount_epilog = process_epilog("""
|
|
|
This command un-mounts a FUSE filesystem that was mounted with ``borg mount``.
|
|
@@ -3276,7 +3213,7 @@ class Archiver:
|
|
|
help='archive or repository to display information about')
|
|
|
subparser.add_argument('--json', action='store_true',
|
|
|
help='format output as JSON')
|
|
|
- self.add_archives_filters_args(subparser)
|
|
|
+ define_archive_filters_group(subparser)
|
|
|
|
|
|
break_lock_epilog = process_epilog("""
|
|
|
This command breaks the repository and cache locks.
|
|
@@ -3347,7 +3284,7 @@ class Archiver:
|
|
|
help='print statistics for the deleted archive')
|
|
|
subparser.add_argument('--list', dest='output_list', action='store_true',
|
|
|
help='output verbose list of archives it keeps/prunes')
|
|
|
- subparser.add_argument('--keep-within', dest='within', type=interval, metavar='INTERVAL',
|
|
|
+ subparser.add_argument('--keep-within', metavar='INTERVAL', dest='within', type=interval,
|
|
|
help='keep all archives within this time interval')
|
|
|
subparser.add_argument('--keep-last', '--keep-secondly', dest='secondly', type=int, default=0,
|
|
|
help='number of secondly archives to keep')
|
|
@@ -3363,7 +3300,7 @@ class Archiver:
|
|
|
help='number of monthly archives to keep')
|
|
|
subparser.add_argument('-y', '--keep-yearly', dest='yearly', type=int, default=0,
|
|
|
help='number of yearly archives to keep')
|
|
|
- self.add_archives_filters_args(subparser, sort_by=False, first_last=False)
|
|
|
+ define_archive_filters_group(subparser, sort_by=False, first_last=False)
|
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
|
help='work slower, but using less space')
|
|
|
subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
@@ -3526,29 +3463,7 @@ class Archiver:
|
|
|
subparser.add_argument('-s', '--stats', dest='stats', action='store_true',
|
|
|
help='print statistics at end')
|
|
|
|
|
|
- exclude_group = subparser.add_argument_group('Exclusion options')
|
|
|
- exclude_group.add_argument('-e', '--exclude', dest='patterns',
|
|
|
- type=parse_exclude_pattern, action='append',
|
|
|
- metavar="PATTERN", help='exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--exclude-from', action=ArgparseExcludeFileAction,
|
|
|
- metavar='EXCLUDEFILE', help='read exclude patterns from EXCLUDEFILE, one per line')
|
|
|
- exclude_group.add_argument('--exclude-caches', dest='exclude_caches',
|
|
|
- action='store_true',
|
|
|
- help='exclude directories that contain a CACHEDIR.TAG file ('
|
|
|
- 'http://www.brynosaurus.com/cachedir/spec.html)')
|
|
|
- exclude_group.add_argument('--exclude-if-present', dest='exclude_if_present',
|
|
|
- metavar='NAME', action='append', type=str,
|
|
|
- help='exclude directories that are tagged by containing a filesystem object with '
|
|
|
- 'the given NAME')
|
|
|
- exclude_group.add_argument('--keep-exclude-tags', '--keep-tag-files', dest='keep_exclude_tags',
|
|
|
- action='store_true',
|
|
|
- help='if tag objects are specified with ``--exclude-if-present``, don\'t omit the tag '
|
|
|
- 'objects themselves from the backup archive')
|
|
|
- exclude_group.add_argument('--pattern',
|
|
|
- action=ArgparsePatternAction,
|
|
|
- metavar="PATTERN", help='experimental: include/exclude paths matching PATTERN')
|
|
|
- exclude_group.add_argument('--patterns-from', action=ArgparsePatternFileAction,
|
|
|
- metavar='PATTERNFILE', help='experimental: read include/exclude patterns from PATTERNFILE, one per line')
|
|
|
+ define_exclusion_group(subparser, tag_files=True)
|
|
|
|
|
|
archive_group = subparser.add_argument_group('Archive options')
|
|
|
archive_group.add_argument('--target', dest='target', metavar='TARGET', default=None,
|
|
@@ -3560,13 +3475,12 @@ class Archiver:
|
|
|
help='write checkpoint every SECONDS seconds (Default: 1800)')
|
|
|
archive_group.add_argument('--comment', dest='comment', metavar='COMMENT', default=None,
|
|
|
help='add a comment text to the archive')
|
|
|
- archive_group.add_argument('--timestamp', dest='timestamp',
|
|
|
+ archive_group.add_argument('--timestamp', metavar='TIMESTAMP', dest='timestamp',
|
|
|
type=timestamp, default=None,
|
|
|
- metavar='TIMESTAMP',
|
|
|
help='manually specify the archive creation date/time (UTC, yyyy-mm-ddThh:mm:ss format). '
|
|
|
'alternatively, give a reference file/directory.')
|
|
|
- archive_group.add_argument('-C', '--compression', dest='compression',
|
|
|
- type=CompressionSpec, default=CompressionSpec('lz4'), metavar='COMPRESSION',
|
|
|
+ archive_group.add_argument('-C', '--compression', metavar='COMPRESSION', dest='compression',
|
|
|
+ type=CompressionSpec, default=CompressionSpec('lz4'),
|
|
|
help='select compression algorithm, see the output of the '
|
|
|
'"borg help compression" command for details.')
|
|
|
archive_group.add_argument('--recompress', dest='recompress', nargs='?', default='never', const='if-different',
|
|
@@ -3575,9 +3489,8 @@ class Archiver:
|
|
|
'When `always`, chunks that are already compressed that way are not skipped, '
|
|
|
'but compressed again. Only the algorithm is considered for `if-different`, '
|
|
|
'not the compression level (if any).')
|
|
|
- archive_group.add_argument('--chunker-params', dest='chunker_params',
|
|
|
+ archive_group.add_argument('--chunker-params', metavar='PARAMS', dest='chunker_params',
|
|
|
type=ChunkerParams, default=CHUNKER_PARAMS,
|
|
|
- metavar='PARAMS',
|
|
|
help='specify the chunker parameters (CHUNK_MIN_EXP, CHUNK_MAX_EXP, '
|
|
|
'HASH_MASK_BITS, HASH_WINDOW_SIZE) or `default` to use the current defaults. '
|
|
|
'default: %d,%d,%d,%d' % CHUNKER_PARAMS)
|
|
@@ -3850,31 +3763,6 @@ class Archiver:
|
|
|
|
|
|
return parser
|
|
|
|
|
|
- @staticmethod
|
|
|
- def add_archives_filters_args(subparser, sort_by=True, first_last=True):
|
|
|
- filters_group = subparser.add_argument_group('filters', 'Archive filters can be applied to repository targets.')
|
|
|
- group = filters_group.add_mutually_exclusive_group()
|
|
|
- group.add_argument('-P', '--prefix', dest='prefix', type=PrefixSpec, default='', metavar='PREFIX',
|
|
|
- help='only consider archive names starting with this prefix.')
|
|
|
- group.add_argument('-a', '--glob-archives', dest='glob_archives', default=None, metavar='GLOB',
|
|
|
- help='only consider archive names matching the glob. '
|
|
|
- 'sh: rules apply, see "borg help patterns". '
|
|
|
- '``--prefix`` and ``--glob-archives`` are mutually exclusive.')
|
|
|
-
|
|
|
- if sort_by:
|
|
|
- sort_by_default = 'timestamp'
|
|
|
- filters_group.add_argument('--sort-by', dest='sort_by', type=SortBySpec, default=sort_by_default,
|
|
|
- metavar='KEYS',
|
|
|
- help='Comma-separated list of sorting keys; valid keys are: {}; default is: {}'
|
|
|
- .format(', '.join(HUMAN_SORT_KEYS), sort_by_default))
|
|
|
-
|
|
|
- if first_last:
|
|
|
- group = filters_group.add_mutually_exclusive_group()
|
|
|
- group.add_argument('--first', dest='first', metavar='N', default=0, type=int,
|
|
|
- help='consider first N archives after other filters were applied')
|
|
|
- group.add_argument('--last', dest='last', metavar='N', default=0, type=int,
|
|
|
- help='consider last N archives after other filters were applied')
|
|
|
-
|
|
|
def get_args(self, argv, cmd):
|
|
|
"""usually, just returns argv, except if we deal with a ssh forced command for borg serve."""
|
|
|
result = self.parse_args(argv[1:])
|