| 
					
				 | 
			
			
				@@ -33,6 +33,7 @@ import msgpack 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import borg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from . import __version__ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from . import helpers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from . import shellpattern 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .algorithms.checksums import crc32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .archive import Archive, ArchiveChecker, ArchiveRecreater, Statistics, is_special 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .archive import BackupOSError, backup_io 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -283,9 +284,11 @@ class Archiver: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if not args.archives_only: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if not repository.check(repair=args.repair, save_space=args.save_space): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return EXIT_WARNING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if args.prefix: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            args.glob_archives = args.prefix + '*' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if not args.repo_only and not ArchiveChecker().check( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 repository, repair=args.repair, archive=args.location.archive, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                first=args.first, last=args.last, sort_by=args.sort_by or 'ts', prefix=args.prefix, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                first=args.first, last=args.last, sort_by=args.sort_by or 'ts', glob=args.glob_archives, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 verify_data=args.verify_data, save_space=args.save_space): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return EXIT_WARNING 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return EXIT_SUCCESS 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1168,7 +1171,7 @@ class Archiver: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @with_repository(exclusive=True, manifest=False) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def do_delete(self, args, repository): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """Delete an existing repository or archives""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if any((args.location.archive, args.first, args.last, args.prefix)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if any((args.location.archive, args.first, args.last, args.prefix, args.glob_archives)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return self._delete_archives(args, repository) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return self._delete_repository(args, repository) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1365,7 +1368,7 @@ class Archiver: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @with_repository(cache=True, compatibility=(Manifest.Operation.READ,)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def do_info(self, args, repository, manifest, key, cache): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """Show archive details such as disk space used""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if any((args.location.archive, args.first, args.last, args.prefix)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if any((args.location.archive, args.first, args.last, args.prefix, args.glob_archives)): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return self._info_archives(args, repository, manifest, key, cache) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return self._info_repository(args, repository, manifest, key, cache) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1463,7 +1466,10 @@ class Archiver: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return self.exit_code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         archives_checkpoints = manifest.archives.list(sort_by=['ts'], reverse=True)  # just a ArchiveInfo list 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if args.prefix: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            archives_checkpoints = [arch for arch in archives_checkpoints if arch.name.startswith(args.prefix)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            args.glob_archives = args.prefix + '*' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if args.glob_archives: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            regex = re.compile(shellpattern.translate(args.glob_archives)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            archives_checkpoints = [arch for arch in archives_checkpoints if regex.match(arch.name) is not None] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         is_checkpoint = re.compile(r'\.checkpoint(\.\d+)?$').search 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         checkpoints = [arch for arch in archives_checkpoints if is_checkpoint(arch.name)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # keep the latest checkpoint, if there is no later non-checkpoint archive 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3344,8 +3350,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') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        subparser.add_argument('-P', '--prefix', dest='prefix', type=PrefixSpec, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               help='only consider archive names starting with this prefix') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.add_archives_filters_args(subparser, sort_by=False, first_last=False) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         subparser.add_argument('--save-space', dest='save_space', action='store_true', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                default=False, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                help='work slower, but using less space') 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3839,21 +3844,28 @@ class Archiver: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return parser 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     @staticmethod 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def add_archives_filters_args(subparser): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    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.') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        filters_group.add_argument('-P', '--prefix', dest='prefix', type=PrefixSpec, default='', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                   help='only consider archive names starting with this prefix') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        sort_by_default = 'timestamp' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        filters_group.add_argument('--sort-by', 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)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         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') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        group.add_argument('-P', '--prefix', dest='prefix', type=PrefixSpec, default='', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           help='only consider archive names starting with this prefix.') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        group.add_argument('-a', '--glob-archives', 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', 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', 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.""" 
			 |