mirror of
https://github.com/borgbackup/borg.git
synced 2025-01-01 04:37:34 +00:00
Adds arguments to filter archives
These are: --sort-by, --first and --last Includes a method to obtain a list of archive infos filtered by these Archives.list: - ensure reverse is always applied - always return a list
This commit is contained in:
parent
23ac8af7fa
commit
f6b9276de9
2 changed files with 56 additions and 4 deletions
|
@ -16,6 +16,7 @@
|
|||
from binascii import unhexlify
|
||||
from datetime import datetime
|
||||
from itertools import zip_longest
|
||||
from operator import attrgetter
|
||||
|
||||
from .logger import create_logger, setup_logging
|
||||
logger = create_logger()
|
||||
|
@ -28,7 +29,8 @@
|
|||
from .constants import * # NOQA
|
||||
from .helpers import EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR
|
||||
from .helpers import Error, NoManifestError
|
||||
from .helpers import location_validator, archivename_validator, ChunkerParams, CompressionSpec, PrefixSpec
|
||||
from .helpers import location_validator, archivename_validator, ChunkerParams, CompressionSpec
|
||||
from .helpers import PrefixSpec, sort_by_spec, HUMAN_SORT_KEYS
|
||||
from .helpers import BaseFormatter, ItemFormatter, ArchiveFormatter, format_time, format_file_size, format_archive
|
||||
from .helpers import safe_encode, remove_surrogates, bin_to_hex
|
||||
from .helpers import prune_within, prune_split
|
||||
|
@ -2549,6 +2551,23 @@ def build_parser(self, prog=None):
|
|||
|
||||
return parser
|
||||
|
||||
@staticmethod
|
||||
def add_archives_filters_args(subparser):
|
||||
filters_group = subparser.add_argument_group('filters', 'Archive filters can be applied to repository targets.')
|
||||
filters_group.add_argument('-P', '--prefix', dest='prefix', type=prefix_spec, default='',
|
||||
help='only consider archive names starting with this prefix')
|
||||
|
||||
sort_by_default = 'timestamp'
|
||||
filters_group.add_argument('--sort-by', dest='sort_by', type=sort_by_spec, default=sort_by_default,
|
||||
help='Comma-separated list of sorting keys; valid keys are: {}; default is: {}'
|
||||
.format(', '.join(HUMAN_SORT_KEYS), sort_by_default))
|
||||
|
||||
group = filters_group.add_mutually_exclusive_group()
|
||||
group.add_argument('--first', dest='first', metavar='N', default=0, type=int,
|
||||
help='select first N archives')
|
||||
group.add_argument('--last', dest='last', metavar='N', default=0, type=int,
|
||||
help='delete last N archives')
|
||||
|
||||
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:])
|
||||
|
@ -2611,6 +2630,25 @@ def run(self, args):
|
|||
logger.warning("Using a pure-python msgpack! This will result in lower performance.")
|
||||
return args.func(args)
|
||||
|
||||
def _get_filtered_archives(self, args, manifest):
|
||||
if args.location.archive:
|
||||
raise Error('The options --first, --last and --prefix can only be used on repository targets.')
|
||||
|
||||
archives = manifest.archives.list()
|
||||
if not archives:
|
||||
logger.critical('There are no archives.')
|
||||
self.exit_code = self.exit_code or EXIT_WARNING
|
||||
return []
|
||||
|
||||
for sortkey in reversed(args.sort_by.split(',')):
|
||||
archives.sort(key=attrgetter(sortkey))
|
||||
if args.last:
|
||||
archives.reverse()
|
||||
|
||||
n = args.first or args.last
|
||||
|
||||
return archives[:n]
|
||||
|
||||
|
||||
def sig_info_handler(sig_no, stack): # pragma: no cover
|
||||
"""search the stack for infos about the currently processed file and print them"""
|
||||
|
|
|
@ -143,10 +143,14 @@ def __delitem__(self, name):
|
|||
del self._archives[name]
|
||||
|
||||
def list(self, sort_by=None, reverse=False):
|
||||
# inexpensive Archive.list_archives replacement if we just need .name, .id, .ts
|
||||
archives = self.values() # [self[name] for name in self]
|
||||
""" Inexpensive Archive.list_archives replacement if we just need .name, .id, .ts
|
||||
Returns list of borg.helpers.ArchiveInfo instances
|
||||
"""
|
||||
archives = list(self.values()) # [self[name] for name in self]
|
||||
if sort_by is not None:
|
||||
archives = sorted(archives, key=attrgetter(sort_by), reverse=reverse)
|
||||
archives = sorted(archives, key=attrgetter(sort_by))
|
||||
if reverse:
|
||||
archives.reverse()
|
||||
return archives
|
||||
|
||||
def set_raw_dict(self, d):
|
||||
|
@ -655,6 +659,16 @@ def replace_placeholders(text):
|
|||
return format_line(text, data)
|
||||
|
||||
|
||||
HUMAN_SORT_KEYS = ['timestamp'] + list(ArchiveInfo._fields)
|
||||
HUMAN_SORT_KEYS.remove('ts')
|
||||
|
||||
def sort_by_spec(text):
|
||||
for token in text.split(','):
|
||||
if token not in HUMAN_SORT_KEYS:
|
||||
raise ValueError('Invalid sort key: %s' % token)
|
||||
return text.replace('timestamp', 'ts')
|
||||
|
||||
|
||||
def safe_timestamp(item_timestamp_ns):
|
||||
try:
|
||||
return datetime.fromtimestamp(bigint_to_int(item_timestamp_ns) / 1e9)
|
||||
|
|
Loading…
Reference in a new issue