From 1c707b7da20ab08bb93f637e64eb8af24c0b724c Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 14 Jun 2022 00:28:47 +0200 Subject: [PATCH 01/21] cli: use --repo option instead of positional repo parameter currently still with ::archive appended. --- src/borg/archiver.py | 149 +-- src/borg/testsuite/__init__.py | 2 +- src/borg/testsuite/archiver.py | 1643 ++++++++++++++++---------------- 3 files changed, 858 insertions(+), 936 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index c92ba7e05..0e2d07855 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -664,34 +664,37 @@ class Archiver: def do_benchmark_crud(self, args): """Benchmark Create, Read, Update, Delete for archives.""" def measurement_run(repo, path): - archive = repo + '::borg-benchmark-crud' compression = '--compression=none' # measure create perf (without files cache to always have it chunking) t_start = time.monotonic() - rc = self.do_create(self.parse_args(['create', compression, '--files-cache=disabled', archive + '1', path])) + rc = self.do_create(self.parse_args([f'--repo={repo}::borg-benchmark-crud1', 'create', + compression, '--files-cache=disabled', path])) t_end = time.monotonic() dt_create = t_end - t_start assert rc == 0 # now build files cache - rc1 = self.do_create(self.parse_args(['create', compression, archive + '2', path])) - rc2 = self.do_delete(self.parse_args(['delete', archive + '2'])) + rc1 = self.do_create(self.parse_args([f'--repo={repo}::borg-benchmark-crud2', 'create', + compression, path])) + rc2 = self.do_delete(self.parse_args([f'--repo={repo}::borg-benchmark-crud2', 'delete'])) assert rc1 == rc2 == 0 # measure a no-change update (archive1 is still present) t_start = time.monotonic() - rc1 = self.do_create(self.parse_args(['create', compression, archive + '3', path])) + rc1 = self.do_create(self.parse_args([f'--repo={repo}::borg-benchmark-crud3', 'create', + compression, path])) t_end = time.monotonic() dt_update = t_end - t_start - rc2 = self.do_delete(self.parse_args(['delete', archive + '3'])) + rc2 = self.do_delete(self.parse_args([f'--repo={repo}::borg-benchmark-crud3', 'delete'])) assert rc1 == rc2 == 0 # measure extraction (dry-run: without writing result to disk) t_start = time.monotonic() - rc = self.do_extract(self.parse_args(['extract', '--dry-run', archive + '1'])) + rc = self.do_extract(self.parse_args([f'--repo={repo}::borg-benchmark-crud1', 'extract', + '--dry-run'])) t_end = time.monotonic() dt_extract = t_end - t_start assert rc == 0 # measure archive deletion (of LAST present archive with the data) t_start = time.monotonic() - rc = self.do_delete(self.parse_args(['delete', archive + '1'])) + rc = self.do_delete(self.parse_args([f'--repo={repo}::borg-benchmark-crud1', 'delete'])) t_end = time.monotonic() dt_delete = t_end - t_start assert rc == 0 @@ -3200,6 +3203,8 @@ class Archiver: 'compatible file can be generated by suffixing FILE with ".pyprof".') add_common_option('--rsh', metavar='RSH', dest='rsh', help="Use this command to connect to the 'borg serve' process (default: 'ssh')") + add_common_option('--repo', metavar='REPO', dest='location', type=location_validator(), + help="repository to use") # XXXYYY def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False): add_option('-e', '--exclude', metavar='PATTERN', dest='patterns', @@ -3263,8 +3268,7 @@ class Archiver: def define_borg_mount(parser): parser.set_defaults(func=self.do_mount) - parser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', type=location_validator(), - help='repository or archive to mount') + # archive name parser.add_argument('--consider-checkpoints', action='store_true', dest='consider_checkpoints', help='Show checkpoint archives in the repository contents list (default: hidden).') parser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str, @@ -3427,10 +3431,6 @@ class Archiver: help='benchmarks borg CRUD (create, extract, update, delete).') subparser.set_defaults(func=self.do_benchmark_crud) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to use for benchmark (must exist)') - subparser.add_argument('path', metavar='PATH', help='path were to create benchmark input data') bench_cpu_epilog = process_epilog(""" @@ -3460,9 +3460,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='break repository and cache locks') subparser.set_defaults(func=self.do_break_lock) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False), - help='repository for which to break the locks') # borg check check_epilog = process_epilog(""" @@ -3545,9 +3542,7 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='verify repository') subparser.set_defaults(func=self.do_check) - subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='', - type=location_validator(), - help='repository or archive to check consistency of') + # archive name subparser.add_argument('--repository-only', dest='repo_only', action='store_true', help='only perform repository checks') subparser.add_argument('--archives-only', dest='archives_only', action='store_true', @@ -3595,9 +3590,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='compact segment files / free space in repo') subparser.set_defaults(func=self.do_compact) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False), - help='repository to compact') subparser.add_argument('--cleanup-commits', dest='cleanup_commits', action='store_true', help='cleanup commit-only 17-byte segment files') subparser.add_argument('--threshold', metavar='PERCENT', dest='threshold', @@ -3635,9 +3627,6 @@ class Archiver: group.add_argument('-l', '--list', dest='list', action='store_true', help='list the configuration of the repo') - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False, proto='file'), - help='repository to configure') subparser.add_argument('name', metavar='NAME', nargs='?', help='name of config key') subparser.add_argument('value', metavar='VALUE', nargs='?', @@ -3921,9 +3910,7 @@ class Archiver: help='select compression algorithm, see the output of the ' '"borg help compression" command for details.') - subparser.add_argument('location', metavar='ARCHIVE', - type=location_validator(archive=True), - help='name of archive to create (must be also a valid directory name)') + # archive name subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to archive') @@ -3966,9 +3953,7 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump archive items (metadata) (debug)') subparser.set_defaults(func=self.do_debug_dump_archive_items) - subparser.add_argument('location', metavar='ARCHIVE', - type=location_validator(archive=True), - help='archive to dump') + # archive name debug_dump_archive_epilog = process_epilog(""" This command dumps all metadata of an archive in a decoded form to a file. @@ -3979,9 +3964,7 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump decoded archive metadata (debug)') subparser.set_defaults(func=self.do_debug_dump_archive) - subparser.add_argument('location', metavar='ARCHIVE', - type=location_validator(archive=True), - help='archive to dump') + # archive name subparser.add_argument('path', metavar='PATH', type=str, help='file to dump data into') @@ -3994,9 +3977,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump decoded repository metadata (debug)') subparser.set_defaults(func=self.do_debug_dump_manifest) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to dump') subparser.add_argument('path', metavar='PATH', type=str, help='file to dump data into') @@ -4009,9 +3989,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump repo objects (debug)') subparser.set_defaults(func=self.do_debug_dump_repo_objs) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to dump') subparser.add_argument('--ghost', dest='ghost', action='store_true', help='dump all segment file contents, including deleted/uncommitted objects and commits.') @@ -4024,9 +4001,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='search repo objects (debug)') subparser.set_defaults(func=self.do_debug_search_repo_objs) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to search') subparser.add_argument('wanted', metavar='WANTED', type=str, help='term to search the repo for, either 0x1234abcd hex term or a string') @@ -4039,9 +4013,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='get object from repository (debug)') subparser.set_defaults(func=self.do_debug_get_obj) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to use') subparser.add_argument('id', metavar='ID', type=str, help='hex object ID to get from the repo') subparser.add_argument('path', metavar='PATH', type=str, @@ -4056,9 +4027,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='put object to repository (debug)') subparser.set_defaults(func=self.do_debug_put_obj) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to use') subparser.add_argument('paths', metavar='PATH', nargs='+', type=str, help='file(s) to read and create object(s) from') @@ -4071,9 +4039,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='delete object from repository (debug)') subparser.set_defaults(func=self.do_debug_delete_obj) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to use') subparser.add_argument('ids', metavar='IDs', nargs='+', type=str, help='hex object ID(s) to delete from the repo') @@ -4086,9 +4051,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='show refcount for object from repository (debug)') subparser.set_defaults(func=self.do_debug_refcount_obj) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to use') subparser.add_argument('ids', metavar='IDs', nargs='+', type=str, help='hex object ID(s) to show refcounts for') @@ -4101,9 +4063,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump repo hints (debug)') subparser.set_defaults(func=self.do_debug_dump_hints) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to dump') subparser.add_argument('path', metavar='PATH', type=str, help='file to dump data into') @@ -4171,9 +4130,7 @@ class Archiver: help='keep the local security info when deleting a repository') subparser.add_argument('--save-space', dest='save_space', action='store_true', help='work slower, but using less space') - subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='', - type=location_validator(), - help='repository or archive to delete') + # archive name subparser.add_argument('archives', metavar='ARCHIVE', nargs='*', help='archives to delete') define_archive_filters_group(subparser) @@ -4210,9 +4167,9 @@ class Archiver: subparser.add_argument('other_location', metavar='SRC_REPOSITORY', type=location_validator(archive=False, other=True), help='source repository') - subparser.add_argument('location', metavar='DST_REPOSITORY', - type=location_validator(archive=False, other=False), - help='destination repository') + # subparser.add_argument('-r', '--repo', dest='location', metavar='DST_REPOSITORY', + # type=location_validator(archive=False, other=False), + # help='destination repository') define_archive_filters_group(subparser) # borg diff @@ -4250,12 +4207,12 @@ class Archiver: help='Sort the output lines by file path.') subparser.add_argument('--json-lines', action='store_true', help='Format output as JSON Lines. ') - subparser.add_argument('location', metavar='REPO::ARCHIVE1', - type=location_validator(archive=True), - help='repository location and ARCHIVE1 name') + subparser.add_argument('archive1', metavar='ARCHIVE1', + type=archivename_validator(), + help='ARCHIVE1 name') subparser.add_argument('archive2', metavar='ARCHIVE2', type=archivename_validator(), - help='ARCHIVE2 name (no repository location allowed)') + help='ARCHIVE2 name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths of items inside the archives to compare; patterns are supported') define_exclusion_group(subparser) @@ -4317,9 +4274,7 @@ class Archiver: subparser.add_argument('--tar-format', metavar='FMT', dest='tar_format', default='GNU', choices=('BORG', 'PAX', 'GNU'), help='select tar format: BORG, PAX or GNU') - subparser.add_argument('location', metavar='ARCHIVE', - type=location_validator(archive=True), - help='archive to export') + # archive name subparser.add_argument('tarfile', metavar='FILE', help='output tar file. "-" to write to stdout instead.') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, @@ -4377,9 +4332,7 @@ class Archiver: help='write all extracted data to stdout') 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') + # archive name subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to extract; patterns are supported') define_exclusion_group(subparser, strip_components=True) @@ -4417,9 +4370,7 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='show repository or archive information') subparser.set_defaults(func=self.do_info) - subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='', - type=location_validator(), - help='repository or archive to display information about') + # archive name subparser.add_argument('--json', action='store_true', help='format output as JSON') define_archive_filters_group(subparser) @@ -4553,9 +4504,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='initialize empty repository') subparser.set_defaults(func=self.do_init) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False), - help='repository to create') subparser.add_argument('--other-location', metavar='OTHER_REPOSITORY', dest='other_location', type=location_validator(archive=False, other=True), help='reuse the key material from the other repository') @@ -4626,8 +4574,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='export repository key for backup') subparser.set_defaults(func=self.do_key_export) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False)) subparser.add_argument('path', metavar='PATH', nargs='?', type=str, help='where to store the backup') subparser.add_argument('--paper', dest='paper', action='store_true', @@ -4657,8 +4603,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='import repository key from backup') subparser.set_defaults(func=self.do_key_import) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False)) subparser.add_argument('path', metavar='PATH', nargs='?', type=str, help='path to the backup (\'-\' to read from stdin)') subparser.add_argument('--paper', dest='paper', action='store_true', @@ -4679,8 +4623,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='change repository passphrase') subparser.set_defaults(func=self.do_change_passphrase) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False)) change_location_epilog = process_epilog(""" Change the location of a borg key. The key can be stored at different locations: @@ -4697,8 +4639,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='change key location') subparser.set_defaults(func=self.do_change_location) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False)) subparser.add_argument('key_mode', metavar='KEY_LOCATION', choices=('repokey', 'keyfile'), help='select key location') subparser.add_argument('--keep', dest='keep', action='store_true', @@ -4741,8 +4681,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='change key algorithm') subparser.set_defaults(func=self.do_change_algorithm) - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False)) subparser.add_argument('algorithm', metavar='ALGORITHM', choices=list(KEY_ALGORITHMS), help='select key algorithm') @@ -4821,9 +4759,7 @@ class Archiver: 'but keys used in it are added to the JSON output. ' 'Some keys are always present. Note: JSON can only represent text. ' 'A "bpath" key is therefore not available.') - subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='', - type=location_validator(), - help='repository or archive to list contents of') + # archive name subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to list; patterns are supported') define_archive_filters_group(subparser) @@ -4926,9 +4862,6 @@ class Archiver: 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='', - type=location_validator(archive=False), - help='repository to prune') # borg recreate recreate_epilog = process_epilog(""" @@ -5036,9 +4969,7 @@ class Archiver: 'HASH_MASK_BITS, HASH_WINDOW_SIZE) or `default` to use the current defaults. ' 'default: %s,%d,%d,%d,%d' % CHUNKER_PARAMS) - subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='', - type=location_validator(), - help='repository or archive to recreate') + # archive name subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to recreate; patterns are supported') @@ -5054,12 +4985,12 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='rename archive') subparser.set_defaults(func=self.do_rename) - subparser.add_argument('location', metavar='ARCHIVE', - type=location_validator(archive=True), - help='archive to rename') + subparser.add_argument('name_current', metavar='OLDNAME', + type=archivename_validator(), + help='the current archive name') subparser.add_argument('name', metavar='NEWNAME', type=archivename_validator(), - help='the new archive name to use') + help='the new archive name') # borg serve serve_epilog = process_epilog(""" @@ -5176,9 +5107,6 @@ class Archiver: help='Enable manifest authentication (in key and cache) (Borg 1.0.9 and later).') subparser.add_argument('--disable-tam', dest='disable_tam', action='store_true', help='Disable manifest authentication (in key and cache).') - subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', - type=location_validator(archive=False), - help='path to the repository to be upgraded') # borg with-lock with_lock_epilog = process_epilog(""" @@ -5202,9 +5130,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='run user command with lock held') subparser.set_defaults(func=self.do_with_lock) - subparser.add_argument('location', metavar='REPOSITORY', - type=location_validator(archive=False), - help='repository to lock') subparser.add_argument('command', metavar='COMMAND', help='command to run') subparser.add_argument('args', metavar='ARGS', nargs=argparse.REMAINDER, @@ -5286,9 +5211,7 @@ class Archiver: help='select compression algorithm, see the output of the ' '"borg help compression" command for details.') - subparser.add_argument('location', metavar='ARCHIVE', - type=location_validator(archive=True), - help='name of archive to create (must be also a valid directory name)') + # archive name subparser.add_argument('tarfile', metavar='TARFILE', help='input tar file. "-" to read from stdin instead.') return parser diff --git a/src/borg/testsuite/__init__.py b/src/borg/testsuite/__init__.py index b1db8aa95..307798e64 100644 --- a/src/borg/testsuite/__init__.py +++ b/src/borg/testsuite/__init__.py @@ -248,7 +248,7 @@ class BaseTestCase(unittest.TestCase): mountpoint = tempfile.mkdtemp() else: os.mkdir(mountpoint) - args = ['mount', location, mountpoint] + list(options) + args = [f'--repo={location}', 'mount', mountpoint] + list(options) if os_fork: # Do not spawn, but actually (OS) fork. if os.fork() == 0: diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index e033d6cf7..1c67a5573 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -147,16 +147,16 @@ def test_return_codes(cmd, tmpdir): input = tmpdir.mkdir('input') output = tmpdir.mkdir('output') input.join('test_file').write('content') - rc, out = cmd('init', '--encryption=none', '%s' % str(repo)) + rc, out = cmd('--repo=%s' % str(repo), 'init', '--encryption=none') assert rc == EXIT_SUCCESS - rc, out = cmd('create', '%s::archive' % repo, str(input)) + rc, out = cmd('--repo=%s::archive' % repo, 'create', str(input)) assert rc == EXIT_SUCCESS with changedir(str(output)): - rc, out = cmd('extract', '%s::archive' % repo) + rc, out = cmd('--repo=%s::archive' % repo, 'extract') assert rc == EXIT_SUCCESS - rc, out = cmd('extract', '%s::archive' % repo, 'does/not/match') + rc, out = cmd('--repo=%s::archive' % repo, 'extract', 'does/not/match') assert rc == EXIT_WARNING # pattern did not match - rc, out = cmd('create', '%s::archive' % repo, str(input)) + rc, out = cmd('--repo=%s::archive' % repo, 'create', str(input)) assert rc == EXIT_ERROR # duplicate archive name @@ -203,7 +203,7 @@ def test_disk_full(cmd): shutil.rmtree(input, ignore_errors=True) # keep some space and some inodes in reserve that we can free up later: make_files(reserve, 80, 100000, rnd=False) - rc, out = cmd('init', repo) + rc, out = cmd(f'--repo={repo}', 'init') if rc != EXIT_SUCCESS: print('init', rc, out) assert rc == EXIT_SUCCESS @@ -219,7 +219,7 @@ def test_disk_full(cmd): break raise try: - rc, out = cmd('create', '%s::test%03d' % (repo, i), input) + rc, out = cmd('--repo=%s::test%03d' % (repo, i), 'create', input) success = rc == EXIT_SUCCESS if not success: print('create', rc, out) @@ -231,10 +231,10 @@ def test_disk_full(cmd): # now some error happened, likely we are out of disk space. # free some space so we can expect borg to be able to work normally: shutil.rmtree(reserve, ignore_errors=True) - rc, out = cmd('list', repo) + rc, out = cmd(f'--repo={repo}', 'list') if rc != EXIT_SUCCESS: print('list', rc, out) - rc, out = cmd('check', '--repair', repo) + rc, out = cmd(f'--repo={repo}', 'check', '--repair') if rc != EXIT_SUCCESS: print('check', rc, out) assert rc == EXIT_SUCCESS @@ -299,7 +299,7 @@ class ArchiverTestCaseBase(BaseTestCase): return output def create_src_archive(self, name): - self.cmd('create', '--compression=lz4', self.repository_location + '::' + name, src_dir) + self.cmd(f'--repo={self.repository_location}::{name}', 'create', '--compression=lz4', src_dir) def open_archive(self, name): repository = Repository(self.repository_path, exclusive=True) @@ -391,16 +391,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_basic_functionality(self): have_root = self.create_test_files() # fork required to test show-rc output - output = self.cmd('init', '--encryption=repokey', '--show-version', '--show-rc', self.repository_location, fork=True) + output = self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--show-version', '--show-rc', fork=True) self.assert_in('borgbackup version', output) self.assert_in('terminating with success status, rc 0', output) - self.cmd('create', '--exclude-nodump', self.repository_location + '::test', 'input') - output = self.cmd('create', '--exclude-nodump', '--stats', self.repository_location + '::test.2', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-nodump', 'input') + output = self.cmd(f'--repo={self.repository_location}::test.2', 'create', '--exclude-nodump', '--stats', 'input') self.assert_in('Archive name: test.2', output) self.assert_in('This archive: ', output) with changedir('output'): - self.cmd('extract', self.repository_location + '::test') - list_output = self.cmd('list', '--short', self.repository_location) + self.cmd(f'--repo={self.repository_location}::test', 'extract') + list_output = self.cmd(f'--repo={self.repository_location}', 'list', '--short') self.assert_in('test', list_output) self.assert_in('test.2', list_output) expected = [ @@ -427,15 +427,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): # remove the file we did not backup, so input and output become equal expected.remove('input/flagfile') # this file is UF_NODUMP os.remove(os.path.join('input', 'flagfile')) - list_output = self.cmd('list', '--short', self.repository_location + '::test') + list_output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--short') for name in expected: self.assert_in(name, list_output) self.assert_dirs_equal('input', 'output/input') - info_output = self.cmd('info', self.repository_location + '::test') + info_output = self.cmd(f'--repo={self.repository_location}::test', 'info') item_count = 5 if has_lchflags else 6 # one file is UF_NODUMP self.assert_in('Number of files: %d' % item_count, info_output) shutil.rmtree(self.cache_path) - info_output2 = self.cmd('info', self.repository_location + '::test') + info_output2 = self.cmd(f'--repo={self.repository_location}::test', 'info') def filter(output): # filter for interesting "info" output, ignore cache rebuilding related stuff @@ -462,10 +462,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): hl_b = os.path.join(path_b, 'hardlink') self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) - self.cmd('init', '--encryption=none', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input', 'input') # give input twice! + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', 'input') # give input twice! # test if created archive has 'input' contents twice: - archive_list = self.cmd('list', '--json-lines', self.repository_location + '::test') + archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] # we have all fs items exactly once! assert sorted(paths) == ['input', 'input/a', 'input/a/hardlink', 'input/b', 'input/b/hardlink'] @@ -476,13 +476,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): repository_location = self.prefix + repository_path with pytest.raises(Repository.ParentPathDoesNotExist): # normal borg init does NOT create missing parent dirs - self.cmd('init', '--encryption=none', repository_location) + self.cmd(f'--repo={repository_location}', 'init', '--encryption=none') # but if told so, it does: - self.cmd('init', '--encryption=none', '--make-parent-dirs', repository_location) + self.cmd(f'--repo={repository_location}', 'init', '--encryption=none', '--make-parent-dirs') assert os.path.exists(parent_path) def test_unix_socket(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(os.path.join(self.input_path, 'unix-socket')) @@ -491,19 +491,19 @@ class ArchiverTestCase(ArchiverTestCaseBase): pytest.skip('unix sockets disabled or not supported') elif err.errno == errno.EACCES: pytest.skip('permission denied to create unix sockets') - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') sock.close() with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') assert not os.path.exists('input/unix-socket') @pytest.mark.skipif(not are_symlinks_supported(), reason='symlinks not supported') def test_symlink_extract(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') assert os.readlink('input/link1') == 'somewhere' @pytest.mark.skipif(not are_symlinks_supported() or not are_hardlinks_supported(), @@ -513,10 +513,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): with changedir('input'): os.symlink('target', 'symlink1') os.link('symlink1', 'symlink2', follow_symlinks=False) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - output = self.cmd('extract', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'extract') print(output) with changedir('input'): assert os.path.exists('target') @@ -547,10 +547,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): atime, mtime = 123456780, 234567890 have_noatime = has_noatime('input/file1') os.utime('input/file1', (atime, mtime)) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', '--atime', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--atime', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert sti.st_mtime_ns == sto.st_mtime_ns == mtime * 1e9 @@ -567,10 +567,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): birthtime, mtime, atime = 946598400, 946684800, 946771200 os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert int(sti.st_birthtime * 1e9) == int(sto.st_birthtime * 1e9) == birthtime * 1e9 @@ -583,10 +583,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): birthtime, mtime, atime = 946598400, 946684800, 946771200 os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', '--nobirthtime', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--nobirthtime', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert int(sti.st_birthtime * 1e9) == birthtime * 1e9 @@ -644,10 +644,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): if sparse_support: # we could create a sparse input file, so creating a backup of it and # extracting it again (as sparse) should also work: - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir(self.output_path): - self.cmd('extract', '--sparse', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--sparse') self.assert_dirs_equal('input', 'output/input') filename = os.path.join(self.output_path, 'input', 'sparse') with open(filename, 'rb') as fd: @@ -663,158 +663,158 @@ class ArchiverTestCase(ArchiverTestCaseBase): filename = os.path.join(self.input_path, filename) with open(filename, 'wb'): pass - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') for filename in filenames: with changedir('output'): - self.cmd('extract', self.repository_location + '::test', os.path.join('input', filename)) + self.cmd(f'--repo={self.repository_location}::test', 'extract', os.path.join('input', filename)) assert os.path.exists(os.path.join('output', 'input', filename)) def test_repository_swap_detection(self): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') shutil.rmtree(self.repository_path) - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) if self.FORK_DEFAULT: - self.cmd('create', self.repository_location + '::test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.EncryptionMethodMismatch): - self.cmd('create', self.repository_location + '::test.2', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') def test_repository_swap_detection2(self): self.create_test_files() - self.cmd('init', '--encryption=none', self.repository_location + '_unencrypted') + self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd('init', '--encryption=repokey', self.repository_location + '_encrypted') - self.cmd('create', self.repository_location + '_encrypted::test', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_encrypted::test', 'create', 'input') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: - self.cmd('create', self.repository_location + '_encrypted::test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.RepositoryAccessAborted): - self.cmd('create', self.repository_location + '_encrypted::test.2', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input') def test_repository_swap_detection_no_cache(self): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') shutil.rmtree(self.repository_path) - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) - self.cmd('delete', '--cache-only', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') if self.FORK_DEFAULT: - self.cmd('create', self.repository_location + '::test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.EncryptionMethodMismatch): - self.cmd('create', self.repository_location + '::test.2', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') def test_repository_swap_detection2_no_cache(self): self.create_test_files() - self.cmd('init', '--encryption=none', self.repository_location + '_unencrypted') + self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd('init', '--encryption=repokey', self.repository_location + '_encrypted') - self.cmd('create', self.repository_location + '_encrypted::test', 'input') - self.cmd('delete', '--cache-only', self.repository_location + '_unencrypted') - self.cmd('delete', '--cache-only', self.repository_location + '_encrypted') + self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_encrypted::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}_unencrypted', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}_encrypted', 'delete', '--cache-only') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: - self.cmd('create', self.repository_location + '_encrypted::test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.RepositoryAccessAborted): - self.cmd('create', self.repository_location + '_encrypted::test.2', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input') def test_repository_swap_detection_repokey_blank_passphrase(self): # Check that a repokey repo with a blank passphrase is considered like a plaintext repo. self.create_test_files() # User initializes her repository with her passphrase - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') # Attacker replaces it with her own repository, which is encrypted but has no passphrase set shutil.rmtree(self.repository_path) with environment_variable(BORG_PASSPHRASE=''): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Delete cache & security database, AKA switch to user perspective - self.cmd('delete', '--cache-only', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') shutil.rmtree(self.get_security_dir()) with environment_variable(BORG_PASSPHRASE=None): # This is the part were the user would be tricked, e.g. she assumes that BORG_PASSPHRASE # is set, while it isn't. Previously this raised no warning, # since the repository is, technically, encrypted. if self.FORK_DEFAULT: - self.cmd('create', self.repository_location + '::test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.CacheInitAbortedError): - self.cmd('create', self.repository_location + '::test.2', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') def test_repository_move(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') security_dir = self.get_security_dir() os.rename(self.repository_path, self.repository_path + '_new') with environment_variable(BORG_RELOCATED_REPO_ACCESS_IS_OK='yes'): - self.cmd('info', self.repository_location + '_new') + self.cmd(f'--repo={self.repository_location}_new', 'info') with open(os.path.join(security_dir, 'location')) as fd: location = fd.read() assert location == Location(self.repository_location + '_new').canonical_path() # Needs no confirmation anymore - self.cmd('info', self.repository_location + '_new') + self.cmd(f'--repo={self.repository_location}_new', 'info') shutil.rmtree(self.cache_path) - self.cmd('info', self.repository_location + '_new') + self.cmd(f'--repo={self.repository_location}_new', 'info') shutil.rmtree(security_dir) - self.cmd('info', self.repository_location + '_new') + self.cmd(f'--repo={self.repository_location}_new', 'info') for file in ('location', 'key-type', 'manifest-timestamp'): assert os.path.exists(os.path.join(security_dir, file)) def test_security_dir_compat(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') with open(os.path.join(self.get_security_dir(), 'location'), 'w') as fd: fd.write('something outdated') # This is fine, because the cache still has the correct information. security_dir and cache can disagree # if older versions are used to confirm a renamed repository. - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') def test_unknown_unencrypted(self): - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') # Ok: repository is known - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') # Ok: repository is still known (through security_dir) shutil.rmtree(self.cache_path) - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') # Needs confirmation: cache and security dir both gone (eg. another host or rm -rf ~) shutil.rmtree(self.cache_path) shutil.rmtree(self.get_security_dir()) if self.FORK_DEFAULT: - self.cmd('info', self.repository_location, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'info', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.CacheInitAbortedError): - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') with environment_variable(BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK='yes'): - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') def test_strip_components(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir/file') - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test', '--strip-components', '3') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '3') assert not os.path.exists('file') with self.assert_creates_file('file'): - self.cmd('extract', self.repository_location + '::test', '--strip-components', '2') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '2') with self.assert_creates_file('dir/file'): - self.cmd('extract', self.repository_location + '::test', '--strip-components', '1') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '1') with self.assert_creates_file('input/dir/file'): - self.cmd('extract', self.repository_location + '::test', '--strip-components', '0') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '0') def _extract_hardlinks_setup(self): os.mkdir(os.path.join(self.input_path, 'dir1')) @@ -832,8 +832,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.link(os.path.join(self.input_path, 'dir1/source2'), os.path.join(self.input_path, 'dir1/aaaa')) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') @requires_hardlinks @unittest.skipUnless(llfuse, 'llfuse not installed') @@ -873,7 +873,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_hardlinks1(self): self._extract_hardlinks_setup() with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') assert os.stat('input/source').st_nlink == 4 assert os.stat('input/abba').st_nlink == 4 assert os.stat('input/dir1/hardlink').st_nlink == 4 @@ -884,14 +884,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_hardlinks2(self): self._extract_hardlinks_setup() with changedir('output'): - self.cmd('extract', self.repository_location + '::test', '--strip-components', '2') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '2') assert os.stat('hardlink').st_nlink == 2 assert os.stat('subdir/hardlink').st_nlink == 2 assert open('subdir/hardlink', 'rb').read() == b'123456' assert os.stat('aaaa').st_nlink == 2 assert os.stat('source2').st_nlink == 2 with changedir('output'): - self.cmd('extract', self.repository_location + '::test', 'input/dir1') + self.cmd(f'--repo={self.repository_location}::test', 'extract', 'input/dir1') assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert open('input/dir1/subdir/hardlink', 'rb').read() == b'123456' @@ -909,11 +909,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): hl_b = os.path.join(path_b, 'hardlink') self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) - self.cmd('init', '--encryption=none', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input', 'input') # give input twice! + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', 'input') # give input twice! # now test extraction with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') # if issue #5603 happens, extraction gives rc == 1 (triggering AssertionError) and warnings like: # input/a/hardlink: link: [Errno 2] No such file or directory: 'input/a/hardlink' -> 'input/a/hardlink' # input/b/hardlink: link: [Errno 2] No such file or directory: 'input/a/hardlink' -> 'input/b/hardlink' @@ -922,24 +922,24 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert os.stat('input/b/hardlink').st_nlink == 2 def test_extract_include_exclude(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) self.create_regular_file('file4', size=1024 * 80) - self.cmd('create', '--exclude=input/file4', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude=input/file4', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test', 'input/file1', ) + self.cmd(f'--repo={self.repository_location}::test', 'extract', 'input/file1', ) self.assert_equal(sorted(os.listdir('output/input')), ['file1']) with changedir('output'): - self.cmd('extract', '--exclude=input/file2', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude=input/file2') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) with changedir('output'): - self.cmd('extract', '--exclude-from=' + self.exclude_file_path, self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) def test_extract_include_exclude_regex(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) @@ -947,32 +947,32 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file333', size=1024 * 80) # Create with regular expression exclusion for file4 - self.cmd('create', '--exclude=re:input/file4$', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude=re:input/file4$', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) shutil.rmtree('output/input') # Extract with regular expression exclusion with changedir('output'): - self.cmd('extract', '--exclude=re:file3+', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude=re:file3+') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2']) shutil.rmtree('output/input') # Combine --exclude with fnmatch and regular expression with changedir('output'): - self.cmd('extract', '--exclude=input/file2', '--exclude=re:file[01]', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude=input/file2', '--exclude=re:file[01]') self.assert_equal(sorted(os.listdir('output/input')), ['file3', 'file333']) shutil.rmtree('output/input') # Combine --exclude-from and regular expression exclusion with changedir('output'): - self.cmd('extract', '--exclude-from=' + self.exclude_file_path, '--exclude=re:file1', - '--exclude=re:file(\\d)\\1\\1$', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path, + '--exclude=re:file1', '--exclude=re:file(\\d)\\1\\1$') self.assert_equal(sorted(os.listdir('output/input')), ['file3']) def test_extract_include_exclude_regex_from_file(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) @@ -985,9 +985,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:input/file4$\n') fd.write(b'fm:*aa:*thing\n') - self.cmd('create', '--exclude-from=' + self.exclude_file_path, self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-from=' + self.exclude_file_path, 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) shutil.rmtree('output/input') @@ -996,7 +996,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:file3+\n') with changedir('output'): - self.cmd('extract', '--exclude-from=' + self.exclude_file_path, self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2']) shutil.rmtree('output/input') @@ -1008,78 +1008,78 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:file2$\n') with changedir('output'): - self.cmd('extract', '--exclude-from=' + self.exclude_file_path, self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file3']) def test_extract_with_pattern(self): - self.cmd("init", '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', "init", '--encryption=repokey') self.create_regular_file("file1", size=1024 * 80) self.create_regular_file("file2", size=1024 * 80) self.create_regular_file("file3", size=1024 * 80) self.create_regular_file("file4", size=1024 * 80) self.create_regular_file("file333", size=1024 * 80) - self.cmd("create", self.repository_location + "::test", "input") + self.cmd(f'--repo={self.repository_location}::test', "create", "input") # Extract everything with regular expression with changedir("output"): - self.cmd("extract", self.repository_location + "::test", "re:.*") + self.cmd(f'--repo={self.repository_location}::test', "extract", "re:.*") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file3", "file333", "file4"]) shutil.rmtree("output/input") # Extract with pattern while also excluding files with changedir("output"): - self.cmd("extract", "--exclude=re:file[34]$", self.repository_location + "::test", r"re:file\d$") + self.cmd(f'--repo={self.repository_location}::test', "extract", "--exclude=re:file[34]$", r"re:file\d$") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2"]) shutil.rmtree("output/input") # Combine --exclude with pattern for extraction with changedir("output"): - self.cmd("extract", "--exclude=input/file1", self.repository_location + "::test", "re:file[12]$") + self.cmd(f'--repo={self.repository_location}::test', "extract", "--exclude=input/file1", "re:file[12]$") self.assert_equal(sorted(os.listdir("output/input")), ["file2"]) shutil.rmtree("output/input") # Multiple pattern with changedir("output"): - self.cmd("extract", self.repository_location + "::test", "fm:input/file1", "fm:*file33*", "input/file2") + self.cmd(f'--repo={self.repository_location}::test', "extract", "fm:input/file1", "fm:*file33*", "input/file2") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file333"]) def test_extract_list_output(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - output = self.cmd('extract', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_not_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd('extract', '--info', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--info') self.assert_not_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd('extract', '--list', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--list') self.assert_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd('extract', '--list', '--info', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--list', '--info') self.assert_in("input/file", output) def test_extract_progress(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - output = self.cmd('extract', self.repository_location + '::test', '--progress') + output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--progress') assert 'Extracting:' in output def _create_test_caches(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('cache1/%s' % CACHE_TAG_NAME, contents=CACHE_TAG_CONTENTS + b' extra stuff') @@ -1093,122 +1093,122 @@ class ArchiverTestCase(ArchiverTestCaseBase): contents=CACHE_TAG_CONTENTS + b' extra stuff') def test_create_stdin(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = b'\x00foo\n\nbar\n \n' - self.cmd('create', self.repository_location + '::test', '-', input=input_data) - item = json.loads(self.cmd('list', '--json-lines', self.repository_location + '::test')) + self.cmd(f'--repo={self.repository_location}::test', 'create', '-', input=input_data) + item = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 assert item['size'] == len(input_data) assert item['path'] == 'stdin' - extracted_data = self.cmd('extract', '--stdout', self.repository_location + '::test', binary_output=True) + extracted_data = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--stdout', binary_output=True) assert extracted_data == input_data def test_create_content_from_command(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = 'some test content' name = 'a/b/c' - self.cmd('create', '--stdin-name', name, '--content-from-command', - self.repository_location + '::test', '--', 'echo', input_data) - item = json.loads(self.cmd('list', '--json-lines', self.repository_location + '::test')) + self.cmd(f'--repo={self.repository_location}::test', 'create', '--stdin-name', name, '--content-from-command', + '--', 'echo', input_data) + item = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 assert item['size'] == len(input_data) + 1 # `echo` adds newline assert item['path'] == name - extracted_data = self.cmd('extract', '--stdout', self.repository_location + '::test') + extracted_data = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--stdout') assert extracted_data == input_data + '\n' def test_create_content_from_command_with_failed_command(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--content-from-command', self.repository_location + '::test', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--content-from-command', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") - archive_list = json.loads(self.cmd('list', '--json', self.repository_location)) + archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) assert archive_list['archives'] == [] def test_create_content_from_command_missing_command(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--content-from-command', self.repository_location + '::test', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--content-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_paths_from_stdin(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file("file1", size=1024 * 80) self.create_regular_file("dir1/file2", size=1024 * 80) self.create_regular_file("dir1/file3", size=1024 * 80) self.create_regular_file("file4", size=1024 * 80) input_data = b'input/file1\0input/dir1\0input/file4' - self.cmd('create', '--paths-from-stdin', '--paths-delimiter', '\\0', - self.repository_location + '::test', input=input_data) - archive_list = self.cmd('list', '--json-lines', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'create', + '--paths-from-stdin', '--paths-delimiter', '\\0', input=input_data) + archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] assert paths == ['input/file1', 'input/dir1', 'input/file4'] def test_create_paths_from_command(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file("file1", size=1024 * 80) self.create_regular_file("file2", size=1024 * 80) self.create_regular_file("file3", size=1024 * 80) self.create_regular_file("file4", size=1024 * 80) input_data = 'input/file1\ninput/file2\ninput/file3' - self.cmd('create', '--paths-from-command', - self.repository_location + '::test', '--', 'echo', input_data) - archive_list = self.cmd('list', '--json-lines', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--paths-from-command', + '--', 'echo', input_data) + archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] assert paths == ['input/file1', 'input/file2', 'input/file3'] def test_create_paths_from_command_with_failed_command(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--paths-from-command', self.repository_location + '::test', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--paths-from-command', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") - archive_list = json.loads(self.cmd('list', '--json', self.repository_location)) + archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) assert archive_list['archives'] == [] def test_create_paths_from_command_missing_command(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--paths-from-command', self.repository_location + '::test', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--paths-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_without_root(self): """test create without a root""" - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', exit_code=2) def test_create_pattern_root(self): """test create with only a root pattern""" - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) - output = self.cmd('create', '-v', '--list', '--pattern=R input', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', '--pattern=R input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) def test_create_pattern(self): """test file patterns during create""" - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - output = self.cmd('create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', '--pattern=+input/file_important', '--pattern=-input/file*', - self.repository_location + '::test', 'input') + 'input') self.assert_in("A input/file_important", output) self.assert_in('x input/file1', output) self.assert_in('x input/file2', output) def test_create_pattern_file(self): """test file patterns during create""" - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('otherfile', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - output = self.cmd('create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', '--pattern=-input/otherfile', '--patterns-from=' + self.patterns_file_path, - self.repository_location + '::test', 'input') + 'input') self.assert_in("A input/file_important", output) self.assert_in('x input/file1', output) self.assert_in('x input/file2', output) @@ -1220,13 +1220,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(self.patterns_file_path2, 'wb') as fd: fd.write(b'+ input/x/b\n- input/x*\n') - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) - output = self.cmd('create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', '--patterns-from=' + self.patterns_file_path2, - self.repository_location + '::test', 'input') + 'input') self.assert_in('x input/x/a/foo_a', output) self.assert_in("A input/x/b/foo_b", output) self.assert_in('A input/y/foo_y', output) @@ -1237,13 +1237,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(self.patterns_file_path2, 'wb') as fd: fd.write(b'+ input/x/b\n! input/x*\n') - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) - output = self.cmd('create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', '--patterns-from=' + self.patterns_file_path2, - self.repository_location + '::test', 'input') + 'input') self.assert_not_in('input/x/a/foo_a', output) self.assert_not_in('input/x/a', output) self.assert_in('A input/y/foo_y', output) @@ -1254,17 +1254,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(self.patterns_file_path2, 'wb') as fd: fd.write(b'+ input/x/a\n+ input/x/b\n- input/x*\n') - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) with changedir('input'): - self.cmd('create', '--patterns-from=' + self.patterns_file_path2, - self.repository_location + '::test', '.') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--patterns-from=' + self.patterns_file_path2, + '.') # list the archive and verify that the "intermediate" folders appear before # their contents - out = self.cmd('list', '--format', '{type} {path}{NL}', self.repository_location + '::test') + out = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{type} {path}{NL}') out_list = out.splitlines() self.assert_in('d x/a', out_list) @@ -1275,50 +1275,49 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_no_cache_sync(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('delete', '--cache-only', self.repository_location) - create_json = json.loads(self.cmd('create', '--no-cache-sync', self.repository_location + '::test', 'input', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + create_json = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'create', '--no-cache-sync', 'input', '--json', '--error')) # ignore experimental warning - info_json = json.loads(self.cmd('info', self.repository_location + '::test', '--json')) + info_json = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'info', '--json')) create_stats = create_json['cache']['stats'] info_stats = info_json['cache']['stats'] assert create_stats == info_stats - self.cmd('delete', '--cache-only', self.repository_location) - self.cmd('create', '--no-cache-sync', self.repository_location + '::test2', 'input') - self.cmd('info', self.repository_location) - self.cmd('check', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}::test2', 'create', '--no-cache-sync', 'input') + self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'check') def test_extract_pattern_opt(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - self.cmd('extract', - '--pattern=+input/file_important', '--pattern=-input/file*', - self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract', + '--pattern=+input/file_important', '--pattern=-input/file*') self.assert_equal(sorted(os.listdir('output/input')), ['file_important']) def _assert_test_caches(self): with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_equal(sorted(os.listdir('output/input')), ['cache2', 'file1']) self.assert_equal(sorted(os.listdir('output/input/cache2')), [CACHE_TAG_NAME]) def test_exclude_caches(self): self._create_test_caches() - self.cmd('create', '--exclude-caches', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-caches', 'input') self._assert_test_caches() def test_recreate_exclude_caches(self): self._create_test_caches() - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('recreate', '--exclude-caches', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-caches') self._assert_test_caches() def _create_test_tagged(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('tagged1/.NOBACKUP') self.create_regular_file('tagged2/00-NOBACKUP') @@ -1326,23 +1325,24 @@ class ArchiverTestCase(ArchiverTestCaseBase): def _assert_test_tagged(self): with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_equal(sorted(os.listdir('output/input')), ['file1']) def test_exclude_tagged(self): self._create_test_tagged() - self.cmd('create', '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-if-present', '.NOBACKUP', + '--exclude-if-present', '00-NOBACKUP', 'input') self._assert_test_tagged() def test_recreate_exclude_tagged(self): self._create_test_tagged() - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('recreate', '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP', - self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-if-present', '.NOBACKUP', + '--exclude-if-present', '00-NOBACKUP') self._assert_test_tagged() def _create_test_keep_tagged(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file0', size=1024) self.create_regular_file('tagged1/.NOBACKUP1') self.create_regular_file('tagged1/file1', size=1024) @@ -1359,7 +1359,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def _assert_test_keep_tagged(self): with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_equal(sorted(os.listdir('output/input')), ['file0', 'tagged1', 'tagged2', 'tagged3', 'taggedall']) self.assert_equal(os.listdir('output/input/tagged1'), ['.NOBACKUP1']) self.assert_equal(os.listdir('output/input/tagged2'), ['.NOBACKUP2']) @@ -1369,29 +1369,29 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_exclude_keep_tagged(self): self._create_test_keep_tagged() - self.cmd('create', '--exclude-if-present', '.NOBACKUP1', '--exclude-if-present', '.NOBACKUP2', - '--exclude-caches', '--keep-exclude-tags', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-if-present', '.NOBACKUP1', + '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags', 'input') self._assert_test_keep_tagged() def test_recreate_exclude_keep_tagged(self): self._create_test_keep_tagged() - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('recreate', '--exclude-if-present', '.NOBACKUP1', '--exclude-if-present', '.NOBACKUP2', - '--exclude-caches', '--keep-exclude-tags', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-if-present', '.NOBACKUP1', + '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags') self._assert_test_keep_tagged() @pytest.mark.skipif(not are_hardlinks_supported(), reason='hardlinks not supported') def test_recreate_hardlinked_tags(self): # test for issue #4911 - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.create_regular_file('file1', contents=CACHE_TAG_CONTENTS) # "wrong" filename, but correct tag contents os.mkdir(os.path.join(self.input_path, 'subdir')) # to make sure the tag is encountered *after* file1 os.link(os.path.join(self.input_path, 'file1'), os.path.join(self.input_path, 'subdir', CACHE_TAG_NAME)) # correct tag name, hardlink to file1 - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') # in the "test" archive, we now have, in this order: # - a regular file item for "file1" # - a hardlink item for "CACHEDIR.TAG" referring back to file1 for its contents - self.cmd('recreate', '--exclude-caches', '--keep-exclude-tags', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-caches', '--keep-exclude-tags') # if issue #4911 is present, the recreate will crash with a KeyError for "input/file1" @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='Linux capabilities test, requires fakeroot >= 1.20.2') @@ -1408,11 +1408,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): capabilities = b'\x01\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' self.create_regular_file('file') xattr.setxattr(b'input/file', b'security.capability', capabilities) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): with patch.object(os, 'fchown', patched_fchown): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') assert xattr.getxattr(b'input/file', b'security.capability') == capabilities @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='xattr not supported on this system or on this version of' @@ -1429,88 +1429,88 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute', b'value') - self.cmd('init', self.repository_location, '-e' 'none') - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): input_abspath = os.path.abspath('input/file') with patch.object(xattr, 'setxattr', patched_setxattr_E2BIG): - out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: too big for this filesystem\n' in out os.remove(input_abspath) with patch.object(xattr, 'setxattr', patched_setxattr_ENOTSUP): - out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: xattrs not supported on this filesystem\n' in out os.remove(input_abspath) with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - out = self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: Permission denied\n' in out assert os.path.isfile(input_abspath) def test_path_normalization(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir1/dir2/file', size=1024 * 80) with changedir('input/dir1/dir2'): - self.cmd('create', self.repository_location + '::test', '../../../input/dir1/../dir1/dir2/..') - output = self.cmd('list', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'create', '../../../input/dir1/../dir1/dir2/..') + output = self.cmd(f'--repo={self.repository_location}::test', 'list') self.assert_not_in('..', output) self.assert_in(' input/dir1/dir2/file', output) def test_exclude_normalization(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) with changedir('input'): - self.cmd('create', '--exclude=file1', self.repository_location + '::test1', '.') + self.cmd(f'--repo={self.repository_location}::test1', 'create', '--exclude=file1', '.') with changedir('output'): - self.cmd('extract', self.repository_location + '::test1') + self.cmd(f'--repo={self.repository_location}::test1', 'extract') self.assert_equal(sorted(os.listdir('output')), ['file2']) with changedir('input'): - self.cmd('create', '--exclude=./file1', self.repository_location + '::test2', '.') + self.cmd(f'--repo={self.repository_location}::test2', 'create', '--exclude=./file1', '.') with changedir('output'): - self.cmd('extract', self.repository_location + '::test2') + self.cmd(f'--repo={self.repository_location}::test2', 'extract') self.assert_equal(sorted(os.listdir('output')), ['file2']) - self.cmd('create', '--exclude=input/./file1', self.repository_location + '::test3', 'input') + self.cmd(f'--repo={self.repository_location}::test3', 'create', '--exclude=input/./file1', 'input') with changedir('output'): - self.cmd('extract', self.repository_location + '::test3') + self.cmd(f'--repo={self.repository_location}::test3', 'extract') self.assert_equal(sorted(os.listdir('output/input')), ['file2']) def test_repeated_files(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', 'input') def test_overwrite(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') # Overwriting regular files and directories should be supported os.mkdir('output/input') os.mkdir('output/input/file1') os.mkdir('output/input/dir2') with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_dirs_equal('input', 'output/input') # But non-empty dirs should fail os.unlink('output/input/file1') os.mkdir('output/input/file1') os.mkdir('output/input/file1/dir') with changedir('output'): - self.cmd('extract', self.repository_location + '::test', exit_code=1) + self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=1) def test_rename(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('create', self.repository_location + '::test.2', 'input') - self.cmd('extract', '--dry-run', self.repository_location + '::test') - self.cmd('extract', '--dry-run', self.repository_location + '::test.2') - self.cmd('rename', self.repository_location + '::test', 'test.3') - self.cmd('extract', '--dry-run', self.repository_location + '::test.2') - self.cmd('rename', self.repository_location + '::test.2', 'test.4') - self.cmd('extract', '--dry-run', self.repository_location + '::test.3') - self.cmd('extract', '--dry-run', self.repository_location + '::test.4') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}::test', 'rename', 'TODO_test', 'test.3') + self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}::test.2', 'rename', 'TODO_test.2', 'test.4') + self.cmd(f'--repo={self.repository_location}::test.3', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}::test.4', 'extract', '--dry-run') # Make sure both archives have been renamed with Repository(self.repository_path) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1520,20 +1520,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - info_repo = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + info_repo = self.cmd(f'--repo={self.repository_location}', 'info') assert 'All archives:' in info_repo - info_archive = self.cmd('info', self.repository_location + '::test') + info_archive = self.cmd(f'--repo={self.repository_location}::test', 'info') assert 'Archive name: test\n' in info_archive - info_archive = self.cmd('info', '--first', '1', self.repository_location) + info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '--first', '1') assert 'Archive name: test\n' in info_archive def test_info_json(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - info_repo = json.loads(self.cmd('info', '--json', self.repository_location)) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json')) repository = info_repo['repository'] assert len(repository['id']) == 64 assert 'last_modified' in repository @@ -1545,7 +1545,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert all(isinstance(o, int) for o in stats.values()) assert all(key in stats for key in ('total_chunks', 'total_size', 'total_unique_chunks', 'unique_size')) - info_archive = json.loads(self.cmd('info', '--json', self.repository_location + '::test')) + info_archive = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'info', '--json')) assert info_repo['repository'] == info_archive['repository'] assert info_repo['cache'] == info_archive['cache'] archives = info_archive['archives'] @@ -1561,47 +1561,47 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info_json_of_empty_archive(self): """See https://github.com/borgbackup/borg/issues/6120""" - self.cmd('init', '--encryption=repokey', self.repository_location) - info_repo = json.loads(self.cmd('info', '--json', '--first=1', self.repository_location)) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json', '--first=1')) assert info_repo["archives"] == [] - info_repo = json.loads(self.cmd('info', '--json', '--last=1', self.repository_location)) + info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json', '--last=1')) assert info_repo["archives"] == [] def test_comment(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test1', 'input') - self.cmd('create', '--comment', 'this is the comment', self.repository_location + '::test2', 'input') - self.cmd('create', '--comment', '"deleted" comment', self.repository_location + '::test3', 'input') - self.cmd('create', '--comment', 'preserved comment', self.repository_location + '::test4', 'input') - assert 'Comment: \n' in self.cmd('info', self.repository_location + '::test1') - assert 'Comment: this is the comment' in self.cmd('info', self.repository_location + '::test2') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test2', 'create', '--comment', 'this is the comment', 'input') + self.cmd(f'--repo={self.repository_location}::test3', 'create', '--comment', '"deleted" comment', 'input') + self.cmd(f'--repo={self.repository_location}::test4', 'create', '--comment', 'preserved comment', 'input') + assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}::test1', 'info') + assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}::test2', 'info') - self.cmd('recreate', self.repository_location + '::test1', '--comment', 'added comment') - self.cmd('recreate', self.repository_location + '::test2', '--comment', 'modified comment') - self.cmd('recreate', self.repository_location + '::test3', '--comment', '') - self.cmd('recreate', self.repository_location + '::test4', '12345') - assert 'Comment: added comment' in self.cmd('info', self.repository_location + '::test1') - assert 'Comment: modified comment' in self.cmd('info', self.repository_location + '::test2') - assert 'Comment: \n' in self.cmd('info', self.repository_location + '::test3') - assert 'Comment: preserved comment' in self.cmd('info', self.repository_location + '::test4') + self.cmd(f'--repo={self.repository_location}::test1', 'recreate', '--comment', 'added comment') + self.cmd(f'--repo={self.repository_location}::test2', 'recreate', '--comment', 'modified comment') + self.cmd(f'--repo={self.repository_location}::test3', 'recreate', '--comment', '') + self.cmd(f'--repo={self.repository_location}::test4', 'recreate', '12345') + assert 'Comment: added comment' in self.cmd(f'--repo={self.repository_location}::test1', 'info') + assert 'Comment: modified comment' in self.cmd(f'--repo={self.repository_location}::test2', 'info') + assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}::test3', 'info') + assert 'Comment: preserved comment' in self.cmd(f'--repo={self.repository_location}::test4', 'info') def test_delete(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('create', self.repository_location + '::test.2', 'input') - self.cmd('create', self.repository_location + '::test.3', 'input') - self.cmd('create', self.repository_location + '::another_test.1', 'input') - self.cmd('create', self.repository_location + '::another_test.2', 'input') - self.cmd('extract', '--dry-run', self.repository_location + '::test') - self.cmd('extract', '--dry-run', self.repository_location + '::test.2') - self.cmd('delete', '--prefix', 'another_', self.repository_location) - self.cmd('delete', '--last', '1', self.repository_location) - self.cmd('delete', self.repository_location + '::test') - self.cmd('extract', '--dry-run', self.repository_location + '::test.2') - output = self.cmd('delete', '--stats', self.repository_location + '::test.2') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test.3', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::another_test.1', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::another_test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'delete', '--prefix', 'another_') + self.cmd(f'--repo={self.repository_location}', 'delete', '--last', '1') + self.cmd(f'--repo={self.repository_location}::test', 'delete') + self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') + output = self.cmd(f'--repo={self.repository_location}::test.2', 'delete', '--stats') self.assert_in('Deleted data:', output) # Make sure all data except the manifest has been deleted with Repository(self.repository_path) as repository: @@ -1609,31 +1609,31 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_delete_multiple(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test1', 'input') - self.cmd('create', self.repository_location + '::test2', 'input') - self.cmd('create', self.repository_location + '::test3', 'input') - self.cmd('delete', self.repository_location + '::test1', 'test2') - self.cmd('extract', '--dry-run', self.repository_location + '::test3') - self.cmd('delete', self.repository_location, 'test3') - assert not self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test3', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test1', 'delete', 'test2') + self.cmd(f'--repo={self.repository_location}::test3', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}::test3', 'delete') + assert not self.cmd(f'--repo={self.repository_location}', 'list') def test_delete_repo(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('create', self.repository_location + '::test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'no' - self.cmd('delete', self.repository_location, exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'delete', exit_code=2) assert os.path.exists(self.repository_path) os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'YES' - self.cmd('delete', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'delete') # Make sure the repo is gone self.assertFalse(os.path.exists(self.repository_path)) def test_delete_force(self): - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.create_src_archive('test') with Repository(self.repository_path, exclusive=True) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1645,14 +1645,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): else: assert False # missed the file repository.commit(compact=False) - output = self.cmd('delete', '--force', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'delete', '--force') self.assert_in('deleted archive was corrupted', output) - self.cmd('check', '--repair', self.repository_location) - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'check', '--repair') + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_not_in('test', output) def test_delete_double_force(self): - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.create_src_archive('test') with Repository(self.repository_path, exclusive=True) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1660,16 +1660,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): id = archive.metadata.items[0] repository.put(id, b'corrupted items metadata stream chunk') repository.commit(compact=False) - self.cmd('delete', '--force', '--force', self.repository_location + '::test') - self.cmd('check', '--repair', self.repository_location) - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}::test', 'delete', '--force', '--force') + self.cmd(f'--repo={self.repository_location}', 'check', '--repair') + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_not_in('test', output) def test_corrupted_repository(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') - self.cmd('extract', '--dry-run', self.repository_location + '::test') - output = self.cmd('check', '--show-version', self.repository_location) + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--dry-run') + output = self.cmd(f'--repo={self.repository_location}', 'check', '--show-version') self.assert_in('borgbackup version', output) # implied output even without --info given self.assert_not_in('Starting repository check', output) # --info not given for root logger @@ -1677,103 +1677,103 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(os.path.join(self.tmpdir, 'repository', 'data', '0', name), 'r+b') as fd: fd.seek(100) fd.write(b'XXXX') - output = self.cmd('check', '--info', self.repository_location, exit_code=1) + output = self.cmd(f'--repo={self.repository_location}', 'check', '--info', exit_code=1) self.assert_in('Starting repository check', output) # --info given for root logger def test_readonly_check(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd('check', '--verify-data', self.repository_location, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'check', '--verify-data', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd('check', '--verify-data', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'check', '--verify-data') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd('check', '--verify-data', self.repository_location, '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'check', '--verify-data', '--bypass-lock') def test_readonly_diff(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('a') self.create_src_archive('b') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd('diff', '%s::a' % self.repository_location, 'b', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}::a', 'diff', 'TODO_a', 'b', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd('diff', '%s::a' % self.repository_location, 'b') + self.cmd(f'--repo={self.repository_location}::a', 'diff', 'TODO_a', 'b') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd('diff', '%s::a' % self.repository_location, 'b', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}::a', 'diff', 'TODO_a', 'b', '--bypass-lock') def test_readonly_export_tar(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd('export-tar', '%s::test' % self.repository_location, 'test.tar', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'test.tar', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd('export-tar', '%s::test' % self.repository_location, 'test.tar') + self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'test.tar') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd('export-tar', '%s::test' % self.repository_location, 'test.tar', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'test.tar', '--bypass-lock') def test_readonly_extract(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd('extract', '%s::test' % self.repository_location, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd('extract', '%s::test' % self.repository_location) + self.cmd(f'--repo={self.repository_location}::test', 'extract') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd('extract', '%s::test' % self.repository_location, '--bypass-lock') + self.cmd(f'--repo={self.repository_location}::test', 'extract', '--bypass-lock') def test_readonly_info(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd('info', self.repository_location, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'info', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd('info', self.repository_location, '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'info', '--bypass-lock') def test_readonly_list(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd('list', self.repository_location, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'list', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'list') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd('list', self.repository_location, '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'list', '--bypass-lock') @unittest.skipUnless(llfuse, 'llfuse not installed') def test_readonly_mount(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1794,14 +1794,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): @pytest.mark.skipif('BORG_TESTS_IGNORE_MODES' in os.environ, reason='modes unreliable') def test_umask(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') mode = os.stat(self.repository_path).st_mode self.assertEqual(stat.S_IMODE(mode), 0o700) def test_create_dry_run(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', '--dry-run', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--dry-run', 'input') # Make sure no archive has been created with Repository(self.repository_path) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1823,56 +1823,56 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert excinfo.value.args == (['unknown-feature'],) def test_unknown_feature_on_create(self): - print(self.cmd('init', '--encryption=repokey', self.repository_location)) + print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) self.add_unknown_feature(Manifest.Operation.WRITE) - self.cmd_raises_unknown_feature(['create', self.repository_location + '::test', 'input']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'create', 'input']) def test_unknown_feature_on_cache_sync(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('delete', '--cache-only', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') self.add_unknown_feature(Manifest.Operation.READ) - self.cmd_raises_unknown_feature(['create', self.repository_location + '::test', 'input']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'create', 'input']) def test_unknown_feature_on_change_passphrase(self): - print(self.cmd('init', '--encryption=repokey', self.repository_location)) + print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) self.add_unknown_feature(Manifest.Operation.CHECK) - self.cmd_raises_unknown_feature(['key', 'change-passphrase', self.repository_location]) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'key', 'change-passphrase']) def test_unknown_feature_on_read(self): - print(self.cmd('init', '--encryption=repokey', self.repository_location)) - self.cmd('create', self.repository_location + '::test', 'input') + print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') self.add_unknown_feature(Manifest.Operation.READ) with changedir('output'): - self.cmd_raises_unknown_feature(['extract', self.repository_location + '::test']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'extract']) - self.cmd_raises_unknown_feature(['list', self.repository_location]) - self.cmd_raises_unknown_feature(['info', self.repository_location + '::test']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'list']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'info']) def test_unknown_feature_on_rename(self): - print(self.cmd('init', '--encryption=repokey', self.repository_location)) - self.cmd('create', self.repository_location + '::test', 'input') + print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') self.add_unknown_feature(Manifest.Operation.CHECK) - self.cmd_raises_unknown_feature(['rename', self.repository_location + '::test', 'other']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'rename', 'TODO_test', 'other']) def test_unknown_feature_on_delete(self): - print(self.cmd('init', '--encryption=repokey', self.repository_location)) - self.cmd('create', self.repository_location + '::test', 'input') + print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') self.add_unknown_feature(Manifest.Operation.DELETE) # delete of an archive raises - self.cmd_raises_unknown_feature(['delete', self.repository_location + '::test']) - self.cmd_raises_unknown_feature(['prune', '--keep-daily=3', self.repository_location]) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'delete']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'prune', '--keep-daily=3']) # delete of the whole repository ignores features - self.cmd('delete', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'delete') @unittest.skipUnless(llfuse, 'llfuse not installed') def test_unknown_feature_on_mount(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') self.add_unknown_feature(Manifest.Operation.READ) mountpoint = os.path.join(self.tmpdir, 'mountpoint') os.mkdir(mountpoint) # XXX this might hang if it doesn't raise an error - self.cmd_raises_unknown_feature(['mount', self.repository_location + '::test', mountpoint]) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'mount', mountpoint]) @pytest.mark.allow_cache_wipe def test_unknown_mandatory_feature_in_cache(self): @@ -1881,7 +1881,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): else: path_prefix = '' - print(self.cmd('init', '--encryption=repokey', self.repository_location)) + print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) with Repository(self.repository_path, exclusive=True) as repository: if path_prefix: @@ -1893,7 +1893,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): cache.commit() if self.FORK_DEFAULT: - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') else: called = False wipe_cache_safe = LocalCache.wipe_cache @@ -1904,7 +1904,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): wipe_cache_safe(*args) with patch.object(LocalCache, 'wipe_cache', wipe_wrapper): - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') assert called @@ -1917,14 +1917,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_progress_on(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--progress', self.repository_location + '::test4', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test4', 'create', '--progress', 'input') self.assert_in("\r", output) def test_progress_off(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', self.repository_location + '::test5', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test5', 'create', 'input') self.assert_not_in("\r", output) def test_file_status(self): @@ -1934,12 +1934,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--list', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--list', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) # should find first file as unmodified - output = self.cmd('create', '--list', self.repository_location + '::test1', 'input') + output = self.cmd(f'--repo={self.repository_location}::test1', 'create', '--list', 'input') self.assert_in("U input/file1", output) # this is expected, although surprising, for why, see: # https://borgbackup.readthedocs.org/en/latest/faq.html#i-am-seeing-a-added-status-for-a-unchanged-file @@ -1950,14 +1950,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', contents=b'123') time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--list', '--files-cache=ctime,size', self.repository_location + '::test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + '--list', '--files-cache=ctime,size', 'input') # modify file1, but cheat with the mtime (and atime) and also keep same size: st = os.stat('input/file1') self.create_regular_file('file1', contents=b'321') os.utime('input/file1', ns=(st.st_atime_ns, st.st_mtime_ns)) # this mode uses ctime for change detection, so it should find file1 as modified - output = self.cmd('create', '--list', '--files-cache=ctime,size', self.repository_location + '::test2', 'input') + output = self.cmd(f'--repo={self.repository_location}::test2', 'create', + '--list', '--files-cache=ctime,size', 'input') self.assert_in("M input/file1", output) def test_file_status_ms_cache_mode(self): @@ -1965,13 +1967,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=10) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--list', '--files-cache=mtime,size', self.repository_location + '::test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + '--list', '--files-cache=mtime,size', 'input') # change mode of file1, no content change: st = os.stat('input/file1') os.chmod('input/file1', st.st_mode ^ stat.S_IRWXO) # this triggers a ctime change, but mtime is unchanged # this mode uses mtime for change detection, so it should find file1 as unmodified - output = self.cmd('create', '--list', '--files-cache=mtime,size', self.repository_location + '::test2', 'input') + output = self.cmd(f'--repo={self.repository_location}::test2', 'create', + '--list', '--files-cache=mtime,size', 'input') self.assert_in("U input/file1", output) def test_file_status_rc_cache_mode(self): @@ -1979,10 +1983,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=10) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--list', '--files-cache=rechunk,ctime', self.repository_location + '::test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + '--list', '--files-cache=rechunk,ctime', 'input') # no changes here, but this mode rechunks unconditionally - output = self.cmd('create', '--list', '--files-cache=rechunk,ctime', self.repository_location + '::test2', 'input') + output = self.cmd(f'--repo={self.repository_location}::test2', 'create', + '--list', '--files-cache=rechunk,ctime', 'input') self.assert_in("A input/file1", output) def test_file_status_excluded(self): @@ -1994,14 +2000,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): if has_lchflags: self.create_regular_file('file3', size=1024 * 80) platform.set_flags(os.path.join(self.input_path, 'file3'), stat.UF_NODUMP) - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('create', '--list', '--exclude-nodump', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--list', '--exclude-nodump', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) if has_lchflags: self.assert_in("x input/file3", output) # should find second file as excluded - output = self.cmd('create', '--list', '--exclude-nodump', self.repository_location + '::test1', 'input', '--exclude', '*/file2') + output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + '--list', '--exclude-nodump', 'input', '--exclude', '*/file2') self.assert_in("U input/file1", output) self.assert_in("x input/file2", output) if has_lchflags: @@ -2009,8 +2016,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_json(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - create_info = json.loads(self.cmd('create', '--json', self.repository_location + '::test', 'input')) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + create_info = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'create', + '--json', 'input')) # The usual keys assert 'encryption' in create_info assert 'repository' in create_info @@ -2028,23 +2036,23 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # no listing by default - output = self.cmd('create', self.repository_location + '::test', 'input') + output = self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') self.assert_not_in('file1', output) # shouldn't be listed even if unchanged - output = self.cmd('create', self.repository_location + '::test0', 'input') + output = self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') self.assert_not_in('file1', output) # should list the file as unchanged - output = self.cmd('create', '--list', '--filter=U', self.repository_location + '::test1', 'input') + output = self.cmd(f'--repo={self.repository_location}::test1', 'create', '--list', '--filter=U', 'input') self.assert_in('file1', output) # should *not* list the file as changed - output = self.cmd('create', '--list', '--filter=AM', self.repository_location + '::test2', 'input') + output = self.cmd(f'--repo={self.repository_location}::test2', 'create', '--list', '--filter=AM', 'input') self.assert_not_in('file1', output) # change the file self.create_regular_file('file1', size=1024 * 100) # should list the file as changed - output = self.cmd('create', '--list', '--filter=AM', self.repository_location + '::test3', 'input') + output = self.cmd(f'--repo={self.repository_location}::test3', 'create', '--list', '--filter=AM', 'input') self.assert_in('file1', output) @pytest.mark.skipif(not are_fifos_supported(), reason='FIFOs not supported') @@ -2058,8 +2066,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): finally: os.close(fd) - self.cmd('init', '--encryption=repokey', self.repository_location) - archive = self.repository_location + '::test' + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') data = b'foobar' * 1000 fifo_fn = os.path.join(self.input_path, 'fifo') @@ -2070,11 +2077,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): t = Thread(target=fifo_feeder, args=(fifo_fn, data)) t.start() try: - self.cmd('create', '--read-special', archive, 'input/link_fifo') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--read-special', 'input/link_fifo') finally: t.join() with changedir('output'): - self.cmd('extract', archive) + self.cmd(f'--repo={self.repository_location}::test', 'extract') fifo_fn = 'input/link_fifo' with open(fifo_fn, 'rb') as f: extracted_data = f.read() @@ -2082,41 +2089,40 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_read_special_broken_symlink(self): os.symlink('somewhere does not exist', os.path.join(self.input_path, 'link')) - self.cmd('init', '--encryption=repokey', self.repository_location) - archive = self.repository_location + '::test' - self.cmd('create', '--read-special', archive, 'input') - output = self.cmd('list', archive) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', '--read-special', 'input') + output = self.cmd(f'--repo={self.repository_location}::test', 'list') assert 'input/link -> somewhere does not exist' in output # def test_cmdline_compatibility(self): # self.create_regular_file('file1', size=1024 * 80) - # self.cmd('init', '--encryption=repokey', self.repository_location) + # self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # self.cmd('create', self.repository_location + '::test', 'input') # output = self.cmd('foo', self.repository_location, '--old') # self.assert_in('"--old" has been deprecated. Use "--new" instead', output) def test_prune_repository(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test1', src_dir) - self.cmd('create', self.repository_location + '::test2', src_dir) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::test2', 'create', src_dir) # these are not really a checkpoints, but they look like some: - self.cmd('create', self.repository_location + '::test3.checkpoint', src_dir) - self.cmd('create', self.repository_location + '::test3.checkpoint.1', src_dir) - self.cmd('create', self.repository_location + '::test4.checkpoint', src_dir) - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=1') + self.cmd(f'--repo={self.repository_location}::test3.checkpoint', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::test3.checkpoint.1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::test4.checkpoint', 'create', src_dir) + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Would prune:\s+test1', output) # must keep the latest non-checkpoint archive: assert re.search(r'Keeping archive \(rule: daily #1\):\s+test2', output) # must keep the latest checkpoint archive: assert re.search(r'Keeping checkpoint archive:\s+test4.checkpoint', output) - output = self.cmd('list', '--consider-checkpoints', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') self.assert_in('test1', output) self.assert_in('test2', output) self.assert_in('test3.checkpoint', output) self.assert_in('test3.checkpoint.1', output) self.assert_in('test4.checkpoint', output) - self.cmd('prune', self.repository_location, '--keep-daily=1') - output = self.cmd('list', '--consider-checkpoints', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') self.assert_not_in('test1', output) # the latest non-checkpoint archive must be still there: self.assert_in('test2', output) @@ -2125,9 +2131,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('test3.checkpoint.1', output) self.assert_in('test4.checkpoint', output) # now we supersede the latest checkpoint by a successful backup: - self.cmd('create', self.repository_location + '::test5', src_dir) - self.cmd('prune', self.repository_location, '--keep-daily=2') - output = self.cmd('list', '--consider-checkpoints', self.repository_location) + self.cmd(f'--repo={self.repository_location}::test5', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=2') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') # all checkpoints should be gone now: self.assert_not_in('checkpoint', output) # the latest archive must be still there @@ -2140,12 +2146,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): return dtime.astimezone(dateutil.tz.UTC).strftime("%Y-%m-%dT%H:%M:%S") def _create_archive_ts(self, name, y, m, d, H=0, M=0, S=0): - loc = self.repository_location + '::' + name - self.cmd('create', '--timestamp', self._to_utc_timestamp(y, m, d, H, M, S), loc, src_dir) + self.cmd(f'--repo={self.repository_location}::{name}', 'create', + '--timestamp', self._to_utc_timestamp(y, m, d, H, M, S), src_dir) # This test must match docs/misc/prune-example.txt def test_prune_repository_example(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Archives that will be kept, per the example # Oldest archive self._create_archive_ts('test01', 2015, 1, 1) @@ -2178,7 +2184,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self._create_archive_ts('test23', 2015, 5, 31) # The next older daily backup self._create_archive_ts('test24', 2015, 12, 16) - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=14', '--keep-monthly=6', '--keep-yearly=1') + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=14', '--keep-monthly=6', '--keep-yearly=1') # Prune second backup of the year assert re.search(r'Would prune:\s+test22', output) # Prune next older monthly and daily backups @@ -2191,12 +2197,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert re.search(r'Keeping archive \(rule: monthly #' + str(i) + r'\):\s+test' + ("%02d" % (8-i)), output) for i in range(1, 15): assert re.search(r'Keeping archive \(rule: daily #' + str(i) + r'\):\s+test' + ("%02d" % (22-i)), output) - output = self.cmd('list', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list') # Nothing pruned after dry run for i in range(1, 25): self.assert_in('test%02d' % i, output) - self.cmd('prune', self.repository_location, '--keep-daily=14', '--keep-monthly=6', '--keep-yearly=1') - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=14', '--keep-monthly=6', '--keep-yearly=1') + output = self.cmd(f'--repo={self.repository_location}', 'list') # All matching backups plus oldest kept for i in range(1, 22): self.assert_in('test%02d' % i, output) @@ -2206,141 +2212,139 @@ class ArchiverTestCase(ArchiverTestCaseBase): # With an initial and daily backup, prune daily until oldest is replaced by a monthly backup def test_prune_retain_and_expire_oldest(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Initial backup self._create_archive_ts('original_archive', 2020, 9, 1, 11, 15) # Archive and prune daily for 30 days for i in range(1, 31): self._create_archive_ts('september%02d' % i, 2020, 9, i, 12) - self.cmd('prune', self.repository_location, '--keep-daily=7', '--keep-monthly=1') + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=7', '--keep-monthly=1') # Archive and prune 6 days into the next month for i in range(1, 7): self._create_archive_ts('october%02d' % i, 2020, 10, i, 12) - self.cmd('prune', self.repository_location, '--keep-daily=7', '--keep-monthly=1') + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=7', '--keep-monthly=1') # Oldest backup is still retained - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=7', '--keep-monthly=1') + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=7', '--keep-monthly=1') assert re.search(r'Keeping archive \(rule: monthly\[oldest\] #1' + r'\):\s+original_archive', output) # Archive one more day and prune. self._create_archive_ts('october07', 2020, 10, 7, 12) - self.cmd('prune', self.repository_location, '--keep-daily=7', '--keep-monthly=1') + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=7', '--keep-monthly=1') # Last day of previous month is retained as monthly, and oldest is expired. - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=7', '--keep-monthly=1') + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=7', '--keep-monthly=1') assert re.search(r'Keeping archive \(rule: monthly #1\):\s+september30', output) self.assert_not_in('original_archive', output) def test_prune_repository_save_space(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test1', src_dir) - self.cmd('create', self.repository_location + '::test2', src_dir) - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=1') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::test2', 'create', src_dir) + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Keeping archive \(rule: daily #1\):\s+test2', output) assert re.search(r'Would prune:\s+test1', output) - output = self.cmd('list', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_in('test1', output) self.assert_in('test2', output) - self.cmd('prune', '--save-space', self.repository_location, '--keep-daily=1') - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'prune', '--save-space', '--keep-daily=1') + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_not_in('test1', output) self.assert_in('test2', output) def test_prune_repository_prefix(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::foo-2015-08-12-10:00', src_dir) - self.cmd('create', self.repository_location + '::foo-2015-08-12-20:00', src_dir) - self.cmd('create', self.repository_location + '::bar-2015-08-12-10:00', src_dir) - self.cmd('create', self.repository_location + '::bar-2015-08-12-20:00', src_dir) - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=1', '--prefix=foo-') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::foo-2015-08-12-10:00', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::foo-2015-08-12-20:00', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::bar-2015-08-12-10:00', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::bar-2015-08-12-20:00', 'create', src_dir) + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--prefix=foo-') assert re.search(r'Keeping archive \(rule: daily #1\):\s+foo-2015-08-12-20:00', output) assert re.search(r'Would prune:\s+foo-2015-08-12-10:00', output) - output = self.cmd('list', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_in('foo-2015-08-12-10:00', output) self.assert_in('foo-2015-08-12-20:00', output) self.assert_in('bar-2015-08-12-10:00', output) self.assert_in('bar-2015-08-12-20:00', output) - self.cmd('prune', self.repository_location, '--keep-daily=1', '--prefix=foo-') - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1', '--prefix=foo-') + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_not_in('foo-2015-08-12-10:00', output) self.assert_in('foo-2015-08-12-20:00', output) self.assert_in('bar-2015-08-12-10:00', output) self.assert_in('bar-2015-08-12-20:00', output) def test_prune_repository_glob(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::2015-08-12-10:00-foo', src_dir) - self.cmd('create', self.repository_location + '::2015-08-12-20:00-foo', src_dir) - self.cmd('create', self.repository_location + '::2015-08-12-10:00-bar', src_dir) - self.cmd('create', self.repository_location + '::2015-08-12-20:00-bar', src_dir) - output = self.cmd('prune', '--list', '--dry-run', self.repository_location, '--keep-daily=1', '--glob-archives=2015-*-foo') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::2015-08-12-10:00-foo', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::2015-08-12-20:00-foo', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::2015-08-12-10:00-bar', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::2015-08-12-20:00-bar', 'create', src_dir) + output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--glob-archives=2015-*-foo') assert re.search(r'Keeping archive \(rule: daily #1\):\s+2015-08-12-20:00-foo', output) assert re.search(r'Would prune:\s+2015-08-12-10:00-foo', output) - output = self.cmd('list', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_in('2015-08-12-10:00-foo', output) self.assert_in('2015-08-12-20:00-foo', output) self.assert_in('2015-08-12-10:00-bar', output) self.assert_in('2015-08-12-20:00-bar', output) - self.cmd('prune', self.repository_location, '--keep-daily=1', '--glob-archives=2015-*-foo') - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1', '--glob-archives=2015-*-foo') + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_not_in('2015-08-12-10:00-foo', output) self.assert_in('2015-08-12-20:00-foo', output) self.assert_in('2015-08-12-10:00-bar', output) self.assert_in('2015-08-12-20:00-bar', output) def test_list_prefix(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test-1', src_dir) - self.cmd('create', self.repository_location + '::something-else-than-test-1', src_dir) - self.cmd('create', self.repository_location + '::test-2', src_dir) - output = self.cmd('list', '--prefix=test-', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test-1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::something-else-than-test-1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::test-2', 'create', src_dir) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--prefix=test-') self.assert_in('test-1', output) self.assert_in('test-2', output) self.assert_not_in('something-else', output) def test_list_format(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - test_archive = self.repository_location + '::test' - self.cmd('create', test_archive, src_dir) - output_1 = self.cmd('list', test_archive) - output_2 = self.cmd('list', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}', test_archive) - output_3 = self.cmd('list', '--format', '{mtime:%s} {path}{NL}', test_archive) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', src_dir) + output_1 = self.cmd(f'--repo={self.repository_location}::test', 'list') + output_2 = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') + output_3 = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{mtime:%s} {path}{NL}') self.assertEqual(output_1, output_2) self.assertNotEqual(output_1, output_3) def test_list_repository_format(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', '--comment', 'comment 1', self.repository_location + '::test-1', src_dir) - self.cmd('create', '--comment', 'comment 2', self.repository_location + '::test-2', src_dir) - output_1 = self.cmd('list', self.repository_location) - output_2 = self.cmd('list', '--format', '{archive:<36} {time} [{id}]{NL}', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test-1', 'create', '--comment', 'comment 1', src_dir) + self.cmd(f'--repo={self.repository_location}::test-2', 'create', '--comment', 'comment 2', src_dir) + output_1 = self.cmd(f'--repo={self.repository_location}', 'list') + output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{archive:<36} {time} [{id}]{NL}') self.assertEqual(output_1, output_2) - output_1 = self.cmd('list', '--short', self.repository_location) + output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--short') self.assertEqual(output_1, 'test-1\ntest-2\n') - output_1 = self.cmd('list', '--format', '{barchive}/', self.repository_location) + output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{barchive}/') self.assertEqual(output_1, 'test-1/test-2/') - output_3 = self.cmd('list', '--format', '{name} {comment}{NL}', self.repository_location) + output_3 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{name} {comment}{NL}') self.assert_in('test-1 comment 1\n', output_3) self.assert_in('test-2 comment 2\n', output_3) def test_list_hash(self): self.create_regular_file('empty_file', size=0) self.create_regular_file('amb', contents=b'a' * 1000000) - self.cmd('init', '--encryption=repokey', self.repository_location) - test_archive = self.repository_location + '::test' - self.cmd('create', test_archive, 'input') - output = self.cmd('list', '--format', '{sha256} {path}{NL}', test_archive) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{sha256} {path}{NL}') assert "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 input/amb" in output assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 input/empty_file" in output def test_list_consider_checkpoints(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test1', 'create', src_dir) # these are not really a checkpoints, but they look like some: - self.cmd('create', self.repository_location + '::test2.checkpoint', src_dir) - self.cmd('create', self.repository_location + '::test3.checkpoint.1', src_dir) - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}::test2.checkpoint', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}::test3.checkpoint.1', 'create', src_dir) + output = self.cmd(f'--repo={self.repository_location}', 'list') assert "test1" in output assert "test2.checkpoint" not in output assert "test3.checkpoint.1" not in output - output = self.cmd('list', '--consider-checkpoints', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') assert "test1" in output assert "test2.checkpoint" in output assert "test3.checkpoint.1" in output @@ -2351,27 +2355,25 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(os.path.join(self.input_path, 'two_chunks'), 'wb') as fd: fd.write(b'abba' * 2000000) fd.write(b'baab' * 2000000) - self.cmd('init', '--encryption=repokey', self.repository_location) - test_archive = self.repository_location + '::test' - self.cmd('create', test_archive, 'input') - output = self.cmd('list', '--format', '{num_chunks} {unique_chunks} {path}{NL}', test_archive) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{num_chunks} {unique_chunks} {path}{NL}') assert "0 0 input/empty_file" in output assert "2 2 input/two_chunks" in output def test_list_size(self): self.create_regular_file('compressible_file', size=10000) - self.cmd('init', '--encryption=repokey', self.repository_location) - test_archive = self.repository_location + '::test' - self.cmd('create', '-C', 'lz4', test_archive, 'input') - output = self.cmd('list', '--format', '{size} {path}{NL}', test_archive) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', '-C', 'lz4', 'input') + output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{size} {path}{NL}') size, path = output.split("\n")[1].split(" ") assert int(size) == 10000 def test_list_json(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - list_repo = json.loads(self.cmd('list', '--json', self.repository_location)) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + list_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) repository = list_repo['repository'] assert len(repository['id']) == 64 assert datetime.strptime(repository['last_modified'], ISO_FORMAT) # must not raise @@ -2380,7 +2382,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): archive0 = list_repo['archives'][0] assert datetime.strptime(archive0['time'], ISO_FORMAT) # must not raise - list_archive = self.cmd('list', '--json-lines', self.repository_location + '::test') + list_archive = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') items = [json.loads(s) for s in list_archive.splitlines()] assert len(items) == 2 file1 = items[1] @@ -2388,7 +2390,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert file1['size'] == 81920 assert datetime.strptime(file1['mtime'], ISO_FORMAT) # must not raise - list_archive = self.cmd('list', '--json-lines', '--format={sha256}', self.repository_location + '::test') + list_archive = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines', '--format={sha256}') items = [json.loads(s) for s in list_archive.splitlines()] assert len(items) == 2 file1 = items[1] @@ -2396,14 +2398,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert file1['sha256'] == 'b2915eb69f260d8d3c25249195f2c8f4f716ea82ec760ae929732c0262442b2b' def test_list_json_args(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('list', '--json-lines', self.repository_location, exit_code=2) - self.cmd('list', '--json', self.repository_location + '::archive', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'list', '--json-lines', exit_code=2) + self.cmd(f'--repo={self.repository_location}::archive', 'list', '--json', exit_code=2) def test_log_json(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - log = self.cmd('create', '--log-json', self.repository_location + '::test', 'input', '--list', '--debug') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + log = self.cmd(f'--repo={self.repository_location}::test', 'create', '--log-json', 'input', '--list', '--debug') messages = {} # type -> message, one of each kind for line in log.splitlines(): msg = json.loads(line) @@ -2420,67 +2422,67 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_profile(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input', '--debug-profile=create.prof') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', '--debug-profile=create.prof') self.cmd('debug', 'convert-profile', 'create.prof', 'create.pyprof') stats = pstats.Stats('create.pyprof') stats.strip_dirs() stats.sort_stats('cumtime') - self.cmd('create', self.repository_location + '::test2', 'input', '--debug-profile=create.pyprof') + self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input', '--debug-profile=create.pyprof') stats = pstats.Stats('create.pyprof') # Only do this on trusted data! stats.strip_dirs() stats.sort_stats('cumtime') def test_common_options(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - log = self.cmd('--debug', 'create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + log = self.cmd(f'--repo={self.repository_location}::test', '--debug', 'create', 'input') assert 'security: read previous location' in log def test_change_passphrase(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') os.environ['BORG_NEW_PASSPHRASE'] = 'newpassphrase' # here we have both BORG_PASSPHRASE and BORG_NEW_PASSPHRASE set: - self.cmd('key', 'change-passphrase', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'key', 'change-passphrase') os.environ['BORG_PASSPHRASE'] = 'newpassphrase' - self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'list') def test_change_location_to_keyfile(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(repokey)' in log - self.cmd('key', 'change-location', self.repository_location, 'keyfile') - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'keyfile') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(key file)' in log def test_change_location_to_b2keyfile(self): - self.cmd('init', '--encryption=repokey-blake2', self.repository_location) - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey-blake2') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(repokey BLAKE2b)' in log - self.cmd('key', 'change-location', self.repository_location, 'keyfile') - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'keyfile') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(key file BLAKE2b)' in log def test_change_location_to_repokey(self): - self.cmd('init', '--encryption=keyfile', self.repository_location) - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(key file)' in log - self.cmd('key', 'change-location', self.repository_location, 'repokey') - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(repokey)' in log def test_change_location_to_b2repokey(self): - self.cmd('init', '--encryption=keyfile-blake2', self.repository_location) - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile-blake2') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(key file BLAKE2b)' in log - self.cmd('key', 'change-location', self.repository_location, 'repokey') - log = self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') + log = self.cmd(f'--repo={self.repository_location}', 'info') assert '(repokey BLAKE2b)' in log def test_break_lock(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('break-lock', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'break-lock') def test_usage(self): self.cmd() @@ -2506,11 +2508,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): noatime_used = flags_noatime != flags_normal return noatime_used and atime_before == atime_after - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_test_files() have_noatime = has_noatime('input/file1') - self.cmd('create', '--exclude-nodump', '--atime', self.repository_location + '::archive', 'input') - self.cmd('create', '--exclude-nodump', '--atime', self.repository_location + '::archive2', 'input') + self.cmd(f'--repo={self.repository_location}::archive', 'create', '--exclude-nodump', '--atime', 'input') + self.cmd(f'--repo={self.repository_location}::archive2', 'create', '--exclude-nodump', '--atime', 'input') if has_lchflags: # remove the file we did not backup, so input and output become equal os.remove(os.path.join('input', 'flagfile')) @@ -2596,15 +2598,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_versions_view(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('test', contents=b'first') if are_hardlinks_supported(): self.create_regular_file('hardlink1', contents=b'123456') os.link('input/hardlink1', 'input/hardlink2') os.link('input/hardlink1', 'input/hardlink3') - self.cmd('create', self.repository_location + '::archive1', 'input') + self.cmd(f'--repo={self.repository_location}::archive1', 'create', 'input') self.create_regular_file('test', contents=b'second') - self.cmd('create', self.repository_location + '::archive2', 'input') + self.cmd(f'--repo={self.repository_location}::archive2', 'create', 'input') mountpoint = os.path.join(self.tmpdir, 'mountpoint') # mount the whole repository, archive contents shall show up in versioned view: with self.fuse_mount(self.repository_location, mountpoint, '-o', 'versions'): @@ -2628,7 +2630,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_allow_damaged_files(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('archive') # Get rid of a chunk and repair it archive, repository = self.open_archive('archive') @@ -2641,7 +2643,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): else: assert False # missed the file repository.commit(compact=False) - self.cmd('check', '--repair', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) mountpoint = os.path.join(self.tmpdir, 'mountpoint') with self.fuse_mount(self.repository_location + '::archive', mountpoint): @@ -2653,7 +2655,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_mount_options(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('arch11') self.create_src_archive('arch12') self.create_src_archive('arch21') @@ -2727,7 +2729,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Decorate borg.locking.Lock.migrate_lock = write_assert_data(borg.locking.Lock.migrate_lock) try: - self.cmd('init', '--encryption=none', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.create_src_archive('arch') mountpoint = os.path.join(self.tmpdir, 'mountpoint') # In order that the decoration is kept for the borg mount process, we must not spawn, but actually fork; @@ -2780,13 +2782,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd('init', '--encryption=' + method, self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=' + method) verify_uniqueness() - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') verify_uniqueness() - self.cmd('create', self.repository_location + '::test.2', 'input') + self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') verify_uniqueness() - self.cmd('delete', self.repository_location + '::test.2') + self.cmd(f'--repo={self.repository_location}::test.2', 'delete') verify_uniqueness() def test_aes_counter_uniqueness_keyfile(self): @@ -2797,41 +2799,41 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_archive_items(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - output = self.cmd('debug', 'dump-archive-items', self.repository_location + '::test') + output = self.cmd(f'--repo={self.repository_location}::test', 'debug', 'dump-archive-items') output_dir = sorted(os.listdir('output')) assert len(output_dir) > 0 and output_dir[0].startswith('000000_') assert 'Done.' in output def test_debug_dump_repo_objs(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): - output = self.cmd('debug', 'dump-repo-objs', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-repo-objs') output_dir = sorted(os.listdir('output')) assert len(output_dir) > 0 and output_dir[0].startswith('00000000_') assert 'Done.' in output def test_debug_put_get_delete_obj(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') data = b'some data' hexkey = sha256(data).hexdigest() self.create_regular_file('file', contents=data) - output = self.cmd('debug', 'put-obj', self.repository_location, 'input/file') + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'put-obj', 'input/file') assert hexkey in output - output = self.cmd('debug', 'get-obj', self.repository_location, hexkey, 'output/file') + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'get-obj', hexkey, 'output/file') assert hexkey in output with open('output/file', 'rb') as f: data_read = f.read() assert data == data_read - output = self.cmd('debug', 'delete-obj', self.repository_location, hexkey) + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'delete-obj', hexkey) assert "deleted" in output - output = self.cmd('debug', 'delete-obj', self.repository_location, hexkey) + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'delete-obj', hexkey) assert "not found" in output - output = self.cmd('debug', 'delete-obj', self.repository_location, 'invalid') + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'delete-obj', 'invalid') assert "is invalid" in output def test_init_interrupt(self): @@ -2839,19 +2841,19 @@ class ArchiverTestCase(ArchiverTestCaseBase): raise EOFError with patch.object(FlexiKey, 'create', raise_eof): - self.cmd('init', '--encryption=repokey', self.repository_location, exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', exit_code=1) assert not os.path.exists(self.repository_location) def test_init_requires_encryption_option(self): - self.cmd('init', self.repository_location, exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', exit_code=2) def test_init_nested_repositories(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') if self.FORK_DEFAULT: - self.cmd('init', '--encryption=repokey', self.repository_location + '/nested', exit_code=2) + self.cmd(f'--repo={self.repository_location}/nested', 'init', '--encryption=repokey', exit_code=2) else: with pytest.raises(Repository.AlreadyExists): - self.cmd('init', '--encryption=repokey', self.repository_location + '/nested') + self.cmd(f'--repo={self.repository_location}/nested', 'init', '--encryption=repokey') def test_init_refuse_to_overwrite_keyfile(self): """BORG_KEY_FILE=something borg init should quit if "something" already exists. @@ -2859,10 +2861,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): See https://github.com/borgbackup/borg/pull/6046""" keyfile = os.path.join(self.tmpdir, 'keyfile') with environment_variable(BORG_KEY_FILE=keyfile): - self.cmd('init', '--encryption=keyfile', self.repository_location + '0') + self.cmd(f'--repo={self.repository_location}0', 'init', '--encryption=keyfile') with open(keyfile) as file: before = file.read() - arg = ('init', '--encryption=keyfile', self.repository_location + '1') + arg = (f'--repo={self.repository_location}1', 'init', '--encryption=keyfile') if self.FORK_DEFAULT: self.cmd(*arg, exit_code=2) else: @@ -2874,7 +2876,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def check_cache(self): # First run a regular borg check - self.cmd('check', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'check') # Then check that the cache on disk matches exactly what's in the repo. with self.open_repository() as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -2894,8 +2896,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert id in seen def test_check_cache(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with self.open_repository() as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) with Cache(repository, key, manifest, sync=False) as cache: @@ -2906,26 +2908,25 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.check_cache() def test_recreate_target_rc(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('recreate', self.repository_location, '--target=asdf', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--target=asdf', exit_code=2) assert 'Need to specify single archive' in output def test_recreate_target(self): self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.check_cache() - archive = self.repository_location + '::test0' - self.cmd('create', archive, 'input') + self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') self.check_cache() - original_archive = self.cmd('list', self.repository_location) - self.cmd('recreate', archive, 'input/dir2', '-e', 'input/dir2/file3', '--target=new-archive') + original_archive = self.cmd(f'--repo={self.repository_location}', 'list') + self.cmd(f'--repo={self.repository_location}::test0', 'recreate', 'input/dir2', + '-e', 'input/dir2/file3', '--target=new-archive') self.check_cache() - archives = self.cmd('list', self.repository_location) + archives = self.cmd(f'--repo={self.repository_location}', 'list') assert original_archive in archives assert 'new-archive' in archives - archive = self.repository_location + '::new-archive' - listing = self.cmd('list', '--short', archive) + listing = self.cmd(f'--repo={self.repository_location}::new-archive', 'list', '--short') assert 'file1' not in listing assert 'dir2/file2' in listing assert 'dir2/file3' not in listing @@ -2933,12 +2934,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_basic(self): self.create_test_files() self.create_regular_file('dir2/file3', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - archive = self.repository_location + '::test0' - self.cmd('create', archive, 'input') - self.cmd('recreate', archive, 'input/dir2', '-e', 'input/dir2/file3') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test0', 'recreate', 'input/dir2', '-e', 'input/dir2/file3') self.check_cache() - listing = self.cmd('list', '--short', archive) + listing = self.cmd(f'--repo={self.repository_location}::test0', 'list', '--short') assert 'file1' not in listing assert 'dir2/file2' in listing assert 'dir2/file3' not in listing @@ -2947,48 +2947,48 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_subtree_hardlinks(self): # This is essentially the same problem set as in test_extract_hardlinks self._extract_hardlinks_setup() - self.cmd('create', self.repository_location + '::test2', 'input') - self.cmd('recreate', self.repository_location + '::test', 'input/dir1') + self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'recreate', 'input/dir1') self.check_cache() with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert os.stat('input/dir1/aaaa').st_nlink == 2 assert os.stat('input/dir1/source2').st_nlink == 2 with changedir('output'): - self.cmd('extract', self.repository_location + '::test2') + self.cmd(f'--repo={self.repository_location}::test2', 'extract') assert os.stat('input/dir1/hardlink').st_nlink == 4 def test_recreate_rechunkify(self): with open(os.path.join(self.input_path, 'large_file'), 'wb') as fd: fd.write(b'a' * 280) fd.write(b'b' * 280) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', '--chunker-params', '7,9,8,128', self.repository_location + '::test1', 'input') - self.cmd('create', self.repository_location + '::test2', 'input', '--files-cache=disabled') - list = self.cmd('list', self.repository_location + '::test1', 'input/large_file', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test1', 'create', '--chunker-params', '7,9,8,128', 'input') + self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input', '--files-cache=disabled') + list = self.cmd(f'--repo={self.repository_location}::test1', 'list', 'input/large_file', '--format', '{num_chunks} {unique_chunks}') num_chunks, unique_chunks = map(int, list.split(' ')) # test1 and test2 do not deduplicate assert num_chunks == unique_chunks - self.cmd('recreate', self.repository_location, '--chunker-params', 'default') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() # test1 and test2 do deduplicate after recreate - assert int(self.cmd('list', self.repository_location + '::test1', 'input/large_file', '--format={size}')) - assert not int(self.cmd('list', self.repository_location + '::test1', 'input/large_file', + assert int(self.cmd(f'--repo={self.repository_location}::test1', 'list', 'input/large_file', '--format={size}')) + assert not int(self.cmd(f'--repo={self.repository_location}::test1', 'list', 'input/large_file', '--format', '{unique_chunks}')) def test_recreate_recompress(self): self.create_regular_file('compressible', size=10000) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input', '-C', 'none') - file_list = self.cmd('list', self.repository_location + '::test', 'input/compressible', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', '-C', 'none') + file_list = self.cmd(f'--repo={self.repository_location}::test', 'list', 'input/compressible', '--format', '{size} {sha256}') size, sha256_before = file_list.split(' ') - self.cmd('recreate', self.repository_location, '-C', 'lz4', '--recompress') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-C', 'lz4', '--recompress') self.check_cache() - file_list = self.cmd('list', self.repository_location + '::test', 'input/compressible', + file_list = self.cmd(f'--repo={self.repository_location}::test', 'list', 'input/compressible', '--format', '{size} {sha256}') size, sha256_after = file_list.split(' ') assert sha256_before == sha256_after @@ -2996,12 +2996,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_timestamp(self): local_timezone = datetime.now(timezone(timedelta(0))).astimezone().tzinfo self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - archive = self.repository_location + '::test0' - self.cmd('create', archive, 'input') - self.cmd('recreate', '--timestamp', "1970-01-02T00:00:00", '--comment', - 'test', archive) - info = self.cmd('info', archive).splitlines() + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test0', 'recreate', '--timestamp', "1970-01-02T00:00:00", + '--comment', 'test') + info = self.cmd(f'--repo={self.repository_location}::test0', 'info').splitlines() dtime = datetime(1970, 1, 2) + local_timezone.utcoffset(None) s_time = dtime.strftime("%Y-%m-%d") assert any([re.search(r'Time \(start\).+ %s' % s_time, item) for item in info]) @@ -3009,70 +3008,70 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_dry_run(self): self.create_regular_file('compressible', size=10000) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - archives_before = self.cmd('list', self.repository_location + '::test') - self.cmd('recreate', self.repository_location, '-n', '-e', 'input/compressible') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + archives_before = self.cmd(f'--repo={self.repository_location}::test', 'list') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-n', '-e', 'input/compressible') self.check_cache() - archives_after = self.cmd('list', self.repository_location + '::test') + archives_after = self.cmd(f'--repo={self.repository_location}::test', 'list') assert archives_after == archives_before def test_recreate_skips_nothing_to_do(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - info_before = self.cmd('info', self.repository_location + '::test') - self.cmd('recreate', self.repository_location, '--chunker-params', 'default') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + info_before = self.cmd(f'--repo={self.repository_location}::test', 'info') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() - info_after = self.cmd('info', self.repository_location + '::test') + info_after = self.cmd(f'--repo={self.repository_location}::test', 'info') assert info_before == info_after # includes archive ID def test_with_lock(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') lock_path = os.path.join(self.repository_path, 'lock.exclusive') cmd = 'python3', '-c', 'import os, sys; sys.exit(42 if os.path.exists("%s") else 23)' % lock_path - self.cmd('with-lock', self.repository_location, *cmd, fork=True, exit_code=42) + self.cmd(f'--repo={self.repository_location}', 'with-lock', *cmd, fork=True, exit_code=42) def test_recreate_list_output(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=0) self.create_regular_file('file2', size=0) self.create_regular_file('file3', size=0) self.create_regular_file('file4', size=0) self.create_regular_file('file5', size=0) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - output = self.cmd('recreate', '--list', '--info', self.repository_location + '::test', '-e', 'input/file2') + output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--list', '--info', '-e', 'input/file2') self.check_cache() self.assert_in("input/file1", output) self.assert_in("x input/file2", output) - output = self.cmd('recreate', '--list', self.repository_location + '::test', '-e', 'input/file3') + output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--list', '-e', 'input/file3') self.check_cache() self.assert_in("input/file1", output) self.assert_in("x input/file3", output) - output = self.cmd('recreate', self.repository_location + '::test', '-e', 'input/file4') + output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '-e', 'input/file4') self.check_cache() self.assert_not_in("input/file1", output) self.assert_not_in("x input/file4", output) - output = self.cmd('recreate', '--info', self.repository_location + '::test', '-e', 'input/file5') + output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--info', '-e', 'input/file5') self.check_cache() self.assert_not_in("input/file1", output) self.assert_not_in("x input/file5", output) def test_bad_filters(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('delete', '--first', '1', '--last', '1', self.repository_location, fork=True, exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'delete', '--first', '1', '--last', '1', fork=True, exit_code=2) def test_key_export_keyfile(self): export_file = self.output_path + '/exported' - self.cmd('init', self.repository_location, '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') repo_id = self._extract_repository_id(self.repository_path) - self.cmd('key', 'export', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'export', export_file) with open(export_file) as fd: export_contents = fd.read() @@ -3088,7 +3087,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.unlink(key_file) - self.cmd('key', 'import', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file) with open(key_file) as fd: key_contents2 = fd.read() @@ -3096,10 +3095,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert key_contents2 == key_contents def test_key_import_keyfile_with_borg_key_file(self): - self.cmd('init', self.repository_location, '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') exported_key_file = os.path.join(self.output_path, 'exported') - self.cmd('key', 'export', self.repository_location, exported_key_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'export', exported_key_file) key_file = os.path.join(self.keys_path, os.listdir(self.keys_path)[0]) with open(key_file) as fd: @@ -3108,7 +3107,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): imported_key_file = os.path.join(self.output_path, 'imported') with environment_variable(BORG_KEY_FILE=imported_key_file): - self.cmd('key', 'import', self.repository_location, exported_key_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', exported_key_file) assert not os.path.isfile(key_file), '"borg key import" should respect BORG_KEY_FILE' with open(imported_key_file) as fd: @@ -3117,9 +3116,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_key_export_repokey(self): export_file = self.output_path + '/exported' - self.cmd('init', self.repository_location, '--encryption', 'repokey') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'repokey') repo_id = self._extract_repository_id(self.repository_path) - self.cmd('key', 'export', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'export', export_file) with open(export_file) as fd: export_contents = fd.read() @@ -3138,7 +3137,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with Repository(self.repository_path) as repository: repository.save_key(b'') - self.cmd('key', 'import', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file) with Repository(self.repository_path) as repository: repo_key2 = RepoKey(repository) @@ -3148,9 +3147,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_key_export_qr(self): export_file = self.output_path + '/exported.html' - self.cmd('init', self.repository_location, '--encryption', 'repokey') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'repokey') repo_id = self._extract_repository_id(self.repository_path) - self.cmd('key', 'export', '--qr-html', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'export', '--qr-html', export_file) with open(export_file, encoding='utf-8') as fd: export_contents = fd.read() @@ -3163,39 +3162,39 @@ class ArchiverTestCase(ArchiverTestCaseBase): export_directory = self.output_path + '/exported' os.mkdir(export_directory) - self.cmd('init', self.repository_location, '--encryption', 'repokey') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'repokey') - self.cmd('key', 'export', self.repository_location, export_directory, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'key', 'export', export_directory, exit_code=EXIT_ERROR) def test_key_import_errors(self): export_file = self.output_path + '/exported' - self.cmd('init', self.repository_location, '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') - self.cmd('key', 'import', self.repository_location, export_file, exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file, exit_code=EXIT_ERROR) with open(export_file, 'w') as fd: fd.write('something not a key\n') if self.FORK_DEFAULT: - self.cmd('key', 'import', self.repository_location, export_file, exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file, exit_code=2) else: with pytest.raises(NotABorgKeyFile): - self.cmd('key', 'import', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file) with open(export_file, 'w') as fd: fd.write('BORG_KEY a0a0a0\n') if self.FORK_DEFAULT: - self.cmd('key', 'import', self.repository_location, export_file, exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file, exit_code=2) else: with pytest.raises(RepoIdMismatch): - self.cmd('key', 'import', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file) def test_key_export_paperkey(self): repo_id = 'e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239' export_file = self.output_path + '/exported' - self.cmd('init', self.repository_location, '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') self._set_repository_id(self.repository_path, unhexlify(repo_id)) key_file = self.keys_path + '/' + os.listdir(self.keys_path)[0] @@ -3204,7 +3203,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(KeyfileKey.FILE_ID + ' ' + repo_id + '\n') fd.write(b2a_base64(b'abcdefghijklmnopqrstu').decode()) - self.cmd('key', 'export', '--paper', self.repository_location, export_file) + self.cmd(f'--repo={self.repository_location}', 'key', 'export', '--paper', export_file) with open(export_file) as fd: export_contents = fd.read() @@ -3219,7 +3218,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_key_import_paperkey(self): repo_id = 'e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239' - self.cmd('init', self.repository_location, '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') self._set_repository_id(self.repository_path, unhexlify(repo_id)) key_file = self.keys_path + '/' + os.listdir(self.keys_path)[0] @@ -3254,20 +3253,20 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 # print(i.to_bytes(2, 'big')) # break - self.cmd('key', 'import', '--paper', self.repository_location, input=typed_input) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', '--paper', input=typed_input) # Test abort paths typed_input = b'\ny\n' - self.cmd('key', 'import', '--paper', self.repository_location, input=typed_input) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', '--paper', input=typed_input) typed_input = b'2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02\n\ny\n' - self.cmd('key', 'import', '--paper', self.repository_location, input=typed_input) + self.cmd(f'--repo={self.repository_location}', 'key', 'import', '--paper', input=typed_input) def test_debug_dump_manifest(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') dump_file = self.output_path + '/dump' - output = self.cmd('debug', 'dump-manifest', self.repository_location, dump_file) + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-manifest', dump_file) assert output == "" with open(dump_file) as f: result = json.load(f) @@ -3279,10 +3278,10 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_archive(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') dump_file = self.output_path + '/dump' - output = self.cmd('debug', 'dump-archive', self.repository_location + "::test", dump_file) + output = self.cmd(f'--repo={self.repository_location}::test', 'debug', 'dump-archive', dump_file) assert output == "" with open(dump_file) as f: result = json.load(f) @@ -3292,17 +3291,17 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 assert '_items' in result def test_debug_refcount_obj(self): - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('debug', 'refcount-obj', self.repository_location, '0' * 64).strip() + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', '0' * 64).strip() assert output == 'object 0000000000000000000000000000000000000000000000000000000000000000 not found [info from chunks cache].' - create_json = json.loads(self.cmd('create', '--json', self.repository_location + '::test', 'input')) + create_json = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'create', '--json', 'input')) archive_id = create_json['archive']['id'] - output = self.cmd('debug', 'refcount-obj', self.repository_location, archive_id).strip() + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', archive_id).strip() assert output == 'object ' + archive_id + ' has 1 referrers [info from chunks cache].' # Invalid IDs do not abort or return an error - output = self.cmd('debug', 'refcount-obj', self.repository_location, '124', 'xyza').strip() + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', '124', 'xyza').strip() assert output == 'object id 124 is invalid.\nobject id xyza is invalid.' def test_debug_info(self): @@ -3311,15 +3310,15 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 assert 'Python' in output def test_benchmark_crud(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') with environment_variable(_BORG_BENCHMARK_CRUD_TEST='YES'): - self.cmd('benchmark', 'crud', self.repository_location, self.input_path) + self.cmd(f'--repo={self.repository_location}', 'benchmark', 'crud', self.input_path) def test_config(self): self.create_test_files() os.unlink('input/flagfile') - self.cmd('init', '--encryption=repokey', self.repository_location) - output = self.cmd('config', '--list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + output = self.cmd(f'--repo={self.repository_location}', 'config', '--list') self.assert_in('[repository]', output) self.assert_in('version', output) self.assert_in('segments_per_dir', output) @@ -3329,30 +3328,30 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.assert_in('id', output) self.assert_not_in('last_segment_checked', output) - output = self.cmd('config', self.repository_location, 'last_segment_checked', exit_code=1) + output = self.cmd(f'--repo={self.repository_location}', 'config', 'last_segment_checked', exit_code=1) self.assert_in('No option ', output) - self.cmd('config', self.repository_location, 'last_segment_checked', '123') - output = self.cmd('config', self.repository_location, 'last_segment_checked') + self.cmd(f'--repo={self.repository_location}', 'config', 'last_segment_checked', '123') + output = self.cmd(f'--repo={self.repository_location}', 'config', 'last_segment_checked') assert output == '123' + '\n' - output = self.cmd('config', '--list', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'config', '--list') self.assert_in('last_segment_checked', output) - self.cmd('config', '--delete', self.repository_location, 'last_segment_checked') + self.cmd(f'--repo={self.repository_location}', 'config', '--delete', 'last_segment_checked') for cfg_key, cfg_value in [ ('additional_free_space', '2G'), ('repository.append_only', '1'), ]: - output = self.cmd('config', self.repository_location, cfg_key) + output = self.cmd(f'--repo={self.repository_location}', 'config', cfg_key) assert output == '0' + '\n' - self.cmd('config', self.repository_location, cfg_key, cfg_value) - output = self.cmd('config', self.repository_location, cfg_key) + self.cmd(f'--repo={self.repository_location}', 'config', cfg_key, cfg_value) + output = self.cmd(f'--repo={self.repository_location}', 'config', cfg_key) assert output == cfg_value + '\n' - self.cmd('config', '--delete', self.repository_location, cfg_key) - self.cmd('config', self.repository_location, cfg_key, exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'config', '--delete', cfg_key) + self.cmd(f'--repo={self.repository_location}', 'config', cfg_key, exit_code=1) - self.cmd('config', '--list', '--delete', self.repository_location, exit_code=2) - self.cmd('config', self.repository_location, exit_code=2) - self.cmd('config', self.repository_location, 'invalid-option', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'config', '--list', '--delete', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'config', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'config', 'invalid-option', exit_code=1) requires_gnutar = pytest.mark.skipif(not have_gnutar(), reason='GNU tar must be installed for this test.') requires_gzip = pytest.mark.skipif(not shutil.which('gzip'), reason='gzip must be installed for this test.') @@ -3361,9 +3360,9 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_export_tar(self): self.create_test_files() os.unlink('input/flagfile') - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - self.cmd('export-tar', self.repository_location + '::test', 'simple.tar', '--progress', '--tar-format=GNU') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'simple.tar', '--progress', '--tar-format=GNU') with changedir('output'): # This probably assumes GNU tar. Note -p switch to extract permissions regardless of umask. subprocess.check_call(['tar', 'xpf', '../simple.tar', '--warning=no-timestamp']) @@ -3376,9 +3375,9 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 pytest.skip('gzip is not installed') self.create_test_files() os.unlink('input/flagfile') - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - list = self.cmd('export-tar', self.repository_location + '::test', 'simple.tar.gz', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + list = self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'simple.tar.gz', '--list', '--tar-format=GNU') assert 'input/file1\n' in list assert 'input/dir2\n' in list @@ -3392,9 +3391,9 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 pytest.skip('gzip is not installed') self.create_test_files() os.unlink('input/flagfile') - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') - list = self.cmd('export-tar', self.repository_location + '::test', 'simple.tar', + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + list = self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'simple.tar', '--strip-components=1', '--list', '--tar-format=GNU') # --list's path are those before processing with --strip-components assert 'input/file1\n' in list @@ -3407,7 +3406,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 @requires_gnutar def test_export_tar_strip_components_links(self): self._extract_hardlinks_setup() - self.cmd('export-tar', self.repository_location + '::test', 'output.tar', + self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'output.tar', '--strip-components=2', '--tar-format=GNU') with changedir('output'): subprocess.check_call(['tar', 'xpf', '../output.tar', '--warning=no-timestamp']) @@ -3420,7 +3419,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 @requires_gnutar def test_extract_hardlinks_tar(self): self._extract_hardlinks_setup() - self.cmd('export-tar', self.repository_location + '::test', 'output.tar', 'input/dir1', '--tar-format=GNU') + self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'output.tar', 'input/dir1', '--tar-format=GNU') with changedir('output'): subprocess.check_call(['tar', 'xpf', '../output.tar', '--warning=no-timestamp']) assert os.stat('input/dir1/hardlink').st_nlink == 2 @@ -3431,12 +3430,12 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_import_tar(self, tar_format='PAX'): self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') - self.cmd('init', '--encryption=none', self.repository_location) - self.cmd('create', self.repository_location + '::src', 'input') - self.cmd('export-tar', self.repository_location + '::src', 'simple.tar', f'--tar-format={tar_format}') - self.cmd('import-tar', self.repository_location + '::dst', 'simple.tar') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}::src', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::src', 'export-tar', 'simple.tar', f'--tar-format={tar_format}') + self.cmd(f'--repo={self.repository_location}::dst', 'import-tar', 'simple.tar') with changedir(self.output_path): - self.cmd('extract', self.repository_location + '::dst') + self.cmd(f'--repo={self.repository_location}::dst', 'extract') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) @requires_gzip @@ -3445,22 +3444,22 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 pytest.skip('gzip is not installed') self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') - self.cmd('init', '--encryption=none', self.repository_location) - self.cmd('create', self.repository_location + '::src', 'input') - self.cmd('export-tar', self.repository_location + '::src', 'simple.tgz', f'--tar-format={tar_format}') - self.cmd('import-tar', self.repository_location + '::dst', 'simple.tgz') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}::src', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::src', 'export-tar', 'simple.tgz', f'--tar-format={tar_format}') + self.cmd(f'--repo={self.repository_location}::dst', 'import-tar', 'simple.tgz') with changedir(self.output_path): - self.cmd('extract', self.repository_location + '::dst') + self.cmd(f'--repo={self.repository_location}::dst', 'extract') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) def test_roundtrip_pax_borg(self): self.create_test_files() - self.cmd('init', '--encryption=none', self.repository_location) - self.cmd('create', self.repository_location + '::src', 'input') - self.cmd('export-tar', self.repository_location + '::src', 'simple.tar', '--tar-format=BORG') - self.cmd('import-tar', self.repository_location + '::dst', 'simple.tar') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}::src', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::src', 'export-tar', 'simple.tar', '--tar-format=BORG') + self.cmd(f'--repo={self.repository_location}::dst', 'import-tar', 'simple.tar') with changedir(self.output_path): - self.cmd('extract', self.repository_location + '::dst') + self.cmd(f'--repo={self.repository_location}::dst', 'extract') self.assert_dirs_equal('input', 'output/input') # derived from test_extract_xattrs_errors() @@ -3489,16 +3488,16 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.makedirs(os.path.join(self.input_path, 'dir%p')) xattr.setxattr(b'input/dir%p', b'user.attribute', b'value') - self.cmd('init', self.repository_location, '-e' 'none') - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) def test_do_not_mention_archive_if_you_can_not_find_repo(self): """https://github.com/borgbackup/borg/issues/6014""" - archive = self.repository_location + '-this-repository-does-not-exist' + '::test' - output = self.cmd('info', archive, exit_code=2, fork=True) + output = self.cmd(f'--repo={self.repository_location}-this-repository-does-not-exist::test', 'info', + exit_code=2, fork=True) self.assert_in('this-repository-does-not-exist', output) self.assert_not_in('this-repository-does-not-exist::test', output) @@ -3508,8 +3507,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 It should be possible to retrieve the data from an archive even if both the client and the server forget the nonce""" self.create_regular_file('file1', contents=b'Hello, borg') - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 os.remove(os.path.join(self.repository_path, 'nonce')) @@ -3517,18 +3516,18 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.remove(os.path.join(self.get_security_dir(), 'nonce')) # The repo should still be readable - repo_info = self.cmd('info', self.repository_location) + repo_info = self.cmd(f'--repo={self.repository_location}', 'info') assert 'All archives:' in repo_info - repo_list = self.cmd('list', self.repository_location) + repo_list = self.cmd(f'--repo={self.repository_location}', 'list') assert 'test' in repo_list # The archive should still be readable - archive_info = self.cmd('info', self.repository_location + '::test') + archive_info = self.cmd(f'--repo={self.repository_location}::test', 'info') assert 'Archive name: test\n' in archive_info - archive_list = self.cmd('list', self.repository_location + '::test') + archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list') assert 'file1' in archive_list # Extracting the archive should work with changedir('output'): - self.cmd('extract', self.repository_location + '::test') + self.cmd(f'--repo={self.repository_location}::test', 'extract') self.assert_dirs_equal('input', 'output/input') def test_recovery_from_deleted_repo_nonce(self): @@ -3539,35 +3538,35 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 repo. Otherwise we can just use our own copy of the nonce. """ self.create_regular_file('file1', contents=b'Hello, borg') - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 nonce = os.path.join(self.repository_path, 'nonce') os.remove(nonce) - self.cmd('create', self.repository_location + '::test2', 'input') + self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') assert os.path.exists(nonce) def test_init_defaults_to_argon2(self): """https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401""" - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') with Repository(self.repository_path) as repository: key = msgpack.unpackb(a2b_base64(repository.load_key())) assert key['algorithm'] == 'argon2 chacha20-poly1305' def test_init_with_explicit_key_algorithm(self): """https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401""" - self.cmd('init', '--encryption=repokey', '--key-algorithm=pbkdf2', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--key-algorithm=pbkdf2') with Repository(self.repository_path) as repository: key = msgpack.unpackb(a2b_base64(repository.load_key())) assert key['algorithm'] == 'sha256' def verify_change_passphrase_does_not_change_algorithm(self, given_algorithm, expected_algorithm): - self.cmd('init', '--encryption=repokey', '--key-algorithm', given_algorithm, self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--key-algorithm', given_algorithm) os.environ['BORG_NEW_PASSPHRASE'] = 'newpassphrase' - self.cmd('key', 'change-passphrase', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'key', 'change-passphrase') with Repository(self.repository_path) as repository: key = msgpack.unpackb(a2b_base64(repository.load_key())) @@ -3580,9 +3579,9 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.verify_change_passphrase_does_not_change_algorithm('pbkdf2', 'sha256') def verify_change_location_does_not_change_algorithm(self, given_algorithm, expected_algorithm): - self.cmd('init', '--encryption=keyfile', '--key-algorithm', given_algorithm, self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile', '--key-algorithm', given_algorithm) - self.cmd('key', 'change-location', self.repository_location, 'repokey') + self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') with Repository(self.repository_path) as repository: key = msgpack.unpackb(a2b_base64(repository.load_key())) @@ -3595,14 +3594,14 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.verify_change_location_does_not_change_algorithm('pbkdf2', 'sha256') def test_key_change_algorithm(self): - self.cmd('init', '--encryption=repokey', '--key-algorithm=pbkdf2', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--key-algorithm=pbkdf2') - self.cmd('key', 'change-algorithm', self.repository_location, 'argon2') + self.cmd(f'--repo={self.repository_location}', 'key', 'change-algorithm', 'argon2') with Repository(self.repository_path) as repository: _, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) assert key._encrypted_key_algorithm == 'argon2 chacha20-poly1305' - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') @unittest.skipUnless('binary' in BORG_EXES, 'no borg.exe available') @@ -3654,30 +3653,30 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): def setUp(self): super().setUp() with patch.object(ChunkBuffer, 'BUFFER_SIZE', 10): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('archive1') self.create_src_archive('archive2') def test_check_usage(self): - output = self.cmd('check', '-v', '--progress', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--progress', exit_code=0) self.assert_in('Starting repository check', output) self.assert_in('Starting archive consistency check', output) self.assert_in('Checking segments', output) # reset logging to new process default to avoid need for fork=True on next check logging.getLogger('borg.output.progress').setLevel(logging.NOTSET) - output = self.cmd('check', '-v', '--repository-only', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--repository-only', exit_code=0) self.assert_in('Starting repository check', output) self.assert_not_in('Starting archive consistency check', output) self.assert_not_in('Checking segments', output) - output = self.cmd('check', '-v', '--archives-only', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', exit_code=0) self.assert_not_in('Starting repository check', output) self.assert_in('Starting archive consistency check', output) - output = self.cmd('check', '-v', '--archives-only', '--prefix=archive2', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', '--prefix=archive2', exit_code=0) self.assert_not_in('archive1', output) - output = self.cmd('check', '-v', '--archives-only', '--first=1', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', '--first=1', exit_code=0) self.assert_in('archive1', output) self.assert_not_in('archive2', output) - output = self.cmd('check', '-v', '--archives-only', '--last=1', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--archives-only', '--last=1', exit_code=0) self.assert_not_in('archive1', output) self.assert_in('archive2', output) @@ -3693,11 +3692,11 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): else: self.fail('should not happen') repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - output = self.cmd('check', '--repair', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + output = self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) self.assert_in('New missing file chunk detected', output) - self.cmd('check', self.repository_location, exit_code=0) - output = self.cmd('list', '--format={health}#{path}{LF}', self.repository_location + '::archive1', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}::archive1', 'list', '--format={health}#{path}{LF}', exit_code=0) self.assert_in('broken#', output) # check that the file in the old archives has now a different chunk list without the killed chunk for archive_name in ('archive1', 'archive2'): @@ -3714,7 +3713,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): with patch.object(ChunkBuffer, 'BUFFER_SIZE', 10): self.create_src_archive('archive3') # check should be able to heal the file now: - output = self.cmd('check', '-v', '--repair', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--repair', exit_code=0) self.assert_in('Healed previously missing file chunk', output) self.assert_in('testsuite/archiver.py: Completely healed previously damaged file!', output) # check that the file in the old archives has the correct chunks again @@ -3728,7 +3727,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): else: self.fail('should not happen') # list is also all-healthy again - output = self.cmd('list', '--format={health}#{path}{LF}', self.repository_location + '::archive1', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}::archive1', 'list', '--format={health}#{path}{LF}', exit_code=0) self.assert_not_in('broken#', output) def test_missing_archive_item_chunk(self): @@ -3736,29 +3735,29 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): with repository: repository.delete(archive.metadata.items[0]) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - self.cmd('check', '--repair', self.repository_location, exit_code=0) - self.cmd('check', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) def test_missing_archive_metadata(self): archive, repository = self.open_archive('archive1') with repository: repository.delete(archive.id) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - self.cmd('check', '--repair', self.repository_location, exit_code=0) - self.cmd('check', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) def test_missing_manifest(self): archive, repository = self.open_archive('archive1') with repository: repository.delete(Manifest.MANIFEST_ID) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - output = self.cmd('check', '-v', '--repair', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--repair', exit_code=0) self.assert_in('archive1', output) self.assert_in('archive2', output) - self.cmd('check', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) def test_corrupted_manifest(self): archive, repository = self.open_archive('archive1') @@ -3767,11 +3766,11 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): corrupted_manifest = manifest + b'corrupted!' repository.put(Manifest.MANIFEST_ID, corrupted_manifest) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - output = self.cmd('check', '-v', '--repair', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--repair', exit_code=0) self.assert_in('archive1', output) self.assert_in('archive2', output) - self.cmd('check', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) def test_manifest_rebuild_corrupted_chunk(self): archive, repository = self.open_archive('archive1') @@ -3784,10 +3783,10 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): corrupted_chunk = chunk + b'corrupted!' repository.put(archive.id, corrupted_chunk) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - output = self.cmd('check', '-v', '--repair', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + output = self.cmd(f'--repo={self.repository_location}', 'check', '-v', '--repair', exit_code=0) self.assert_in('archive2', output) - self.cmd('check', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) def test_manifest_rebuild_duplicate_archive(self): archive, repository = self.open_archive('archive1') @@ -3809,27 +3808,27 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): archive_id = key.id_hash(archive) repository.put(archive_id, key.encrypt(archive_id, archive)) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - self.cmd('check', '--repair', self.repository_location, exit_code=0) - output = self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_in('archive1', output) self.assert_in('archive1.1', output) self.assert_in('archive2', output) def test_extra_chunks(self): - self.cmd('check', self.repository_location, exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) with Repository(self.repository_location, exclusive=True) as repository: repository.put(b'01234567890123456789012345678901', b'xxxx') repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) - self.cmd('check', self.repository_location, exit_code=1) - self.cmd('check', '--repair', self.repository_location, exit_code=0) - self.cmd('check', self.repository_location, exit_code=0) - self.cmd('extract', '--dry-run', self.repository_location + '::archive1', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) + self.cmd(f'--repo={self.repository_location}::archive1', 'extract', '--dry-run', exit_code=0) def _test_verify_data(self, *init_args): shutil.rmtree(self.repository_path) - self.cmd('init', self.repository_location, *init_args) + self.cmd(f'--repo={self.repository_location}', 'init', *init_args) self.create_src_archive('archive1') archive, repository = self.open_archive('archive1') with repository: @@ -3840,11 +3839,11 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): repository.put(chunk.id, data) break repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=0) - output = self.cmd('check', '--verify-data', self.repository_location, exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '--verify-data', exit_code=1) assert bin_to_hex(chunk.id) + ', integrity error' in output # repair (heal is tested in another test) - output = self.cmd('check', '--repair', '--verify-data', self.repository_location, exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'check', '--repair', '--verify-data', exit_code=0) assert bin_to_hex(chunk.id) + ', integrity error' in output assert 'testsuite/archiver.py: New missing file chunk detected' in output @@ -3859,7 +3858,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): for id_ in repository.list(): repository.delete(id_) repository.commit(compact=False) - self.cmd('check', self.repository_location, exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) class ManifestAuthenticationTest(ArchiverTestCaseBase): @@ -3875,7 +3874,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): repository.commit(compact=False) def test_fresh_init_tam_required(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository = Repository(self.repository_path, exclusive=True) with repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -3887,10 +3886,10 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): repository.commit(compact=False) with pytest.raises(TAMRequiredError): - self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'list') def test_not_required(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('archive1234') repository = Repository(self.repository_path, exclusive=True) with repository: @@ -3903,39 +3902,39 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): del manifest['tam'] repository.put(Manifest.MANIFEST_ID, key.encrypt(Manifest.MANIFEST_ID, msgpack.packb(manifest))) repository.commit(compact=False) - output = self.cmd('list', '--debug', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--debug') assert 'archive1234' in output assert 'TAM not found and not required' in output # Run upgrade - self.cmd('upgrade', '--tam', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'upgrade', '--tam') # Manifest must be authenticated now - output = self.cmd('list', '--debug', self.repository_location) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--debug') assert 'archive1234' in output assert 'TAM-verified manifest' in output # Try to spoof / modify pre-1.0.9 self.spoof_manifest(repository) # Fails with pytest.raises(TAMRequiredError): - self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'list') # Force upgrade - self.cmd('upgrade', '--tam', '--force', self.repository_location) - self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'upgrade', '--tam', '--force') + self.cmd(f'--repo={self.repository_location}', 'list') def test_disable(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('archive1234') - self.cmd('upgrade', '--disable-tam', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'upgrade', '--disable-tam') repository = Repository(self.repository_path, exclusive=True) self.spoof_manifest(repository) - assert not self.cmd('list', self.repository_location) + assert not self.cmd(f'--repo={self.repository_location}', 'list') def test_disable2(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('archive1234') repository = Repository(self.repository_path, exclusive=True) self.spoof_manifest(repository) - self.cmd('upgrade', '--disable-tam', self.repository_location) - assert not self.cmd('list', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'upgrade', '--disable-tam') + assert not self.cmd(f'--repo={self.repository_location}', 'list') class RemoteArchiverTestCase(ArchiverTestCase): @@ -3947,32 +3946,32 @@ class RemoteArchiverTestCase(ArchiverTestCase): def test_remote_repo_restrict_to_path(self): # restricted to repo directory itself: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', self.repository_path]): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # restricted to repo directory itself, fail for other directories with same prefix: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', self.repository_path]): with pytest.raises(PathNotAllowed): - self.cmd('init', '--encryption=repokey', self.repository_location + '_0') + self.cmd(f'--repo={self.repository_location}_0', 'init', '--encryption=repokey') # restricted to a completely different path: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', '/foo']): with pytest.raises(PathNotAllowed): - self.cmd('init', '--encryption=repokey', self.repository_location + '_1') + self.cmd(f'--repo={self.repository_location}_1', 'init', '--encryption=repokey') path_prefix = os.path.dirname(self.repository_path) # restrict to repo directory's parent directory: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', path_prefix]): - self.cmd('init', '--encryption=repokey', self.repository_location + '_2') + self.cmd(f'--repo={self.repository_location}_2', 'init', '--encryption=repokey') # restrict to repo directory's parent directory and another directory: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', '/foo', '--restrict-to-path', path_prefix]): - self.cmd('init', '--encryption=repokey', self.repository_location + '_3') + self.cmd(f'--repo={self.repository_location}_3', 'init', '--encryption=repokey') def test_remote_repo_restrict_to_repository(self): # restricted to repo directory itself: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-repository', self.repository_path]): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') parent_path = os.path.join(self.repository_path, '..') with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-repository', parent_path]): with pytest.raises(PathNotAllowed): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @unittest.skip('only works locally') def test_debug_put_get_delete_obj(self): @@ -3987,25 +3986,25 @@ class RemoteArchiverTestCase(ArchiverTestCase): pass def test_remote_repo_strip_components_doesnt_leak(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir/file', contents=b"test file contents 1") self.create_regular_file('dir/file2', contents=b"test file contents 2") self.create_regular_file('skipped-file1', contents=b"test file contents 3") self.create_regular_file('skipped-file2', contents=b"test file contents 4") self.create_regular_file('skipped-file3', contents=b"test file contents 5") - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') marker = 'cached responses left in RemoteRepository' with changedir('output'): - res = self.cmd('extract', "--debug", self.repository_location + '::test', '--strip-components', '3') + res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '3') assert marker not in res with self.assert_creates_file('file'): - res = self.cmd('extract', "--debug", self.repository_location + '::test', '--strip-components', '2') + res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '2') assert marker not in res with self.assert_creates_file('dir/file'): - res = self.cmd('extract', "--debug", self.repository_location + '::test', '--strip-components', '1') + res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '1') assert marker not in res with self.assert_creates_file('input/dir/file'): - res = self.cmd('extract', "--debug", self.repository_location + '::test', '--strip-components', '0') + res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '0') assert marker not in res @@ -4013,8 +4012,8 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): def setUp(self): super().setUp() self.create_test_files() - self.cmd('init', '--encryption=repokey', self.repository_location) - self.cache_path = json.loads(self.cmd('info', self.repository_location, '--json'))['cache']['path'] + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cache_path = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json'))['cache']['path'] def corrupt(self, file, amount=1): with open(file, 'r+b') as fd: @@ -4027,28 +4026,28 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): self.corrupt(os.path.join(self.cache_path, 'chunks')) if self.FORK_DEFAULT: - out = self.cmd('info', self.repository_location, exit_code=2) + out = self.cmd(f'--repo={self.repository_location}', 'info', exit_code=2) assert 'failed integrity check' in out else: with pytest.raises(FileIntegrityError): - self.cmd('info', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'info') def test_cache_files(self): - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') self.corrupt(os.path.join(self.cache_path, 'files')) - out = self.cmd('create', self.repository_location + '::test1', 'input') + out = self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') # borg warns about the corrupt files cache, but then continues without files cache. assert 'files cache is corrupted' in out def test_chunks_archive(self): - self.cmd('create', self.repository_location + '::test1', 'input') + self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') # Find ID of test1 so we can corrupt it later :) - target_id = self.cmd('list', self.repository_location, '--format={id}{LF}').strip() - self.cmd('create', self.repository_location + '::test2', 'input') + target_id = self.cmd(f'--repo={self.repository_location}', 'list', '--format={id}{LF}').strip() + self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') # Force cache sync, creating archive chunks of test1 and test2 in chunks.archive.d - self.cmd('delete', '--cache-only', self.repository_location) - self.cmd('info', self.repository_location, '--json') + self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'info', '--json') chunks_archive = os.path.join(self.cache_path, 'chunks.archive.d') assert len(os.listdir(chunks_archive)) == 4 # two archives, one chunks cache and one .integrity file each @@ -4064,7 +4063,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): config.write(fd) # Cache sync notices corrupted archive chunks, but automatically recovers. - out = self.cmd('create', '-v', self.repository_location + '::test3', 'input', exit_code=1) + out = self.cmd(f'--repo={self.repository_location}::test3', 'create', '-v', 'input', exit_code=1) assert 'Reading cached archive chunk index for test1' in out assert 'Cached archive chunk index of test1 is corrupted' in out assert 'Fetching and building archive index for test1' in out @@ -4079,7 +4078,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): with open(config_path, 'w') as fd: config.write(fd) - out = self.cmd('info', self.repository_location) + out = self.cmd(f'--repo={self.repository_location}', 'info') assert 'Cache integrity data not available: old Borg version modified the cache.' in out @@ -4107,10 +4106,10 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): os.link('input/file_removed', 'input/hardlink_removed') os.link('input/file_removed2', 'input/hardlink_target_removed') - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Create the first snapshot - self.cmd('create', self.repository_location + '::test0', 'input') + self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') # Setup files for the second snapshot self.create_regular_file('file_added', size=2048) @@ -4141,8 +4140,8 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): fd.write(b'appended_data') # Create the second snapshot - self.cmd('create', self.repository_location + '::test1a', 'input') - self.cmd('create', '--chunker-params', '16,18,17,4095', self.repository_location + '::test1b', 'input') + self.cmd(f'--repo={self.repository_location}::test1a', 'create', 'input') + self.cmd(f'--repo={self.repository_location}::test1b', 'create', '--chunker-params', '16,18,17,4095', 'input') def do_asserts(output, can_compare_ids): # File contents changed (deleted and replaced with a new file) @@ -4287,19 +4286,19 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): if are_hardlinks_supported(): assert not any(get_changes('input/hardlink_target_replaced', joutput)) - do_asserts(self.cmd('diff', self.repository_location + '::test0', 'test1a'), True) + do_asserts(self.cmd(f'--repo={self.repository_location}::test0', 'diff', 'TODO_test0', 'test1a'), True) # We expect exit_code=1 due to the chunker params warning - do_asserts(self.cmd('diff', self.repository_location + '::test0', 'test1b', exit_code=1), False) - do_json_asserts(self.cmd('diff', self.repository_location + '::test0', 'test1a', '--json-lines'), True) + do_asserts(self.cmd(f'--repo={self.repository_location}::test0', 'diff', 'TODO_test0', 'test1b', exit_code=1), False) + do_json_asserts(self.cmd(f'--repo={self.repository_location}::test0', 'diff', 'TODO_test0', 'test1a', '--json-lines'), True) def test_sort_option(self): - self.cmd('init', '--encryption=repokey', self.repository_location) + self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('a_file_removed', size=8) self.create_regular_file('f_file_removed', size=16) self.create_regular_file('c_file_changed', size=32) self.create_regular_file('e_file_changed', size=64) - self.cmd('create', self.repository_location + '::test0', 'input') + self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') os.unlink('input/a_file_removed') os.unlink('input/f_file_removed') @@ -4309,9 +4308,9 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('e_file_changed', size=1024) self.create_regular_file('b_file_added', size=128) self.create_regular_file('d_file_added', size=256) - self.cmd('create', self.repository_location + '::test1', 'input') + self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') - output = self.cmd('diff', '--sort', self.repository_location + '::test0', 'test1') + output = self.cmd(f'--repo={self.repository_location}::test0', 'diff', '--sort', 'TODO_test0', 'test1') expected = [ 'a_file_removed', 'b_file_added', @@ -4353,7 +4352,7 @@ def test_get_args(): assert args.restrict_to_repositories == ['/r1', '/r2'] # trying to cheat - try to execute different subcommand args = archiver.get_args(['borg', 'serve', '--restrict-to-path=/p1', '--restrict-to-path=/p2', ], - 'borg init --encryption=repokey /') + 'borg --repo=/ init --encryption=repokey') assert args.func == archiver.do_serve # Check that environment variables in the forced command don't cause issues. If the command From 1bf2a6a2409f41bb71ab4473fa79c5ef89d85759 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 15 Jun 2022 17:07:42 +0200 Subject: [PATCH 02/21] remove archive checks from location_validator, use --other-repo --- src/borg/archiver.py | 19 ++++++++----------- src/borg/helpers/parseformat.py | 6 +----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 0e2d07855..cea035ab0 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -4143,12 +4143,12 @@ class Archiver: # initialize DST_REPO reusing key material from SRC_REPO, so that # chunking and chunk id generation will work in the same way as before. - borg init --other-location=SRC_REPO --encryption=DST_ENC DST_REPO + borg --repo=DST_REPO init --other-repo=SRC_REPO --encryption=DST_ENC # transfer archives from SRC_REPO to DST_REPO - borg transfer --dry-run SRC_REPO DST_REPO # check what it would do - borg transfer SRC_REPO DST_REPO # do it! - borg transfer --dry-run SRC_REPO DST_REPO # check! anything left? + borg --repo=DST_REPO transfer --other-repo=SRC_REPO --dry-run # check what it would do + borg --repo=DST_REPO transfer --other-repo=SRC_REPO # do it! + borg --repo=DST_REPO transfer --other-repo=SRC_REPO --dry-run # check! anything left? The default is to transfer all archives, including checkpoint archives. @@ -4164,12 +4164,9 @@ class Archiver: subparser.set_defaults(func=self.do_transfer) subparser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true', help='do not change repository, just check') - subparser.add_argument('other_location', metavar='SRC_REPOSITORY', - type=location_validator(archive=False, other=True), + subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location', + type=location_validator(other=True), help='source repository') - # subparser.add_argument('-r', '--repo', dest='location', metavar='DST_REPOSITORY', - # type=location_validator(archive=False, other=False), - # help='destination repository') define_archive_filters_group(subparser) # borg diff @@ -4504,8 +4501,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='initialize empty repository') subparser.set_defaults(func=self.do_init) - subparser.add_argument('--other-location', metavar='OTHER_REPOSITORY', dest='other_location', - type=location_validator(archive=False, other=True), + subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location', + type=location_validator(other=True), help='reuse the key material from the other repository') subparser.add_argument('-e', '--encryption', metavar='MODE', dest='encryption', required=True, choices=key_argument_names(), diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index 43e8d05eb..e4b54f0c8 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -507,16 +507,12 @@ class Location: return loc -def location_validator(archive=None, proto=None, other=False): +def location_validator(proto=None, other=False): def validator(text): try: loc = Location(text, other=other) except ValueError as err: raise argparse.ArgumentTypeError(str(err)) from None - if archive is True and not loc.archive: - raise argparse.ArgumentTypeError('"%s": No archive specified' % text) - elif archive is False and loc.archive: - raise argparse.ArgumentTypeError('"%s": No archive can be specified' % text) if proto is not None and loc.proto != proto: if proto == 'file': raise argparse.ArgumentTypeError('"%s": Repository must be local' % text) From 0f0cd2435465a5e11fd320a4e2c21bc40ee9e254 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 15 Jun 2022 17:44:38 +0200 Subject: [PATCH 03/21] if --(other-)repo option is not given, use default from environment remove tests composing a repo+archive location with repo from env and location from cli. --- src/borg/archiver.py | 17 ++++--- src/borg/helpers/parseformat.py | 45 ++++++++----------- src/borg/testsuite/helpers.py | 80 --------------------------------- 3 files changed, 29 insertions(+), 113 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index cea035ab0..1b668f618 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -174,8 +174,10 @@ def with_repository(fake=False, invert_fake=False, create=False, lock=True, def decorator(method): @functools.wraps(method) def wrapper(self, args, **kwargs): + location = getattr(args, 'location') + if not location.valid: # location always must be given + raise Error('missing repository, please use --repo or BORG_REPO env var!') lock = getattr(args, 'lock', _lock) - location = args.location # note: 'location' must be always present in args append_only = getattr(args, 'append_only', False) storage_quota = getattr(args, 'storage_quota', None) make_parent_dirs = getattr(args, 'make_parent_dirs', False) @@ -220,8 +222,8 @@ def with_other_repository(manifest=False, key=False, cache=False, compatibility= def decorator(method): @functools.wraps(method) def wrapper(self, args, **kwargs): - location = getattr(args, 'other_location', None) - if location is None: # nothing to do + location = getattr(args, 'other_location') + if not location.valid: # nothing to do return method(self, args, **kwargs) repository = get_repository(location, create=False, exclusive=True, @@ -3203,8 +3205,9 @@ class Archiver: 'compatible file can be generated by suffixing FILE with ".pyprof".') add_common_option('--rsh', metavar='RSH', dest='rsh', help="Use this command to connect to the 'borg serve' process (default: 'ssh')") - add_common_option('--repo', metavar='REPO', dest='location', type=location_validator(), - help="repository to use") # XXXYYY + add_common_option('--repo', metavar='REPO', dest='location', + type=location_validator(other=False), default=Location(other=False), + help="repository to use") def define_exclude_and_patterns(add_option, *, tag_files=False, strip_components=False): add_option('-e', '--exclude', metavar='PATTERN', dest='patterns', @@ -4165,7 +4168,7 @@ class Archiver: subparser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true', help='do not change repository, just check') subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location', - type=location_validator(other=True), + type=location_validator(other=True), default=Location(other=True), help='source repository') define_archive_filters_group(subparser) @@ -4502,7 +4505,7 @@ class Archiver: help='initialize empty repository') subparser.set_defaults(func=self.do_init) subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location', - type=location_validator(other=True), + type=location_validator(other=True), default=Location(other=True), help='reuse the key material from the other repository') subparser.add_argument('-e', '--encryption', metavar='MODE', dest='encryption', required=True, choices=key_argument_names(), diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index e4b54f0c8..7c25437b0 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -365,15 +365,6 @@ class Location: local_re = re.compile( local_path_re + optional_archive_re, re.VERBOSE) # local path with optional archive - # get the repo from BORG_REPO env and the optional archive from param. - # if the syntax requires giving REPOSITORY (see "borg mount"), - # use "::" to let it use the env var. - # if REPOSITORY argument is optional, it'll automatically use the env. - env_re = re.compile(r""" # the repo part is fetched from BORG_REPO - (?:::$) # just "::" is ok (when a pos. arg is required, no archive) - | # or - """ + optional_archive_re, re.VERBOSE) # archive name (optional, may be empty) - win_file_re = re.compile(r""" (?:file://)? # optional file protocol (?P @@ -384,27 +375,29 @@ class Location: def __init__(self, text='', overrides={}, other=False): self.repo_env_var = 'BORG_OTHER_REPO' if other else 'BORG_REPO' - if not self.parse(text, overrides): - raise ValueError('Invalid location format: "%s"' % self.processed) + self.valid = False + self.proto = None + self.user = None + self._host = None + self.port = None + self.path = None + self.archive = None + self.parse(text, overrides) def parse(self, text, overrides={}): + if not text: + # we did not get a text to parse, so we try to fetch from the environment + text = os.environ.get(self.repo_env_var) + if text is None: + return + self.raw = text # as given by user, might contain placeholders - self.processed = text = replace_placeholders(text, overrides) # after placeholder replacement - valid = self._parse(text) + self.processed = replace_placeholders(self.raw, overrides) # after placeholder replacement + valid = self._parse(self.processed) if valid: - return True - m = self.env_re.match(text) - if not m: - return False - repo_raw = os.environ.get(self.repo_env_var) - if repo_raw is None: - return False - repo = replace_placeholders(repo_raw, overrides) - valid = self._parse(repo) - self.archive = m.group('archive') - self.raw = repo_raw if not self.archive else repo_raw + self.raw - self.processed = repo if not self.archive else f'{repo}::{self.archive}' - return valid + self.valid = True + else: + raise ValueError('Invalid location format: "%s"' % self.processed) def _parse(self, text): def normpath_special(p): diff --git a/src/borg/testsuite/helpers.py b/src/borg/testsuite/helpers.py index fd0414116..81469a133 100644 --- a/src/borg/testsuite/helpers.py +++ b/src/borg/testsuite/helpers.py @@ -166,15 +166,6 @@ class TestLocationWithoutEnv: assert repr(Location('path::archive-{utcnow}').with_timestamp(datetime(2002, 9, 19, tzinfo=timezone.utc))) == \ "Location(proto='file', user=None, host=None, port=None, path='path', archive='archive-2002-09-19T00:00:00')" - def test_underspecified(self, monkeypatch): - monkeypatch.delenv('BORG_REPO', raising=False) - with pytest.raises(ValueError): - Location('::archive') - with pytest.raises(ValueError): - Location('::') - with pytest.raises(ValueError): - Location() - def test_no_slashes(self, monkeypatch): monkeypatch.delenv('BORG_REPO', raising=False) with pytest.raises(ValueError): @@ -213,77 +204,6 @@ class TestLocationWithoutEnv: assert loc_without_archive.processed == "ssh://user@host:1234/repos/%s" % hostname -class TestLocationWithEnv: - def test_ssh(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', 'ssh://user@host:1234/some/path') - assert repr(Location('::archive')) == \ - "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive='archive')" - assert repr(Location('::')) == \ - "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive=None)" - assert repr(Location()) == \ - "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive=None)" - - def test_ssh_placeholder(self, monkeypatch): - from borg.platform import hostname - monkeypatch.setenv('BORG_REPO', 'ssh://user@host:1234/{hostname}') - assert repr(Location('::archive')) == \ - f"Location(proto='ssh', user='user', host='host', port=1234, path='/{hostname}', archive='archive')" - assert repr(Location('::')) == \ - f"Location(proto='ssh', user='user', host='host', port=1234, path='/{hostname}', archive=None)" - assert repr(Location()) == \ - f"Location(proto='ssh', user='user', host='host', port=1234, path='/{hostname}', archive=None)" - - def test_file(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', 'file:///some/path') - assert repr(Location('::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive='archive')" - assert repr(Location('::')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive=None)" - assert repr(Location()) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive=None)" - - def test_folder(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', 'path') - assert repr(Location('::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='path', archive='archive')" - assert repr(Location('::')) == \ - "Location(proto='file', user=None, host=None, port=None, path='path', archive=None)" - assert repr(Location()) == \ - "Location(proto='file', user=None, host=None, port=None, path='path', archive=None)" - - def test_abspath(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', '/some/absolute/path') - assert repr(Location('::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive='archive')" - assert repr(Location('::')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive=None)" - assert repr(Location()) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive=None)" - - def test_relpath(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', 'some/relative/path') - assert repr(Location('::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive='archive')" - assert repr(Location('::')) == \ - "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive=None)" - assert repr(Location()) == \ - "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive=None)" - - def test_with_colons(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', '/abs/path:w:cols') - assert repr(Location('::arch:col')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive='arch:col')" - assert repr(Location('::')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive=None)" - assert repr(Location()) == \ - "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive=None)" - - def test_no_slashes(self, monkeypatch): - monkeypatch.setenv('BORG_REPO', '/some/absolute/path') - with pytest.raises(ValueError): - Location('::archive_name_with/slashes/is_invalid') - - class FormatTimedeltaTestCase(BaseTestCase): def test(self): From 281bbbc16bafd6f2e8dff81ce8d1c704408f42ed Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 15 Jun 2022 19:00:19 +0200 Subject: [PATCH 04/21] fix tests and benchmarks --- src/borg/archiver.py | 106 +++-- src/borg/fuse.py | 4 +- src/borg/helpers/manifest.py | 2 +- src/borg/helpers/parseformat.py | 2 + src/borg/testsuite/archiver.py | 773 ++++++++++++++++---------------- src/borg/testsuite/benchmark.py | 42 +- 6 files changed, 477 insertions(+), 452 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 1b668f618..2e112fafe 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -52,7 +52,7 @@ try: from .helpers import EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR, EXIT_SIGNAL_BASE from .helpers import Error, NoManifestError, set_ec from .helpers import positive_int_validator, location_validator, archivename_validator, ChunkerParams, Location - from .helpers import PrefixSpec, GlobSpec, CommentSpec, SortBySpec, FilesCacheMode + from .helpers import PrefixSpec, GlobSpec, NameSpec, CommentSpec, SortBySpec, FilesCacheMode from .helpers import BaseFormatter, ItemFormatter, ArchiveFormatter from .helpers import format_timedelta, format_file_size, parse_file_size, format_archive from .helpers import remove_surrogates, bin_to_hex, prepare_dump_dict, eval_escapes @@ -257,7 +257,9 @@ def with_other_repository(manifest=False, key=False, cache=False, compatibility= def with_archive(method): @functools.wraps(method) def wrapper(self, args, repository, key, manifest, **kwargs): - archive = Archive(repository, key, manifest, args.location.archive, + archive_name = getattr(args, 'name', None) + assert archive_name is not None + archive = Archive(repository, key, manifest, archive_name, numeric_ids=getattr(args, 'numeric_ids', False), noflags=getattr(args, 'nobsdflags', False) or getattr(args, 'noflags', False), noacls=getattr(args, 'noacls', False), @@ -541,7 +543,7 @@ class Archiver: if args.prefix is not None: args.glob_archives = args.prefix + '*' if not args.repo_only and not ArchiveChecker().check( - repository, repair=args.repair, archive=args.location.archive, + repository, repair=args.repair, archive=args.name, 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 @@ -669,34 +671,34 @@ class Archiver: compression = '--compression=none' # measure create perf (without files cache to always have it chunking) t_start = time.monotonic() - rc = self.do_create(self.parse_args([f'--repo={repo}::borg-benchmark-crud1', 'create', + rc = self.do_create(self.parse_args([f'--repo={repo}', 'create', '--name=borg-benchmark-crud1', compression, '--files-cache=disabled', path])) t_end = time.monotonic() dt_create = t_end - t_start assert rc == 0 # now build files cache - rc1 = self.do_create(self.parse_args([f'--repo={repo}::borg-benchmark-crud2', 'create', + rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', '--name=borg-benchmark-crud2', compression, path])) - rc2 = self.do_delete(self.parse_args([f'--repo={repo}::borg-benchmark-crud2', 'delete'])) + rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud2'])) assert rc1 == rc2 == 0 # measure a no-change update (archive1 is still present) t_start = time.monotonic() - rc1 = self.do_create(self.parse_args([f'--repo={repo}::borg-benchmark-crud3', 'create', + rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', '--name=borg-benchmark-crud3', compression, path])) t_end = time.monotonic() dt_update = t_end - t_start - rc2 = self.do_delete(self.parse_args([f'--repo={repo}::borg-benchmark-crud3', 'delete'])) + rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud3'])) assert rc1 == rc2 == 0 # measure extraction (dry-run: without writing result to disk) t_start = time.monotonic() - rc = self.do_extract(self.parse_args([f'--repo={repo}::borg-benchmark-crud1', 'extract', + rc = self.do_extract(self.parse_args([f'--repo={repo}', 'extract', '--name=borg-benchmark-crud1', '--dry-run'])) t_end = time.monotonic() dt_extract = t_end - t_start assert rc == 0 # measure archive deletion (of LAST present archive with the data) t_start = time.monotonic() - rc = self.do_delete(self.parse_args([f'--repo={repo}::borg-benchmark-crud1', 'delete'])) + rc = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud1'])) t_end = time.monotonic() dt_delete = t_end - t_start assert rc == 0 @@ -1012,7 +1014,7 @@ class Archiver: with Cache(repository, key, manifest, progress=args.progress, lock_wait=self.lock_wait, permit_adhoc_cache=args.no_cache_sync, cache_mode=args.files_cache_mode, iec=args.iec) as cache: - archive = Archive(repository, key, manifest, args.location.archive, cache=cache, + archive = Archive(repository, key, manifest, args.name, cache=cache, create=True, checkpoint_interval=args.checkpoint_interval, numeric_ids=args.numeric_ids, noatime=not args.atime, noctime=args.noctime, progress=args.progress, @@ -1475,7 +1477,7 @@ class Archiver: print_output = print_json_output if args.json_lines else print_text_output archive1 = archive - archive2 = Archive(repository, key, manifest, args.archive2, + archive2 = Archive(repository, key, manifest, args.name2, consider_part_files=args.consider_part_files) can_compare_chunk_ids = archive1.metadata.get('chunker_params', False) == archive2.metadata.get( @@ -1506,7 +1508,7 @@ class Archiver: @with_archive def do_rename(self, args, repository, manifest, key, cache, archive): """Rename an existing archive""" - archive.rename(args.name) + archive.rename(args.name2) manifest.write() repository.commit(compact=False) cache.commit() @@ -1516,7 +1518,7 @@ class Archiver: def do_delete(self, args, repository): """Delete an existing repository or archives""" archive_filter_specified = any((args.first, args.last, args.prefix is not None, args.glob_archives)) - explicit_archives_specified = args.location.archive or args.archives + explicit_archives_specified = args.name or args.archives self.output_list = args.output_list if archive_filter_specified and explicit_archives_specified: self.print_error('Mixing archive filters and explicitly named archives is not supported.') @@ -1532,10 +1534,10 @@ class Archiver: manifest, key = Manifest.load(repository, (Manifest.Operation.DELETE,)) - if args.location.archive or args.archives: + if args.name or args.archives: archives = list(args.archives) - if args.location.archive: - archives.insert(0, args.location.archive) + if args.name: + archives.insert(0, args.name) archive_names = tuple(archives) else: args.consider_checkpoints = True @@ -1699,7 +1701,7 @@ class Archiver: @with_repository(compatibility=(Manifest.Operation.READ,)) def do_list(self, args, repository, manifest, key): """List archive or repository contents""" - if args.location.archive: + if args.name: if args.json: self.print_error('The --json option is only valid for listing archives, not archive contents.') return self.exit_code @@ -1720,7 +1722,7 @@ class Archiver: format = "{mode} {user:6} {group:6} {size:8} {mtime} {path}{extra}{NL}" def _list_inner(cache): - archive = Archive(repository, key, manifest, args.location.archive, cache=cache, + archive = Archive(repository, key, manifest, args.name, cache=cache, consider_part_files=args.consider_part_files) formatter = ItemFormatter(archive, format, json_lines=args.json_lines) @@ -1763,7 +1765,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 is not None, args.glob_archives)): + if any((args.name, args.first, args.last, args.prefix is not None, args.glob_archives)): return self._info_archives(args, repository, manifest, key, cache) else: return self._info_repository(args, repository, manifest, key, cache) @@ -1772,8 +1774,8 @@ class Archiver: def format_cmdline(cmdline): return remove_surrogates(' '.join(shlex.quote(x) for x in cmdline)) - if args.location.archive: - archive_names = (args.location.archive,) + if args.name: + archive_names = (args.name,) else: args.consider_checkpoints = True archive_names = tuple(x.name for x in manifest.archives.list_considering(args)) @@ -2003,8 +2005,8 @@ class Archiver: checkpoint_interval=args.checkpoint_interval, dry_run=args.dry_run, timestamp=args.timestamp) - if args.location.archive: - name = args.location.archive + if args.name: + name = args.name if recreater.is_temporary_archive(name): self.print_error('Refusing to work on temporary archive of prior recreate: %s', name) return self.exit_code @@ -2048,7 +2050,7 @@ class Archiver: t0 = datetime.utcnow() t0_monotonic = time.monotonic() - archive = Archive(repository, key, manifest, args.location.archive, cache=cache, + archive = Archive(repository, key, manifest, args.name, cache=cache, create=True, checkpoint_interval=args.checkpoint_interval, progress=args.progress, chunker_params=args.chunker_params, start=t0, start_monotonic=t0_monotonic, @@ -2289,7 +2291,7 @@ class Archiver: @with_repository(compatibility=Manifest.NO_OPERATION_CHECK) def do_debug_dump_archive_items(self, args, repository, manifest, key): """dump (decrypted, decompressed) archive items metadata (not: data)""" - archive = Archive(repository, key, manifest, args.location.archive, + archive = Archive(repository, key, manifest, args.name, consider_part_files=args.consider_part_files) for i, item_id in enumerate(archive.metadata.items): data = key.decrypt(item_id, repository.get(item_id)) @@ -2305,9 +2307,9 @@ class Archiver: """dump decoded archive metadata (not: data)""" try: - archive_meta_orig = manifest.archives.get_raw_dict()[args.location.archive] + archive_meta_orig = manifest.archives.get_raw_dict()[args.name] except KeyError: - raise Archive.DoesNotExist(args.location.archive) + raise Archive.DoesNotExist(args.name) indent = 4 @@ -2317,7 +2319,7 @@ class Archiver: def output(fd): # this outputs megabytes of data for a modest sized archive, so some manual streaming json output fd.write('{\n') - fd.write(' "_name": ' + json.dumps(args.location.archive) + ",\n") + fd.write(' "_name": ' + json.dumps(args.name) + ",\n") fd.write(' "_manifest_entry":\n') fd.write(do_indent(prepare_dump_dict(archive_meta_orig))) fd.write(',\n') @@ -2808,7 +2810,7 @@ class Archiver: This allows you to share the same patterns between multiple repositories without needing to specify them on the command line.\n\n''') helptext['placeholders'] = textwrap.dedent(''' - Repository (or Archive) URLs, ``--prefix``, ``--glob-archives``, ``--comment`` + Repository URLs, ``--name``, ``--prefix``, ``--glob-archives``, ``--comment`` and ``--remote-path`` values support these placeholders: {hostname} @@ -3271,7 +3273,8 @@ class Archiver: def define_borg_mount(parser): parser.set_defaults(func=self.do_mount) - # archive name + parser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') parser.add_argument('--consider-checkpoints', action='store_true', dest='consider_checkpoints', help='Show checkpoint archives in the repository contents list (default: hidden).') parser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str, @@ -3545,7 +3548,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='verify repository') subparser.set_defaults(func=self.do_check) - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('--repository-only', dest='repo_only', action='store_true', help='only perform repository checks') subparser.add_argument('--archives-only', dest='archives_only', action='store_true', @@ -3895,6 +3899,8 @@ class Archiver: 'regular files. Also follows symlinks pointing to these kinds of files.') archive_group = subparser.add_argument_group('Archive options') + archive_group.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, default='{hostname}-{now}', + help='specify the name for the archive') archive_group.add_argument('--comment', dest='comment', metavar='COMMENT', type=CommentSpec, default='', help='add a comment text to the archive') archive_group.add_argument('--timestamp', metavar='TIMESTAMP', dest='timestamp', @@ -3913,7 +3919,6 @@ class Archiver: help='select compression algorithm, see the output of the ' '"borg help compression" command for details.') - # archive name subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to archive') @@ -3956,7 +3961,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump archive items (metadata) (debug)') subparser.set_defaults(func=self.do_debug_dump_archive_items) - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') debug_dump_archive_epilog = process_epilog(""" This command dumps all metadata of an archive in a decoded form to a file. @@ -3967,7 +3973,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump decoded archive metadata (debug)') subparser.set_defaults(func=self.do_debug_dump_archive) - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('path', metavar='PATH', type=str, help='file to dump data into') @@ -4133,7 +4140,8 @@ class Archiver: help='keep the local security info when deleting a repository') subparser.add_argument('--save-space', dest='save_space', action='store_true', help='work slower, but using less space') - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('archives', metavar='ARCHIVE', nargs='*', help='archives to delete') define_archive_filters_group(subparser) @@ -4207,10 +4215,10 @@ class Archiver: help='Sort the output lines by file path.') subparser.add_argument('--json-lines', action='store_true', help='Format output as JSON Lines. ') - subparser.add_argument('archive1', metavar='ARCHIVE1', + subparser.add_argument('--name', metavar='ARCHIVE1', type=archivename_validator(), help='ARCHIVE1 name') - subparser.add_argument('archive2', metavar='ARCHIVE2', + subparser.add_argument('--name2', metavar='ARCHIVE2', type=archivename_validator(), help='ARCHIVE2 name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, @@ -4267,6 +4275,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='create tarball from archive') subparser.set_defaults(func=self.do_export_tar) + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') 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', @@ -4274,7 +4284,6 @@ class Archiver: subparser.add_argument('--tar-format', metavar='FMT', dest='tar_format', default='GNU', choices=('BORG', 'PAX', 'GNU'), help='select tar format: BORG, PAX or GNU') - # archive name subparser.add_argument('tarfile', metavar='FILE', help='output tar file. "-" to write to stdout instead.') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, @@ -4312,6 +4321,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='extract archive contents') subparser.set_defaults(func=self.do_extract) + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') 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', action='store_true', @@ -4332,7 +4343,6 @@ class Archiver: help='write all extracted data to stdout') subparser.add_argument('--sparse', dest='sparse', action='store_true', help='create holes in output sparse file from all-zero chunks') - # archive name subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to extract; patterns are supported') define_exclusion_group(subparser, strip_components=True) @@ -4370,7 +4380,8 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='show repository or archive information') subparser.set_defaults(func=self.do_info) - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('--json', action='store_true', help='format output as JSON') define_archive_filters_group(subparser) @@ -4759,7 +4770,8 @@ class Archiver: 'but keys used in it are added to the JSON output. ' 'Some keys are always present. Note: JSON can only represent text. ' 'A "bpath" key is therefore not available.') - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to list; patterns are supported') define_archive_filters_group(subparser) @@ -4969,7 +4981,8 @@ class Archiver: 'HASH_MASK_BITS, HASH_WINDOW_SIZE) or `default` to use the current defaults. ' 'default: %s,%d,%d,%d,%d' % CHUNKER_PARAMS) - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to recreate; patterns are supported') @@ -4985,10 +4998,10 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='rename archive') subparser.set_defaults(func=self.do_rename) - subparser.add_argument('name_current', metavar='OLDNAME', + subparser.add_argument('--name', metavar='OLDNAME', type=archivename_validator(), help='the current archive name') - subparser.add_argument('name', metavar='NEWNAME', + subparser.add_argument('--name2', metavar='NEWNAME', type=archivename_validator(), help='the new archive name') @@ -5211,7 +5224,8 @@ class Archiver: help='select compression algorithm, see the output of the ' '"borg help compression" command for details.') - # archive name + subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('tarfile', metavar='TARFILE', help='input tar file. "-" to read from stdin instead.') return parser diff --git a/src/borg/fuse.py b/src/borg/fuse.py index 5c9f8b935..5203a2959 100644 --- a/src/borg/fuse.py +++ b/src/borg/fuse.py @@ -272,11 +272,11 @@ class FuseBackend: def _create_filesystem(self): self._create_dir(parent=1) # first call, create root dir (inode == 1) - if self._args.location.archive: + if self._args.name: if self.versions: raise Error("for versions view, do not specify a single archive, " "but always give the repository as location.") - self._process_archive(self._args.location.archive) + self._process_archive(self._args.name) else: self.versions_index = FuseVersionsIndex() for archive in self._manifest.archives.list_considering(self._args): diff --git a/src/borg/helpers/manifest.py b/src/borg/helpers/manifest.py index 1b9d91fb4..587176b49 100644 --- a/src/borg/helpers/manifest.py +++ b/src/borg/helpers/manifest.py @@ -103,7 +103,7 @@ class Archives(abc.MutableMapping): """ get a list of archives, considering --first/last/prefix/glob-archives/sort/consider-checkpoints cmdline args """ - if args.location.archive: + if args.name: raise Error('The options --first, --last, --prefix, and --glob-archives, and --consider-checkpoints can only be used on repository targets.') if args.prefix is not None: args.glob_archives = args.prefix + '*' diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index 7c25437b0..ab420dea7 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -213,6 +213,8 @@ PrefixSpec = replace_placeholders GlobSpec = replace_placeholders +NameSpec = replace_placeholders + CommentSpec = replace_placeholders diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 1c67a5573..a22eebe4a 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -149,14 +149,14 @@ def test_return_codes(cmd, tmpdir): input.join('test_file').write('content') rc, out = cmd('--repo=%s' % str(repo), 'init', '--encryption=none') assert rc == EXIT_SUCCESS - rc, out = cmd('--repo=%s::archive' % repo, 'create', str(input)) + rc, out = cmd('--repo=%s' % repo, 'create', '--name=archive', str(input)) assert rc == EXIT_SUCCESS with changedir(str(output)): - rc, out = cmd('--repo=%s::archive' % repo, 'extract') + rc, out = cmd('--repo=%s' % repo, 'extract', '--name=archive') assert rc == EXIT_SUCCESS - rc, out = cmd('--repo=%s::archive' % repo, 'extract', 'does/not/match') + rc, out = cmd('--repo=%s' % repo, 'extract', '--name=archive', 'does/not/match') assert rc == EXIT_WARNING # pattern did not match - rc, out = cmd('--repo=%s::archive' % repo, 'create', str(input)) + rc, out = cmd('--repo=%s' % repo, 'create', '--name=archive', str(input)) assert rc == EXIT_ERROR # duplicate archive name @@ -219,7 +219,7 @@ def test_disk_full(cmd): break raise try: - rc, out = cmd('--repo=%s::test%03d' % (repo, i), 'create', input) + rc, out = cmd('--repo=%s' % repo, 'create', '--name=test%03d' % i, input) success = rc == EXIT_SUCCESS if not success: print('create', rc, out) @@ -299,7 +299,7 @@ class ArchiverTestCaseBase(BaseTestCase): return output def create_src_archive(self, name): - self.cmd(f'--repo={self.repository_location}::{name}', 'create', '--compression=lz4', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', f'--name={name}', '--compression=lz4', src_dir) def open_archive(self, name): repository = Repository(self.repository_path, exclusive=True) @@ -394,12 +394,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--show-version', '--show-rc', fork=True) self.assert_in('borgbackup version', output) self.assert_in('terminating with success status, rc 0', output) - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-nodump', 'input') - output = self.cmd(f'--repo={self.repository_location}::test.2', 'create', '--exclude-nodump', '--stats', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-nodump', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', '--exclude-nodump', '--stats', 'input') self.assert_in('Archive name: test.2', output) self.assert_in('This archive: ', output) with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') list_output = self.cmd(f'--repo={self.repository_location}', 'list', '--short') self.assert_in('test', list_output) self.assert_in('test.2', list_output) @@ -427,15 +427,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): # remove the file we did not backup, so input and output become equal expected.remove('input/flagfile') # this file is UF_NODUMP os.remove(os.path.join('input', 'flagfile')) - list_output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--short') + list_output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--short') for name in expected: self.assert_in(name, list_output) self.assert_dirs_equal('input', 'output/input') - info_output = self.cmd(f'--repo={self.repository_location}::test', 'info') + info_output = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') item_count = 5 if has_lchflags else 6 # one file is UF_NODUMP self.assert_in('Number of files: %d' % item_count, info_output) shutil.rmtree(self.cache_path) - info_output2 = self.cmd(f'--repo={self.repository_location}::test', 'info') + info_output2 = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') def filter(output): # filter for interesting "info" output, ignore cache rebuilding related stuff @@ -463,9 +463,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', 'input') # give input twice! + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', 'input') # give input twice! # test if created archive has 'input' contents twice: - archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] # we have all fs items exactly once! assert sorted(paths) == ['input', 'input/a', 'input/a/hardlink', 'input/b', 'input/b/hardlink'] @@ -491,19 +491,19 @@ class ArchiverTestCase(ArchiverTestCaseBase): pytest.skip('unix sockets disabled or not supported') elif err.errno == errno.EACCES: pytest.skip('permission denied to create unix sockets') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') sock.close() with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') assert not os.path.exists('input/unix-socket') @pytest.mark.skipif(not are_symlinks_supported(), reason='symlinks not supported') def test_symlink_extract(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') assert os.readlink('input/link1') == 'somewhere' @pytest.mark.skipif(not are_symlinks_supported() or not are_hardlinks_supported(), @@ -514,9 +514,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.symlink('target', 'symlink1') os.link('symlink1', 'symlink2', follow_symlinks=False) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'extract') + output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') print(output) with changedir('input'): assert os.path.exists('target') @@ -548,9 +548,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): have_noatime = has_noatime('input/file1') os.utime('input/file1', (atime, mtime)) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', '--atime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--atime', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert sti.st_mtime_ns == sto.st_mtime_ns == mtime * 1e9 @@ -568,9 +568,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert int(sti.st_birthtime * 1e9) == int(sto.st_birthtime * 1e9) == birthtime * 1e9 @@ -584,9 +584,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', '--nobirthtime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--nobirthtime', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert int(sti.st_birthtime * 1e9) == birthtime * 1e9 @@ -645,9 +645,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): # we could create a sparse input file, so creating a backup of it and # extracting it again (as sparse) should also work: self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--sparse') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--sparse') self.assert_dirs_equal('input', 'output/input') filename = os.path.join(self.output_path, 'input', 'sparse') with open(filename, 'rb') as fd: @@ -664,10 +664,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(filename, 'wb'): pass self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') for filename in filenames: with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', os.path.join('input', filename)) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', os.path.join('input', filename)) assert os.path.exists(os.path.join('output', 'input', filename)) def test_repository_swap_detection(self): @@ -675,70 +675,70 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') shutil.rmtree(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.EncryptionMethodMismatch): - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') def test_repository_swap_detection2(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}_encrypted::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test', 'input') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.RepositoryAccessAborted): - self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input') def test_repository_swap_detection_no_cache(self): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') shutil.rmtree(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.EncryptionMethodMismatch): - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') def test_repository_swap_detection2_no_cache(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}_encrypted::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test', 'input') self.cmd(f'--repo={self.repository_location}_unencrypted', 'delete', '--cache-only') self.cmd(f'--repo={self.repository_location}_encrypted', 'delete', '--cache-only') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.RepositoryAccessAborted): - self.cmd(f'--repo={self.repository_location}_encrypted::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input') def test_repository_swap_detection_repokey_blank_passphrase(self): # Check that a repokey repo with a blank passphrase is considered like a plaintext repo. self.create_test_files() # User initializes her repository with her passphrase self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') # Attacker replaces it with her own repository, which is encrypted but has no passphrase set shutil.rmtree(self.repository_path) with environment_variable(BORG_PASSPHRASE=''): @@ -751,10 +751,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): # is set, while it isn't. Previously this raised no warning, # since the repository is, technically, encrypted. if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.CacheInitAbortedError): - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') def test_repository_move(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -805,16 +805,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_strip_components(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir/file') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '3') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '3') assert not os.path.exists('file') with self.assert_creates_file('file'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '2') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '2') with self.assert_creates_file('dir/file'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '1') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '1') with self.assert_creates_file('input/dir/file'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '0') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '0') def _extract_hardlinks_setup(self): os.mkdir(os.path.join(self.input_path, 'dir1')) @@ -833,7 +833,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.path.join(self.input_path, 'dir1/aaaa')) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') @requires_hardlinks @unittest.skipUnless(llfuse, 'llfuse not installed') @@ -847,21 +847,21 @@ class ArchiverTestCase(ArchiverTestCaseBase): ignore_perms = ['-o', 'ignore_permissions,defer_permissions'] else: ignore_perms = ['-o', 'ignore_permissions'] - with self.fuse_mount(self.repository_location + '::test', mountpoint, '--strip-components=2', *ignore_perms), \ + with self.fuse_mount(self.repository_location, mountpoint, '--name=test', '--strip-components=2', *ignore_perms), \ changedir(mountpoint): assert os.stat('hardlink').st_nlink == 2 assert os.stat('subdir/hardlink').st_nlink == 2 assert open('subdir/hardlink', 'rb').read() == b'123456' assert os.stat('aaaa').st_nlink == 2 assert os.stat('source2').st_nlink == 2 - with self.fuse_mount(self.repository_location + '::test', mountpoint, 'input/dir1', *ignore_perms), \ + with self.fuse_mount(self.repository_location, mountpoint, 'input/dir1', '--name=test', *ignore_perms), \ changedir(mountpoint): assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert open('input/dir1/subdir/hardlink', 'rb').read() == b'123456' assert os.stat('input/dir1/aaaa').st_nlink == 2 assert os.stat('input/dir1/source2').st_nlink == 2 - with self.fuse_mount(self.repository_location + '::test', mountpoint, *ignore_perms), \ + with self.fuse_mount(self.repository_location, mountpoint, '--name=test', *ignore_perms), \ changedir(mountpoint): assert os.stat('input/source').st_nlink == 4 assert os.stat('input/abba').st_nlink == 4 @@ -873,7 +873,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_hardlinks1(self): self._extract_hardlinks_setup() with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') assert os.stat('input/source').st_nlink == 4 assert os.stat('input/abba').st_nlink == 4 assert os.stat('input/dir1/hardlink').st_nlink == 4 @@ -884,14 +884,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_hardlinks2(self): self._extract_hardlinks_setup() with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--strip-components', '2') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '2') assert os.stat('hardlink').st_nlink == 2 assert os.stat('subdir/hardlink').st_nlink == 2 assert open('subdir/hardlink', 'rb').read() == b'123456' assert os.stat('aaaa').st_nlink == 2 assert os.stat('source2').st_nlink == 2 with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', 'input/dir1') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', 'input/dir1') assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert open('input/dir1/subdir/hardlink', 'rb').read() == b'123456' @@ -910,10 +910,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', 'input') # give input twice! + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', 'input') # give input twice! # now test extraction with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') # if issue #5603 happens, extraction gives rc == 1 (triggering AssertionError) and warnings like: # input/a/hardlink: link: [Errno 2] No such file or directory: 'input/a/hardlink' -> 'input/a/hardlink' # input/b/hardlink: link: [Errno 2] No such file or directory: 'input/a/hardlink' -> 'input/b/hardlink' @@ -927,15 +927,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) self.create_regular_file('file4', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude=input/file4', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude=input/file4', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', 'input/file1', ) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', 'input/file1', ) self.assert_equal(sorted(os.listdir('output/input')), ['file1']) with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude=input/file2') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude=input/file2') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) def test_extract_include_exclude_regex(self): @@ -947,27 +947,27 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file333', size=1024 * 80) # Create with regular expression exclusion for file4 - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude=re:input/file4$', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude=re:input/file4$', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) shutil.rmtree('output/input') # Extract with regular expression exclusion with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude=re:file3+') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude=re:file3+') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2']) shutil.rmtree('output/input') # Combine --exclude with fnmatch and regular expression with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude=input/file2', '--exclude=re:file[01]') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude=input/file2', '--exclude=re:file[01]') self.assert_equal(sorted(os.listdir('output/input')), ['file3', 'file333']) shutil.rmtree('output/input') # Combine --exclude-from and regular expression exclusion with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path, + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path, '--exclude=re:file1', '--exclude=re:file(\\d)\\1\\1$') self.assert_equal(sorted(os.listdir('output/input')), ['file3']) @@ -985,9 +985,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:input/file4$\n') fd.write(b'fm:*aa:*thing\n') - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-from=' + self.exclude_file_path, 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-from=' + self.exclude_file_path, 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) shutil.rmtree('output/input') @@ -996,7 +996,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:file3+\n') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2']) shutil.rmtree('output/input') @@ -1008,7 +1008,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:file2$\n') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--exclude-from=' + self.exclude_file_path) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file3']) def test_extract_with_pattern(self): @@ -1019,63 +1019,63 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) self.create_regular_file("file333", size=1024 * 80) - self.cmd(f'--repo={self.repository_location}::test', "create", "input") + self.cmd(f'--repo={self.repository_location}', "create", "--name=test", "input") # Extract everything with regular expression with changedir("output"): - self.cmd(f'--repo={self.repository_location}::test', "extract", "re:.*") + self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "re:.*") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file3", "file333", "file4"]) shutil.rmtree("output/input") # Extract with pattern while also excluding files with changedir("output"): - self.cmd(f'--repo={self.repository_location}::test', "extract", "--exclude=re:file[34]$", r"re:file\d$") + self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "--exclude=re:file[34]$", r"re:file\d$") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2"]) shutil.rmtree("output/input") # Combine --exclude with pattern for extraction with changedir("output"): - self.cmd(f'--repo={self.repository_location}::test', "extract", "--exclude=input/file1", "re:file[12]$") + self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "--exclude=input/file1", "re:file[12]$") self.assert_equal(sorted(os.listdir("output/input")), ["file2"]) shutil.rmtree("output/input") # Multiple pattern with changedir("output"): - self.cmd(f'--repo={self.repository_location}::test', "extract", "fm:input/file1", "fm:*file33*", "input/file2") + self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "fm:input/file1", "fm:*file33*", "input/file2") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file333"]) def test_extract_list_output(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'extract') + output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_not_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--info') + output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--info') self.assert_not_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--list') + output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--list') self.assert_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--list', '--info') + output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--list', '--info') self.assert_in("input/file", output) def test_extract_progress(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--progress') + output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--progress') assert 'Extracting:' in output def _create_test_caches(self): @@ -1095,32 +1095,32 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_stdin(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = b'\x00foo\n\nbar\n \n' - self.cmd(f'--repo={self.repository_location}::test', 'create', '-', input=input_data) - item = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines')) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-', input=input_data) + item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 assert item['size'] == len(input_data) assert item['path'] == 'stdin' - extracted_data = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--stdout', binary_output=True) + extracted_data = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--stdout', binary_output=True) assert extracted_data == input_data def test_create_content_from_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = 'some test content' name = 'a/b/c' - self.cmd(f'--repo={self.repository_location}::test', 'create', '--stdin-name', name, '--content-from-command', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--stdin-name', name, '--content-from-command', '--', 'echo', input_data) - item = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines')) + item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 assert item['size'] == len(input_data) + 1 # `echo` adds newline assert item['path'] == name - extracted_data = self.cmd(f'--repo={self.repository_location}::test', 'extract', '--stdout') + extracted_data = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--stdout') assert extracted_data == input_data + '\n' def test_create_content_from_command_with_failed_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--content-from-command', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--content-from-command', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) @@ -1128,7 +1128,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_content_from_command_missing_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--content-from-command', exit_code=2) + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--content-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_paths_from_stdin(self): @@ -1139,9 +1139,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) input_data = b'input/file1\0input/dir1\0input/file4' - self.cmd(f'--repo={self.repository_location}::test', 'create', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-stdin', '--paths-delimiter', '\\0', input=input_data) - archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] assert paths == ['input/file1', 'input/dir1', 'input/file4'] @@ -1153,15 +1153,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) input_data = 'input/file1\ninput/file2\ninput/file3' - self.cmd(f'--repo={self.repository_location}::test', 'create', '--paths-from-command', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-command', '--', 'echo', input_data) - archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] assert paths == ['input/file1', 'input/file2', 'input/file3'] def test_create_paths_from_command_with_failed_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--paths-from-command', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-command', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) @@ -1169,20 +1169,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_paths_from_command_missing_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--paths-from-command', exit_code=2) + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_without_root(self): """test create without a root""" self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', exit_code=2) def test_create_pattern_root(self): """test create with only a root pattern""" self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', '--pattern=R input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', '--pattern=R input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) @@ -1192,7 +1192,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', '--pattern=+input/file_important', '--pattern=-input/file*', 'input') self.assert_in("A input/file_important", output) @@ -1206,7 +1206,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('otherfile', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', '--pattern=-input/otherfile', '--patterns-from=' + self.patterns_file_path, 'input') self.assert_in("A input/file_important", output) @@ -1224,7 +1224,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', '--patterns-from=' + self.patterns_file_path2, 'input') self.assert_in('x input/x/a/foo_a', output) @@ -1241,7 +1241,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', '--patterns-from=' + self.patterns_file_path2, 'input') self.assert_not_in('input/x/a/foo_a', output) @@ -1259,12 +1259,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) with changedir('input'): - self.cmd(f'--repo={self.repository_location}::test', 'create', '--patterns-from=' + self.patterns_file_path2, - '.') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', + '--patterns-from=' + self.patterns_file_path2, '.') # list the archive and verify that the "intermediate" folders appear before # their contents - out = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{type} {path}{NL}') + out = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{type} {path}{NL}') out_list = out.splitlines() self.assert_in('d x/a', out_list) @@ -1277,14 +1277,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') - create_json = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'create', '--no-cache-sync', 'input', + create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', + '--no-cache-sync', 'input', '--json', '--error')) # ignore experimental warning - info_json = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'info', '--json')) + info_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--name=test', '--json')) create_stats = create_json['cache']['stats'] info_stats = info_json['cache']['stats'] assert create_stats == info_stats self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') - self.cmd(f'--repo={self.repository_location}::test2', 'create', '--no-cache-sync', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--no-cache-sync', 'input') self.cmd(f'--repo={self.repository_location}', 'info') self.cmd(f'--repo={self.repository_location}', 'check') @@ -1293,27 +1294,27 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--pattern=+input/file_important', '--pattern=-input/file*') self.assert_equal(sorted(os.listdir('output/input')), ['file_important']) def _assert_test_caches(self): with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['cache2', 'file1']) self.assert_equal(sorted(os.listdir('output/input/cache2')), [CACHE_TAG_NAME]) def test_exclude_caches(self): self._create_test_caches() - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-caches', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-caches', 'input') self._assert_test_caches() def test_recreate_exclude_caches(self): self._create_test_caches() - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-caches') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-caches') self._assert_test_caches() def _create_test_tagged(self): @@ -1325,19 +1326,19 @@ class ArchiverTestCase(ArchiverTestCaseBase): def _assert_test_tagged(self): with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['file1']) def test_exclude_tagged(self): self._create_test_tagged() - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-if-present', '.NOBACKUP', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP', 'input') self._assert_test_tagged() def test_recreate_exclude_tagged(self): self._create_test_tagged() - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-if-present', '.NOBACKUP', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP') self._assert_test_tagged() @@ -1359,7 +1360,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def _assert_test_keep_tagged(self): with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['file0', 'tagged1', 'tagged2', 'tagged3', 'taggedall']) self.assert_equal(os.listdir('output/input/tagged1'), ['.NOBACKUP1']) self.assert_equal(os.listdir('output/input/tagged2'), ['.NOBACKUP2']) @@ -1369,14 +1370,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_exclude_keep_tagged(self): self._create_test_keep_tagged() - self.cmd(f'--repo={self.repository_location}::test', 'create', '--exclude-if-present', '.NOBACKUP1', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-if-present', '.NOBACKUP1', '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags', 'input') self._assert_test_keep_tagged() def test_recreate_exclude_keep_tagged(self): self._create_test_keep_tagged() - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-if-present', '.NOBACKUP1', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-if-present', '.NOBACKUP1', '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags') self._assert_test_keep_tagged() @@ -1387,11 +1388,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.mkdir(os.path.join(self.input_path, 'subdir')) # to make sure the tag is encountered *after* file1 os.link(os.path.join(self.input_path, 'file1'), os.path.join(self.input_path, 'subdir', CACHE_TAG_NAME)) # correct tag name, hardlink to file1 - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') # in the "test" archive, we now have, in this order: # - a regular file item for "file1" # - a hardlink item for "CACHEDIR.TAG" referring back to file1 for its contents - self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--exclude-caches', '--keep-exclude-tags') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-caches', '--keep-exclude-tags') # if issue #4911 is present, the recreate will crash with a KeyError for "input/file1" @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='Linux capabilities test, requires fakeroot >= 1.20.2') @@ -1409,10 +1410,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file') xattr.setxattr(b'input/file', b'security.capability', capabilities) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): with patch.object(os, 'fchown', patched_fchown): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') assert xattr.getxattr(b'input/file', b'security.capability') == capabilities @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='xattr not supported on this system or on this version of' @@ -1430,19 +1431,19 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute', b'value') self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): input_abspath = os.path.abspath('input/file') with patch.object(xattr, 'setxattr', patched_setxattr_E2BIG): - out = self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: too big for this filesystem\n' in out os.remove(input_abspath) with patch.object(xattr, 'setxattr', patched_setxattr_ENOTSUP): - out = self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: xattrs not supported on this filesystem\n' in out os.remove(input_abspath) with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - out = self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: Permission denied\n' in out assert os.path.isfile(input_abspath) @@ -1450,8 +1451,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir1/dir2/file', size=1024 * 80) with changedir('input/dir1/dir2'): - self.cmd(f'--repo={self.repository_location}::test', 'create', '../../../input/dir1/../dir1/dir2/..') - output = self.cmd(f'--repo={self.repository_location}::test', 'list') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', + '../../../input/dir1/../dir1/dir2/..') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') self.assert_not_in('..', output) self.assert_in(' input/dir1/dir2/file', output) @@ -1460,57 +1462,57 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) with changedir('input'): - self.cmd(f'--repo={self.repository_location}::test1', 'create', '--exclude=file1', '.') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--exclude=file1', '.') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test1', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test1') self.assert_equal(sorted(os.listdir('output')), ['file2']) with changedir('input'): - self.cmd(f'--repo={self.repository_location}::test2', 'create', '--exclude=./file1', '.') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--exclude=./file1', '.') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test2', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test2') self.assert_equal(sorted(os.listdir('output')), ['file2']) - self.cmd(f'--repo={self.repository_location}::test3', 'create', '--exclude=input/./file1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '--exclude=input/./file1', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test3', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test3') self.assert_equal(sorted(os.listdir('output/input')), ['file2']) def test_repeated_files(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', 'input') def test_overwrite(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') # Overwriting regular files and directories should be supported os.mkdir('output/input') os.mkdir('output/input/file1') os.mkdir('output/input/dir2') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_dirs_equal('input', 'output/input') # But non-empty dirs should fail os.unlink('output/input/file1') os.mkdir('output/input/file1') os.mkdir('output/input/file1/dir') with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=1) def test_rename(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--dry-run') - self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') - self.cmd(f'--repo={self.repository_location}::test', 'rename', 'TODO_test', 'test.3') - self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') - self.cmd(f'--repo={self.repository_location}::test.2', 'rename', 'TODO_test.2', 'test.4') - self.cmd(f'--repo={self.repository_location}::test.3', 'extract', '--dry-run') - self.cmd(f'--repo={self.repository_location}::test.4', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'rename', '--name=test', '--name2=test.3') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'rename', '--name=test.2', '--name2=test.4') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.3', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.4', '--dry-run') # Make sure both archives have been renamed with Repository(self.repository_path) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1521,10 +1523,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') info_repo = self.cmd(f'--repo={self.repository_location}', 'info') assert 'All archives:' in info_repo - info_archive = self.cmd(f'--repo={self.repository_location}::test', 'info') + info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') assert 'Archive name: test\n' in info_archive info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '--first', '1') assert 'Archive name: test\n' in info_archive @@ -1532,7 +1534,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info_json(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json')) repository = info_repo['repository'] assert len(repository['id']) == 64 @@ -1545,7 +1547,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert all(isinstance(o, int) for o in stats.values()) assert all(key in stats for key in ('total_chunks', 'total_size', 'total_unique_chunks', 'unique_size')) - info_archive = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'info', '--json')) + info_archive = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--name=test', '--json')) assert info_repo['repository'] == info_archive['repository'] assert info_repo['cache'] == info_archive['cache'] archives = info_archive['archives'] @@ -1570,38 +1572,38 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_comment(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test2', 'create', '--comment', 'this is the comment', 'input') - self.cmd(f'--repo={self.repository_location}::test3', 'create', '--comment', '"deleted" comment', 'input') - self.cmd(f'--repo={self.repository_location}::test4', 'create', '--comment', 'preserved comment', 'input') - assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}::test1', 'info') - assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}::test2', 'info') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--comment', 'this is the comment', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '--comment', '"deleted" comment', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test4', '--comment', 'preserved comment', 'input') + assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') + assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') - self.cmd(f'--repo={self.repository_location}::test1', 'recreate', '--comment', 'added comment') - self.cmd(f'--repo={self.repository_location}::test2', 'recreate', '--comment', 'modified comment') - self.cmd(f'--repo={self.repository_location}::test3', 'recreate', '--comment', '') - self.cmd(f'--repo={self.repository_location}::test4', 'recreate', '12345') - assert 'Comment: added comment' in self.cmd(f'--repo={self.repository_location}::test1', 'info') - assert 'Comment: modified comment' in self.cmd(f'--repo={self.repository_location}::test2', 'info') - assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}::test3', 'info') - assert 'Comment: preserved comment' in self.cmd(f'--repo={self.repository_location}::test4', 'info') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test1', '--comment', 'added comment') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test2', '--comment', 'modified comment') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test3', '--comment', '') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test4', '12345') + assert 'Comment: added comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') + assert 'Comment: modified comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') + assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test3') + assert 'Comment: preserved comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test4') def test_delete(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test.3', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::another_test.1', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::another_test.2', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--dry-run') - self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.3', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=another_test.1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=another_test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--prefix', 'another_') self.cmd(f'--repo={self.repository_location}', 'delete', '--last', '1') - self.cmd(f'--repo={self.repository_location}::test', 'delete') - self.cmd(f'--repo={self.repository_location}::test.2', 'extract', '--dry-run') - output = self.cmd(f'--repo={self.repository_location}::test.2', 'delete', '--stats') + self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + output = self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test.2', '--stats') self.assert_in('Deleted data:', output) # Make sure all data except the manifest has been deleted with Repository(self.repository_path) as repository: @@ -1610,20 +1612,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_delete_multiple(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test3', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test1', 'delete', 'test2') - self.cmd(f'--repo={self.repository_location}::test3', 'extract', '--dry-run') - self.cmd(f'--repo={self.repository_location}::test3', 'delete') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', 'input') + self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test1', 'test2') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test3', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test3') assert not self.cmd(f'--repo={self.repository_location}', 'list') def test_delete_repo(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'no' self.cmd(f'--repo={self.repository_location}', 'delete', exit_code=2) assert os.path.exists(self.repository_path) @@ -1645,7 +1647,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): else: assert False # missed the file repository.commit(compact=False) - output = self.cmd(f'--repo={self.repository_location}::test', 'delete', '--force') + output = self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test', '--force') self.assert_in('deleted archive was corrupted', output) self.cmd(f'--repo={self.repository_location}', 'check', '--repair') output = self.cmd(f'--repo={self.repository_location}', 'list') @@ -1660,7 +1662,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): id = archive.metadata.items[0] repository.put(id, b'corrupted items metadata stream chunk') repository.commit(compact=False) - self.cmd(f'--repo={self.repository_location}::test', 'delete', '--force', '--force') + self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test', '--force', '--force') self.cmd(f'--repo={self.repository_location}', 'check', '--repair') output = self.cmd(f'--repo={self.repository_location}', 'list') self.assert_not_in('test', output) @@ -1668,7 +1670,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_corrupted_repository(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') output = self.cmd(f'--repo={self.repository_location}', 'check', '--show-version') self.assert_in('borgbackup version', output) # implied output even without --info given self.assert_not_in('Starting repository check', output) # --info not given for root logger @@ -1702,14 +1704,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::a', 'diff', 'TODO_a', 'b', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'diff', '--name=a', '--name2=b', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}::a', 'diff', 'TODO_a', 'b') + self.cmd(f'--repo={self.repository_location}', 'diff', '--name=a', '--name=b') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}::a', 'diff', 'TODO_a', 'b', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'diff', '--name=a', '--name2=b', '--bypass-lock') def test_readonly_export_tar(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -1717,14 +1719,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'test.tar', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'test.tar', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'test.tar') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'test.tar') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'test.tar', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'test.tar', '--bypass-lock') def test_readonly_extract(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -1732,14 +1734,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}::test', 'extract', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--bypass-lock') def test_readonly_info(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -1795,13 +1797,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_umask(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') mode = os.stat(self.repository_path).st_mode self.assertEqual(stat.S_IMODE(mode), 0o700) def test_create_dry_run(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', '--dry-run', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--dry-run', 'input') # Make sure no archive has been created with Repository(self.repository_path) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1825,13 +1827,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_unknown_feature_on_create(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) self.add_unknown_feature(Manifest.Operation.WRITE) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'create', 'input']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', '--name=test', 'input']) def test_unknown_feature_on_cache_sync(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') self.add_unknown_feature(Manifest.Operation.READ) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'create', 'input']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', '--name=test', 'input']) def test_unknown_feature_on_change_passphrase(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) @@ -1840,26 +1842,26 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_unknown_feature_on_read(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.add_unknown_feature(Manifest.Operation.READ) with changedir('output'): - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'extract']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'extract', '--name=test']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'list']) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'info']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'info', '--name=test']) def test_unknown_feature_on_rename(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.add_unknown_feature(Manifest.Operation.CHECK) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'rename', 'TODO_test', 'other']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rename', '--name=test', '--name2=other']) def test_unknown_feature_on_delete(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.add_unknown_feature(Manifest.Operation.DELETE) # delete of an archive raises - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}::test', 'delete']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'delete', '--name=test']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'prune', '--keep-daily=3']) # delete of the whole repository ignores features self.cmd(f'--repo={self.repository_location}', 'delete') @@ -1867,7 +1869,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_unknown_feature_on_mount(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.add_unknown_feature(Manifest.Operation.READ) mountpoint = os.path.join(self.tmpdir, 'mountpoint') os.mkdir(mountpoint) @@ -1893,7 +1895,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): cache.commit() if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') else: called = False wipe_cache_safe = LocalCache.wipe_cache @@ -1904,7 +1906,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): wipe_cache_safe(*args) with patch.object(LocalCache, 'wipe_cache', wipe_wrapper): - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') assert called @@ -1918,13 +1920,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_progress_on(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test4', 'create', '--progress', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test4', '--progress', 'input') self.assert_in("\r", output) def test_progress_off(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test5', 'create', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test5', 'input') self.assert_not_in("\r", output) def test_file_status(self): @@ -1935,11 +1937,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--list', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--list', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) # should find first file as unmodified - output = self.cmd(f'--repo={self.repository_location}::test1', 'create', '--list', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', 'input') self.assert_in("U input/file1", output) # this is expected, although surprising, for why, see: # https://borgbackup.readthedocs.org/en/latest/faq.html#i-am-seeing-a-added-status-for-a-unchanged-file @@ -1951,14 +1953,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--list', '--files-cache=ctime,size', 'input') # modify file1, but cheat with the mtime (and atime) and also keep same size: st = os.stat('input/file1') self.create_regular_file('file1', contents=b'321') os.utime('input/file1', ns=(st.st_atime_ns, st.st_mtime_ns)) # this mode uses ctime for change detection, so it should find file1 as modified - output = self.cmd(f'--repo={self.repository_location}::test2', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', '--files-cache=ctime,size', 'input') self.assert_in("M input/file1", output) @@ -1968,13 +1970,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--list', '--files-cache=mtime,size', 'input') # change mode of file1, no content change: st = os.stat('input/file1') os.chmod('input/file1', st.st_mode ^ stat.S_IRWXO) # this triggers a ctime change, but mtime is unchanged # this mode uses mtime for change detection, so it should find file1 as unmodified - output = self.cmd(f'--repo={self.repository_location}::test2', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', '--files-cache=mtime,size', 'input') self.assert_in("U input/file1", output) @@ -1984,10 +1986,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--list', '--files-cache=rechunk,ctime', 'input') # no changes here, but this mode rechunks unconditionally - output = self.cmd(f'--repo={self.repository_location}::test2', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', '--files-cache=rechunk,ctime', 'input') self.assert_in("A input/file1", output) @@ -2001,13 +2003,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file3', size=1024 * 80) platform.set_flags(os.path.join(self.input_path, 'file3'), stat.UF_NODUMP) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}::test', 'create', '--list', '--exclude-nodump', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--list', '--exclude-nodump', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) if has_lchflags: self.assert_in("x input/file3", output) # should find second file as excluded - output = self.cmd(f'--repo={self.repository_location}::test1', 'create', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--list', '--exclude-nodump', 'input', '--exclude', '*/file2') self.assert_in("U input/file1", output) self.assert_in("x input/file2", output) @@ -2017,7 +2019,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_json(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - create_info = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'create', + create_info = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--json', 'input')) # The usual keys assert 'encryption' in create_info @@ -2038,21 +2040,21 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # no listing by default - output = self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.assert_not_in('file1', output) # shouldn't be listed even if unchanged - output = self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') self.assert_not_in('file1', output) # should list the file as unchanged - output = self.cmd(f'--repo={self.repository_location}::test1', 'create', '--list', '--filter=U', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--list', '--filter=U', 'input') self.assert_in('file1', output) # should *not* list the file as changed - output = self.cmd(f'--repo={self.repository_location}::test2', 'create', '--list', '--filter=AM', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', '--filter=AM', 'input') self.assert_not_in('file1', output) # change the file self.create_regular_file('file1', size=1024 * 100) # should list the file as changed - output = self.cmd(f'--repo={self.repository_location}::test3', 'create', '--list', '--filter=AM', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '--list', '--filter=AM', 'input') self.assert_in('file1', output) @pytest.mark.skipif(not are_fifos_supported(), reason='FIFOs not supported') @@ -2077,11 +2079,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): t = Thread(target=fifo_feeder, args=(fifo_fn, data)) t.start() try: - self.cmd(f'--repo={self.repository_location}::test', 'create', '--read-special', 'input/link_fifo') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--read-special', 'input/link_fifo') finally: t.join() with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') fifo_fn = 'input/link_fifo' with open(fifo_fn, 'rb') as f: extracted_data = f.read() @@ -2090,25 +2092,25 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_read_special_broken_symlink(self): os.symlink('somewhere does not exist', os.path.join(self.input_path, 'link')) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', '--read-special', 'input') - output = self.cmd(f'--repo={self.repository_location}::test', 'list') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--read-special', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') assert 'input/link -> somewhere does not exist' in output # def test_cmdline_compatibility(self): # self.create_regular_file('file1', size=1024 * 80) # self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - # self.cmd('create', self.repository_location + '::test', 'input') + # self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') # output = self.cmd('foo', self.repository_location, '--old') # self.assert_in('"--old" has been deprecated. Use "--new" instead', output) def test_prune_repository(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test1', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::test2', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', src_dir) # these are not really a checkpoints, but they look like some: - self.cmd(f'--repo={self.repository_location}::test3.checkpoint', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::test3.checkpoint.1', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::test4.checkpoint', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3.checkpoint', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3.checkpoint.1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test4.checkpoint', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Would prune:\s+test1', output) # must keep the latest non-checkpoint archive: @@ -2131,7 +2133,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('test3.checkpoint.1', output) self.assert_in('test4.checkpoint', output) # now we supersede the latest checkpoint by a successful backup: - self.cmd(f'--repo={self.repository_location}::test5', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test5', src_dir) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=2') output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') # all checkpoints should be gone now: @@ -2146,7 +2148,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): return dtime.astimezone(dateutil.tz.UTC).strftime("%Y-%m-%dT%H:%M:%S") def _create_archive_ts(self, name, y, m, d, H=0, M=0, S=0): - self.cmd(f'--repo={self.repository_location}::{name}', 'create', + self.cmd(f'--repo={self.repository_location}', 'create', f'--name={name}', '--timestamp', self._to_utc_timestamp(y, m, d, H, M, S), src_dir) # This test must match docs/misc/prune-example.txt @@ -2236,8 +2238,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_prune_repository_save_space(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test1', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::test2', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Keeping archive \(rule: daily #1\):\s+test2', output) assert re.search(r'Would prune:\s+test1', output) @@ -2251,10 +2253,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_prune_repository_prefix(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::foo-2015-08-12-10:00', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::foo-2015-08-12-20:00', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::bar-2015-08-12-10:00', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::bar-2015-08-12-20:00', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=foo-2015-08-12-10:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=foo-2015-08-12-20:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=bar-2015-08-12-10:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=bar-2015-08-12-20:00', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--prefix=foo-') assert re.search(r'Keeping archive \(rule: daily #1\):\s+foo-2015-08-12-20:00', output) assert re.search(r'Would prune:\s+foo-2015-08-12-10:00', output) @@ -2272,10 +2274,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_prune_repository_glob(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::2015-08-12-10:00-foo', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::2015-08-12-20:00-foo', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::2015-08-12-10:00-bar', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::2015-08-12-20:00-bar', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-10:00-foo', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-20:00-foo', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-10:00-bar', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-20:00-bar', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--glob-archives=2015-*-foo') assert re.search(r'Keeping archive \(rule: daily #1\):\s+2015-08-12-20:00-foo', output) assert re.search(r'Would prune:\s+2015-08-12-10:00-foo', output) @@ -2293,9 +2295,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_prefix(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test-1', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::something-else-than-test-1', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::test-2', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=something-else-than-test-1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-2', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'list', '--prefix=test-') self.assert_in('test-1', output) self.assert_in('test-2', output) @@ -2303,17 +2305,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_format(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', src_dir) - output_1 = self.cmd(f'--repo={self.repository_location}::test', 'list') - output_2 = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') - output_3 = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{mtime:%s} {path}{NL}') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', src_dir) + output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') + output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') + output_3 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{mtime:%s} {path}{NL}') self.assertEqual(output_1, output_2) self.assertNotEqual(output_1, output_3) def test_list_repository_format(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test-1', 'create', '--comment', 'comment 1', src_dir) - self.cmd(f'--repo={self.repository_location}::test-2', 'create', '--comment', 'comment 2', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-1', '--comment', 'comment 1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-2', '--comment', 'comment 2', src_dir) output_1 = self.cmd(f'--repo={self.repository_location}', 'list') output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{archive:<36} {time} [{id}]{NL}') self.assertEqual(output_1, output_2) @@ -2329,17 +2331,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('empty_file', size=0) self.create_regular_file('amb', contents=b'a' * 1000000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{sha256} {path}{NL}') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{sha256} {path}{NL}') assert "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 input/amb" in output assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 input/empty_file" in output def test_list_consider_checkpoints(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', src_dir) # these are not really a checkpoints, but they look like some: - self.cmd(f'--repo={self.repository_location}::test2.checkpoint', 'create', src_dir) - self.cmd(f'--repo={self.repository_location}::test3.checkpoint.1', 'create', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2.checkpoint', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3.checkpoint.1', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'list') assert "test1" in output assert "test2.checkpoint" not in output @@ -2356,23 +2358,23 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b'abba' * 2000000) fd.write(b'baab' * 2000000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{num_chunks} {unique_chunks} {path}{NL}') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{num_chunks} {unique_chunks} {path}{NL}') assert "0 0 input/empty_file" in output assert "2 2 input/two_chunks" in output def test_list_size(self): self.create_regular_file('compressible_file', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', '-C', 'lz4', 'input') - output = self.cmd(f'--repo={self.repository_location}::test', 'list', '--format', '{size} {path}{NL}') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-C', 'lz4', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{size} {path}{NL}') size, path = output.split("\n")[1].split(" ") assert int(size) == 10000 def test_list_json(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') list_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) repository = list_repo['repository'] assert len(repository['id']) == 64 @@ -2382,7 +2384,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): archive0 = list_repo['archives'][0] assert datetime.strptime(archive0['time'], ISO_FORMAT) # must not raise - list_archive = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines') + list_archive = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') items = [json.loads(s) for s in list_archive.splitlines()] assert len(items) == 2 file1 = items[1] @@ -2390,7 +2392,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert file1['size'] == 81920 assert datetime.strptime(file1['mtime'], ISO_FORMAT) # must not raise - list_archive = self.cmd(f'--repo={self.repository_location}::test', 'list', '--json-lines', '--format={sha256}') + list_archive = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines', '--format={sha256}') items = [json.loads(s) for s in list_archive.splitlines()] assert len(items) == 2 file1 = items[1] @@ -2400,12 +2402,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_json_args(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'list', '--json-lines', exit_code=2) - self.cmd(f'--repo={self.repository_location}::archive', 'list', '--json', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'list', '--name=archive', '--json', exit_code=2) def test_log_json(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - log = self.cmd(f'--repo={self.repository_location}::test', 'create', '--log-json', 'input', '--list', '--debug') + log = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--log-json', 'input', '--list', '--debug') messages = {} # type -> message, one of each kind for line in log.splitlines(): msg = json.loads(line) @@ -2423,13 +2425,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_profile(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', '--debug-profile=create.prof') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', '--debug-profile=create.prof') self.cmd('debug', 'convert-profile', 'create.prof', 'create.pyprof') stats = pstats.Stats('create.pyprof') stats.strip_dirs() stats.sort_stats('cumtime') - self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input', '--debug-profile=create.pyprof') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input', '--debug-profile=create.pyprof') stats = pstats.Stats('create.pyprof') # Only do this on trusted data! stats.strip_dirs() stats.sort_stats('cumtime') @@ -2437,7 +2439,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_common_options(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - log = self.cmd(f'--repo={self.repository_location}::test', '--debug', 'create', 'input') + log = self.cmd(f'--repo={self.repository_location}', '--debug', 'create', '--name=test', 'input') assert 'security: read previous location' in log def test_change_passphrase(self): @@ -2511,8 +2513,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_test_files() have_noatime = has_noatime('input/file1') - self.cmd(f'--repo={self.repository_location}::archive', 'create', '--exclude-nodump', '--atime', 'input') - self.cmd(f'--repo={self.repository_location}::archive2', 'create', '--exclude-nodump', '--atime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive', '--exclude-nodump', '--atime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive2', '--exclude-nodump', '--atime', 'input') if has_lchflags: # remove the file we did not backup, so input and output become equal os.remove(os.path.join('input', 'flagfile')) @@ -2526,7 +2528,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive2', 'input'), ignore_flags=True, ignore_xattrs=True) # mount only 1 archive, its contents shall show up directly in mountpoint: - with self.fuse_mount(self.repository_location + '::archive', mountpoint): + with self.fuse_mount(self.repository_location, mountpoint, '--name=archive'): self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'input'), ignore_flags=True, ignore_xattrs=True) # regular file @@ -2604,9 +2606,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('hardlink1', contents=b'123456') os.link('input/hardlink1', 'input/hardlink2') os.link('input/hardlink1', 'input/hardlink3') - self.cmd(f'--repo={self.repository_location}::archive1', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive1', 'input') self.create_regular_file('test', contents=b'second') - self.cmd(f'--repo={self.repository_location}::archive2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive2', 'input') mountpoint = os.path.join(self.tmpdir, 'mountpoint') # mount the whole repository, archive contents shall show up in versioned view: with self.fuse_mount(self.repository_location, mountpoint, '-o', 'versions'): @@ -2646,11 +2648,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) mountpoint = os.path.join(self.tmpdir, 'mountpoint') - with self.fuse_mount(self.repository_location + '::archive', mountpoint): + with self.fuse_mount(self.repository_location, mountpoint, '--name=archive'): with pytest.raises(OSError) as excinfo: open(os.path.join(mountpoint, path)) assert excinfo.value.errno == errno.EIO - with self.fuse_mount(self.repository_location + '::archive', mountpoint, '-o', 'allow_damaged_files'): + with self.fuse_mount(self.repository_location, mountpoint, '--name=archive', '-o', 'allow_damaged_files'): open(os.path.join(mountpoint, path)).close() @unittest.skipUnless(llfuse, 'llfuse not installed') @@ -2784,11 +2786,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=' + method) verify_uniqueness() - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') verify_uniqueness() - self.cmd(f'--repo={self.repository_location}::test.2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') verify_uniqueness() - self.cmd(f'--repo={self.repository_location}::test.2', 'delete') + self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test.2') verify_uniqueness() def test_aes_counter_uniqueness_keyfile(self): @@ -2800,9 +2802,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_archive_items(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}::test', 'debug', 'dump-archive-items') + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive-items', '--name=test') output_dir = sorted(os.listdir('output')) assert len(output_dir) > 0 and output_dir[0].startswith('000000_') assert 'Done.' in output @@ -2810,7 +2812,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_repo_objs(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-repo-objs') output_dir = sorted(os.listdir('output')) @@ -2897,7 +2899,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_check_cache(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with self.open_repository() as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) with Cache(repository, key, manifest, sync=False) as cache: @@ -2916,17 +2918,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.check_cache() - self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') self.check_cache() original_archive = self.cmd(f'--repo={self.repository_location}', 'list') - self.cmd(f'--repo={self.repository_location}::test0', 'recreate', 'input/dir2', + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', 'input/dir2', '-e', 'input/dir2/file3', '--target=new-archive') self.check_cache() archives = self.cmd(f'--repo={self.repository_location}', 'list') assert original_archive in archives assert 'new-archive' in archives - listing = self.cmd(f'--repo={self.repository_location}::new-archive', 'list', '--short') + listing = self.cmd(f'--repo={self.repository_location}', 'list', '--name=new-archive', '--short') assert 'file1' not in listing assert 'dir2/file2' in listing assert 'dir2/file3' not in listing @@ -2935,10 +2937,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.create_regular_file('dir2/file3', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test0', 'recreate', 'input/dir2', '-e', 'input/dir2/file3') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', 'input/dir2', '-e', 'input/dir2/file3') self.check_cache() - listing = self.cmd(f'--repo={self.repository_location}::test0', 'list', '--short') + listing = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test0', '--short') assert 'file1' not in listing assert 'dir2/file2' in listing assert 'dir2/file3' not in listing @@ -2947,17 +2949,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_subtree_hardlinks(self): # This is essentially the same problem set as in test_extract_hardlinks self._extract_hardlinks_setup() - self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'recreate', 'input/dir1') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', 'input/dir1') self.check_cache() with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert os.stat('input/dir1/aaaa').st_nlink == 2 assert os.stat('input/dir1/source2').st_nlink == 2 with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test2', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test2') assert os.stat('input/dir1/hardlink').st_nlink == 4 def test_recreate_rechunkify(self): @@ -2965,9 +2967,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b'a' * 280) fd.write(b'b' * 280) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test1', 'create', '--chunker-params', '7,9,8,128', 'input') - self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input', '--files-cache=disabled') - list = self.cmd(f'--repo={self.repository_location}::test1', 'list', 'input/large_file', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--chunker-params', '7,9,8,128', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input', '--files-cache=disabled') + list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', '--format', '{num_chunks} {unique_chunks}') num_chunks, unique_chunks = map(int, list.split(' ')) # test1 and test2 do not deduplicate @@ -2975,20 +2977,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() # test1 and test2 do deduplicate after recreate - assert int(self.cmd(f'--repo={self.repository_location}::test1', 'list', 'input/large_file', '--format={size}')) - assert not int(self.cmd(f'--repo={self.repository_location}::test1', 'list', 'input/large_file', + assert int(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', '--format={size}')) + assert not int(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', '--format', '{unique_chunks}')) def test_recreate_recompress(self): self.create_regular_file('compressible', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input', '-C', 'none') - file_list = self.cmd(f'--repo={self.repository_location}::test', 'list', 'input/compressible', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', '-C', 'none') + file_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', 'input/compressible', '--format', '{size} {sha256}') size, sha256_before = file_list.split(' ') self.cmd(f'--repo={self.repository_location}', 'recreate', '-C', 'lz4', '--recompress') self.check_cache() - file_list = self.cmd(f'--repo={self.repository_location}::test', 'list', 'input/compressible', + file_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', 'input/compressible', '--format', '{size} {sha256}') size, sha256_after = file_list.split(' ') assert sha256_before == sha256_after @@ -2997,10 +2999,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): local_timezone = datetime.now(timezone(timedelta(0))).astimezone().tzinfo self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test0', 'recreate', '--timestamp', "1970-01-02T00:00:00", + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', '--timestamp', "1970-01-02T00:00:00", '--comment', 'test') - info = self.cmd(f'--repo={self.repository_location}::test0', 'info').splitlines() + info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test0').splitlines() dtime = datetime(1970, 1, 2) + local_timezone.utcoffset(None) s_time = dtime.strftime("%Y-%m-%d") assert any([re.search(r'Time \(start\).+ %s' % s_time, item) for item in info]) @@ -3009,21 +3011,21 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_dry_run(self): self.create_regular_file('compressible', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - archives_before = self.cmd(f'--repo={self.repository_location}::test', 'list') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + archives_before = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') self.cmd(f'--repo={self.repository_location}', 'recreate', '-n', '-e', 'input/compressible') self.check_cache() - archives_after = self.cmd(f'--repo={self.repository_location}::test', 'list') + archives_after = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') assert archives_after == archives_before def test_recreate_skips_nothing_to_do(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - info_before = self.cmd(f'--repo={self.repository_location}::test', 'info') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + info_before = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() - info_after = self.cmd(f'--repo={self.repository_location}::test', 'info') + info_after = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') assert info_before == info_after # includes archive ID def test_with_lock(self): @@ -3040,31 +3042,31 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file4', size=0) self.create_regular_file('file5', size=0) - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') - output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--list', '--info', '-e', 'input/file2') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--list', '--info', '-e', 'input/file2') self.check_cache() self.assert_in("input/file1", output) self.assert_in("x input/file2", output) - output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--list', '-e', 'input/file3') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--list', '-e', 'input/file3') self.check_cache() self.assert_in("input/file1", output) self.assert_in("x input/file3", output) - output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '-e', 'input/file4') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '-e', 'input/file4') self.check_cache() self.assert_not_in("input/file1", output) self.assert_not_in("x input/file4", output) - output = self.cmd(f'--repo={self.repository_location}::test', 'recreate', '--info', '-e', 'input/file5') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--info', '-e', 'input/file5') self.check_cache() self.assert_not_in("input/file1", output) self.assert_not_in("x input/file5", output) def test_bad_filters(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.cmd(f'--repo={self.repository_location}', 'delete', '--first', '1', '--last', '1', fork=True, exit_code=2) def test_key_export_keyfile(self): @@ -3264,7 +3266,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_manifest(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') dump_file = self.output_path + '/dump' output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-manifest', dump_file) assert output == "" @@ -3279,9 +3281,9 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_archive(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') dump_file = self.output_path + '/dump' - output = self.cmd(f'--repo={self.repository_location}::test', 'debug', 'dump-archive', dump_file) + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive', '--name=test', dump_file) assert output == "" with open(dump_file) as f: result = json.load(f) @@ -3295,7 +3297,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', '0' * 64).strip() assert output == 'object 0000000000000000000000000000000000000000000000000000000000000000 not found [info from chunks cache].' - create_json = json.loads(self.cmd(f'--repo={self.repository_location}::test', 'create', '--json', 'input')) + create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--json', 'input')) archive_id = create_json['archive']['id'] output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', archive_id).strip() assert output == 'object ' + archive_id + ' has 1 referrers [info from chunks cache].' @@ -3361,8 +3363,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'simple.tar', '--progress', '--tar-format=GNU') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar', '--progress', '--tar-format=GNU') with changedir('output'): # This probably assumes GNU tar. Note -p switch to extract permissions regardless of umask. subprocess.check_call(['tar', 'xpf', '../simple.tar', '--warning=no-timestamp']) @@ -3376,8 +3378,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - list = self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'simple.tar.gz', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + list = self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar.gz', '--list', '--tar-format=GNU') assert 'input/file1\n' in list assert 'input/dir2\n' in list @@ -3392,8 +3394,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') - list = self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'simple.tar', + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + list = self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar', '--strip-components=1', '--list', '--tar-format=GNU') # --list's path are those before processing with --strip-components assert 'input/file1\n' in list @@ -3406,7 +3408,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 @requires_gnutar def test_export_tar_strip_components_links(self): self._extract_hardlinks_setup() - self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'output.tar', + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'output.tar', '--strip-components=2', '--tar-format=GNU') with changedir('output'): subprocess.check_call(['tar', 'xpf', '../output.tar', '--warning=no-timestamp']) @@ -3419,7 +3421,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 @requires_gnutar def test_extract_hardlinks_tar(self): self._extract_hardlinks_setup() - self.cmd(f'--repo={self.repository_location}::test', 'export-tar', 'output.tar', 'input/dir1', '--tar-format=GNU') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'output.tar', 'input/dir1', '--tar-format=GNU') with changedir('output'): subprocess.check_call(['tar', 'xpf', '../output.tar', '--warning=no-timestamp']) assert os.stat('input/dir1/hardlink').st_nlink == 2 @@ -3431,11 +3433,11 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}::src', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::src', 'export-tar', 'simple.tar', f'--tar-format={tar_format}') - self.cmd(f'--repo={self.repository_location}::dst', 'import-tar', 'simple.tar') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=src', 'input') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', f'--tar-format={tar_format}') + self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}::dst', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=dst') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) @requires_gzip @@ -3445,21 +3447,21 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}::src', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::src', 'export-tar', 'simple.tgz', f'--tar-format={tar_format}') - self.cmd(f'--repo={self.repository_location}::dst', 'import-tar', 'simple.tgz') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=src', 'input') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tgz', f'--tar-format={tar_format}') + self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tgz') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}::dst', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=dst') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) def test_roundtrip_pax_borg(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}::src', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::src', 'export-tar', 'simple.tar', '--tar-format=BORG') - self.cmd(f'--repo={self.repository_location}::dst', 'import-tar', 'simple.tar') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=src', 'input') + self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', '--tar-format=BORG') + self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}::dst', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=dst') self.assert_dirs_equal('input', 'output/input') # derived from test_extract_xattrs_errors() @@ -3473,10 +3475,10 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute%p', b'value') self.cmd('init', self.repository_location, '-e' 'none') - self.cmd('create', self.repository_location + '::test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - self.cmd('extract', self.repository_location + '::test', exit_code=EXIT_WARNING) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) # derived from test_extract_xattrs_errors() @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='xattr not supported on this system or on this version of' @@ -3489,14 +3491,14 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.makedirs(os.path.join(self.input_path, 'dir%p')) xattr.setxattr(b'input/dir%p', b'user.attribute', b'value') self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - self.cmd(f'--repo={self.repository_location}::test', 'extract', exit_code=EXIT_WARNING) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) def test_do_not_mention_archive_if_you_can_not_find_repo(self): """https://github.com/borgbackup/borg/issues/6014""" - output = self.cmd(f'--repo={self.repository_location}-this-repository-does-not-exist::test', 'info', + output = self.cmd(f'--repo={self.repository_location}-this-repository-does-not-exist', 'info', '--name=test', exit_code=2, fork=True) self.assert_in('this-repository-does-not-exist', output) self.assert_not_in('this-repository-does-not-exist::test', output) @@ -3508,7 +3510,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 both the client and the server forget the nonce""" self.create_regular_file('file1', contents=b'Hello, borg') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 os.remove(os.path.join(self.repository_path, 'nonce')) @@ -3521,13 +3523,13 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 repo_list = self.cmd(f'--repo={self.repository_location}', 'list') assert 'test' in repo_list # The archive should still be readable - archive_info = self.cmd(f'--repo={self.repository_location}::test', 'info') + archive_info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') assert 'Archive name: test\n' in archive_info - archive_list = self.cmd(f'--repo={self.repository_location}::test', 'list') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') assert 'file1' in archive_list # Extracting the archive should work with changedir('output'): - self.cmd(f'--repo={self.repository_location}::test', 'extract') + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_dirs_equal('input', 'output/input') def test_recovery_from_deleted_repo_nonce(self): @@ -3539,13 +3541,13 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 """ self.create_regular_file('file1', contents=b'Hello, borg') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 nonce = os.path.join(self.repository_path, 'nonce') os.remove(nonce) - self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') assert os.path.exists(nonce) def test_init_defaults_to_argon2(self): @@ -3696,7 +3698,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) self.assert_in('New missing file chunk detected', output) self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) - output = self.cmd(f'--repo={self.repository_location}::archive1', 'list', '--format={health}#{path}{LF}', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=archive1', '--format={health}#{path}{LF}', exit_code=0) self.assert_in('broken#', output) # check that the file in the old archives has now a different chunk list without the killed chunk for archive_name in ('archive1', 'archive2'): @@ -3727,7 +3729,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): else: self.fail('should not happen') # list is also all-healthy again - output = self.cmd(f'--repo={self.repository_location}::archive1', 'list', '--format={health}#{path}{LF}', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=archive1', '--format={health}#{path}{LF}', exit_code=0) self.assert_not_in('broken#', output) def test_missing_archive_item_chunk(self): @@ -3824,7 +3826,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) - self.cmd(f'--repo={self.repository_location}::archive1', 'extract', '--dry-run', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'extract', '--name=archive1', '--dry-run', exit_code=0) def _test_verify_data(self, *init_args): shutil.rmtree(self.repository_path) @@ -3992,19 +3994,19 @@ class RemoteArchiverTestCase(ArchiverTestCase): self.create_regular_file('skipped-file1', contents=b"test file contents 3") self.create_regular_file('skipped-file2', contents=b"test file contents 4") self.create_regular_file('skipped-file3', contents=b"test file contents 5") - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') marker = 'cached responses left in RemoteRepository' with changedir('output'): - res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '3') + res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '3') assert marker not in res with self.assert_creates_file('file'): - res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '2') + res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '2') assert marker not in res with self.assert_creates_file('dir/file'): - res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '1') + res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '1') assert marker not in res with self.assert_creates_file('input/dir/file'): - res = self.cmd(f'--repo={self.repository_location}::test', 'extract', "--debug", '--strip-components', '0') + res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '0') assert marker not in res @@ -4033,17 +4035,17 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'info') def test_cache_files(self): - self.cmd(f'--repo={self.repository_location}::test', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.corrupt(os.path.join(self.cache_path, 'files')) - out = self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') + out = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') # borg warns about the corrupt files cache, but then continues without files cache. assert 'files cache is corrupted' in out def test_chunks_archive(self): - self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') # Find ID of test1 so we can corrupt it later :) target_id = self.cmd(f'--repo={self.repository_location}', 'list', '--format={id}{LF}').strip() - self.cmd(f'--repo={self.repository_location}::test2', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') # Force cache sync, creating archive chunks of test1 and test2 in chunks.archive.d self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') @@ -4063,7 +4065,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): config.write(fd) # Cache sync notices corrupted archive chunks, but automatically recovers. - out = self.cmd(f'--repo={self.repository_location}::test3', 'create', '-v', 'input', exit_code=1) + out = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '-v', 'input', exit_code=1) assert 'Reading cached archive chunk index for test1' in out assert 'Cached archive chunk index of test1 is corrupted' in out assert 'Fetching and building archive index for test1' in out @@ -4109,7 +4111,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Create the first snapshot - self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') # Setup files for the second snapshot self.create_regular_file('file_added', size=2048) @@ -4140,8 +4142,8 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): fd.write(b'appended_data') # Create the second snapshot - self.cmd(f'--repo={self.repository_location}::test1a', 'create', 'input') - self.cmd(f'--repo={self.repository_location}::test1b', 'create', '--chunker-params', '16,18,17,4095', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1a', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1b', '--chunker-params', '16,18,17,4095', 'input') def do_asserts(output, can_compare_ids): # File contents changed (deleted and replaced with a new file) @@ -4286,10 +4288,10 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): if are_hardlinks_supported(): assert not any(get_changes('input/hardlink_target_replaced', joutput)) - do_asserts(self.cmd(f'--repo={self.repository_location}::test0', 'diff', 'TODO_test0', 'test1a'), True) + do_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1a'), True) # We expect exit_code=1 due to the chunker params warning - do_asserts(self.cmd(f'--repo={self.repository_location}::test0', 'diff', 'TODO_test0', 'test1b', exit_code=1), False) - do_json_asserts(self.cmd(f'--repo={self.repository_location}::test0', 'diff', 'TODO_test0', 'test1a', '--json-lines'), True) + do_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1b', exit_code=1), False) + do_json_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1a', '--json-lines'), True) def test_sort_option(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -4298,7 +4300,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('f_file_removed', size=16) self.create_regular_file('c_file_changed', size=32) self.create_regular_file('e_file_changed', size=64) - self.cmd(f'--repo={self.repository_location}::test0', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') os.unlink('input/a_file_removed') os.unlink('input/f_file_removed') @@ -4308,9 +4310,10 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('e_file_changed', size=1024) self.create_regular_file('b_file_added', size=128) self.create_regular_file('d_file_added', size=256) - self.cmd(f'--repo={self.repository_location}::test1', 'create', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') - output = self.cmd(f'--repo={self.repository_location}::test0', 'diff', '--sort', 'TODO_test0', 'test1') + output = self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1', + '--sort') expected = [ 'a_file_removed', 'b_file_added', diff --git a/src/borg/testsuite/benchmark.py b/src/borg/testsuite/benchmark.py index f3ec06f2a..4eb3a3da6 100644 --- a/src/borg/testsuite/benchmark.py +++ b/src/borg/testsuite/benchmark.py @@ -28,7 +28,7 @@ def repo_url(request, tmpdir, monkeypatch): @pytest.fixture(params=["none", "repokey"]) def repo(request, cmd, repo_url): - cmd('init', '--encryption', request.param, repo_url) + cmd(f'--repo={repo_url}', 'init', '--encryption', request.param) return repo_url @@ -55,46 +55,52 @@ def testdata(request, tmpdir_factory): @pytest.fixture(params=['none', 'lz4']) -def archive(request, cmd, repo, testdata): - archive_url = repo + '::test' - cmd('create', '--compression', request.param, archive_url, testdata) - return archive_url +def repo_archive(request, cmd, repo, testdata): + archive = 'test' + cmd(f'--repo={repo}', 'create', f'--name={archive}', '--compression', request.param, testdata) + return repo, archive def test_create_none(benchmark, cmd, repo, testdata): - result, out = benchmark.pedantic(cmd, ('create', '--compression', 'none', repo + '::test', testdata)) + result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'create', '--compression', 'none', + '--name', 'test', testdata)) assert result == 0 def test_create_lz4(benchmark, cmd, repo, testdata): - result, out = benchmark.pedantic(cmd, ('create', '--compression', 'lz4', repo + '::test', testdata)) + result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'create', '--compression', 'lz4', + '--name', 'test', testdata)) assert result == 0 -def test_extract(benchmark, cmd, archive, tmpdir): +def test_extract(benchmark, cmd, repo_archive, tmpdir): + repo, archive = repo_archive with changedir(str(tmpdir)): - result, out = benchmark.pedantic(cmd, ('extract', archive)) + result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'extract', '--name', archive)) assert result == 0 -def test_delete(benchmark, cmd, archive): - result, out = benchmark.pedantic(cmd, ('delete', archive)) +def test_delete(benchmark, cmd, repo_archive): + repo, archive = repo_archive + result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'delete', '--name', archive)) assert result == 0 -def test_list(benchmark, cmd, archive): - result, out = benchmark(cmd, 'list', archive) +def test_list(benchmark, cmd, repo_archive): + repo, archive = repo_archive + result, out = benchmark(cmd, f'--repo={repo}', 'list', '--name', archive) assert result == 0 -def test_info(benchmark, cmd, archive): - result, out = benchmark(cmd, 'info', archive) +def test_info(benchmark, cmd, repo_archive): + repo, archive = repo_archive + result, out = benchmark(cmd, f'--repo={repo}', 'info', '--name', archive) assert result == 0 -def test_check(benchmark, cmd, archive): - repo = archive.split('::')[0] - result, out = benchmark(cmd, 'check', repo) +def test_check(benchmark, cmd, repo_archive): + repo, archive = repo_archive + result, out = benchmark(cmd, f'--repo={repo}', 'check') assert result == 0 From 7dbf125083afc80714255233038210ab3c7ac72b Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 16 Jun 2022 00:58:21 +0200 Subject: [PATCH 05/21] Location: remove archive name --- src/borg/archiver.py | 2 +- src/borg/helpers/parseformat.py | 41 +++------- src/borg/testsuite/helpers.py | 129 +++++++++++++------------------- 3 files changed, 60 insertions(+), 112 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 2e112fafe..62636c1a0 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -116,7 +116,7 @@ def argument(args, str_or_bool): def get_repository(location, *, create, exclusive, lock_wait, lock, append_only, make_parent_dirs, storage_quota, args): if location.proto == 'ssh': - repository = RemoteRepository(location.omit_archive(), create=create, exclusive=exclusive, + repository = RemoteRepository(location, create=create, exclusive=exclusive, lock_wait=lock_wait, lock=lock, append_only=append_only, make_parent_dirs=make_parent_dirs, args=args) diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index ab420dea7..808466776 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -301,9 +301,7 @@ def parse_stringified_list(s): class Location: - """Object representing a repository / archive location - """ - proto = user = _host = port = path = archive = None + """Object representing a repository location""" # user must not contain "@", ":" or "/". # Quoting adduser error message: @@ -335,15 +333,6 @@ class Location: (?P(/([^:]|(:(?!:)))+)) # start with /, then any chars, but no "::" """ - # optional ::archive_name at the end, archive name must not contain "/". - # borg mount's FUSE filesystem creates one level of directories from - # the archive names and of course "/" is not valid in a directory name. - optional_archive_re = r""" - (?: - :: # "::" as separator - (?P[^/]+) # archive name must not contain "/" - )?$""" # must match until the end - # host NAME, or host IP ADDRESS (v4 or v6, v6 must be in square brackets) host_re = r""" (?P( @@ -358,14 +347,13 @@ class Location: (?Pssh):// # ssh:// """ + optional_user_re + host_re + r""" # user@ (optional), host name or address (?::(?P\d+))? # :port (optional) - """ + abs_path_re + optional_archive_re, re.VERBOSE) # path or path::archive + """ + abs_path_re, re.VERBOSE) # path file_re = re.compile(r""" (?Pfile):// # file:// - """ + file_path_re + optional_archive_re, re.VERBOSE) # servername/path, path or path::archive + """ + file_path_re, re.VERBOSE) # servername/path or path - local_re = re.compile( - local_path_re + optional_archive_re, re.VERBOSE) # local path with optional archive + local_re = re.compile(local_path_re, re.VERBOSE) # local path win_file_re = re.compile(r""" (?:file://)? # optional file protocol @@ -373,7 +361,7 @@ class Location: (?:[a-zA-Z]:)? # Drive letter followed by a colon (optional) (?:[^:]+) # Anything which does not contain a :, at least one character ) - """ + optional_archive_re, re.VERBOSE) # archive name (optional, may be empty) + """, re.VERBOSE) def __init__(self, text='', overrides={}, other=False): self.repo_env_var = 'BORG_OTHER_REPO' if other else 'BORG_REPO' @@ -383,7 +371,8 @@ class Location: self._host = None self.port = None self.path = None - self.archive = None + self.raw = None + self.processed = None self.parse(text, overrides) def parse(self, text, overrides={}): @@ -413,10 +402,9 @@ class Location: if m: self.proto = 'file' self.path = m.group('path') - self.archive = m.group('archive') return True - # On windows we currently only support windows paths + # On windows we currently only support windows paths. return False m = self.ssh_re.match(text) @@ -426,19 +414,16 @@ class Location: self._host = m.group('host') self.port = m.group('port') and int(m.group('port')) or None self.path = normpath_special(m.group('path')) - self.archive = m.group('archive') return True m = self.file_re.match(text) if m: self.proto = m.group('proto') self.path = normpath_special(m.group('path')) - self.archive = m.group('archive') return True m = self.local_re.match(text) if m: - self.path = normpath_special(m.group('path')) - self.archive = m.group('archive') self.proto = 'file' + self.path = normpath_special(m.group('path')) return True return False @@ -449,7 +434,6 @@ class Location: 'host=%r' % self.host, 'port=%r' % self.port, 'path=%r' % self.path, - 'archive=%r' % self.archive, ] return ', '.join(items) @@ -494,13 +478,6 @@ class Location: 'utcnow': DatetimeWrapper(timestamp), }) - def omit_archive(self): - loc = Location(self.raw) - loc.archive = None - loc.raw = loc.raw.split("::")[0] - loc.processed = loc.processed.split("::")[0] - return loc - def location_validator(proto=None, other=False): def validator(text): diff --git a/src/borg/testsuite/helpers.py b/src/borg/testsuite/helpers.py index 81469a133..52bbd207b 100644 --- a/src/borg/testsuite/helpers.py +++ b/src/borg/testsuite/helpers.py @@ -54,65 +54,63 @@ class TestLocationWithoutEnv: def test_ssh(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('ssh://user@host:1234/some/path::archive')) == \ - "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive='archive')" - assert Location('ssh://user@host:1234/some/path::archive').to_key_filename() == keys_dir + 'host__some_path' assert repr(Location('ssh://user@host:1234/some/path')) == \ - "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path')" + assert Location('ssh://user@host:1234/some/path').to_key_filename() == keys_dir + 'host__some_path' + assert repr(Location('ssh://user@host:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='host', port=1234, path='/some/path')" assert repr(Location('ssh://user@host/some/path')) == \ - "Location(proto='ssh', user='user', host='host', port=None, path='/some/path', archive=None)" - assert repr(Location('ssh://user@[::]:1234/some/path::archive')) == \ - "Location(proto='ssh', user='user', host='::', port=1234, path='/some/path', archive='archive')" + "Location(proto='ssh', user='user', host='host', port=None, path='/some/path')" assert repr(Location('ssh://user@[::]:1234/some/path')) == \ - "Location(proto='ssh', user='user', host='::', port=1234, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='::', port=1234, path='/some/path')" + assert repr(Location('ssh://user@[::]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='::', port=1234, path='/some/path')" assert Location('ssh://user@[::]:1234/some/path').to_key_filename() == keys_dir + '____some_path' assert repr(Location('ssh://user@[::]/some/path')) == \ - "Location(proto='ssh', user='user', host='::', port=None, path='/some/path', archive=None)" - assert repr(Location('ssh://user@[2001:db8::]:1234/some/path::archive')) == \ - "Location(proto='ssh', user='user', host='2001:db8::', port=1234, path='/some/path', archive='archive')" + "Location(proto='ssh', user='user', host='::', port=None, path='/some/path')" assert repr(Location('ssh://user@[2001:db8::]:1234/some/path')) == \ - "Location(proto='ssh', user='user', host='2001:db8::', port=1234, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='2001:db8::', port=1234, path='/some/path')" + assert repr(Location('ssh://user@[2001:db8::]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::', port=1234, path='/some/path')" assert Location('ssh://user@[2001:db8::]:1234/some/path').to_key_filename() == keys_dir + '2001_db8____some_path' assert repr(Location('ssh://user@[2001:db8::]/some/path')) == \ - "Location(proto='ssh', user='user', host='2001:db8::', port=None, path='/some/path', archive=None)" - assert repr(Location('ssh://user@[2001:db8::c0:ffee]:1234/some/path::archive')) == \ - "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=1234, path='/some/path', archive='archive')" + "Location(proto='ssh', user='user', host='2001:db8::', port=None, path='/some/path')" assert repr(Location('ssh://user@[2001:db8::c0:ffee]:1234/some/path')) == \ - "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=1234, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=1234, path='/some/path')" + assert repr(Location('ssh://user@[2001:db8::c0:ffee]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=1234, path='/some/path')" assert repr(Location('ssh://user@[2001:db8::c0:ffee]/some/path')) == \ - "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=None, path='/some/path', archive=None)" - assert repr(Location('ssh://user@[2001:db8::192.0.2.1]:1234/some/path::archive')) == \ - "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=1234, path='/some/path', archive='archive')" + "Location(proto='ssh', user='user', host='2001:db8::c0:ffee', port=None, path='/some/path')" assert repr(Location('ssh://user@[2001:db8::192.0.2.1]:1234/some/path')) == \ - "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=1234, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=1234, path='/some/path')" + assert repr(Location('ssh://user@[2001:db8::192.0.2.1]:1234/some/path')) == \ + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=1234, path='/some/path')" assert repr(Location('ssh://user@[2001:db8::192.0.2.1]/some/path')) == \ - "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path')" assert Location('ssh://user@[2001:db8::192.0.2.1]/some/path').to_key_filename() == keys_dir + '2001_db8__192_0_2_1__some_path' assert repr(Location('ssh://user@[2a02:0001:0002:0003:0004:0005:0006:0007]/some/path')) == \ - "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=None, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=None, path='/some/path')" assert repr(Location('ssh://user@[2a02:0001:0002:0003:0004:0005:0006:0007]:1234/some/path')) == \ - "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=1234, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=1234, path='/some/path')" def test_file(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('file:///some/path::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive='archive')" assert repr(Location('file:///some/path')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/path', archive=None)" + "Location(proto='file', user=None, host=None, port=None, path='/some/path')" + assert repr(Location('file:///some/path')) == \ + "Location(proto='file', user=None, host=None, port=None, path='/some/path')" assert Location('file:///some/path').to_key_filename() == keys_dir + 'some_path' def test_smb(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('file:////server/share/path::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='//server/share/path', archive='archive')" - assert Location('file:////server/share/path::archive').to_key_filename() == keys_dir + 'server_share_path' + assert repr(Location('file:////server/share/path')) == \ + "Location(proto='file', user=None, host=None, port=None, path='//server/share/path')" + assert Location('file:////server/share/path').to_key_filename() == keys_dir + 'server_share_path' def test_folder(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('path::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='path', archive='archive')" assert repr(Location('path')) == \ - "Location(proto='file', user=None, host=None, port=None, path='path', archive=None)" + "Location(proto='file', user=None, host=None, port=None, path='path')" assert Location('path').to_key_filename() == keys_dir + 'path' def test_long_path(self, monkeypatch, keys_dir): @@ -121,88 +119,61 @@ class TestLocationWithoutEnv: def test_abspath(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('/some/absolute/path::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive='archive')" assert repr(Location('/some/absolute/path')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path', archive=None)" + "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path')" + assert repr(Location('/some/absolute/path')) == \ + "Location(proto='file', user=None, host=None, port=None, path='/some/absolute/path')" assert Location('/some/absolute/path').to_key_filename() == keys_dir + 'some_absolute_path' assert repr(Location('ssh://user@host/some/path')) == \ - "Location(proto='ssh', user='user', host='host', port=None, path='/some/path', archive=None)" + "Location(proto='ssh', user='user', host='host', port=None, path='/some/path')" assert Location('ssh://user@host/some/path').to_key_filename() == keys_dir + 'host__some_path' def test_relpath(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('some/relative/path::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive='archive')" assert repr(Location('some/relative/path')) == \ - "Location(proto='file', user=None, host=None, port=None, path='some/relative/path', archive=None)" + "Location(proto='file', user=None, host=None, port=None, path='some/relative/path')" + assert repr(Location('some/relative/path')) == \ + "Location(proto='file', user=None, host=None, port=None, path='some/relative/path')" assert Location('some/relative/path').to_key_filename() == keys_dir + 'some_relative_path' assert repr(Location('ssh://user@host/./some/path')) == \ - "Location(proto='ssh', user='user', host='host', port=None, path='/./some/path', archive=None)" + "Location(proto='ssh', user='user', host='host', port=None, path='/./some/path')" assert Location('ssh://user@host/./some/path').to_key_filename() == keys_dir + 'host__some_path' assert repr(Location('ssh://user@host/~/some/path')) == \ - "Location(proto='ssh', user='user', host='host', port=None, path='/~/some/path', archive=None)" + "Location(proto='ssh', user='user', host='host', port=None, path='/~/some/path')" assert Location('ssh://user@host/~/some/path').to_key_filename() == keys_dir + 'host__some_path' assert repr(Location('ssh://user@host/~user/some/path')) == \ - "Location(proto='ssh', user='user', host='host', port=None, path='/~user/some/path', archive=None)" + "Location(proto='ssh', user='user', host='host', port=None, path='/~user/some/path')" assert Location('ssh://user@host/~user/some/path').to_key_filename() == keys_dir + 'host__user_some_path' def test_with_colons(self, monkeypatch, keys_dir): monkeypatch.delenv('BORG_REPO', raising=False) - assert repr(Location('/abs/path:w:cols::arch:col')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols', archive='arch:col')" - assert repr(Location('/abs/path:with:colons::archive')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/abs/path:with:colons', archive='archive')" + assert repr(Location('/abs/path:w:cols')) == \ + "Location(proto='file', user=None, host=None, port=None, path='/abs/path:w:cols')" assert repr(Location('/abs/path:with:colons')) == \ - "Location(proto='file', user=None, host=None, port=None, path='/abs/path:with:colons', archive=None)" + "Location(proto='file', user=None, host=None, port=None, path='/abs/path:with:colons')" + assert repr(Location('/abs/path:with:colons')) == \ + "Location(proto='file', user=None, host=None, port=None, path='/abs/path:with:colons')" assert Location('/abs/path:with:colons').to_key_filename() == keys_dir + 'abs_path_with_colons' def test_user_parsing(self): # see issue #1930 - assert repr(Location('ssh://host/path::2016-12-31@23:59:59')) == \ - "Location(proto='ssh', user=None, host='host', port=None, path='/path', archive='2016-12-31@23:59:59')" - - def test_with_timestamp(self): - assert repr(Location('path::archive-{utcnow}').with_timestamp(datetime(2002, 9, 19, tzinfo=timezone.utc))) == \ - "Location(proto='file', user=None, host=None, port=None, path='path', archive='archive-2002-09-19T00:00:00')" - - def test_no_slashes(self, monkeypatch): - monkeypatch.delenv('BORG_REPO', raising=False) - with pytest.raises(ValueError): - Location('/some/path/to/repo::archive_name_with/slashes/is_invalid') + assert repr(Location('ssh://host/path')) == \ + "Location(proto='ssh', user=None, host='host', port=None, path='/path')" def test_canonical_path(self, monkeypatch): monkeypatch.delenv('BORG_REPO', raising=False) - locations = ['some/path::archive', 'file://some/path::archive', 'host:some/path::archive', - 'host:~user/some/path::archive', 'ssh://host/some/path::archive', - 'ssh://user@host:1234/some/path::archive'] + locations = ['some/path', 'file://some/path', 'host:some/path', + 'host:~user/some/path', 'ssh://host/some/path', + 'ssh://user@host:1234/some/path'] for location in locations: assert Location(location).canonical_path() == \ Location(Location(location).canonical_path()).canonical_path(), "failed: %s" % location - def test_format_path(self, monkeypatch): - monkeypatch.delenv('BORG_REPO', raising=False) - test_pid = os.getpid() - assert repr(Location('/some/path::archive{pid}')) == \ - f"Location(proto='file', user=None, host=None, port=None, path='/some/path', archive='archive{test_pid}')" - location_time1 = Location('/some/path::archive{now:%s}') - sleep(1.1) - location_time2 = Location('/some/path::archive{now:%s}') - assert location_time1.archive != location_time2.archive - def test_bad_syntax(self): with pytest.raises(ValueError): # this is invalid due to the 2nd colon, correct: 'ssh://user@host/path' Location('ssh://user@host:/path') - def test_omit_archive(self): - from borg.platform import hostname - loc = Location('ssh://user@host:1234/repos/{hostname}::archive') - loc_without_archive = loc.omit_archive() - assert loc_without_archive.archive is None - assert loc_without_archive.raw == "ssh://user@host:1234/repos/{hostname}" - assert loc_without_archive.processed == "ssh://user@host:1234/repos/%s" % hostname - class FormatTimedeltaTestCase(BaseTestCase): From 3e765522de4dccc820e9305758cbee75c664a916 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 16 Jun 2022 14:23:47 +0200 Subject: [PATCH 06/21] help: transfer from other repo --- src/borg/archiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 62636c1a0..415bfc001 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -4177,7 +4177,7 @@ class Archiver: help='do not change repository, just check') subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location', type=location_validator(other=True), default=Location(other=True), - help='source repository') + help='transfer archives from the other repository') define_archive_filters_group(subparser) # borg diff From 801ce819a317d6432c2c25ea6a7c8c7b63221026 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 16 Jun 2022 14:32:40 +0200 Subject: [PATCH 07/21] help: archive name --- src/borg/archiver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 415bfc001..dd834f592 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -3900,7 +3900,7 @@ class Archiver: archive_group = subparser.add_argument_group('Archive options') archive_group.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, default='{hostname}-{now}', - help='specify the name for the archive') + help='specify the archive name') archive_group.add_argument('--comment', dest='comment', metavar='COMMENT', type=CommentSpec, default='', help='add a comment text to the archive') archive_group.add_argument('--timestamp', metavar='TIMESTAMP', dest='timestamp', @@ -5000,10 +5000,10 @@ class Archiver: subparser.set_defaults(func=self.do_rename) subparser.add_argument('--name', metavar='OLDNAME', type=archivename_validator(), - help='the current archive name') + help='specify the archive name') subparser.add_argument('--name2', metavar='NEWNAME', type=archivename_validator(), - help='the new archive name') + help='specify the new archive name') # borg serve serve_epilog = process_epilog(""" From 206245f3cdee48e551e38294a6d1d0dc71308a4b Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 16 Jun 2022 15:41:37 +0200 Subject: [PATCH 08/21] --repo: add -r short option --- src/borg/archiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index dd834f592..487b31a16 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -3207,7 +3207,7 @@ class Archiver: 'compatible file can be generated by suffixing FILE with ".pyprof".') add_common_option('--rsh', metavar='RSH', dest='rsh', help="Use this command to connect to the 'borg serve' process (default: 'ssh')") - add_common_option('--repo', metavar='REPO', dest='location', + add_common_option('-r', '--repo', metavar='REPO', dest='location', type=location_validator(other=False), default=Location(other=False), help="repository to use") From c085c2744ba2c2ba9f8c76242090d6bca81ea944 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 15:18:24 +0200 Subject: [PATCH 09/21] borg rename NAME NEWNAME --- src/borg/archiver.py | 6 +++--- src/borg/testsuite/archiver.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 487b31a16..a12034e3c 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -1508,7 +1508,7 @@ class Archiver: @with_archive def do_rename(self, args, repository, manifest, key, cache, archive): """Rename an existing archive""" - archive.rename(args.name2) + archive.rename(args.newname) manifest.write() repository.commit(compact=False) cache.commit() @@ -4998,10 +4998,10 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='rename archive') subparser.set_defaults(func=self.do_rename) - subparser.add_argument('--name', metavar='OLDNAME', + subparser.add_argument('name', metavar='OLDNAME', type=archivename_validator(), help='specify the archive name') - subparser.add_argument('--name2', metavar='NEWNAME', + subparser.add_argument('newname', metavar='NEWNAME', type=archivename_validator(), help='specify the new archive name') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index a22eebe4a..918e8f089 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1508,9 +1508,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'rename', '--name=test', '--name2=test.3') + self.cmd(f'--repo={self.repository_location}', 'rename', 'test', 'test.3') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'rename', '--name=test.2', '--name2=test.4') + self.cmd(f'--repo={self.repository_location}', 'rename', 'test.2', 'test.4') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.3', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.4', '--dry-run') # Make sure both archives have been renamed @@ -1854,7 +1854,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') self.add_unknown_feature(Manifest.Operation.CHECK) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rename', '--name=test', '--name2=other']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rename', 'test', 'other']) def test_unknown_feature_on_delete(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) From 3fd5b73e1e89f8b1d1a4f22cd910f2f3e9e81ca2 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 15:31:26 +0200 Subject: [PATCH 10/21] borg create NAME ... --- src/borg/archiver.py | 16 +- src/borg/testsuite/archiver.py | 438 ++++++++++++++++---------------- src/borg/testsuite/benchmark.py | 6 +- 3 files changed, 230 insertions(+), 230 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index a12034e3c..1daf2a91c 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -671,20 +671,20 @@ class Archiver: compression = '--compression=none' # measure create perf (without files cache to always have it chunking) t_start = time.monotonic() - rc = self.do_create(self.parse_args([f'--repo={repo}', 'create', '--name=borg-benchmark-crud1', - compression, '--files-cache=disabled', path])) + rc = self.do_create(self.parse_args([f'--repo={repo}', 'create', compression, '--files-cache=disabled', + 'borg-benchmark-crud1', path])) t_end = time.monotonic() dt_create = t_end - t_start assert rc == 0 # now build files cache - rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', '--name=borg-benchmark-crud2', - compression, path])) + rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', compression, + 'borg-benchmark-crud2', path])) rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud2'])) assert rc1 == rc2 == 0 # measure a no-change update (archive1 is still present) t_start = time.monotonic() - rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', '--name=borg-benchmark-crud3', - compression, path])) + rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', compression, + 'borg-benchmark-crud3', path])) t_end = time.monotonic() dt_update = t_end - t_start rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud3'])) @@ -3899,8 +3899,6 @@ class Archiver: 'regular files. Also follows symlinks pointing to these kinds of files.') archive_group = subparser.add_argument_group('Archive options') - archive_group.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, default='{hostname}-{now}', - help='specify the archive name') archive_group.add_argument('--comment', dest='comment', metavar='COMMENT', type=CommentSpec, default='', help='add a comment text to the archive') archive_group.add_argument('--timestamp', metavar='TIMESTAMP', dest='timestamp', @@ -3919,6 +3917,8 @@ class Archiver: help='select compression algorithm, see the output of the ' '"borg help compression" command for details.') + subparser.add_argument('name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to archive') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 918e8f089..48f682f23 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -149,14 +149,14 @@ def test_return_codes(cmd, tmpdir): input.join('test_file').write('content') rc, out = cmd('--repo=%s' % str(repo), 'init', '--encryption=none') assert rc == EXIT_SUCCESS - rc, out = cmd('--repo=%s' % repo, 'create', '--name=archive', str(input)) + rc, out = cmd('--repo=%s' % repo, 'create', 'archive', str(input)) assert rc == EXIT_SUCCESS with changedir(str(output)): rc, out = cmd('--repo=%s' % repo, 'extract', '--name=archive') assert rc == EXIT_SUCCESS rc, out = cmd('--repo=%s' % repo, 'extract', '--name=archive', 'does/not/match') assert rc == EXIT_WARNING # pattern did not match - rc, out = cmd('--repo=%s' % repo, 'create', '--name=archive', str(input)) + rc, out = cmd('--repo=%s' % repo, 'create', 'archive', str(input)) assert rc == EXIT_ERROR # duplicate archive name @@ -219,7 +219,7 @@ def test_disk_full(cmd): break raise try: - rc, out = cmd('--repo=%s' % repo, 'create', '--name=test%03d' % i, input) + rc, out = cmd('--repo=%s' % repo, 'create', 'test%03d' % i, input) success = rc == EXIT_SUCCESS if not success: print('create', rc, out) @@ -299,7 +299,7 @@ class ArchiverTestCaseBase(BaseTestCase): return output def create_src_archive(self, name): - self.cmd(f'--repo={self.repository_location}', 'create', f'--name={name}', '--compression=lz4', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--compression=lz4', name, src_dir) def open_archive(self, name): repository = Repository(self.repository_path, exclusive=True) @@ -394,8 +394,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--show-version', '--show-rc', fork=True) self.assert_in('borgbackup version', output) self.assert_in('terminating with success status, rc 0', output) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-nodump', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', '--exclude-nodump', '--stats', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-nodump', 'test', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-nodump', '--stats', 'test.2', 'input') self.assert_in('Archive name: test.2', output) self.assert_in('This archive: ', output) with changedir('output'): @@ -463,7 +463,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', 'input') # give input twice! + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') # give input twice! # test if created archive has 'input' contents twice: archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] @@ -491,7 +491,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): pytest.skip('unix sockets disabled or not supported') elif err.errno == errno.EACCES: pytest.skip('permission denied to create unix sockets') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') sock.close() with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') @@ -501,7 +501,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_symlink_extract(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') assert os.readlink('input/link1') == 'somewhere' @@ -514,7 +514,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.symlink('target', 'symlink1') os.link('symlink1', 'symlink2', follow_symlinks=False) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') print(output) @@ -548,7 +548,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): have_noatime = has_noatime('input/file1') os.utime('input/file1', (atime, mtime)) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--atime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--atime', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') sti = os.stat('input/file1') @@ -568,7 +568,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') sti = os.stat('input/file1') @@ -584,7 +584,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--nobirthtime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--nobirthtime') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') sti = os.stat('input/file1') @@ -645,7 +645,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # we could create a sparse input file, so creating a backup of it and # extracting it again (as sparse) should also work: self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir(self.output_path): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--sparse') self.assert_dirs_equal('input', 'output/input') @@ -664,7 +664,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(filename, 'wb'): pass self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') for filename in filenames: with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', os.path.join('input', filename)) @@ -675,70 +675,70 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') shutil.rmtree(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.EncryptionMethodMismatch): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') def test_repository_swap_detection2(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test', 'input') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.RepositoryAccessAborted): - self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test.2', 'input') def test_repository_swap_detection_no_cache(self): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') shutil.rmtree(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.EncryptionMethodMismatch): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') def test_repository_swap_detection2_no_cache(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}_unencrypted', 'delete', '--cache-only') self.cmd(f'--repo={self.repository_location}_encrypted', 'delete', '--cache-only') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.RepositoryAccessAborted): - self.cmd(f'--repo={self.repository_location}_encrypted', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test.2', 'input') def test_repository_swap_detection_repokey_blank_passphrase(self): # Check that a repokey repo with a blank passphrase is considered like a plaintext repo. self.create_test_files() # User initializes her repository with her passphrase self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Attacker replaces it with her own repository, which is encrypted but has no passphrase set shutil.rmtree(self.repository_path) with environment_variable(BORG_PASSPHRASE=''): @@ -751,10 +751,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): # is set, while it isn't. Previously this raised no warning, # since the repository is, technically, encrypted. if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.CacheInitAbortedError): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') def test_repository_move(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -805,7 +805,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_strip_components(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir/file') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '3') assert not os.path.exists('file') @@ -833,7 +833,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.path.join(self.input_path, 'dir1/aaaa')) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') @requires_hardlinks @unittest.skipUnless(llfuse, 'llfuse not installed') @@ -910,7 +910,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', 'input') # give input twice! + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') # give input twice! # now test extraction with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') @@ -927,7 +927,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) self.create_regular_file('file4', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude=input/file4', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--exclude=input/file4', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', 'input/file1', ) self.assert_equal(sorted(os.listdir('output/input')), ['file1']) @@ -947,7 +947,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file333', size=1024 * 80) # Create with regular expression exclusion for file4 - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude=re:input/file4$', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--exclude=re:input/file4$', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) @@ -985,7 +985,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:input/file4$\n') fd.write(b'fm:*aa:*thing\n') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-from=' + self.exclude_file_path, 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-from=' + self.exclude_file_path, 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) @@ -1019,7 +1019,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) self.create_regular_file("file333", size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', "create", "--name=test", "input") + self.cmd(f'--repo={self.repository_location}', 'create', "test", "input") # Extract everything with regular expression with changedir("output"): @@ -1048,7 +1048,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') @@ -1072,7 +1072,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_progress(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--progress') @@ -1095,7 +1095,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_stdin(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = b'\x00foo\n\nbar\n \n' - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-', input=input_data) + self.cmd(f'--repo={self.repository_location}', 'create', 'test', '-', input=input_data) item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 @@ -1108,8 +1108,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = 'some test content' name = 'a/b/c' - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--stdin-name', name, '--content-from-command', - '--', 'echo', input_data) + self.cmd(f'--repo={self.repository_location}', 'create', '--stdin-name', name, '--content-from-command', + 'test', '--', 'echo', input_data) item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 @@ -1120,7 +1120,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_content_from_command_with_failed_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--content-from-command', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--content-from-command', 'test', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) @@ -1128,7 +1128,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_content_from_command_missing_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--content-from-command', exit_code=2) + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', '--content-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_paths_from_stdin(self): @@ -1139,7 +1139,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) input_data = b'input/file1\0input/dir1\0input/file4' - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', + self.cmd(f'--repo={self.repository_location}', 'create', 'test', '--paths-from-stdin', '--paths-delimiter', '\\0', input=input_data) archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] @@ -1153,7 +1153,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) input_data = 'input/file1\ninput/file2\ninput/file3' - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-command', + self.cmd(f'--repo={self.repository_location}', 'create', '--paths-from-command', 'test', '--', 'echo', input_data) archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] @@ -1161,7 +1161,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_paths_from_command_with_failed_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-command', + output = self.cmd(f'--repo={self.repository_location}', 'create', '--paths-from-command', 'test', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) @@ -1169,20 +1169,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_paths_from_command_missing_command(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--paths-from-command', exit_code=2) + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', '--paths-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_without_root(self): """test create without a root""" self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'create', 'test', exit_code=2) def test_create_pattern_root(self): """test create with only a root pattern""" self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', '--pattern=R input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', '-v', '--list', '--pattern=R input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) @@ -1192,9 +1192,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '-v', '--list', '--pattern=+input/file_important', '--pattern=-input/file*', - 'input') + 'test', 'input') self.assert_in("A input/file_important", output) self.assert_in('x input/file1', output) self.assert_in('x input/file2', output) @@ -1206,9 +1206,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('otherfile', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '-v', '--list', '--pattern=-input/otherfile', '--patterns-from=' + self.patterns_file_path, - 'input') + 'test', 'input') self.assert_in("A input/file_important", output) self.assert_in('x input/file1', output) self.assert_in('x input/file2', output) @@ -1224,9 +1224,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '-v', '--list', '--patterns-from=' + self.patterns_file_path2, - 'input') + 'test', 'input') self.assert_in('x input/x/a/foo_a', output) self.assert_in("A input/x/b/foo_b", output) self.assert_in('A input/y/foo_y', output) @@ -1241,9 +1241,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-v', '--list', + output = self.cmd(f'--repo={self.repository_location}', 'create', '-v', '--list', '--patterns-from=' + self.patterns_file_path2, - 'input') + 'test', 'input') self.assert_not_in('input/x/a/foo_a', output) self.assert_not_in('input/x/a', output) self.assert_in('A input/y/foo_y', output) @@ -1259,8 +1259,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) with changedir('input'): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', - '--patterns-from=' + self.patterns_file_path2, '.') + self.cmd(f'--repo={self.repository_location}', 'create', '--patterns-from=' + self.patterns_file_path2, + 'test', '.') # list the archive and verify that the "intermediate" folders appear before # their contents @@ -1277,15 +1277,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') - create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', - '--no-cache-sync', 'input', - '--json', '--error')) # ignore experimental warning + create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', + '--no-cache-sync', '--json', '--error', + 'test', 'input')) # ignore experimental warning info_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--name=test', '--json')) create_stats = create_json['cache']['stats'] info_stats = info_json['cache']['stats'] assert create_stats == info_stats self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--no-cache-sync', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--no-cache-sync', 'test2', 'input') self.cmd(f'--repo={self.repository_location}', 'info') self.cmd(f'--repo={self.repository_location}', 'check') @@ -1294,7 +1294,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--pattern=+input/file_important', '--pattern=-input/file*') @@ -1308,12 +1308,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_exclude_caches(self): self._create_test_caches() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-caches', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--exclude-caches') self._assert_test_caches() def test_recreate_exclude_caches(self): self._create_test_caches() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-caches') self._assert_test_caches() @@ -1331,13 +1331,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_exclude_tagged(self): self._create_test_tagged() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-if-present', '.NOBACKUP', - '--exclude-if-present', '00-NOBACKUP', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', + '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP') self._assert_test_tagged() def test_recreate_exclude_tagged(self): self._create_test_tagged() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP') self._assert_test_tagged() @@ -1370,13 +1370,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_exclude_keep_tagged(self): self._create_test_keep_tagged() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--exclude-if-present', '.NOBACKUP1', - '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--exclude-if-present', '.NOBACKUP1', + '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags') self._assert_test_keep_tagged() def test_recreate_exclude_keep_tagged(self): self._create_test_keep_tagged() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-if-present', '.NOBACKUP1', '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags') self._assert_test_keep_tagged() @@ -1388,7 +1388,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.mkdir(os.path.join(self.input_path, 'subdir')) # to make sure the tag is encountered *after* file1 os.link(os.path.join(self.input_path, 'file1'), os.path.join(self.input_path, 'subdir', CACHE_TAG_NAME)) # correct tag name, hardlink to file1 - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # in the "test" archive, we now have, in this order: # - a regular file item for "file1" # - a hardlink item for "CACHEDIR.TAG" referring back to file1 for its contents @@ -1410,7 +1410,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file') xattr.setxattr(b'input/file', b'security.capability', capabilities) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(os, 'fchown', patched_fchown): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') @@ -1431,7 +1431,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute', b'value') self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): input_abspath = os.path.abspath('input/file') with patch.object(xattr, 'setxattr', patched_setxattr_E2BIG): @@ -1451,7 +1451,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_regular_file('dir1/dir2/file', size=1024 * 80) with changedir('input/dir1/dir2'): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', + self.cmd(f'--repo={self.repository_location}', 'create', 'test', '../../../input/dir1/../dir1/dir2/..') output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') self.assert_not_in('..', output) @@ -1462,16 +1462,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) with changedir('input'): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--exclude=file1', '.') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', '.', '--exclude=file1') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test1') self.assert_equal(sorted(os.listdir('output')), ['file2']) with changedir('input'): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--exclude=./file1', '.') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', '.', '--exclude=./file1') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test2') self.assert_equal(sorted(os.listdir('output')), ['file2']) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '--exclude=input/./file1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input', '--exclude=input/./file1') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test3') self.assert_equal(sorted(os.listdir('output/input')), ['file2']) @@ -1479,13 +1479,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_repeated_files(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') def test_overwrite(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Overwriting regular files and directories should be supported os.mkdir('output/input') os.mkdir('output/input/file1') @@ -1504,8 +1504,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'rename', 'test', 'test.3') @@ -1523,7 +1523,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') info_repo = self.cmd(f'--repo={self.repository_location}', 'info') assert 'All archives:' in info_repo info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') @@ -1534,7 +1534,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info_json(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json')) repository = info_repo['repository'] assert len(repository['id']) == 64 @@ -1572,10 +1572,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_comment(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--comment', 'this is the comment', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '--comment', '"deleted" comment', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test4', '--comment', 'preserved comment', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--comment', 'this is the comment') + self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input', '--comment', '"deleted" comment') + self.cmd(f'--repo={self.repository_location}', 'create', 'test4', 'input', '--comment', 'preserved comment') assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') @@ -1592,11 +1592,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.3', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=another_test.1', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=another_test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.3', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'another_test.1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'another_test.2', 'input') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--prefix', 'another_') @@ -1612,9 +1612,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_delete_multiple(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input') self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test1', 'test2') self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test3', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test3') @@ -1624,8 +1624,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'no' self.cmd(f'--repo={self.repository_location}', 'delete', exit_code=2) assert os.path.exists(self.repository_path) @@ -1797,13 +1797,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_umask(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') mode = os.stat(self.repository_path).st_mode self.assertEqual(stat.S_IMODE(mode), 0o700) def test_create_dry_run(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--dry-run', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--dry-run', 'test', 'input') # Make sure no archive has been created with Repository(self.repository_path) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1827,13 +1827,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_unknown_feature_on_create(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) self.add_unknown_feature(Manifest.Operation.WRITE) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', '--name=test', 'input']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', 'test', 'input']) def test_unknown_feature_on_cache_sync(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') self.add_unknown_feature(Manifest.Operation.READ) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', '--name=test', 'input']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', 'test', 'input']) def test_unknown_feature_on_change_passphrase(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) @@ -1842,7 +1842,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_unknown_feature_on_read(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.READ) with changedir('output'): self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'extract', '--name=test']) @@ -1852,13 +1852,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_unknown_feature_on_rename(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.CHECK) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rename', 'test', 'other']) def test_unknown_feature_on_delete(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.DELETE) # delete of an archive raises self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'delete', '--name=test']) @@ -1869,7 +1869,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_unknown_feature_on_mount(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.READ) mountpoint = os.path.join(self.tmpdir, 'mountpoint') os.mkdir(mountpoint) @@ -1895,7 +1895,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): cache.commit() if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') else: called = False wipe_cache_safe = LocalCache.wipe_cache @@ -1906,7 +1906,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): wipe_cache_safe(*args) with patch.object(LocalCache, 'wipe_cache', wipe_wrapper): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') assert called @@ -1920,13 +1920,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_progress_on(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test4', '--progress', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test4', 'input', '--progress') self.assert_in("\r", output) def test_progress_off(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test5', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test5', 'input') self.assert_not_in("\r", output) def test_file_status(self): @@ -1937,11 +1937,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--list', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', 'test', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) # should find first file as unmodified - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', 'test2', 'input') self.assert_in("U input/file1", output) # this is expected, although surprising, for why, see: # https://borgbackup.readthedocs.org/en/latest/faq.html#i-am-seeing-a-added-status-for-a-unchanged-file @@ -1953,15 +1953,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', - '--list', '--files-cache=ctime,size', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', + '--list', '--files-cache=ctime,size') # modify file1, but cheat with the mtime (and atime) and also keep same size: st = os.stat('input/file1') self.create_regular_file('file1', contents=b'321') os.utime('input/file1', ns=(st.st_atime_ns, st.st_mtime_ns)) # this mode uses ctime for change detection, so it should find file1 as modified - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', - '--list', '--files-cache=ctime,size', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', + '--list', '--files-cache=ctime,size') self.assert_in("M input/file1", output) def test_file_status_ms_cache_mode(self): @@ -1970,14 +1970,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', - '--list', '--files-cache=mtime,size', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', + '--list', '--files-cache=mtime,size', 'test1', 'input') # change mode of file1, no content change: st = os.stat('input/file1') os.chmod('input/file1', st.st_mode ^ stat.S_IRWXO) # this triggers a ctime change, but mtime is unchanged # this mode uses mtime for change detection, so it should find file1 as unmodified - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', - '--list', '--files-cache=mtime,size', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', + '--list', '--files-cache=mtime,size', 'test2', 'input') self.assert_in("U input/file1", output) def test_file_status_rc_cache_mode(self): @@ -1986,11 +1986,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', - '--list', '--files-cache=rechunk,ctime', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', + '--list', '--files-cache=rechunk,ctime', 'test1', 'input') # no changes here, but this mode rechunks unconditionally - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', - '--list', '--files-cache=rechunk,ctime', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', + '--list', '--files-cache=rechunk,ctime', 'test2', 'input') self.assert_in("A input/file1", output) def test_file_status_excluded(self): @@ -2003,14 +2003,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file3', size=1024 * 80) platform.set_flags(os.path.join(self.input_path, 'file3'), stat.UF_NODUMP) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--list', '--exclude-nodump', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', '--exclude-nodump', 'test', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) if has_lchflags: self.assert_in("x input/file3", output) # should find second file as excluded - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', - '--list', '--exclude-nodump', 'input', '--exclude', '*/file2') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', + '--list', '--exclude-nodump', '--exclude', '*/file2') self.assert_in("U input/file1", output) self.assert_in("x input/file2", output) if has_lchflags: @@ -2019,8 +2019,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_json(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - create_info = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', - '--json', 'input')) + create_info = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--json', + 'test', 'input')) # The usual keys assert 'encryption' in create_info assert 'repository' in create_info @@ -2040,21 +2040,21 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file2', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # no listing by default - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.assert_not_in('file1', output) # shouldn't be listed even if unchanged - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.assert_not_in('file1', output) # should list the file as unchanged - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--list', '--filter=U', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', '--list', '--filter=U') self.assert_in('file1', output) # should *not* list the file as changed - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', '--list', '--filter=AM', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--list', '--filter=AM') self.assert_not_in('file1', output) # change the file self.create_regular_file('file1', size=1024 * 100) # should list the file as changed - output = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '--list', '--filter=AM', 'input') + output = self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input', '--list', '--filter=AM') self.assert_in('file1', output) @pytest.mark.skipif(not are_fifos_supported(), reason='FIFOs not supported') @@ -2079,7 +2079,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): t = Thread(target=fifo_feeder, args=(fifo_fn, data)) t.start() try: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--read-special', 'input/link_fifo') + self.cmd(f'--repo={self.repository_location}', 'create', '--read-special', 'test', 'input/link_fifo') finally: t.join() with changedir('output'): @@ -2092,25 +2092,25 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_read_special_broken_symlink(self): os.symlink('somewhere does not exist', os.path.join(self.input_path, 'link')) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--read-special', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--read-special', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') assert 'input/link -> somewhere does not exist' in output # def test_cmdline_compatibility(self): # self.create_regular_file('file1', size=1024 * 80) # self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - # self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + # self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # output = self.cmd('foo', self.repository_location, '--old') # self.assert_in('"--old" has been deprecated. Use "--new" instead', output) def test_prune_repository(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', src_dir) # these are not really a checkpoints, but they look like some: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3.checkpoint', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3.checkpoint.1', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test4.checkpoint', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test3.checkpoint', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test3.checkpoint.1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test4.checkpoint', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Would prune:\s+test1', output) # must keep the latest non-checkpoint archive: @@ -2133,7 +2133,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('test3.checkpoint.1', output) self.assert_in('test4.checkpoint', output) # now we supersede the latest checkpoint by a successful backup: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test5', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test5', src_dir) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=2') output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') # all checkpoints should be gone now: @@ -2148,8 +2148,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): return dtime.astimezone(dateutil.tz.UTC).strftime("%Y-%m-%dT%H:%M:%S") def _create_archive_ts(self, name, y, m, d, H=0, M=0, S=0): - self.cmd(f'--repo={self.repository_location}', 'create', f'--name={name}', - '--timestamp', self._to_utc_timestamp(y, m, d, H, M, S), src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', + '--timestamp', self._to_utc_timestamp(y, m, d, H, M, S), name, src_dir) # This test must match docs/misc/prune-example.txt def test_prune_repository_example(self): @@ -2238,8 +2238,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_prune_repository_save_space(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Keeping archive \(rule: daily #1\):\s+test2', output) assert re.search(r'Would prune:\s+test1', output) @@ -2253,10 +2253,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_prune_repository_prefix(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=foo-2015-08-12-10:00', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=foo-2015-08-12-20:00', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=bar-2015-08-12-10:00', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=bar-2015-08-12-20:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'foo-2015-08-12-10:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'foo-2015-08-12-20:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'bar-2015-08-12-10:00', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'bar-2015-08-12-20:00', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--prefix=foo-') assert re.search(r'Keeping archive \(rule: daily #1\):\s+foo-2015-08-12-20:00', output) assert re.search(r'Would prune:\s+foo-2015-08-12-10:00', output) @@ -2274,10 +2274,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_prune_repository_glob(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-10:00-foo', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-20:00-foo', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-10:00-bar', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=2015-08-12-20:00-bar', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-10:00-foo', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-20:00-foo', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-10:00-bar', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-20:00-bar', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--glob-archives=2015-*-foo') assert re.search(r'Keeping archive \(rule: daily #1\):\s+2015-08-12-20:00-foo', output) assert re.search(r'Would prune:\s+2015-08-12-10:00-foo', output) @@ -2295,9 +2295,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_prefix(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-1', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=something-else-than-test-1', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-2', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test-1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'something-else-than-test-1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test-2', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'list', '--prefix=test-') self.assert_in('test-1', output) self.assert_in('test-2', output) @@ -2305,7 +2305,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_format(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test', src_dir) output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') output_3 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{mtime:%s} {path}{NL}') @@ -2314,8 +2314,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_repository_format(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-1', '--comment', 'comment 1', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test-2', '--comment', 'comment 2', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--comment', 'comment 1', 'test-1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', '--comment', 'comment 2', 'test-2', src_dir) output_1 = self.cmd(f'--repo={self.repository_location}', 'list') output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{archive:<36} {time} [{id}]{NL}') self.assertEqual(output_1, output_2) @@ -2331,17 +2331,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('empty_file', size=0) self.create_regular_file('amb', contents=b'a' * 1000000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{sha256} {path}{NL}') assert "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 input/amb" in output assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 input/empty_file" in output def test_list_consider_checkpoints(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', src_dir) # these are not really a checkpoints, but they look like some: - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2.checkpoint', src_dir) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3.checkpoint.1', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test2.checkpoint', src_dir) + self.cmd(f'--repo={self.repository_location}', 'create', 'test3.checkpoint.1', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'list') assert "test1" in output assert "test2.checkpoint" not in output @@ -2358,7 +2358,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b'abba' * 2000000) fd.write(b'baab' * 2000000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{num_chunks} {unique_chunks} {path}{NL}') assert "0 0 input/empty_file" in output assert "2 2 input/two_chunks" in output @@ -2366,7 +2366,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_size(self): self.create_regular_file('compressible_file', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '-C', 'lz4', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '-C', 'lz4', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{size} {path}{NL}') size, path = output.split("\n")[1].split(" ") assert int(size) == 10000 @@ -2374,7 +2374,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_json(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') list_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) repository = list_repo['repository'] assert len(repository['id']) == 64 @@ -2407,7 +2407,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_log_json(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - log = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--log-json', 'input', '--list', '--debug') + log = self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--log-json', '--list', '--debug') messages = {} # type -> message, one of each kind for line in log.splitlines(): msg = json.loads(line) @@ -2425,13 +2425,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_profile(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', '--debug-profile=create.prof') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--debug-profile=create.prof') self.cmd('debug', 'convert-profile', 'create.prof', 'create.pyprof') stats = pstats.Stats('create.pyprof') stats.strip_dirs() stats.sort_stats('cumtime') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input', '--debug-profile=create.pyprof') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--debug-profile=create.pyprof') stats = pstats.Stats('create.pyprof') # Only do this on trusted data! stats.strip_dirs() stats.sort_stats('cumtime') @@ -2439,7 +2439,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_common_options(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - log = self.cmd(f'--repo={self.repository_location}', '--debug', 'create', '--name=test', 'input') + log = self.cmd(f'--repo={self.repository_location}', '--debug', 'create', 'test', 'input') assert 'security: read previous location' in log def test_change_passphrase(self): @@ -2513,8 +2513,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_test_files() have_noatime = has_noatime('input/file1') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive', '--exclude-nodump', '--atime', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive2', '--exclude-nodump', '--atime', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-nodump', '--atime', 'archive', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-nodump', '--atime', 'archive2', 'input') if has_lchflags: # remove the file we did not backup, so input and output become equal os.remove(os.path.join('input', 'flagfile')) @@ -2606,9 +2606,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('hardlink1', contents=b'123456') os.link('input/hardlink1', 'input/hardlink2') os.link('input/hardlink1', 'input/hardlink3') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'archive1', 'input') self.create_regular_file('test', contents=b'second') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=archive2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'archive2', 'input') mountpoint = os.path.join(self.tmpdir, 'mountpoint') # mount the whole repository, archive contents shall show up in versioned view: with self.fuse_mount(self.repository_location, mountpoint, '-o', 'versions'): @@ -2786,9 +2786,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=' + method) verify_uniqueness() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') verify_uniqueness() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test.2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') verify_uniqueness() self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test.2') verify_uniqueness() @@ -2802,7 +2802,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_archive_items(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive-items', '--name=test') output_dir = sorted(os.listdir('output')) @@ -2812,7 +2812,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_repo_objs(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-repo-objs') output_dir = sorted(os.listdir('output')) @@ -2899,7 +2899,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_check_cache(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with self.open_repository() as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) with Cache(repository, key, manifest, sync=False) as cache: @@ -2918,7 +2918,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.check_cache() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.check_cache() original_archive = self.cmd(f'--repo={self.repository_location}', 'list') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', 'input/dir2', @@ -2937,7 +2937,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.create_regular_file('dir2/file3', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', 'input/dir2', '-e', 'input/dir2/file3') self.check_cache() listing = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test0', '--short') @@ -2949,7 +2949,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_subtree_hardlinks(self): # This is essentially the same problem set as in test_extract_hardlinks self._extract_hardlinks_setup() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', 'input/dir1') self.check_cache() with changedir('output'): @@ -2967,8 +2967,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b'a' * 280) fd.write(b'b' * 280) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', '--chunker-params', '7,9,8,128', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input', '--files-cache=disabled') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', '--chunker-params', '7,9,8,128') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--files-cache=disabled') list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', '--format', '{num_chunks} {unique_chunks}') num_chunks, unique_chunks = map(int, list.split(' ')) @@ -2984,7 +2984,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_recompress(self): self.create_regular_file('compressible', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input', '-C', 'none') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '-C', 'none') file_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', 'input/compressible', '--format', '{size} {sha256}') size, sha256_before = file_list.split(' ') @@ -2999,7 +2999,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): local_timezone = datetime.now(timezone(timedelta(0))).astimezone().tzinfo self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', '--timestamp', "1970-01-02T00:00:00", '--comment', 'test') info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test0').splitlines() @@ -3011,7 +3011,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_dry_run(self): self.create_regular_file('compressible', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') archives_before = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') self.cmd(f'--repo={self.repository_location}', 'recreate', '-n', '-e', 'input/compressible') self.check_cache() @@ -3021,7 +3021,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_skips_nothing_to_do(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') info_before = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() @@ -3042,7 +3042,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file4', size=0) self.create_regular_file('file5', size=0) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--list', '--info', '-e', 'input/file2') self.check_cache() @@ -3066,7 +3066,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_bad_filters(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'delete', '--first', '1', '--last', '1', fork=True, exit_code=2) def test_key_export_keyfile(self): @@ -3266,7 +3266,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_manifest(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') dump_file = self.output_path + '/dump' output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-manifest', dump_file) assert output == "" @@ -3281,7 +3281,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_archive(self): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') dump_file = self.output_path + '/dump' output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive', '--name=test', dump_file) assert output == "" @@ -3297,7 +3297,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', '0' * 64).strip() assert output == 'object 0000000000000000000000000000000000000000000000000000000000000000 not found [info from chunks cache].' - create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', '--json', 'input')) + create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--json', 'test', 'input')) archive_id = create_json['archive']['id'] output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', archive_id).strip() assert output == 'object ' + archive_id + ' has 1 referrers [info from chunks cache].' @@ -3363,7 +3363,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar', '--progress', '--tar-format=GNU') with changedir('output'): # This probably assumes GNU tar. Note -p switch to extract permissions regardless of umask. @@ -3378,7 +3378,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') list = self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar.gz', '--list', '--tar-format=GNU') assert 'input/file1\n' in list @@ -3394,7 +3394,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') list = self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar', '--strip-components=1', '--list', '--tar-format=GNU') # --list's path are those before processing with --strip-components @@ -3433,7 +3433,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=src', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', f'--tar-format={tar_format}') self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') with changedir(self.output_path): @@ -3447,7 +3447,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=src', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tgz', f'--tar-format={tar_format}') self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tgz') with changedir(self.output_path): @@ -3457,7 +3457,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_roundtrip_pax_borg(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=src', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', '--tar-format=BORG') self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') with changedir(self.output_path): @@ -3475,7 +3475,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute%p', b'value') self.cmd('init', self.repository_location, '-e' 'none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) @@ -3491,7 +3491,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.makedirs(os.path.join(self.input_path, 'dir%p')) xattr.setxattr(b'input/dir%p', b'user.attribute', b'value') self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) @@ -3510,7 +3510,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 both the client and the server forget the nonce""" self.create_regular_file('file1', contents=b'Hello, borg') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 os.remove(os.path.join(self.repository_path, 'nonce')) @@ -3541,13 +3541,13 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 """ self.create_regular_file('file1', contents=b'Hello, borg') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 nonce = os.path.join(self.repository_path, 'nonce') os.remove(nonce) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') assert os.path.exists(nonce) def test_init_defaults_to_argon2(self): @@ -3994,7 +3994,7 @@ class RemoteArchiverTestCase(ArchiverTestCase): self.create_regular_file('skipped-file1', contents=b"test file contents 3") self.create_regular_file('skipped-file2', contents=b"test file contents 4") self.create_regular_file('skipped-file3', contents=b"test file contents 5") - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') marker = 'cached responses left in RemoteRepository' with changedir('output'): res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '3') @@ -4035,17 +4035,17 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'info') def test_cache_files(self): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.corrupt(os.path.join(self.cache_path, 'files')) - out = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') + out = self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') # borg warns about the corrupt files cache, but then continues without files cache. assert 'files cache is corrupted' in out def test_chunks_archive(self): - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') # Find ID of test1 so we can corrupt it later :) target_id = self.cmd(f'--repo={self.repository_location}', 'list', '--format={id}{LF}').strip() - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test2', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') # Force cache sync, creating archive chunks of test1 and test2 in chunks.archive.d self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') @@ -4065,7 +4065,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): config.write(fd) # Cache sync notices corrupted archive chunks, but automatically recovers. - out = self.cmd(f'--repo={self.repository_location}', 'create', '--name=test3', '-v', 'input', exit_code=1) + out = self.cmd(f'--repo={self.repository_location}', 'create', '-v', 'test3', 'input', exit_code=1) assert 'Reading cached archive chunk index for test1' in out assert 'Cached archive chunk index of test1 is corrupted' in out assert 'Fetching and building archive index for test1' in out @@ -4111,7 +4111,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Create the first snapshot - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') # Setup files for the second snapshot self.create_regular_file('file_added', size=2048) @@ -4142,8 +4142,8 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): fd.write(b'appended_data') # Create the second snapshot - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1a', 'input') - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1b', '--chunker-params', '16,18,17,4095', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1a', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1b', 'input', '--chunker-params', '16,18,17,4095') def do_asserts(output, can_compare_ids): # File contents changed (deleted and replaced with a new file) @@ -4300,7 +4300,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('f_file_removed', size=16) self.create_regular_file('c_file_changed', size=32) self.create_regular_file('e_file_changed', size=64) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test0', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') os.unlink('input/a_file_removed') os.unlink('input/f_file_removed') @@ -4310,7 +4310,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('e_file_changed', size=1024) self.create_regular_file('b_file_added', size=128) self.create_regular_file('d_file_added', size=256) - self.cmd(f'--repo={self.repository_location}', 'create', '--name=test1', 'input') + self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') output = self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1', '--sort') diff --git a/src/borg/testsuite/benchmark.py b/src/borg/testsuite/benchmark.py index 4eb3a3da6..fac828c13 100644 --- a/src/borg/testsuite/benchmark.py +++ b/src/borg/testsuite/benchmark.py @@ -57,19 +57,19 @@ def testdata(request, tmpdir_factory): @pytest.fixture(params=['none', 'lz4']) def repo_archive(request, cmd, repo, testdata): archive = 'test' - cmd(f'--repo={repo}', 'create', f'--name={archive}', '--compression', request.param, testdata) + cmd(f'--repo={repo}', 'create', f'{archive}', '--compression', request.param, testdata) return repo, archive def test_create_none(benchmark, cmd, repo, testdata): result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'create', '--compression', 'none', - '--name', 'test', testdata)) + 'test', testdata)) assert result == 0 def test_create_lz4(benchmark, cmd, repo, testdata): result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'create', '--compression', 'lz4', - '--name', 'test', testdata)) + 'test', testdata)) assert result == 0 From f8d2024578e199a2c20d4d478839808fc98eefd0 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 15:56:03 +0200 Subject: [PATCH 11/21] borg recreate -a ARCHIVE_GLOB ... --- src/borg/archiver.py | 28 +++++++++------------------- src/borg/helpers/manifest.py | 8 +++++--- src/borg/testsuite/archiver.py | 32 ++++++++++++++++---------------- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 1daf2a91c..f82b4726b 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -2005,25 +2005,16 @@ class Archiver: checkpoint_interval=args.checkpoint_interval, dry_run=args.dry_run, timestamp=args.timestamp) - if args.name: - name = args.name + archive_names = tuple(archive.name for archive in manifest.archives.list_considering(args)) + if args.target is not None and len(archive_names) != 1: + self.print_error('--target: Need to specify single archive') + return self.exit_code + for name in archive_names: if recreater.is_temporary_archive(name): - self.print_error('Refusing to work on temporary archive of prior recreate: %s', name) - return self.exit_code + continue + print('Processing', name) if not recreater.recreate(name, args.comment, args.target): - self.print_error('Nothing to do. Archive was not processed.\n' - 'Specify at least one pattern, PATH, --comment, re-compression or re-chunking option.') - else: - if args.target is not None: - self.print_error('--target: Need to specify single archive') - return self.exit_code - for archive in manifest.archives.list(sort_by=['ts']): - name = archive.name - if recreater.is_temporary_archive(name): - continue - print('Processing', name) - if not recreater.recreate(name, args.comment): - logger.info('Skipped archive %s: Nothing to do. Archive was not processed.', name) + logger.info('Skipped archive %s: Nothing to do. Archive was not processed.', name) if not args.dry_run: manifest.write() repository.commit(compact=False) @@ -4946,6 +4937,7 @@ class Archiver: define_exclusion_group(subparser, tag_files=True) archive_group = subparser.add_argument_group('Archive options') + define_archive_filters_group(archive_group) archive_group.add_argument('--target', dest='target', metavar='TARGET', default=None, type=archivename_validator(), help='create a new archive with the name ARCHIVE, do not replace existing archive ' @@ -4981,8 +4973,6 @@ class Archiver: 'HASH_MASK_BITS, HASH_WINDOW_SIZE) or `default` to use the current defaults. ' 'default: %s,%d,%d,%d,%d' % CHUNKER_PARAMS) - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, - help='specify the archive name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to recreate; patterns are supported') diff --git a/src/borg/helpers/manifest.py b/src/borg/helpers/manifest.py index 587176b49..786eb27bb 100644 --- a/src/borg/helpers/manifest.py +++ b/src/borg/helpers/manifest.py @@ -103,11 +103,13 @@ class Archives(abc.MutableMapping): """ get a list of archives, considering --first/last/prefix/glob-archives/sort/consider-checkpoints cmdline args """ - if args.name: - raise Error('The options --first, --last, --prefix, and --glob-archives, and --consider-checkpoints can only be used on repository targets.') + name = getattr(args, 'name', None) + consider_checkpoints = getattr(args, 'consider_checkpoints', None) + if name is not None: + raise Error('Giving a specific name is incompatible with options --first, --last, --prefix, and --glob-archives, and --consider-checkpoints.') if args.prefix is not None: args.glob_archives = args.prefix + '*' - return self.list(sort_by=args.sort_by.split(','), consider_checkpoints=args.consider_checkpoints, glob=args.glob_archives, first=args.first, last=args.last) + return self.list(sort_by=args.sort_by.split(','), consider_checkpoints=consider_checkpoints, glob=args.glob_archives, first=args.first, last=args.last) def set_raw_dict(self, d): """set the dict we get from the msgpack unpacker""" diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 48f682f23..b9c18ec22 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1314,7 +1314,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_exclude_caches(self): self._create_test_caches() self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-caches') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '--exclude-caches') self._assert_test_caches() def _create_test_tagged(self): @@ -1338,7 +1338,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_exclude_tagged(self): self._create_test_tagged() self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-if-present', '.NOBACKUP', + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '--exclude-if-present', '.NOBACKUP', '--exclude-if-present', '00-NOBACKUP') self._assert_test_tagged() @@ -1377,7 +1377,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_exclude_keep_tagged(self): self._create_test_keep_tagged() self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-if-present', '.NOBACKUP1', + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '--exclude-if-present', '.NOBACKUP1', '--exclude-if-present', '.NOBACKUP2', '--exclude-caches', '--keep-exclude-tags') self._assert_test_keep_tagged() @@ -1392,7 +1392,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # in the "test" archive, we now have, in this order: # - a regular file item for "file1" # - a hardlink item for "CACHEDIR.TAG" referring back to file1 for its contents - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--exclude-caches', '--keep-exclude-tags') + self.cmd(f'--repo={self.repository_location}', 'recreate', 'test', '--exclude-caches', '--keep-exclude-tags') # if issue #4911 is present, the recreate will crash with a KeyError for "input/file1" @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='Linux capabilities test, requires fakeroot >= 1.20.2') @@ -1579,10 +1579,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test1', '--comment', 'added comment') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test2', '--comment', 'modified comment') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test3', '--comment', '') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test4', '12345') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test1', '--comment', 'added comment') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test2', '--comment', 'modified comment') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test3', '--comment', '') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test4', '12345') assert 'Comment: added comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') assert 'Comment: modified comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test3') @@ -2921,7 +2921,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.check_cache() original_archive = self.cmd(f'--repo={self.repository_location}', 'list') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', 'input/dir2', + self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', 'input/dir2', '-e', 'input/dir2/file3', '--target=new-archive') self.check_cache() archives = self.cmd(f'--repo={self.repository_location}', 'list') @@ -2938,7 +2938,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('dir2/file3', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', 'input/dir2', '-e', 'input/dir2/file3') + self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', 'input/dir2', '-e', 'input/dir2/file3') self.check_cache() listing = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test0', '--short') assert 'file1' not in listing @@ -2950,7 +2950,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # This is essentially the same problem set as in test_extract_hardlinks self._extract_hardlinks_setup() self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', 'input/dir1') + self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', 'input/dir1') self.check_cache() with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') @@ -3000,7 +3000,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') - self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test0', '--timestamp', "1970-01-02T00:00:00", + self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', '--timestamp', "1970-01-02T00:00:00", '--comment', 'test') info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test0').splitlines() dtime = datetime(1970, 1, 2) + local_timezone.utcoffset(None) @@ -3044,22 +3044,22 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--list', '--info', '-e', 'input/file2') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '--list', '--info', '-e', 'input/file2') self.check_cache() self.assert_in("input/file1", output) self.assert_in("x input/file2", output) - output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--list', '-e', 'input/file3') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '--list', '-e', 'input/file3') self.check_cache() self.assert_in("input/file1", output) self.assert_in("x input/file3", output) - output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '-e', 'input/file4') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '-e', 'input/file4') self.check_cache() self.assert_not_in("input/file1", output) self.assert_not_in("x input/file4", output) - output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--name=test', '--info', '-e', 'input/file5') + output = self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', '--info', '-e', 'input/file5') self.check_cache() self.assert_not_in("input/file1", output) self.assert_not_in("x input/file5", output) From b8c7c53dde1df9cbf69566606d796f2a3f606352 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 16:04:58 +0200 Subject: [PATCH 12/21] borg extract NAME ... --- src/borg/archiver.py | 6 +- src/borg/testsuite/archiver.py | 162 ++++++++++++++++---------------- src/borg/testsuite/benchmark.py | 2 +- 3 files changed, 85 insertions(+), 85 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index f82b4726b..8dd84d56a 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -691,7 +691,7 @@ class Archiver: assert rc1 == rc2 == 0 # measure extraction (dry-run: without writing result to disk) t_start = time.monotonic() - rc = self.do_extract(self.parse_args([f'--repo={repo}', 'extract', '--name=borg-benchmark-crud1', + rc = self.do_extract(self.parse_args([f'--repo={repo}', 'extract', 'borg-benchmark-crud1', '--dry-run'])) t_end = time.monotonic() dt_extract = t_end - t_start @@ -4312,8 +4312,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='extract archive contents') subparser.set_defaults(func=self.do_extract) - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, - help='specify the archive name') 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', action='store_true', @@ -4334,6 +4332,8 @@ class Archiver: help='write all extracted data to stdout') subparser.add_argument('--sparse', dest='sparse', action='store_true', help='create holes in output sparse file from all-zero chunks') + subparser.add_argument('name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to extract; patterns are supported') define_exclusion_group(subparser, strip_components=True) diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index b9c18ec22..5093ee511 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -152,9 +152,9 @@ def test_return_codes(cmd, tmpdir): rc, out = cmd('--repo=%s' % repo, 'create', 'archive', str(input)) assert rc == EXIT_SUCCESS with changedir(str(output)): - rc, out = cmd('--repo=%s' % repo, 'extract', '--name=archive') + rc, out = cmd('--repo=%s' % repo, 'extract', 'archive') assert rc == EXIT_SUCCESS - rc, out = cmd('--repo=%s' % repo, 'extract', '--name=archive', 'does/not/match') + rc, out = cmd('--repo=%s' % repo, 'extract', 'archive', 'does/not/match') assert rc == EXIT_WARNING # pattern did not match rc, out = cmd('--repo=%s' % repo, 'create', 'archive', str(input)) assert rc == EXIT_ERROR # duplicate archive name @@ -399,7 +399,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('Archive name: test.2', output) self.assert_in('This archive: ', output) with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') list_output = self.cmd(f'--repo={self.repository_location}', 'list', '--short') self.assert_in('test', list_output) self.assert_in('test.2', list_output) @@ -494,7 +494,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') sock.close() with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') assert not os.path.exists('input/unix-socket') @pytest.mark.skipif(not are_symlinks_supported(), reason='symlinks not supported') @@ -503,7 +503,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') assert os.readlink('input/link1') == 'somewhere' @pytest.mark.skipif(not are_symlinks_supported() or not are_hardlinks_supported(), @@ -516,7 +516,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test') print(output) with changedir('input'): assert os.path.exists('target') @@ -550,7 +550,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--atime', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert sti.st_mtime_ns == sto.st_mtime_ns == mtime * 1e9 @@ -570,7 +570,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert int(sti.st_birthtime * 1e9) == int(sto.st_birthtime * 1e9) == birthtime * 1e9 @@ -586,7 +586,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--nobirthtime') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') sti = os.stat('input/file1') sto = os.stat('output/input/file1') assert int(sti.st_birthtime * 1e9) == birthtime * 1e9 @@ -647,7 +647,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--sparse') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--sparse') self.assert_dirs_equal('input', 'output/input') filename = os.path.join(self.output_path, 'input', 'sparse') with open(filename, 'rb') as fd: @@ -667,7 +667,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') for filename in filenames: with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', os.path.join('input', filename)) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', os.path.join('input', filename)) assert os.path.exists(os.path.join('output', 'input', filename)) def test_repository_swap_detection(self): @@ -807,14 +807,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('dir/file') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '3') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--strip-components', '3') assert not os.path.exists('file') with self.assert_creates_file('file'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '2') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--strip-components', '2') with self.assert_creates_file('dir/file'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '1') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--strip-components', '1') with self.assert_creates_file('input/dir/file'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '0') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--strip-components', '0') def _extract_hardlinks_setup(self): os.mkdir(os.path.join(self.input_path, 'dir1')) @@ -873,7 +873,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_hardlinks1(self): self._extract_hardlinks_setup() with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') assert os.stat('input/source').st_nlink == 4 assert os.stat('input/abba').st_nlink == 4 assert os.stat('input/dir1/hardlink').st_nlink == 4 @@ -884,14 +884,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_extract_hardlinks2(self): self._extract_hardlinks_setup() with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--strip-components', '2') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--strip-components', '2') assert os.stat('hardlink').st_nlink == 2 assert os.stat('subdir/hardlink').st_nlink == 2 assert open('subdir/hardlink', 'rb').read() == b'123456' assert os.stat('aaaa').st_nlink == 2 assert os.stat('source2').st_nlink == 2 with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', 'input/dir1') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', 'input/dir1') assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert open('input/dir1/subdir/hardlink', 'rb').read() == b'123456' @@ -913,7 +913,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') # give input twice! # now test extraction with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') # if issue #5603 happens, extraction gives rc == 1 (triggering AssertionError) and warnings like: # input/a/hardlink: link: [Errno 2] No such file or directory: 'input/a/hardlink' -> 'input/a/hardlink' # input/b/hardlink: link: [Errno 2] No such file or directory: 'input/a/hardlink' -> 'input/b/hardlink' @@ -929,13 +929,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file4', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'create', '--exclude=input/file4', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', 'input/file1', ) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', 'input/file1', ) self.assert_equal(sorted(os.listdir('output/input')), ['file1']) with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude=input/file2') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude=input/file2') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) def test_extract_include_exclude_regex(self): @@ -949,25 +949,25 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Create with regular expression exclusion for file4 self.cmd(f'--repo={self.repository_location}', 'create', '--exclude=re:input/file4$', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) shutil.rmtree('output/input') # Extract with regular expression exclusion with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude=re:file3+') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude=re:file3+') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2']) shutil.rmtree('output/input') # Combine --exclude with fnmatch and regular expression with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude=input/file2', '--exclude=re:file[01]') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude=input/file2', '--exclude=re:file[01]') self.assert_equal(sorted(os.listdir('output/input')), ['file3', 'file333']) shutil.rmtree('output/input') # Combine --exclude-from and regular expression exclusion with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path, + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude-from=' + self.exclude_file_path, '--exclude=re:file1', '--exclude=re:file(\\d)\\1\\1$') self.assert_equal(sorted(os.listdir('output/input')), ['file3']) @@ -987,7 +987,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-from=' + self.exclude_file_path, 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2', 'file3', 'file333']) shutil.rmtree('output/input') @@ -996,7 +996,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:file3+\n') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file2']) shutil.rmtree('output/input') @@ -1008,7 +1008,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b're:file2$\n') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--exclude-from=' + self.exclude_file_path) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--exclude-from=' + self.exclude_file_path) self.assert_equal(sorted(os.listdir('output/input')), ['file3']) def test_extract_with_pattern(self): @@ -1023,25 +1023,25 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Extract everything with regular expression with changedir("output"): - self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "re:.*") + self.cmd(f'--repo={self.repository_location}', "extract", "test", "re:.*") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file3", "file333", "file4"]) shutil.rmtree("output/input") # Extract with pattern while also excluding files with changedir("output"): - self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "--exclude=re:file[34]$", r"re:file\d$") + self.cmd(f'--repo={self.repository_location}', "extract", "--exclude=re:file[34]$", "test", r"re:file\d$") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2"]) shutil.rmtree("output/input") # Combine --exclude with pattern for extraction with changedir("output"): - self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "--exclude=input/file1", "re:file[12]$") + self.cmd(f'--repo={self.repository_location}', "extract", "--exclude=input/file1", "test", "re:file[12]$") self.assert_equal(sorted(os.listdir("output/input")), ["file2"]) shutil.rmtree("output/input") # Multiple pattern with changedir("output"): - self.cmd(f'--repo={self.repository_location}', "extract", "--name=test", "fm:input/file1", "fm:*file33*", "input/file2") + self.cmd(f'--repo={self.repository_location}', "extract", "test", "fm:input/file1", "fm:*file33*", "input/file2") self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file333"]) def test_extract_list_output(self): @@ -1051,22 +1051,22 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_not_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--info') + output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--info') self.assert_not_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--list') + output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--list') self.assert_in("input/file", output) shutil.rmtree('output/input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--list', '--info') + output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--list', '--info') self.assert_in("input/file", output) def test_extract_progress(self): @@ -1075,7 +1075,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--progress') + output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--progress') assert 'Extracting:' in output def _create_test_caches(self): @@ -1101,7 +1101,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert item['gid'] == 0 assert item['size'] == len(input_data) assert item['path'] == 'stdin' - extracted_data = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--stdout', binary_output=True) + extracted_data = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--stdout', binary_output=True) assert extracted_data == input_data def test_create_content_from_command(self): @@ -1115,7 +1115,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert item['gid'] == 0 assert item['size'] == len(input_data) + 1 # `echo` adds newline assert item['path'] == name - extracted_data = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--stdout') + extracted_data = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--stdout') assert extracted_data == input_data + '\n' def test_create_content_from_command_with_failed_command(self): @@ -1296,13 +1296,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file_important', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--pattern=+input/file_important', '--pattern=-input/file*') self.assert_equal(sorted(os.listdir('output/input')), ['file_important']) def _assert_test_caches(self): with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_equal(sorted(os.listdir('output/input')), ['cache2', 'file1']) self.assert_equal(sorted(os.listdir('output/input/cache2')), [CACHE_TAG_NAME]) @@ -1326,7 +1326,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def _assert_test_tagged(self): with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_equal(sorted(os.listdir('output/input')), ['file1']) def test_exclude_tagged(self): @@ -1360,7 +1360,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def _assert_test_keep_tagged(self): with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_equal(sorted(os.listdir('output/input')), ['file0', 'tagged1', 'tagged2', 'tagged3', 'taggedall']) self.assert_equal(os.listdir('output/input/tagged1'), ['.NOBACKUP1']) self.assert_equal(os.listdir('output/input/tagged2'), ['.NOBACKUP2']) @@ -1413,7 +1413,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(os, 'fchown', patched_fchown): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') assert xattr.getxattr(b'input/file', b'security.capability') == capabilities @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='xattr not supported on this system or on this version of' @@ -1435,15 +1435,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): with changedir('output'): input_abspath = os.path.abspath('input/file') with patch.object(xattr, 'setxattr', patched_setxattr_E2BIG): - out = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: too big for this filesystem\n' in out os.remove(input_abspath) with patch.object(xattr, 'setxattr', patched_setxattr_ENOTSUP): - out = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: xattrs not supported on this filesystem\n' in out os.remove(input_abspath) with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - out = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) + out = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=EXIT_WARNING) assert ': when setting extended attribute user.attribute: Permission denied\n' in out assert os.path.isfile(input_abspath) @@ -1464,16 +1464,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): with changedir('input'): self.cmd(f'--repo={self.repository_location}', 'create', 'test1', '.', '--exclude=file1') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test1') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test1') self.assert_equal(sorted(os.listdir('output')), ['file2']) with changedir('input'): self.cmd(f'--repo={self.repository_location}', 'create', 'test2', '.', '--exclude=./file1') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test2') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test2') self.assert_equal(sorted(os.listdir('output')), ['file2']) self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input', '--exclude=input/./file1') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test3') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test3') self.assert_equal(sorted(os.listdir('output/input')), ['file2']) def test_repeated_files(self): @@ -1491,14 +1491,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.mkdir('output/input/file1') os.mkdir('output/input/dir2') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_dirs_equal('input', 'output/input') # But non-empty dirs should fail os.unlink('output/input/file1') os.mkdir('output/input/file1') os.mkdir('output/input/file1/dir') with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=1) def test_rename(self): self.create_regular_file('file1', size=1024 * 80) @@ -1506,13 +1506,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'rename', 'test', 'test.3') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'rename', 'test.2', 'test.4') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.3', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.4', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test.3', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test.4', '--dry-run') # Make sure both archives have been renamed with Repository(self.repository_path) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1597,12 +1597,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test.3', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'another_test.1', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'another_test.2', 'input') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--prefix', 'another_') self.cmd(f'--repo={self.repository_location}', 'delete', '--last', '1') self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test.2', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') output = self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test.2', '--stats') self.assert_in('Deleted data:', output) # Make sure all data except the manifest has been deleted @@ -1616,7 +1616,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input') self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test1', 'test2') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test3', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test3', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test3') assert not self.cmd(f'--repo={self.repository_location}', 'list') @@ -1670,7 +1670,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_corrupted_repository(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.create_src_archive('test') - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--dry-run') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--dry-run') output = self.cmd(f'--repo={self.repository_location}', 'check', '--show-version') self.assert_in('borgbackup version', output) # implied output even without --info given self.assert_not_in('Starting repository check', output) # --info not given for root logger @@ -1734,14 +1734,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--bypass-lock') def test_readonly_info(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -1845,7 +1845,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.READ) with changedir('output'): - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'extract', '--name=test']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'extract', 'test']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'list']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'info', '--name=test']) @@ -2083,7 +2083,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): finally: t.join() with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') fifo_fn = 'input/link_fifo' with open(fifo_fn, 'rb') as f: extracted_data = f.read() @@ -2953,13 +2953,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test', 'input/dir1') self.check_cache() with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert os.stat('input/dir1/aaaa').st_nlink == 2 assert os.stat('input/dir1/source2').st_nlink == 2 with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test2') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test2') assert os.stat('input/dir1/hardlink').st_nlink == 4 def test_recreate_rechunkify(self): @@ -3437,7 +3437,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', f'--tar-format={tar_format}') self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=dst') + self.cmd(f'--repo={self.repository_location}', 'extract', 'dst') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) @requires_gzip @@ -3451,7 +3451,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tgz', f'--tar-format={tar_format}') self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tgz') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=dst') + self.cmd(f'--repo={self.repository_location}', 'extract', 'dst') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) def test_roundtrip_pax_borg(self): @@ -3461,7 +3461,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', '--tar-format=BORG') self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') with changedir(self.output_path): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=dst') + self.cmd(f'--repo={self.repository_location}', 'extract', 'dst') self.assert_dirs_equal('input', 'output/input') # derived from test_extract_xattrs_errors() @@ -3478,7 +3478,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=EXIT_WARNING) # derived from test_extract_xattrs_errors() @pytest.mark.skipif(not xattr.XATTR_FAKEROOT, reason='xattr not supported on this system or on this version of' @@ -3494,7 +3494,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', exit_code=EXIT_WARNING) + self.cmd(f'--repo={self.repository_location}', 'extract', 'test', exit_code=EXIT_WARNING) def test_do_not_mention_archive_if_you_can_not_find_repo(self): """https://github.com/borgbackup/borg/issues/6014""" @@ -3529,7 +3529,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 assert 'file1' in archive_list # Extracting the archive should work with changedir('output'): - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'extract', 'test') self.assert_dirs_equal('input', 'output/input') def test_recovery_from_deleted_repo_nonce(self): @@ -3826,7 +3826,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) - self.cmd(f'--repo={self.repository_location}', 'extract', '--name=archive1', '--dry-run', exit_code=0) + self.cmd(f'--repo={self.repository_location}', 'extract', 'archive1', '--dry-run', exit_code=0) def _test_verify_data(self, *init_args): shutil.rmtree(self.repository_path) @@ -3997,16 +3997,16 @@ class RemoteArchiverTestCase(ArchiverTestCase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') marker = 'cached responses left in RemoteRepository' with changedir('output'): - res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '3') + res = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', "--debug", '--strip-components', '3') assert marker not in res with self.assert_creates_file('file'): - res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '2') + res = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', "--debug", '--strip-components', '2') assert marker not in res with self.assert_creates_file('dir/file'): - res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '1') + res = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', "--debug", '--strip-components', '1') assert marker not in res with self.assert_creates_file('input/dir/file'): - res = self.cmd(f'--repo={self.repository_location}', 'extract', '--name=test', "--debug", '--strip-components', '0') + res = self.cmd(f'--repo={self.repository_location}', 'extract', 'test', "--debug", '--strip-components', '0') assert marker not in res diff --git a/src/borg/testsuite/benchmark.py b/src/borg/testsuite/benchmark.py index fac828c13..0a9a4373a 100644 --- a/src/borg/testsuite/benchmark.py +++ b/src/borg/testsuite/benchmark.py @@ -76,7 +76,7 @@ def test_create_lz4(benchmark, cmd, repo, testdata): def test_extract(benchmark, cmd, repo_archive, tmpdir): repo, archive = repo_archive with changedir(str(tmpdir)): - result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'extract', '--name', archive)) + result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'extract', archive)) assert result == 0 From 75b53de37ef2244180a35e693709ba08de1779e5 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 16:50:36 +0200 Subject: [PATCH 13/21] borg diff ARCH1 ARCH2 --- src/borg/archiver.py | 6 +++--- src/borg/testsuite/archiver.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 8dd84d56a..b3bd9de68 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -1477,7 +1477,7 @@ class Archiver: print_output = print_json_output if args.json_lines else print_text_output archive1 = archive - archive2 = Archive(repository, key, manifest, args.name2, + archive2 = Archive(repository, key, manifest, args.other_name, consider_part_files=args.consider_part_files) can_compare_chunk_ids = archive1.metadata.get('chunker_params', False) == archive2.metadata.get( @@ -4206,10 +4206,10 @@ class Archiver: help='Sort the output lines by file path.') subparser.add_argument('--json-lines', action='store_true', help='Format output as JSON Lines. ') - subparser.add_argument('--name', metavar='ARCHIVE1', + subparser.add_argument('name', metavar='ARCHIVE1', type=archivename_validator(), help='ARCHIVE1 name') - subparser.add_argument('--name2', metavar='ARCHIVE2', + subparser.add_argument('other_name', metavar='ARCHIVE2', type=archivename_validator(), help='ARCHIVE2 name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 5093ee511..f31813264 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1704,14 +1704,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'diff', '--name=a', '--name2=b', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'diff', 'a', 'b', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}', 'diff', '--name=a', '--name=b') + self.cmd(f'--repo={self.repository_location}', 'diff', 'a', 'b') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}', 'diff', '--name=a', '--name2=b', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'diff', 'a', 'b', '--bypass-lock') def test_readonly_export_tar(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -4288,10 +4288,10 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): if are_hardlinks_supported(): assert not any(get_changes('input/hardlink_target_replaced', joutput)) - do_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1a'), True) + do_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', 'test0', 'test1a'), True) # We expect exit_code=1 due to the chunker params warning - do_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1b', exit_code=1), False) - do_json_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1a', '--json-lines'), True) + do_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', 'test0', 'test1b', exit_code=1), False) + do_json_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', 'test0', 'test1a', '--json-lines'), True) def test_sort_option(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -4312,7 +4312,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('d_file_added', size=256) self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'diff', '--name=test0', '--name2=test1', + output = self.cmd(f'--repo={self.repository_location}', 'diff', 'test0', 'test1', '--sort') expected = [ 'a_file_removed', From 1ed7e5b2921674aaadbc408afc5246bc537b6ce4 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 19:40:06 +0200 Subject: [PATCH 14/21] borg dump-archive NAME / dump-archive-items NAME --- src/borg/archiver.py | 4 ++-- src/borg/testsuite/archiver.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index b3bd9de68..dd9f0e20d 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -3952,7 +3952,7 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump archive items (metadata) (debug)') subparser.set_defaults(func=self.do_debug_dump_archive_items) - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + subparser.add_argument('name', metavar='NAME', type=NameSpec, help='specify the archive name') debug_dump_archive_epilog = process_epilog(""" @@ -3964,7 +3964,7 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='dump decoded archive metadata (debug)') subparser.set_defaults(func=self.do_debug_dump_archive) - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + subparser.add_argument('name', metavar='NAME', type=NameSpec, help='specify the archive name') subparser.add_argument('path', metavar='PATH', type=str, help='file to dump data into') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index f31813264..5512d0bfb 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -2804,7 +2804,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): - output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive-items', '--name=test') + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive-items', 'test') output_dir = sorted(os.listdir('output')) assert len(output_dir) > 0 and output_dir[0].startswith('000000_') assert 'Done.' in output @@ -3283,7 +3283,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') dump_file = self.output_path + '/dump' - output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive', '--name=test', dump_file) + output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive', 'test', dump_file) assert output == "" with open(dump_file) as f: result = json.load(f) From e6a8984c999102ef29221b2949435c215c1eacf4 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 19:43:13 +0200 Subject: [PATCH 15/21] borg (import|export)-tar NAME ... --- src/borg/archiver.py | 6 +++--- src/borg/testsuite/archiver.py | 28 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index dd9f0e20d..fd6356268 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -4266,8 +4266,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='create tarball from archive') subparser.set_defaults(func=self.do_export_tar) - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, - help='specify the archive name') 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', @@ -4275,6 +4273,8 @@ class Archiver: subparser.add_argument('--tar-format', metavar='FMT', dest='tar_format', default='GNU', choices=('BORG', 'PAX', 'GNU'), help='select tar format: BORG, PAX or GNU') + subparser.add_argument('name', metavar='NAME', type=NameSpec, + help='specify the archive name') subparser.add_argument('tarfile', metavar='FILE', help='output tar file. "-" to write to stdout instead.') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, @@ -5214,7 +5214,7 @@ class Archiver: help='select compression algorithm, see the output of the ' '"borg help compression" command for details.') - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + subparser.add_argument('name', metavar='NAME', type=NameSpec, help='specify the archive name') subparser.add_argument('tarfile', metavar='TARFILE', help='input tar file. "-" to read from stdin instead.') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 5512d0bfb..71fb0a064 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1719,14 +1719,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'test.tar', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'test.tar', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'test.tar') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'test.tar') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'test.tar', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'test.tar', '--bypass-lock') def test_readonly_extract(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -3364,7 +3364,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar', '--progress', '--tar-format=GNU') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'simple.tar', '--progress', '--tar-format=GNU') with changedir('output'): # This probably assumes GNU tar. Note -p switch to extract permissions regardless of umask. subprocess.check_call(['tar', 'xpf', '../simple.tar', '--warning=no-timestamp']) @@ -3379,7 +3379,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - list = self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar.gz', + list = self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'simple.tar.gz', '--list', '--tar-format=GNU') assert 'input/file1\n' in list assert 'input/dir2\n' in list @@ -3395,7 +3395,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - list = self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'simple.tar', + list = self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'simple.tar', '--strip-components=1', '--list', '--tar-format=GNU') # --list's path are those before processing with --strip-components assert 'input/file1\n' in list @@ -3408,7 +3408,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 @requires_gnutar def test_export_tar_strip_components_links(self): self._extract_hardlinks_setup() - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'output.tar', + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'output.tar', '--strip-components=2', '--tar-format=GNU') with changedir('output'): subprocess.check_call(['tar', 'xpf', '../output.tar', '--warning=no-timestamp']) @@ -3421,7 +3421,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 @requires_gnutar def test_extract_hardlinks_tar(self): self._extract_hardlinks_setup() - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=test', 'output.tar', 'input/dir1', '--tar-format=GNU') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'output.tar', 'input/dir1', '--tar-format=GNU') with changedir('output'): subprocess.check_call(['tar', 'xpf', '../output.tar', '--warning=no-timestamp']) assert os.stat('input/dir1/hardlink').st_nlink == 2 @@ -3434,8 +3434,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', f'--tar-format={tar_format}') - self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'src', 'simple.tar', f'--tar-format={tar_format}') + self.cmd(f'--repo={self.repository_location}', 'import-tar', 'dst', 'simple.tar') with changedir(self.output_path): self.cmd(f'--repo={self.repository_location}', 'extract', 'dst') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) @@ -3448,8 +3448,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.unlink('input/flagfile') self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tgz', f'--tar-format={tar_format}') - self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tgz') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'src', 'simple.tgz', f'--tar-format={tar_format}') + self.cmd(f'--repo={self.repository_location}', 'import-tar', 'dst', 'simple.tgz') with changedir(self.output_path): self.cmd(f'--repo={self.repository_location}', 'extract', 'dst') self.assert_dirs_equal('input', 'output/input', ignore_ns=True, ignore_xattrs=True) @@ -3458,8 +3458,8 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') - self.cmd(f'--repo={self.repository_location}', 'export-tar', '--name=src', 'simple.tar', '--tar-format=BORG') - self.cmd(f'--repo={self.repository_location}', 'import-tar', '--name=dst', 'simple.tar') + self.cmd(f'--repo={self.repository_location}', 'export-tar', 'src', 'simple.tar', '--tar-format=BORG') + self.cmd(f'--repo={self.repository_location}', 'import-tar', 'dst', 'simple.tar') with changedir(self.output_path): self.cmd(f'--repo={self.repository_location}', 'extract', 'dst') self.assert_dirs_equal('input', 'output/input') From 6addafd784ddfaddf4adbbce29a069c37d9d5cd7 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Mon, 20 Jun 2022 20:11:26 +0200 Subject: [PATCH 16/21] borg mount -a ARCHIVE_GLOB mountpoint ... --- src/borg/archiver.py | 2 -- src/borg/fuse.py | 26 ++++++++++--------------- src/borg/testsuite/archiver.py | 35 +++++++++++++++++----------------- 3 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index fd6356268..c463f1809 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -3264,8 +3264,6 @@ class Archiver: def define_borg_mount(parser): parser.set_defaults(func=self.do_mount) - parser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, - help='specify the archive name') parser.add_argument('--consider-checkpoints', action='store_true', dest='consider_checkpoints', help='Show checkpoint archives in the repository contents list (default: hidden).') parser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str, diff --git a/src/borg/fuse.py b/src/borg/fuse.py index 5203a2959..b6349da7d 100644 --- a/src/borg/fuse.py +++ b/src/borg/fuse.py @@ -35,7 +35,7 @@ from .crypto.low_level import blake2b_128 from .archiver import Archiver from .archive import Archive, get_item_uid_gid from .hashindex import FuseVersionsIndex -from .helpers import daemonize, daemonizing, signal_handler, format_file_size, Error +from .helpers import daemonize, daemonizing, signal_handler, format_file_size from .helpers import HardLinkManager from .helpers import msgpack from .item import Item @@ -272,22 +272,16 @@ class FuseBackend: def _create_filesystem(self): self._create_dir(parent=1) # first call, create root dir (inode == 1) - if self._args.name: + self.versions_index = FuseVersionsIndex() + for archive in self._manifest.archives.list_considering(self._args): if self.versions: - raise Error("for versions view, do not specify a single archive, " - "but always give the repository as location.") - self._process_archive(self._args.name) - else: - self.versions_index = FuseVersionsIndex() - for archive in self._manifest.archives.list_considering(self._args): - if self.versions: - # process archives immediately - self._process_archive(archive.name) - else: - # lazily load archives, create archive placeholder inode - archive_inode = self._create_dir(parent=1, mtime=int(archive.ts.timestamp() * 1e9)) - self.contents[1][os.fsencode(archive.name)] = archive_inode - self.pending_archives[archive_inode] = archive.name + # process archives immediately + self._process_archive(archive.name) + else: + # lazily load archives, create archive placeholder inode + archive_inode = self._create_dir(parent=1, mtime=int(archive.ts.timestamp() * 1e9)) + self.contents[1][os.fsencode(archive.name)] = archive_inode + self.pending_archives[archive_inode] = archive.name def get_item(self, inode): item = self._inode_cache.get(inode) diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 71fb0a064..a73580c1c 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -847,22 +847,22 @@ class ArchiverTestCase(ArchiverTestCaseBase): ignore_perms = ['-o', 'ignore_permissions,defer_permissions'] else: ignore_perms = ['-o', 'ignore_permissions'] - with self.fuse_mount(self.repository_location, mountpoint, '--name=test', '--strip-components=2', *ignore_perms), \ - changedir(mountpoint): + with self.fuse_mount(self.repository_location, mountpoint, '-a', 'test', '--strip-components=2', *ignore_perms), \ + changedir(os.path.join(mountpoint, 'test')): assert os.stat('hardlink').st_nlink == 2 assert os.stat('subdir/hardlink').st_nlink == 2 assert open('subdir/hardlink', 'rb').read() == b'123456' assert os.stat('aaaa').st_nlink == 2 assert os.stat('source2').st_nlink == 2 - with self.fuse_mount(self.repository_location, mountpoint, 'input/dir1', '--name=test', *ignore_perms), \ - changedir(mountpoint): + with self.fuse_mount(self.repository_location, mountpoint, 'input/dir1', '-a', 'test', *ignore_perms), \ + changedir(os.path.join(mountpoint, 'test')): assert os.stat('input/dir1/hardlink').st_nlink == 2 assert os.stat('input/dir1/subdir/hardlink').st_nlink == 2 assert open('input/dir1/subdir/hardlink', 'rb').read() == b'123456' assert os.stat('input/dir1/aaaa').st_nlink == 2 assert os.stat('input/dir1/source2').st_nlink == 2 - with self.fuse_mount(self.repository_location, mountpoint, '--name=test', *ignore_perms), \ - changedir(mountpoint): + with self.fuse_mount(self.repository_location, mountpoint, '-a', 'test', *ignore_perms), \ + changedir(os.path.join(mountpoint, 'test')): assert os.stat('input/source').st_nlink == 4 assert os.stat('input/abba').st_nlink == 4 assert os.stat('input/dir1/hardlink').st_nlink == 4 @@ -2527,13 +2527,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): ignore_flags=True, ignore_xattrs=True) self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive2', 'input'), ignore_flags=True, ignore_xattrs=True) - # mount only 1 archive, its contents shall show up directly in mountpoint: - with self.fuse_mount(self.repository_location, mountpoint, '--name=archive'): - self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'input'), + with self.fuse_mount(self.repository_location, mountpoint, '-a', 'archive'): + self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive', 'input'), ignore_flags=True, ignore_xattrs=True) # regular file in_fn = 'input/file1' - out_fn = os.path.join(mountpoint, 'input', 'file1') + out_fn = os.path.join(mountpoint, 'archive', 'input', 'file1') # stat sti1 = os.stat(in_fn) sto1 = os.stat(out_fn) @@ -2554,7 +2553,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # hardlink (to 'input/file1') if are_hardlinks_supported(): in_fn = 'input/hardlink' - out_fn = os.path.join(mountpoint, 'input', 'hardlink') + out_fn = os.path.join(mountpoint, 'archive', 'input', 'hardlink') sti2 = os.stat(in_fn) sto2 = os.stat(out_fn) assert sti2.st_nlink == sto2.st_nlink == 2 @@ -2562,7 +2561,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # symlink if are_symlinks_supported(): in_fn = 'input/link1' - out_fn = os.path.join(mountpoint, 'input', 'link1') + out_fn = os.path.join(mountpoint, 'archive', 'input', 'link1') sti = os.stat(in_fn, follow_symlinks=False) sto = os.stat(out_fn, follow_symlinks=False) assert sti.st_size == len('somewhere') @@ -2572,13 +2571,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert os.readlink(in_fn) == os.readlink(out_fn) # FIFO if are_fifos_supported(): - out_fn = os.path.join(mountpoint, 'input', 'fifo1') + out_fn = os.path.join(mountpoint, 'archive', 'input', 'fifo1') sto = os.stat(out_fn) assert stat.S_ISFIFO(sto.st_mode) # list/read xattrs try: in_fn = 'input/fusexattr' - out_fn = os.fsencode(os.path.join(mountpoint, 'input', 'fusexattr')) + out_fn = os.fsencode(os.path.join(mountpoint, 'archive', 'input', 'fusexattr')) if not xattr.XATTR_FAKEROOT and xattr.is_enabled(self.input_path): assert sorted(no_selinux(xattr.listxattr(out_fn))) == [b'user.empty', b'user.foo', ] assert xattr.getxattr(out_fn, b'user.foo') == b'bar' @@ -2648,12 +2647,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) mountpoint = os.path.join(self.tmpdir, 'mountpoint') - with self.fuse_mount(self.repository_location, mountpoint, '--name=archive'): + with self.fuse_mount(self.repository_location, mountpoint, '-a', 'archive'): with pytest.raises(OSError) as excinfo: - open(os.path.join(mountpoint, path)) + open(os.path.join(mountpoint, 'archive', path)) assert excinfo.value.errno == errno.EIO - with self.fuse_mount(self.repository_location, mountpoint, '--name=archive', '-o', 'allow_damaged_files'): - open(os.path.join(mountpoint, path)).close() + with self.fuse_mount(self.repository_location, mountpoint, '-a', 'archive', '-o', 'allow_damaged_files'): + open(os.path.join(mountpoint, 'archive', path)).close() @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_mount_options(self): From 1bf8f71e69093c93347b096d3f1a981a4b1e418e Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 21 Jun 2022 00:35:05 +0200 Subject: [PATCH 17/21] borg list ARCHIVE, borg rlist --- src/borg/archiver.py | 110 +++++++++++++---------- src/borg/testsuite/archiver.py | 155 ++++++++++++++++----------------- 2 files changed, 137 insertions(+), 128 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index c463f1809..37d7464b8 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -1700,19 +1700,7 @@ class Archiver: @with_repository(compatibility=(Manifest.Operation.READ,)) def do_list(self, args, repository, manifest, key): - """List archive or repository contents""" - if args.name: - if args.json: - self.print_error('The --json option is only valid for listing archives, not archive contents.') - return self.exit_code - return self._list_archive(args, repository, manifest, key) - else: - if args.json_lines: - self.print_error('The --json-lines option is only valid for listing archive contents, not archives.') - return self.exit_code - return self._list_repository(args, repository, manifest, key) - - def _list_archive(self, args, repository, manifest, key): + """List archive contents""" matcher = self.build_matcher(args.patterns, args.paths) if args.format is not None: format = args.format @@ -1738,7 +1726,9 @@ class Archiver: return self.exit_code - def _list_repository(self, args, repository, manifest, key): + @with_repository(compatibility=(Manifest.Operation.READ,)) + def do_rlist(self, args, repository, manifest, key): + """List the archives contained in a repository""" if args.format is not None: format = args.format elif args.short: @@ -4686,7 +4676,7 @@ class Archiver: # borg list list_epilog = process_epilog(""" - This command lists the contents of a repository or an archive. + This command lists the contents of an archive. For more help on include/exclude patterns, see the :ref:`borg_patterns` command output. @@ -4701,35 +4691,20 @@ class Archiver: Examples: :: - $ borg list --format '{archive}{NL}' /path/to/repo - ArchiveFoo - ArchiveBar - ... - - # {VAR:NUMBER} - pad to NUMBER columns. - # Strings are left-aligned, numbers are right-aligned. - # Note: time columns except ``isomtime``, ``isoctime`` and ``isoatime`` cannot be padded. - $ borg list --format '{archive:36} {time} [{id}]{NL}' /path/to/repo - ArchiveFoo Thu, 2021-12-09 10:22:28 [0b8e9a312bef3f2f6e2d0fc110c196827786c15eba0188738e81697a7fa3b274] - $ borg list --format '{mode} {user:6} {group:6} {size:8} {mtime} {path}{extra}{NL}' /path/to/repo::ArchiveFoo + $ borg list --format '{mode} {user:6} {group:6} {size:8} {mtime} {path}{extra}{NL}' ArchiveFoo -rw-rw-r-- user user 1024 Thu, 2021-12-09 10:22:17 file-foo ... # {VAR:NUMBER} - pad to NUMBER columns right-aligned. - $ borg list --format '{mode} {user:>6} {group:>6} {size:<8} {mtime} {path}{extra}{NL}' /path/to/repo::ArchiveFoo + $ borg list --format '{mode} {user:>6} {group:>6} {size:<8} {mtime} {path}{extra}{NL}' ArchiveFoo -rw-rw-r-- user user 1024 Thu, 2021-12-09 10:22:17 file-foo ... The following keys are always available: - """) + BaseFormatter.keys_help() + textwrap.dedent(""" - Keys available only when listing archives in a repository: - - """) + ArchiveFormatter.keys_help() + textwrap.dedent(""" - Keys available only when listing files in an archive: """) + ItemFormatter.keys_help() @@ -4737,35 +4712,74 @@ class Archiver: description=self.do_list.__doc__, epilog=list_epilog, formatter_class=argparse.RawDescriptionHelpFormatter, - help='list archive or repository contents') + help='list archive contents') subparser.set_defaults(func=self.do_list) - subparser.add_argument('--consider-checkpoints', action='store_true', dest='consider_checkpoints', - help='Show checkpoint archives in the repository contents list (default: hidden).') subparser.add_argument('--short', dest='short', action='store_true', help='only print file/directory names, nothing else') subparser.add_argument('--format', metavar='FORMAT', dest='format', - help='specify format for file or archive listing ' - '(default for files: "{mode} {user:6} {group:6} {size:8} {mtime} {path}{extra}{NL}"; ' - 'for archives: "{archive:<36} {time} [{id}]{NL}")') - subparser.add_argument('--json', action='store_true', - help='Only valid for listing repository contents. Format output as JSON. ' - 'The form of ``--format`` is ignored, ' - 'but keys used in it are added to the JSON output. ' - 'Some keys are always present. Note: JSON can only represent text. ' - 'A "barchive" key is therefore not available.') + help='specify format for file listing ' + '(default: "{mode} {user:6} {group:6} {size:8} {mtime} {path}{extra}{NL}")') subparser.add_argument('--json-lines', action='store_true', - help='Only valid for listing archive contents. Format output as JSON Lines. ' + help='Format output as JSON Lines. ' 'The form of ``--format`` is ignored, ' 'but keys used in it are added to the JSON output. ' 'Some keys are always present. Note: JSON can only represent text. ' 'A "bpath" key is therefore not available.') - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, + subparser.add_argument('name', metavar='NAME', type=NameSpec, help='specify the archive name') subparser.add_argument('paths', metavar='PATH', nargs='*', type=str, help='paths to list; patterns are supported') - define_archive_filters_group(subparser) define_exclusion_group(subparser) + # borg rlist + rlist_epilog = process_epilog(""" + This command lists the archives contained in a repository. + .. man NOTES + The FORMAT specifier syntax + +++++++++++++++++++++++++++ + The ``--format`` option uses python's `format string syntax + `_. + Examples: + :: + $ borg rlist --format '{archive}{NL}' + ArchiveFoo + ArchiveBar + ... + + # {VAR:NUMBER} - pad to NUMBER columns. + # Strings are left-aligned, numbers are right-aligned. + # Note: time columns except ``isomtime``, ``isoctime`` and ``isoatime`` cannot be padded. + $ borg rlist --format '{archive:36} {time} [{id}]{NL}' /path/to/repo + ArchiveFoo Thu, 2021-12-09 10:22:28 [0b8e9a312bef3f2f6e2d0fc110c196827786c15eba0188738e81697a7fa3b274] + ... + + The following keys are always available: + + """) + BaseFormatter.keys_help() + textwrap.dedent(""" + Keys available only when listing archives in a repository: + + """) + ArchiveFormatter.keys_help() + subparser = subparsers.add_parser('rlist', parents=[common_parser], add_help=False, + description=self.do_rlist.__doc__, + epilog=rlist_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='list repository contents') + subparser.set_defaults(func=self.do_rlist) + subparser.add_argument('--consider-checkpoints', action='store_true', dest='consider_checkpoints', + help='Show checkpoint archives in the repository contents list (default: hidden).') + subparser.add_argument('--short', dest='short', action='store_true', + help='only print the archive names, nothing else') + subparser.add_argument('--format', metavar='FORMAT', dest='format', + help='specify format for archive listing ' + '(default: "{archive:<36} {time} [{id}]{NL}")') + subparser.add_argument('--json', action='store_true', + help='Format output as JSON. ' + 'The form of ``--format`` is ignored, ' + 'but keys used in it are added to the JSON output. ' + 'Some keys are always present. Note: JSON can only represent text. ' + 'A "barchive" key is therefore not available.') + define_archive_filters_group(subparser) + subparser = subparsers.add_parser('mount', parents=[common_parser], add_help=False, description=self.do_mount.__doc__, epilog=mount_epilog, @@ -5280,7 +5294,7 @@ class Archiver: if not getattr(args, 'lock', True): # Option --bypass-lock sets args.lock = False bypass_allowed = {self.do_check, self.do_config, self.do_diff, self.do_export_tar, self.do_extract, self.do_info, - self.do_list, self.do_mount, self.do_umount} + self.do_list, self.do_rlist, self.do_mount, self.do_umount} if func not in bypass_allowed: raise Error('Not allowed to bypass locking mechanism for chosen command') if getattr(args, 'timestamp', None): diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index a73580c1c..ce97c3fe7 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -231,9 +231,9 @@ def test_disk_full(cmd): # now some error happened, likely we are out of disk space. # free some space so we can expect borg to be able to work normally: shutil.rmtree(reserve, ignore_errors=True) - rc, out = cmd(f'--repo={repo}', 'list') + rc, out = cmd(f'--repo={repo}', 'rlist') if rc != EXIT_SUCCESS: - print('list', rc, out) + print('rlist', rc, out) rc, out = cmd(f'--repo={repo}', 'check', '--repair') if rc != EXIT_SUCCESS: print('check', rc, out) @@ -400,7 +400,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('This archive: ', output) with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', 'test') - list_output = self.cmd(f'--repo={self.repository_location}', 'list', '--short') + list_output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--short') self.assert_in('test', list_output) self.assert_in('test.2', list_output) expected = [ @@ -427,7 +427,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # remove the file we did not backup, so input and output become equal expected.remove('input/flagfile') # this file is UF_NODUMP os.remove(os.path.join('input', 'flagfile')) - list_output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--short') + list_output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--short') for name in expected: self.assert_in(name, list_output) self.assert_dirs_equal('input', 'output/input') @@ -465,7 +465,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') # give input twice! # test if created archive has 'input' contents twice: - archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] # we have all fs items exactly once! assert sorted(paths) == ['input', 'input/a', 'input/a/hardlink', 'input/b', 'input/b/hardlink'] @@ -1096,7 +1096,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') input_data = b'\x00foo\n\nbar\n \n' self.cmd(f'--repo={self.repository_location}', 'create', 'test', '-', input=input_data) - item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines')) + item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 assert item['size'] == len(input_data) @@ -1110,7 +1110,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): name = 'a/b/c' self.cmd(f'--repo={self.repository_location}', 'create', '--stdin-name', name, '--content-from-command', 'test', '--', 'echo', input_data) - item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines')) + item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines')) assert item['uid'] == 0 assert item['gid'] == 0 assert item['size'] == len(input_data) + 1 # `echo` adds newline @@ -1123,7 +1123,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'create', '--content-from-command', 'test', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") - archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) + archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'rlist', '--json')) assert archive_list['archives'] == [] def test_create_content_from_command_missing_command(self): @@ -1141,7 +1141,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): input_data = b'input/file1\0input/dir1\0input/file4' self.cmd(f'--repo={self.repository_location}', 'create', 'test', '--paths-from-stdin', '--paths-delimiter', '\\0', input=input_data) - archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] assert paths == ['input/file1', 'input/dir1', 'input/file4'] @@ -1155,7 +1155,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): input_data = 'input/file1\ninput/file2\ninput/file3' self.cmd(f'--repo={self.repository_location}', 'create', '--paths-from-command', 'test', '--', 'echo', input_data) - archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines') paths = [json.loads(line)['path'] for line in archive_list.split('\n') if line] assert paths == ['input/file1', 'input/file2', 'input/file3'] @@ -1164,7 +1164,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'create', '--paths-from-command', 'test', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") - archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) + archive_list = json.loads(self.cmd(f'--repo={self.repository_location}', 'rlist', '--json')) assert archive_list['archives'] == [] def test_create_paths_from_command_missing_command(self): @@ -1264,7 +1264,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # list the archive and verify that the "intermediate" folders appear before # their contents - out = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{type} {path}{NL}') + out = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{type} {path}{NL}') out_list = out.splitlines() self.assert_in('d x/a', out_list) @@ -1453,7 +1453,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with changedir('input/dir1/dir2'): self.cmd(f'--repo={self.repository_location}', 'create', 'test', '../../../input/dir1/../dir1/dir2/..') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') + output = self.cmd(f'--repo={self.repository_location}', 'list', 'test') self.assert_not_in('..', output) self.assert_in(' input/dir1/dir2/file', output) @@ -1618,7 +1618,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test1', 'test2') self.cmd(f'--repo={self.repository_location}', 'extract', 'test3', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test3') - assert not self.cmd(f'--repo={self.repository_location}', 'list') + assert not self.cmd(f'--repo={self.repository_location}', 'rlist') def test_delete_repo(self): self.create_regular_file('file1', size=1024 * 80) @@ -1650,7 +1650,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test', '--force') self.assert_in('deleted archive was corrupted', output) self.cmd(f'--repo={self.repository_location}', 'check', '--repair') - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('test', output) def test_delete_double_force(self): @@ -1664,7 +1664,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): repository.commit(compact=False) self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test', '--force', '--force') self.cmd(f'--repo={self.repository_location}', 'check', '--repair') - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('test', output) def test_corrupted_repository(self): @@ -1764,14 +1764,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'list', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'rlist', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}', 'list') + self.cmd(f'--repo={self.repository_location}', 'rlist') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}', 'list', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'rlist', '--bypass-lock') @unittest.skipUnless(llfuse, 'llfuse not installed') def test_readonly_mount(self): @@ -1847,7 +1847,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with changedir('output'): self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'extract', 'test']) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'list']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rlist']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'info', '--name=test']) def test_unknown_feature_on_rename(self): @@ -2093,7 +2093,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.symlink('somewhere does not exist', os.path.join(self.input_path, 'link')) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--read-special', 'test', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') + output = self.cmd(f'--repo={self.repository_location}', 'list', 'test') assert 'input/link -> somewhere does not exist' in output # def test_cmdline_compatibility(self): @@ -2117,14 +2117,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert re.search(r'Keeping archive \(rule: daily #1\):\s+test2', output) # must keep the latest checkpoint archive: assert re.search(r'Keeping checkpoint archive:\s+test4.checkpoint', output) - output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--consider-checkpoints') self.assert_in('test1', output) self.assert_in('test2', output) self.assert_in('test3.checkpoint', output) self.assert_in('test3.checkpoint.1', output) self.assert_in('test4.checkpoint', output) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--consider-checkpoints') self.assert_not_in('test1', output) # the latest non-checkpoint archive must be still there: self.assert_in('test2', output) @@ -2135,7 +2135,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # now we supersede the latest checkpoint by a successful backup: self.cmd(f'--repo={self.repository_location}', 'create', 'test5', src_dir) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=2') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--consider-checkpoints') # all checkpoints should be gone now: self.assert_not_in('checkpoint', output) # the latest archive must be still there @@ -2199,12 +2199,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert re.search(r'Keeping archive \(rule: monthly #' + str(i) + r'\):\s+test' + ("%02d" % (8-i)), output) for i in range(1, 15): assert re.search(r'Keeping archive \(rule: daily #' + str(i) + r'\):\s+test' + ("%02d" % (22-i)), output) - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') # Nothing pruned after dry run for i in range(1, 25): self.assert_in('test%02d' % i, output) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=14', '--keep-monthly=6', '--keep-yearly=1') - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') # All matching backups plus oldest kept for i in range(1, 22): self.assert_in('test%02d' % i, output) @@ -2243,11 +2243,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') assert re.search(r'Keeping archive \(rule: daily #1\):\s+test2', output) assert re.search(r'Would prune:\s+test1', output) - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_in('test1', output) self.assert_in('test2', output) self.cmd(f'--repo={self.repository_location}', 'prune', '--save-space', '--keep-daily=1') - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('test1', output) self.assert_in('test2', output) @@ -2260,13 +2260,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--prefix=foo-') assert re.search(r'Keeping archive \(rule: daily #1\):\s+foo-2015-08-12-20:00', output) assert re.search(r'Would prune:\s+foo-2015-08-12-10:00', output) - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_in('foo-2015-08-12-10:00', output) self.assert_in('foo-2015-08-12-20:00', output) self.assert_in('bar-2015-08-12-10:00', output) self.assert_in('bar-2015-08-12-20:00', output) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1', '--prefix=foo-') - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('foo-2015-08-12-10:00', output) self.assert_in('foo-2015-08-12-20:00', output) self.assert_in('bar-2015-08-12-10:00', output) @@ -2281,13 +2281,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1', '--glob-archives=2015-*-foo') assert re.search(r'Keeping archive \(rule: daily #1\):\s+2015-08-12-20:00-foo', output) assert re.search(r'Would prune:\s+2015-08-12-10:00-foo', output) - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_in('2015-08-12-10:00-foo', output) self.assert_in('2015-08-12-20:00-foo', output) self.assert_in('2015-08-12-10:00-bar', output) self.assert_in('2015-08-12-20:00-bar', output) self.cmd(f'--repo={self.repository_location}', 'prune', '--keep-daily=1', '--glob-archives=2015-*-foo') - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('2015-08-12-10:00-foo', output) self.assert_in('2015-08-12-20:00-foo', output) self.assert_in('2015-08-12-10:00-bar', output) @@ -2298,7 +2298,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'something-else-than-test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'test-2', src_dir) - output = self.cmd(f'--repo={self.repository_location}', 'list', '--prefix=test-') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--prefix=test-') self.assert_in('test-1', output) self.assert_in('test-2', output) self.assert_not_in('something-else', output) @@ -2306,24 +2306,24 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_format(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', src_dir) - output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') - output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') - output_3 = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{mtime:%s} {path}{NL}') + output_1 = self.cmd(f'--repo={self.repository_location}', 'list', 'test') + output_2 = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') + output_3 = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{mtime:%s} {path}{NL}') self.assertEqual(output_1, output_2) self.assertNotEqual(output_1, output_3) - def test_list_repository_format(self): + def test_archives_format(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--comment', 'comment 1', 'test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', '--comment', 'comment 2', 'test-2', src_dir) - output_1 = self.cmd(f'--repo={self.repository_location}', 'list') - output_2 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{archive:<36} {time} [{id}]{NL}') + output_1 = self.cmd(f'--repo={self.repository_location}', 'rlist') + output_2 = self.cmd(f'--repo={self.repository_location}', 'rlist', '--format', '{archive:<36} {time} [{id}]{NL}') self.assertEqual(output_1, output_2) - output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--short') + output_1 = self.cmd(f'--repo={self.repository_location}', 'rlist', '--short') self.assertEqual(output_1, 'test-1\ntest-2\n') - output_1 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{barchive}/') + output_1 = self.cmd(f'--repo={self.repository_location}', 'rlist', '--format', '{barchive}/') self.assertEqual(output_1, 'test-1/test-2/') - output_3 = self.cmd(f'--repo={self.repository_location}', 'list', '--format', '{name} {comment}{NL}') + output_3 = self.cmd(f'--repo={self.repository_location}', 'rlist', '--format', '{name} {comment}{NL}') self.assert_in('test-1 comment 1\n', output_3) self.assert_in('test-2 comment 2\n', output_3) @@ -2332,7 +2332,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('amb', contents=b'a' * 1000000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{sha256} {path}{NL}') + output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{sha256} {path}{NL}') assert "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 input/amb" in output assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 input/empty_file" in output @@ -2342,11 +2342,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): # these are not really a checkpoints, but they look like some: self.cmd(f'--repo={self.repository_location}', 'create', 'test2.checkpoint', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'test3.checkpoint.1', src_dir) - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') assert "test1" in output assert "test2.checkpoint" not in output assert "test3.checkpoint.1" not in output - output = self.cmd(f'--repo={self.repository_location}', 'list', '--consider-checkpoints') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--consider-checkpoints') assert "test1" in output assert "test2.checkpoint" in output assert "test3.checkpoint.1" in output @@ -2359,7 +2359,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b'baab' * 2000000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{num_chunks} {unique_chunks} {path}{NL}') + output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{num_chunks} {unique_chunks} {path}{NL}') assert "0 0 input/empty_file" in output assert "2 2 input/two_chunks" in output @@ -2367,7 +2367,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('compressible_file', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '-C', 'lz4', 'test', 'input') - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--format', '{size} {path}{NL}') + output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{size} {path}{NL}') size, path = output.split("\n")[1].split(" ") assert int(size) == 10000 @@ -2375,7 +2375,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - list_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', '--json')) + list_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'rlist', '--json')) repository = list_repo['repository'] assert len(repository['id']) == 64 assert datetime.strptime(repository['last_modified'], ISO_FORMAT) # must not raise @@ -2384,7 +2384,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): archive0 = list_repo['archives'][0] assert datetime.strptime(archive0['time'], ISO_FORMAT) # must not raise - list_archive = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines') + list_archive = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines') items = [json.loads(s) for s in list_archive.splitlines()] assert len(items) == 2 file1 = items[1] @@ -2392,18 +2392,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert file1['size'] == 81920 assert datetime.strptime(file1['mtime'], ISO_FORMAT) # must not raise - list_archive = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', '--json-lines', '--format={sha256}') + list_archive = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines', '--format={sha256}') items = [json.loads(s) for s in list_archive.splitlines()] assert len(items) == 2 file1 = items[1] assert file1['path'] == 'input/file1' assert file1['sha256'] == 'b2915eb69f260d8d3c25249195f2c8f4f716ea82ec760ae929732c0262442b2b' - def test_list_json_args(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'list', '--json-lines', exit_code=2) - self.cmd(f'--repo={self.repository_location}', 'list', '--name=archive', '--json', exit_code=2) - def test_log_json(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -2448,7 +2443,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # here we have both BORG_PASSPHRASE and BORG_NEW_PASSPHRASE set: self.cmd(f'--repo={self.repository_location}', 'key', 'change-passphrase') os.environ['BORG_PASSPHRASE'] = 'newpassphrase' - self.cmd(f'--repo={self.repository_location}', 'list') + self.cmd(f'--repo={self.repository_location}', 'rlist') def test_change_location_to_keyfile(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -2919,15 +2914,15 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.check_cache() self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.check_cache() - original_archive = self.cmd(f'--repo={self.repository_location}', 'list') + original_archive = self.cmd(f'--repo={self.repository_location}', 'rlist') self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', 'input/dir2', '-e', 'input/dir2/file3', '--target=new-archive') self.check_cache() - archives = self.cmd(f'--repo={self.repository_location}', 'list') + archives = self.cmd(f'--repo={self.repository_location}', 'rlist') assert original_archive in archives assert 'new-archive' in archives - listing = self.cmd(f'--repo={self.repository_location}', 'list', '--name=new-archive', '--short') + listing = self.cmd(f'--repo={self.repository_location}', 'list', 'new-archive', '--short') assert 'file1' not in listing assert 'dir2/file2' in listing assert 'dir2/file3' not in listing @@ -2939,7 +2934,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', 'input/dir2', '-e', 'input/dir2/file3') self.check_cache() - listing = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test0', '--short') + listing = self.cmd(f'--repo={self.repository_location}', 'list', 'test0', '--short') assert 'file1' not in listing assert 'dir2/file2' in listing assert 'dir2/file3' not in listing @@ -2968,7 +2963,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', '--chunker-params', '7,9,8,128') self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--files-cache=disabled') - list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', + list = self.cmd(f'--repo={self.repository_location}', 'list', 'test1', 'input/large_file', '--format', '{num_chunks} {unique_chunks}') num_chunks, unique_chunks = map(int, list.split(' ')) # test1 and test2 do not deduplicate @@ -2976,20 +2971,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() # test1 and test2 do deduplicate after recreate - assert int(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', '--format={size}')) - assert not int(self.cmd(f'--repo={self.repository_location}', 'list', '--name=test1', 'input/large_file', + assert int(self.cmd(f'--repo={self.repository_location}', 'list', 'test1', 'input/large_file', '--format={size}')) + assert not int(self.cmd(f'--repo={self.repository_location}', 'list', 'test1', 'input/large_file', '--format', '{unique_chunks}')) def test_recreate_recompress(self): self.create_regular_file('compressible', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '-C', 'none') - file_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', 'input/compressible', + file_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', 'input/compressible', '--format', '{size} {sha256}') size, sha256_before = file_list.split(' ') self.cmd(f'--repo={self.repository_location}', 'recreate', '-C', 'lz4', '--recompress') self.check_cache() - file_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test', 'input/compressible', + file_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', 'input/compressible', '--format', '{size} {sha256}') size, sha256_after = file_list.split(' ') assert sha256_before == sha256_after @@ -3011,10 +3006,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('compressible', size=10000) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - archives_before = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') + archives_before = self.cmd(f'--repo={self.repository_location}', 'list', 'test') self.cmd(f'--repo={self.repository_location}', 'recreate', '-n', '-e', 'input/compressible') self.check_cache() - archives_after = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') + archives_after = self.cmd(f'--repo={self.repository_location}', 'list', 'test') assert archives_after == archives_before def test_recreate_skips_nothing_to_do(self): @@ -3519,12 +3514,12 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 # The repo should still be readable repo_info = self.cmd(f'--repo={self.repository_location}', 'info') assert 'All archives:' in repo_info - repo_list = self.cmd(f'--repo={self.repository_location}', 'list') + repo_list = self.cmd(f'--repo={self.repository_location}', 'rlist') assert 'test' in repo_list # The archive should still be readable archive_info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') assert 'Archive name: test\n' in archive_info - archive_list = self.cmd(f'--repo={self.repository_location}', 'list', '--name=test') + archive_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test') assert 'file1' in archive_list # Extracting the archive should work with changedir('output'): @@ -3697,7 +3692,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): output = self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) self.assert_in('New missing file chunk detected', output) self.cmd(f'--repo={self.repository_location}', 'check', exit_code=0) - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=archive1', '--format={health}#{path}{LF}', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'list', 'archive1', '--format={health}#{path}{LF}', exit_code=0) self.assert_in('broken#', output) # check that the file in the old archives has now a different chunk list without the killed chunk for archive_name in ('archive1', 'archive2'): @@ -3728,7 +3723,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): else: self.fail('should not happen') # list is also all-healthy again - output = self.cmd(f'--repo={self.repository_location}', 'list', '--name=archive1', '--format={health}#{path}{LF}', exit_code=0) + output = self.cmd(f'--repo={self.repository_location}', 'list', 'archive1', '--format={health}#{path}{LF}', exit_code=0) self.assert_not_in('broken#', output) def test_missing_archive_item_chunk(self): @@ -3811,7 +3806,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): repository.commit(compact=False) self.cmd(f'--repo={self.repository_location}', 'check', exit_code=1) self.cmd(f'--repo={self.repository_location}', 'check', '--repair', exit_code=0) - output = self.cmd(f'--repo={self.repository_location}', 'list') + output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_in('archive1', output) self.assert_in('archive1.1', output) self.assert_in('archive2', output) @@ -3887,7 +3882,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): repository.commit(compact=False) with pytest.raises(TAMRequiredError): - self.cmd(f'--repo={self.repository_location}', 'list') + self.cmd(f'--repo={self.repository_location}', 'rlist') def test_not_required(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -3903,23 +3898,23 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): del manifest['tam'] repository.put(Manifest.MANIFEST_ID, key.encrypt(Manifest.MANIFEST_ID, msgpack.packb(manifest))) repository.commit(compact=False) - output = self.cmd(f'--repo={self.repository_location}', 'list', '--debug') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--debug') assert 'archive1234' in output assert 'TAM not found and not required' in output # Run upgrade self.cmd(f'--repo={self.repository_location}', 'upgrade', '--tam') # Manifest must be authenticated now - output = self.cmd(f'--repo={self.repository_location}', 'list', '--debug') + output = self.cmd(f'--repo={self.repository_location}', 'rlist', '--debug') assert 'archive1234' in output assert 'TAM-verified manifest' in output # Try to spoof / modify pre-1.0.9 self.spoof_manifest(repository) # Fails with pytest.raises(TAMRequiredError): - self.cmd(f'--repo={self.repository_location}', 'list') + self.cmd(f'--repo={self.repository_location}', 'rlist') # Force upgrade self.cmd(f'--repo={self.repository_location}', 'upgrade', '--tam', '--force') - self.cmd(f'--repo={self.repository_location}', 'list') + self.cmd(f'--repo={self.repository_location}', 'rlist') def test_disable(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -3927,7 +3922,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'upgrade', '--disable-tam') repository = Repository(self.repository_path, exclusive=True) self.spoof_manifest(repository) - assert not self.cmd(f'--repo={self.repository_location}', 'list') + assert not self.cmd(f'--repo={self.repository_location}', 'rlist') def test_disable2(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -3935,7 +3930,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): repository = Repository(self.repository_path, exclusive=True) self.spoof_manifest(repository) self.cmd(f'--repo={self.repository_location}', 'upgrade', '--disable-tam') - assert not self.cmd(f'--repo={self.repository_location}', 'list') + assert not self.cmd(f'--repo={self.repository_location}', 'rlist') class RemoteArchiverTestCase(ArchiverTestCase): @@ -4043,7 +4038,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): def test_chunks_archive(self): self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') # Find ID of test1 so we can corrupt it later :) - target_id = self.cmd(f'--repo={self.repository_location}', 'list', '--format={id}{LF}').strip() + target_id = self.cmd(f'--repo={self.repository_location}', 'rlist', '--format={id}{LF}').strip() self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') # Force cache sync, creating archive chunks of test1 and test2 in chunks.archive.d From 9e5a8a352f1256b792d76431a7a705eb0490e756 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 21 Jun 2022 01:04:41 +0200 Subject: [PATCH 18/21] borg info -a ARCH_GLOB, borg rinfo --- src/borg/archiver.py | 107 ++++++++++++++++++--------------- src/borg/testsuite/archiver.py | 96 ++++++++++++++--------------- 2 files changed, 108 insertions(+), 95 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 37d7464b8..a1ad72b67 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -1752,23 +1752,48 @@ class Archiver: return self.exit_code + @with_repository(cache=True, compatibility=(Manifest.Operation.READ,)) + def do_rinfo(self, args, repository, manifest, key, cache): + """Show repository infos""" + info = basic_json_data(manifest, cache=cache, extra={ + 'security_dir': cache.security_manager.dir, + }) + + if args.json: + json_print(info) + else: + encryption = 'Encrypted: ' + if key.NAME in ('plaintext', 'authenticated'): + encryption += 'No' + else: + encryption += 'Yes (%s)' % key.NAME + if key.NAME.startswith('key file'): + encryption += '\nKey file: %s' % key.find_key() + info['encryption'] = encryption + + print(textwrap.dedent(""" + Repository ID: {id} + Location: {location} + {encryption} + Cache: {cache.path} + Security dir: {security_dir} + """).strip().format( + id=bin_to_hex(repository.id), + location=repository._location.canonical_path(), + **info)) + print(DASHES) + print(STATS_HEADER) + print(str(cache)) + return self.exit_code + @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.name, args.first, args.last, args.prefix is not None, args.glob_archives)): - return self._info_archives(args, repository, manifest, key, cache) - else: - return self._info_repository(args, repository, manifest, key, cache) - - def _info_archives(self, args, repository, manifest, key, cache): def format_cmdline(cmdline): return remove_surrogates(' '.join(shlex.quote(x) for x in cmdline)) - if args.name: - archive_names = (args.name,) - else: - args.consider_checkpoints = True - archive_names = tuple(x.name for x in manifest.archives.list_considering(args)) + args.consider_checkpoints = True + archive_names = tuple(x.name for x in manifest.archives.list_considering(args)) output_data = [] @@ -1809,38 +1834,6 @@ class Archiver: })) return self.exit_code - def _info_repository(self, args, repository, manifest, key, cache): - info = basic_json_data(manifest, cache=cache, extra={ - 'security_dir': cache.security_manager.dir, - }) - - if args.json: - json_print(info) - else: - encryption = 'Encrypted: ' - if key.NAME in ('plaintext', 'authenticated'): - encryption += 'No' - else: - encryption += 'Yes (%s)' % key.NAME - if key.NAME.startswith('key file'): - encryption += '\nKey file: %s' % key.find_key() - info['encryption'] = encryption - - print(textwrap.dedent(""" - Repository ID: {id} - Location: {location} - {encryption} - Cache: {cache.path} - Security dir: {security_dir} - """).strip().format( - id=bin_to_hex(repository.id), - location=repository._location.canonical_path(), - **info)) - print(DASHES) - print(STATS_HEADER) - print(str(cache)) - return self.exit_code - @with_repository(exclusive=True, compatibility=(Manifest.Operation.DELETE,)) def do_prune(self, args, repository, manifest, key): """Prune repository archives according to specified rules""" @@ -4335,9 +4328,31 @@ class Archiver: subparser.add_argument('topic', metavar='TOPIC', type=str, nargs='?', help='additional help on TOPIC') + # borg rinfo + rinfo_epilog = process_epilog(""" + This command displays detailed information about the repository. + + Please note that the deduplicated sizes of the individual archives do not add + up to the deduplicated size of the repository ("all archives"), because the two + are meaning different things: + + This archive / deduplicated size = amount of data stored ONLY for this archive + = unique chunks of this archive. + All archives / deduplicated size = amount of data stored in the repo + = all chunks in the repository. + """) + subparser = subparsers.add_parser('rinfo', parents=[common_parser], add_help=False, + description=self.do_rinfo.__doc__, + epilog=rinfo_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='show repository information') + subparser.set_defaults(func=self.do_rinfo) + subparser.add_argument('--json', action='store_true', + help='format output as JSON') + # borg info info_epilog = process_epilog(""" - This command displays detailed information about the specified archive or repository. + This command displays detailed information about the specified archive. Please note that the deduplicated sizes of the individual archives do not add up to the deduplicated size of the repository ("all archives"), because the two @@ -4359,8 +4374,6 @@ class Archiver: formatter_class=argparse.RawDescriptionHelpFormatter, help='show repository or archive information') subparser.set_defaults(func=self.do_info) - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, - help='specify the archive name') subparser.add_argument('--json', action='store_true', help='format output as JSON') define_archive_filters_group(subparser) @@ -5293,7 +5306,7 @@ class Archiver: parser.error('Need at least one PATH argument.') if not getattr(args, 'lock', True): # Option --bypass-lock sets args.lock = False bypass_allowed = {self.do_check, self.do_config, self.do_diff, - self.do_export_tar, self.do_extract, self.do_info, + self.do_export_tar, self.do_extract, self.do_info, self.do_rinfo, self.do_list, self.do_rlist, self.do_mount, self.do_umount} if func not in bypass_allowed: raise Error('Not allowed to bypass locking mechanism for chosen command') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index ce97c3fe7..c5b5c10a5 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -431,11 +431,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): for name in expected: self.assert_in(name, list_output) self.assert_dirs_equal('input', 'output/input') - info_output = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') + info_output = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') item_count = 5 if has_lchflags else 6 # one file is UF_NODUMP self.assert_in('Number of files: %d' % item_count, info_output) shutil.rmtree(self.cache_path) - info_output2 = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') + info_output2 = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') def filter(output): # filter for interesting "info" output, ignore cache rebuilding related stuff @@ -761,16 +761,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): security_dir = self.get_security_dir() os.rename(self.repository_path, self.repository_path + '_new') with environment_variable(BORG_RELOCATED_REPO_ACCESS_IS_OK='yes'): - self.cmd(f'--repo={self.repository_location}_new', 'info') + self.cmd(f'--repo={self.repository_location}_new', 'rinfo') with open(os.path.join(security_dir, 'location')) as fd: location = fd.read() assert location == Location(self.repository_location + '_new').canonical_path() # Needs no confirmation anymore - self.cmd(f'--repo={self.repository_location}_new', 'info') + self.cmd(f'--repo={self.repository_location}_new', 'rinfo') shutil.rmtree(self.cache_path) - self.cmd(f'--repo={self.repository_location}_new', 'info') + self.cmd(f'--repo={self.repository_location}_new', 'rinfo') shutil.rmtree(security_dir) - self.cmd(f'--repo={self.repository_location}_new', 'info') + self.cmd(f'--repo={self.repository_location}_new', 'rinfo') for file in ('location', 'key-type', 'manifest-timestamp'): assert os.path.exists(os.path.join(security_dir, file)) @@ -780,27 +780,27 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write('something outdated') # This is fine, because the cache still has the correct information. security_dir and cache can disagree # if older versions are used to confirm a renamed repository. - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') def test_unknown_unencrypted(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') # Ok: repository is known - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') # Ok: repository is still known (through security_dir) shutil.rmtree(self.cache_path) - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') # Needs confirmation: cache and security dir both gone (eg. another host or rm -rf ~) shutil.rmtree(self.cache_path) shutil.rmtree(self.get_security_dir()) if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'info', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'rinfo', exit_code=EXIT_ERROR) else: with pytest.raises(Cache.CacheInitAbortedError): - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') with environment_variable(BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK='yes'): - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') def test_strip_components(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -1280,13 +1280,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--no-cache-sync', '--json', '--error', 'test', 'input')) # ignore experimental warning - info_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--name=test', '--json')) + info_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test', '--json')) create_stats = create_json['cache']['stats'] info_stats = info_json['cache']['stats'] assert create_stats == info_stats self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') self.cmd(f'--repo={self.repository_location}', 'create', '--no-cache-sync', 'test2', 'input') - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') self.cmd(f'--repo={self.repository_location}', 'check') def test_extract_pattern_opt(self): @@ -1524,9 +1524,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - info_repo = self.cmd(f'--repo={self.repository_location}', 'info') + info_repo = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert 'All archives:' in info_repo - info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') + info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') assert 'Archive name: test\n' in info_archive info_archive = self.cmd(f'--repo={self.repository_location}', 'info', '--first', '1') assert 'Archive name: test\n' in info_archive @@ -1535,7 +1535,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json')) + info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'rinfo', '--json')) repository = info_repo['repository'] assert len(repository['id']) == 64 assert 'last_modified' in repository @@ -1547,7 +1547,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert all(isinstance(o, int) for o in stats.values()) assert all(key in stats for key in ('total_chunks', 'total_size', 'total_unique_chunks', 'unique_size')) - info_archive = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--name=test', '--json')) + info_archive = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test', '--json')) assert info_repo['repository'] == info_archive['repository'] assert info_repo['cache'] == info_archive['cache'] archives = info_archive['archives'] @@ -1576,17 +1576,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--comment', 'this is the comment') self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input', '--comment', '"deleted" comment') self.cmd(f'--repo={self.repository_location}', 'create', 'test4', 'input', '--comment', 'preserved comment') - assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') - assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') + assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test1') + assert 'Comment: this is the comment' in self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test2') self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test1', '--comment', 'added comment') self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test2', '--comment', 'modified comment') self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test3', '--comment', '') self.cmd(f'--repo={self.repository_location}', 'recreate', '-a', 'test4', '12345') - assert 'Comment: added comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test1') - assert 'Comment: modified comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test2') - assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test3') - assert 'Comment: preserved comment' in self.cmd(f'--repo={self.repository_location}', 'info', '--name=test4') + assert 'Comment: added comment' in self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test1') + assert 'Comment: modified comment' in self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test2') + assert 'Comment: \n' in self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test3') + assert 'Comment: preserved comment' in self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test4') def test_delete(self): self.create_regular_file('file1', size=1024 * 80) @@ -1749,14 +1749,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}', 'info', exit_code=EXIT_ERROR) + self.cmd(f'--repo={self.repository_location}', 'rinfo', exit_code=EXIT_ERROR) else: with pytest.raises((LockFailed, RemoteRepository.RPCError)) as excinfo: - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') if isinstance(excinfo.value, RemoteRepository.RPCError): assert excinfo.value.exception_class == 'LockFailed' # verify that command works with read-only repo when using --bypass-lock - self.cmd(f'--repo={self.repository_location}', 'info', '--bypass-lock') + self.cmd(f'--repo={self.repository_location}', 'rinfo', '--bypass-lock') def test_readonly_list(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') @@ -1848,7 +1848,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'extract', 'test']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rlist']) - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'info', '--name=test']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'info', '-a', 'test']) def test_unknown_feature_on_rename(self): print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) @@ -2447,34 +2447,34 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_change_location_to_keyfile(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(repokey)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'keyfile') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(key file)' in log def test_change_location_to_b2keyfile(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey-blake2') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(repokey BLAKE2b)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'keyfile') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(key file BLAKE2b)' in log def test_change_location_to_repokey(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(key file)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(repokey)' in log def test_change_location_to_b2repokey(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile-blake2') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(key file BLAKE2b)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') - log = self.cmd(f'--repo={self.repository_location}', 'info') + log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(repokey BLAKE2b)' in log def test_break_lock(self): @@ -2996,7 +2996,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', '--timestamp', "1970-01-02T00:00:00", '--comment', 'test') - info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test0').splitlines() + info = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test0').splitlines() dtime = datetime(1970, 1, 2) + local_timezone.utcoffset(None) s_time = dtime.strftime("%Y-%m-%d") assert any([re.search(r'Time \(start\).+ %s' % s_time, item) for item in info]) @@ -3016,10 +3016,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') - info_before = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') + info_before = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') self.check_cache() - info_after = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') + info_after = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') assert info_before == info_after # includes archive ID def test_with_lock(self): @@ -3492,7 +3492,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_do_not_mention_archive_if_you_can_not_find_repo(self): """https://github.com/borgbackup/borg/issues/6014""" - output = self.cmd(f'--repo={self.repository_location}-this-repository-does-not-exist', 'info', '--name=test', + output = self.cmd(f'--repo={self.repository_location}-this-repository-does-not-exist', 'info', '-a', 'test', exit_code=2, fork=True) self.assert_in('this-repository-does-not-exist', output) self.assert_not_in('this-repository-does-not-exist::test', output) @@ -3512,12 +3512,12 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.remove(os.path.join(self.get_security_dir(), 'nonce')) # The repo should still be readable - repo_info = self.cmd(f'--repo={self.repository_location}', 'info') + repo_info = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert 'All archives:' in repo_info repo_list = self.cmd(f'--repo={self.repository_location}', 'rlist') assert 'test' in repo_list # The archive should still be readable - archive_info = self.cmd(f'--repo={self.repository_location}', 'info', '--name=test') + archive_info = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') assert 'Archive name: test\n' in archive_info archive_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test') assert 'file1' in archive_list @@ -3597,7 +3597,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 with Repository(self.repository_path) as repository: _, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) assert key._encrypted_key_algorithm == 'argon2 chacha20-poly1305' - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') @unittest.skipUnless('binary' in BORG_EXES, 'no borg.exe available') @@ -4009,7 +4009,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): super().setUp() self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cache_path = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json'))['cache']['path'] + self.cache_path = json.loads(self.cmd(f'--repo={self.repository_location}', 'rinfo', '--json'))['cache']['path'] def corrupt(self, file, amount=1): with open(file, 'r+b') as fd: @@ -4022,11 +4022,11 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): self.corrupt(os.path.join(self.cache_path, 'chunks')) if self.FORK_DEFAULT: - out = self.cmd(f'--repo={self.repository_location}', 'info', exit_code=2) + out = self.cmd(f'--repo={self.repository_location}', 'rinfo', exit_code=2) assert 'failed integrity check' in out else: with pytest.raises(FileIntegrityError): - self.cmd(f'--repo={self.repository_location}', 'info') + self.cmd(f'--repo={self.repository_location}', 'rinfo') def test_cache_files(self): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') @@ -4043,7 +4043,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): # Force cache sync, creating archive chunks of test1 and test2 in chunks.archive.d self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') - self.cmd(f'--repo={self.repository_location}', 'info', '--json') + self.cmd(f'--repo={self.repository_location}', 'rinfo', '--json') chunks_archive = os.path.join(self.cache_path, 'chunks.archive.d') assert len(os.listdir(chunks_archive)) == 4 # two archives, one chunks cache and one .integrity file each @@ -4074,7 +4074,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): with open(config_path, 'w') as fd: config.write(fd) - out = self.cmd(f'--repo={self.repository_location}', 'info') + out = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert 'Cache integrity data not available: old Borg version modified the cache.' in out From 34b6248d755784048353de256faf0119804fe184 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 21 Jun 2022 02:10:48 +0200 Subject: [PATCH 19/21] borg delete -a ARCH_GLOB, borg rdelete --- src/borg/archiver.py | 205 +++++++++++++++++---------------- src/borg/testsuite/archiver.py | 39 ++++--- 2 files changed, 125 insertions(+), 119 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index a1ad72b67..436aa8ddc 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -679,7 +679,7 @@ class Archiver: # now build files cache rc1 = self.do_create(self.parse_args([f'--repo={repo}', 'create', compression, 'borg-benchmark-crud2', path])) - rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud2'])) + rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '-a', 'borg-benchmark-crud2'])) assert rc1 == rc2 == 0 # measure a no-change update (archive1 is still present) t_start = time.monotonic() @@ -687,7 +687,7 @@ class Archiver: 'borg-benchmark-crud3', path])) t_end = time.monotonic() dt_update = t_end - t_start - rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud3'])) + rc2 = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '-a', 'borg-benchmark-crud3'])) assert rc1 == rc2 == 0 # measure extraction (dry-run: without writing result to disk) t_start = time.monotonic() @@ -698,7 +698,7 @@ class Archiver: assert rc == 0 # measure archive deletion (of LAST present archive with the data) t_start = time.monotonic() - rc = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '--name=borg-benchmark-crud1'])) + rc = self.do_delete(self.parse_args([f'--repo={repo}', 'delete', '-a', 'borg-benchmark-crud1'])) t_end = time.monotonic() dt_delete = t_end - t_start assert rc == 0 @@ -1515,35 +1515,80 @@ class Archiver: return self.exit_code @with_repository(exclusive=True, manifest=False) - def do_delete(self, args, repository): - """Delete an existing repository or archives""" - archive_filter_specified = any((args.first, args.last, args.prefix is not None, args.glob_archives)) - explicit_archives_specified = args.name or args.archives + def do_rdelete(self, args, repository): + """Delete a repository""" self.output_list = args.output_list - if archive_filter_specified and explicit_archives_specified: - self.print_error('Mixing archive filters and explicitly named archives is not supported.') - return self.exit_code - if archive_filter_specified or explicit_archives_specified: - return self._delete_archives(args, repository) - else: - return self._delete_repository(args, repository) - - def _delete_archives(self, args, repository): - """Delete archives""" dry_run = args.dry_run + keep_security_info = args.keep_security_info - manifest, key = Manifest.load(repository, (Manifest.Operation.DELETE,)) + if not args.cache_only: + if args.forced == 0: # without --force, we let the user see the archives list and confirm. + id = bin_to_hex(repository.id) + location = repository._location.canonical_path() + msg = [] + try: + manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) + n_archives = len(manifest.archives) + msg.append(f"You requested to completely DELETE the following repository " + f"*including* {n_archives} archives it contains:") + except NoManifestError: + n_archives = None + msg.append("You requested to completely DELETE the following repository " + "*including* all archives it may contain:") - if args.name or args.archives: - archives = list(args.archives) - if args.name: - archives.insert(0, args.name) - archive_names = tuple(archives) + msg.append(DASHES) + msg.append(f"Repository ID: {id}") + msg.append(f"Location: {location}") + + if self.output_list: + msg.append("") + msg.append("Archives:") + + if n_archives is not None: + if n_archives > 0: + for archive_info in manifest.archives.list(sort_by=['ts']): + msg.append(format_archive(archive_info)) + else: + msg.append("This repository seems to not have any archives.") + else: + msg.append("This repository seems to have no manifest, so we can't " + "tell anything about its contents.") + + msg.append(DASHES) + msg.append("Type 'YES' if you understand this and want to continue: ") + msg = '\n'.join(msg) + if not yes(msg, false_msg="Aborting.", invalid_msg='Invalid answer, aborting.', truish=('YES',), + retry=False, env_var_override='BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'): + self.exit_code = EXIT_ERROR + return self.exit_code + if not dry_run: + repository.destroy() + logger.info("Repository deleted.") + if not keep_security_info: + SecurityManager.destroy(repository) + else: + logger.info("Would delete repository.") + logger.info("Would %s security info." % ("keep" if keep_security_info else "delete")) + if not dry_run: + Cache.destroy(repository) + logger.info("Cache deleted.") else: - args.consider_checkpoints = True - archive_names = tuple(x.name for x in manifest.archives.list_considering(args)) - if not archive_names: - return self.exit_code + logger.info("Would delete cache.") + return self.exit_code + + @with_repository(exclusive=True, manifest=False) + def do_delete(self, args, repository): + """Delete archives""" + self.output_list = args.output_list + dry_run = args.dry_run + manifest, key = Manifest.load(repository, (Manifest.Operation.DELETE,)) + archive_names = tuple(x.name for x in manifest.archives.list_considering(args)) + if not archive_names: + return self.exit_code + if args.glob_archives is None and args.first == 0 and args.last == 0: + self.print_error("Aborting: if you really want to delete all archives, please use -a '*' " + "or just delete the whole repository (might be much faster).") + return EXIT_ERROR if args.forced == 2: deleted = False @@ -1605,66 +1650,6 @@ class Archiver: return self.exit_code - def _delete_repository(self, args, repository): - """Delete a repository""" - dry_run = args.dry_run - keep_security_info = args.keep_security_info - - if not args.cache_only: - if args.forced == 0: # without --force, we let the user see the archives list and confirm. - id = bin_to_hex(repository.id) - location = repository._location.canonical_path() - msg = [] - try: - manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) - n_archives = len(manifest.archives) - msg.append(f"You requested to completely DELETE the following repository " - f"*including* {n_archives} archives it contains:") - except NoManifestError: - n_archives = None - msg.append("You requested to completely DELETE the following repository " - "*including* all archives it may contain:") - - msg.append(DASHES) - msg.append(f"Repository ID: {id}") - msg.append(f"Location: {location}") - - if self.output_list: - msg.append("") - msg.append("Archives:") - - if n_archives is not None: - if n_archives > 0: - for archive_info in manifest.archives.list(sort_by=['ts']): - msg.append(format_archive(archive_info)) - else: - msg.append("This repository seems to not have any archives.") - else: - msg.append("This repository seems to have no manifest, so we can't " - "tell anything about its contents.") - - msg.append(DASHES) - msg.append("Type 'YES' if you understand this and want to continue: ") - msg = '\n'.join(msg) - if not yes(msg, false_msg="Aborting.", invalid_msg='Invalid answer, aborting.', truish=('YES',), - retry=False, env_var_override='BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'): - self.exit_code = EXIT_ERROR - return self.exit_code - if not dry_run: - repository.destroy() - logger.info("Repository deleted.") - if not keep_security_info: - SecurityManager.destroy(repository) - else: - logger.info("Would delete repository.") - logger.info("Would %s security info." % ("keep" if keep_security_info else "delete")) - if not dry_run: - Cache.destroy(repository) - logger.info("Cache deleted.") - else: - logger.info("Would delete cache.") - return self.exit_code - def do_mount(self, args): """Mount archive or an entire repository as a FUSE filesystem""" # Perform these checks before opening the repository and asking for a passphrase. @@ -4062,18 +4047,42 @@ class Archiver: subparser.add_argument('output', metavar='OUTPUT', type=argparse.FileType('wb'), help='Output file') - # borg delete - delete_epilog = process_epilog(""" - This command deletes an archive from the repository or the complete repository. - - Important: When deleting archives, repository disk space is **not** freed until - you run ``borg compact``. + # borg rdelete + rdelete_epilog = process_epilog(""" + This command deletes the complete repository. When you delete a complete repository, the security info and local cache for it (if any) are also deleted. Alternatively, you can delete just the local cache with the ``--cache-only`` option, or keep the security info with the ``--keep-security-info`` option. + Always first use ``--dry-run --list`` to see what would be deleted. + """) + subparser = subparsers.add_parser('rdelete', parents=[common_parser], add_help=False, + description=self.do_rdelete.__doc__, + epilog=rdelete_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + help='delete repository') + subparser.set_defaults(func=self.do_rdelete) + subparser.add_argument('-n', '--dry-run', dest='dry_run', action='store_true', + help='do not change repository') + subparser.add_argument('--list', dest='output_list', action='store_true', + help='output verbose list of archives') + subparser.add_argument('--force', dest='forced', action='count', default=0, + help='force deletion of corrupted archives, ' + 'use ``--force --force`` in case ``--force`` does not work.') + subparser.add_argument('--cache-only', dest='cache_only', action='store_true', + help='delete only the local cache for the given repository') + subparser.add_argument('--keep-security-info', dest='keep_security_info', action='store_true', + help='keep the local security info when deleting a repository') + + # borg delete + delete_epilog = process_epilog(""" + This command deletes archives from the repository. + + Important: When deleting archives, repository disk space is **not** freed until + you run ``borg compact``. + When in doubt, use ``--dry-run --list`` to see what would be deleted. When using ``--stats``, you will get some statistics about how much data was @@ -4087,9 +4096,7 @@ class Archiver: (for more info on these patterns, see :ref:`borg_patterns`). Note that these two options are mutually exclusive. - To avoid accidentally deleting archives, especially when using glob patterns, - it might be helpful to use the ``--dry-run`` to test out the command without - actually making any changes to the repository. + Always first use ``--dry-run --list`` to see what would be deleted. """) subparser = subparsers.add_parser('delete', parents=[common_parser], add_help=False, description=self.do_delete.__doc__, @@ -4101,6 +4108,8 @@ class Archiver: help='do not change repository') subparser.add_argument('--list', dest='output_list', action='store_true', help='output verbose list of archives') + subparser.add_argument('--consider-checkpoints', action='store_true', dest='consider_checkpoints', + help='consider checkpoint archives for deletion (default: not considered).') subparser.add_argument('-s', '--stats', dest='stats', action='store_true', help='print statistics for the deleted archive') subparser.add_argument('--cache-only', dest='cache_only', action='store_true', @@ -4112,10 +4121,6 @@ class Archiver: help='keep the local security info when deleting a repository') subparser.add_argument('--save-space', dest='save_space', action='store_true', help='work slower, but using less space') - subparser.add_argument('--name', dest='name', metavar='NAME', type=NameSpec, - help='specify the archive name') - subparser.add_argument('archives', metavar='ARCHIVE', nargs='*', - help='archives to delete') define_archive_filters_group(subparser) # borg transfer diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index c5b5c10a5..11587efef 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -710,7 +710,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) - self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') if self.FORK_DEFAULT: self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input', exit_code=EXIT_ERROR) else: @@ -723,8 +723,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.environ['BORG_PASSPHRASE'] = 'passphrase' self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test', 'input') - self.cmd(f'--repo={self.repository_location}_unencrypted', 'delete', '--cache-only') - self.cmd(f'--repo={self.repository_location}_encrypted', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}_unencrypted', 'rdelete', '--cache-only') + self.cmd(f'--repo={self.repository_location}_encrypted', 'rdelete', '--cache-only') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') if self.FORK_DEFAULT: @@ -744,7 +744,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with environment_variable(BORG_PASSPHRASE=''): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') # Delete cache & security database, AKA switch to user perspective - self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') shutil.rmtree(self.get_security_dir()) with environment_variable(BORG_PASSPHRASE=None): # This is the part were the user would be tricked, e.g. she assumes that BORG_PASSPHRASE @@ -1276,7 +1276,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_no_cache_sync(self): self.create_test_files() self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--no-cache-sync', '--json', '--error', 'test', 'input')) # ignore experimental warning @@ -1284,7 +1284,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): create_stats = create_json['cache']['stats'] info_stats = info_json['cache']['stats'] assert create_stats == info_stats - self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') self.cmd(f'--repo={self.repository_location}', 'create', '--no-cache-sync', 'test2', 'input') self.cmd(f'--repo={self.repository_location}', 'rinfo') self.cmd(f'--repo={self.repository_location}', 'check') @@ -1601,9 +1601,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') self.cmd(f'--repo={self.repository_location}', 'delete', '--prefix', 'another_') self.cmd(f'--repo={self.repository_location}', 'delete', '--last', '1') - self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test') + self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test') self.cmd(f'--repo={self.repository_location}', 'extract', 'test.2', '--dry-run') - output = self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test.2', '--stats') + output = self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test.2', '--stats') self.assert_in('Deleted data:', output) # Make sure all data except the manifest has been deleted with Repository(self.repository_path) as repository: @@ -1615,9 +1615,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input') - self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test1', 'test2') + self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test1') + self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test2') self.cmd(f'--repo={self.repository_location}', 'extract', 'test3', '--dry-run') - self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test3') + self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test3') assert not self.cmd(f'--repo={self.repository_location}', 'rlist') def test_delete_repo(self): @@ -1627,10 +1628,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'no' - self.cmd(f'--repo={self.repository_location}', 'delete', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'rdelete', exit_code=2) assert os.path.exists(self.repository_path) os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'YES' - self.cmd(f'--repo={self.repository_location}', 'delete') + self.cmd(f'--repo={self.repository_location}', 'rdelete') # Make sure the repo is gone self.assertFalse(os.path.exists(self.repository_path)) @@ -1647,7 +1648,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): else: assert False # missed the file repository.commit(compact=False) - output = self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test', '--force') + output = self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test', '--force') self.assert_in('deleted archive was corrupted', output) self.cmd(f'--repo={self.repository_location}', 'check', '--repair') output = self.cmd(f'--repo={self.repository_location}', 'rlist') @@ -1662,7 +1663,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): id = archive.metadata.items[0] repository.put(id, b'corrupted items metadata stream chunk') repository.commit(compact=False) - self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test', '--force', '--force') + self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test', '--force', '--force') self.cmd(f'--repo={self.repository_location}', 'check', '--repair') output = self.cmd(f'--repo={self.repository_location}', 'rlist') self.assert_not_in('test', output) @@ -1831,7 +1832,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_unknown_feature_on_cache_sync(self): self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') - self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') self.add_unknown_feature(Manifest.Operation.READ) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', 'test', 'input']) @@ -1861,10 +1862,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.DELETE) # delete of an archive raises - self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'delete', '--name=test']) + self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'delete', '-a', 'test']) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'prune', '--keep-daily=3']) # delete of the whole repository ignores features - self.cmd(f'--repo={self.repository_location}', 'delete') + self.cmd(f'--repo={self.repository_location}', 'rdelete') @unittest.skipUnless(llfuse, 'llfuse not installed') def test_unknown_feature_on_mount(self): @@ -2784,7 +2785,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): verify_uniqueness() self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') verify_uniqueness() - self.cmd(f'--repo={self.repository_location}', 'delete', '--name=test.2') + self.cmd(f'--repo={self.repository_location}', 'delete', '-a', 'test.2') verify_uniqueness() def test_aes_counter_uniqueness_keyfile(self): @@ -4042,7 +4043,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') # Force cache sync, creating archive chunks of test1 and test2 in chunks.archive.d - self.cmd(f'--repo={self.repository_location}', 'delete', '--cache-only') + self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') self.cmd(f'--repo={self.repository_location}', 'rinfo', '--json') chunks_archive = os.path.join(self.cache_path, 'chunks.archive.d') From d00d650d8862d4ddf89b60f171be97174e461af7 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 23 Jun 2022 09:16:29 +0200 Subject: [PATCH 20/21] borg init -> borg rcreate this is to complement borg rdelete, see also borg create / delete. --- setup_docs.py | 2 +- src/borg/archiver.py | 20 +- src/borg/testsuite/archiver.py | 408 ++++++++++++++++---------------- src/borg/testsuite/benchmark.py | 2 +- 4 files changed, 216 insertions(+), 216 deletions(-) diff --git a/setup_docs.py b/setup_docs.py index 056c23213..2f9dcb35d 100644 --- a/setup_docs.py +++ b/setup_docs.py @@ -280,7 +280,7 @@ class build_man(Command): 'recreate': ('patterns', 'placeholders', 'compression'), 'list': ('info', 'diff', 'prune', 'patterns'), 'info': ('list', 'diff'), - 'init': ('create', 'delete', 'check', 'list', 'key-import', 'key-export', 'key-change-passphrase'), + 'rcreate': ('rdelete', 'rlist', 'check', 'key-import', 'key-export', 'key-change-passphrase'), 'key-import': ('key-export', ), 'key-export': ('key-import', ), 'mount': ('umount', 'extract'), # Would be cooler if these two were on the same page diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 436aa8ddc..3273e8cb5 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -472,8 +472,8 @@ class Archiver: @with_repository(create=True, exclusive=True, manifest=False) @with_other_repository(key=True, compatibility=(Manifest.Operation.READ, )) - def do_init(self, args, repository, *, other_repository=None, other_key=None): - """Initialize an empty repository""" + def do_rcreate(self, args, repository, *, other_repository=None, other_key=None): + """Create a new, empty repository""" path = args.location.canonical_path() logger.info('Initializing repository at "%s"' % path) try: @@ -4383,9 +4383,9 @@ class Archiver: help='format output as JSON') define_archive_filters_group(subparser) - # borg init - init_epilog = process_epilog(""" - This command initializes an empty repository. A repository is a filesystem + # borg rcreate + rcreate_epilog = process_epilog(""" + This command creates a new, empty repository. A repository is a filesystem directory containing the deduplicated data from zero or more archives. Encryption mode TLDR @@ -4398,7 +4398,7 @@ class Archiver: :: - borg init --encryption repokey /path/to/repo + borg rcreate --encryption repokey /path/to/repo Borg will: @@ -4507,11 +4507,11 @@ class Archiver: Neither is inherently linked to the key derivation function, but since we were going to break backwards compatibility anyway we took the opportunity to fix all 3 issues at once. """) - subparser = subparsers.add_parser('init', parents=[common_parser], add_help=False, - description=self.do_init.__doc__, epilog=init_epilog, + subparser = subparsers.add_parser('rcreate', parents=[common_parser], add_help=False, + description=self.do_rcreate.__doc__, epilog=rcreate_epilog, formatter_class=argparse.RawDescriptionHelpFormatter, - help='initialize empty repository') - subparser.set_defaults(func=self.do_init) + help='create a new, empty repository') + subparser.set_defaults(func=self.do_rcreate) subparser.add_argument('--other-repo', metavar='SRC_REPOSITORY', dest='other_location', type=location_validator(other=True), default=Location(other=True), help='reuse the key material from the other repository') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 11587efef..ef22bf58b 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -147,7 +147,7 @@ def test_return_codes(cmd, tmpdir): input = tmpdir.mkdir('input') output = tmpdir.mkdir('output') input.join('test_file').write('content') - rc, out = cmd('--repo=%s' % str(repo), 'init', '--encryption=none') + rc, out = cmd('--repo=%s' % str(repo), 'rcreate', '--encryption=none') assert rc == EXIT_SUCCESS rc, out = cmd('--repo=%s' % repo, 'create', 'archive', str(input)) assert rc == EXIT_SUCCESS @@ -203,9 +203,9 @@ def test_disk_full(cmd): shutil.rmtree(input, ignore_errors=True) # keep some space and some inodes in reserve that we can free up later: make_files(reserve, 80, 100000, rnd=False) - rc, out = cmd(f'--repo={repo}', 'init') + rc, out = cmd(f'--repo={repo}', 'rcreate') if rc != EXIT_SUCCESS: - print('init', rc, out) + print('rcreate', rc, out) assert rc == EXIT_SUCCESS try: success, i = True, 0 @@ -391,7 +391,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_basic_functionality(self): have_root = self.create_test_files() # fork required to test show-rc output - output = self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--show-version', '--show-rc', fork=True) + output = self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey', '--show-version', '--show-rc', fork=True) self.assert_in('borgbackup version', output) self.assert_in('terminating with success status, rc 0', output) self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-nodump', 'test', 'input') @@ -462,7 +462,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): hl_b = os.path.join(path_b, 'hardlink') self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') # give input twice! # test if created archive has 'input' contents twice: archive_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines') @@ -476,13 +476,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): repository_location = self.prefix + repository_path with pytest.raises(Repository.ParentPathDoesNotExist): # normal borg init does NOT create missing parent dirs - self.cmd(f'--repo={repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={repository_location}', 'rcreate', '--encryption=none') # but if told so, it does: - self.cmd(f'--repo={repository_location}', 'init', '--encryption=none', '--make-parent-dirs') + self.cmd(f'--repo={repository_location}', 'rcreate', '--encryption=none', '--make-parent-dirs') assert os.path.exists(parent_path) def test_unix_socket(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(os.path.join(self.input_path, 'unix-socket')) @@ -500,7 +500,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @pytest.mark.skipif(not are_symlinks_supported(), reason='symlinks not supported') def test_symlink_extract(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', 'test') @@ -513,7 +513,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with changedir('input'): os.symlink('target', 'symlink1') os.link('symlink1', 'symlink2', follow_symlinks=False) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'extract', 'test') @@ -547,7 +547,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): atime, mtime = 123456780, 234567890 have_noatime = has_noatime('input/file1') os.utime('input/file1', (atime, mtime)) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--atime', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', 'test') @@ -567,7 +567,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): birthtime, mtime, atime = 946598400, 946684800, 946771200 os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', 'test') @@ -583,7 +583,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): birthtime, mtime, atime = 946598400, 946684800, 946771200 os.utime('input/file1', (atime, birthtime)) os.utime('input/file1', (atime, mtime)) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--nobirthtime') with changedir('output'): self.cmd(f'--repo={self.repository_location}', 'extract', 'test') @@ -644,7 +644,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): if sparse_support: # we could create a sparse input file, so creating a backup of it and # extracting it again (as sparse) should also work: - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir(self.output_path): self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--sparse') @@ -663,7 +663,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): filename = os.path.join(self.input_path, filename) with open(filename, 'wb'): pass - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') for filename in filenames: with changedir('output'): @@ -673,11 +673,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_repository_swap_detection(self): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') shutil.rmtree(self.repository_path) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) if self.FORK_DEFAULT: @@ -688,9 +688,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_repository_swap_detection2(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}_unencrypted', 'rcreate', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_encrypted', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test', 'input') shutil.rmtree(self.repository_path + '_encrypted') os.rename(self.repository_path + '_unencrypted', self.repository_path + '_encrypted') @@ -703,11 +703,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_repository_swap_detection_no_cache(self): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') repository_id = self._extract_repository_id(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') shutil.rmtree(self.repository_path) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self._set_repository_id(self.repository_path, repository_id) self.assert_equal(repository_id, self._extract_repository_id(self.repository_path)) self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') @@ -719,9 +719,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_repository_swap_detection2_no_cache(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}_unencrypted', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}_unencrypted', 'rcreate', '--encryption=none') os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd(f'--repo={self.repository_location}_encrypted', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_encrypted', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}_encrypted', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}_unencrypted', 'rdelete', '--cache-only') self.cmd(f'--repo={self.repository_location}_encrypted', 'rdelete', '--cache-only') @@ -737,12 +737,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Check that a repokey repo with a blank passphrase is considered like a plaintext repo. self.create_test_files() # User initializes her repository with her passphrase - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Attacker replaces it with her own repository, which is encrypted but has no passphrase set shutil.rmtree(self.repository_path) with environment_variable(BORG_PASSPHRASE=''): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # Delete cache & security database, AKA switch to user perspective self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') shutil.rmtree(self.get_security_dir()) @@ -757,7 +757,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') def test_repository_move(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') security_dir = self.get_security_dir() os.rename(self.repository_path, self.repository_path + '_new') with environment_variable(BORG_RELOCATED_REPO_ACCESS_IS_OK='yes'): @@ -775,7 +775,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert os.path.exists(os.path.join(security_dir, file)) def test_security_dir_compat(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') with open(os.path.join(self.get_security_dir(), 'location'), 'w') as fd: fd.write('something outdated') # This is fine, because the cache still has the correct information. security_dir and cache can disagree @@ -783,7 +783,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'rinfo') def test_unknown_unencrypted(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') # Ok: repository is known self.cmd(f'--repo={self.repository_location}', 'rinfo') @@ -803,7 +803,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'rinfo') def test_strip_components(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('dir/file') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): @@ -832,7 +832,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.link(os.path.join(self.input_path, 'dir1/source2'), os.path.join(self.input_path, 'dir1/aaaa')) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') @requires_hardlinks @@ -909,7 +909,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): hl_b = os.path.join(path_b, 'hardlink') self.create_regular_file(hl_a, contents=b'123456') os.link(hl_a, hl_b) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') # give input twice! # now test extraction with changedir('output'): @@ -922,7 +922,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert os.stat('input/b/hardlink').st_nlink == 2 def test_extract_include_exclude(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) @@ -939,7 +939,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3']) def test_extract_include_exclude_regex(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) @@ -972,7 +972,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_equal(sorted(os.listdir('output/input')), ['file3']) def test_extract_include_exclude_regex_from_file(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file3', size=1024 * 80) @@ -1012,7 +1012,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_equal(sorted(os.listdir('output/input')), ['file3']) def test_extract_with_pattern(self): - self.cmd(f'--repo={self.repository_location}', "init", '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file("file1", size=1024 * 80) self.create_regular_file("file2", size=1024 * 80) self.create_regular_file("file3", size=1024 * 80) @@ -1045,7 +1045,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file333"]) def test_extract_list_output(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') @@ -1070,7 +1070,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in("input/file", output) def test_extract_progress(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file', size=1024 * 80) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') @@ -1079,7 +1079,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert 'Extracting:' in output def _create_test_caches(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('cache1/%s' % CACHE_TAG_NAME, contents=CACHE_TAG_CONTENTS + b' extra stuff') @@ -1093,7 +1093,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): contents=CACHE_TAG_CONTENTS + b' extra stuff') def test_create_stdin(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') input_data = b'\x00foo\n\nbar\n \n' self.cmd(f'--repo={self.repository_location}', 'create', 'test', '-', input=input_data) item = json.loads(self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--json-lines')) @@ -1105,7 +1105,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert extracted_data == input_data def test_create_content_from_command(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') input_data = 'some test content' name = 'a/b/c' self.cmd(f'--repo={self.repository_location}', 'create', '--stdin-name', name, '--content-from-command', @@ -1119,7 +1119,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert extracted_data == input_data + '\n' def test_create_content_from_command_with_failed_command(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', '--content-from-command', 'test', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") @@ -1127,12 +1127,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert archive_list['archives'] == [] def test_create_content_from_command_missing_command(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', '--content-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_paths_from_stdin(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file("file1", size=1024 * 80) self.create_regular_file("dir1/file2", size=1024 * 80) self.create_regular_file("dir1/file3", size=1024 * 80) @@ -1146,7 +1146,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert paths == ['input/file1', 'input/dir1', 'input/file4'] def test_create_paths_from_command(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file("file1", size=1024 * 80) self.create_regular_file("file2", size=1024 * 80) self.create_regular_file("file3", size=1024 * 80) @@ -1160,7 +1160,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert paths == ['input/file1', 'input/file2', 'input/file3'] def test_create_paths_from_command_with_failed_command(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', '--paths-from-command', 'test', '--', 'sh', '-c', 'exit 73;', exit_code=2) assert output.endswith("Command 'sh' exited with status 73\n") @@ -1168,18 +1168,18 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert archive_list['archives'] == [] def test_create_paths_from_command_missing_command(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', '--paths-from-command', exit_code=2) assert output.endswith('No command given.\n') def test_create_without_root(self): """test create without a root""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', exit_code=2) def test_create_pattern_root(self): """test create with only a root pattern""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', '-v', '--list', '--pattern=R input') @@ -1188,7 +1188,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_pattern(self): """test file patterns during create""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) @@ -1201,7 +1201,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_pattern_file(self): """test file patterns during create""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('otherfile', size=1024 * 80) @@ -1220,7 +1220,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(self.patterns_file_path2, 'wb') as fd: fd.write(b'+ input/x/b\n- input/x*\n') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) @@ -1237,7 +1237,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(self.patterns_file_path2, 'wb') as fd: fd.write(b'+ input/x/b\n! input/x*\n') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) self.create_regular_file('y/foo_y', size=1024 * 80) @@ -1254,7 +1254,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(self.patterns_file_path2, 'wb') as fd: fd.write(b'+ input/x/a\n+ input/x/b\n- input/x*\n') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('x/a/foo_a', size=1024 * 80) self.create_regular_file('x/b/foo_b', size=1024 * 80) @@ -1275,7 +1275,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_no_cache_sync(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') create_json = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--no-cache-sync', '--json', '--error', @@ -1290,7 +1290,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'check') def test_extract_pattern_opt(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) self.create_regular_file('file_important', size=1024 * 80) @@ -1318,7 +1318,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self._assert_test_caches() def _create_test_tagged(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('tagged1/.NOBACKUP') self.create_regular_file('tagged2/00-NOBACKUP') @@ -1343,7 +1343,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self._assert_test_tagged() def _create_test_keep_tagged(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file0', size=1024) self.create_regular_file('tagged1/.NOBACKUP1') self.create_regular_file('tagged1/file1', size=1024) @@ -1383,7 +1383,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @pytest.mark.skipif(not are_hardlinks_supported(), reason='hardlinks not supported') def test_recreate_hardlinked_tags(self): # test for issue #4911 - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.create_regular_file('file1', contents=CACHE_TAG_CONTENTS) # "wrong" filename, but correct tag contents os.mkdir(os.path.join(self.input_path, 'subdir')) # to make sure the tag is encountered *after* file1 os.link(os.path.join(self.input_path, 'file1'), @@ -1409,7 +1409,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): capabilities = b'\x01\x00\x00\x02\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' self.create_regular_file('file') xattr.setxattr(b'input/file', b'security.capability', capabilities) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(os, 'fchown', patched_fchown): @@ -1430,7 +1430,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute', b'value') - self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '-e' 'none') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): input_abspath = os.path.abspath('input/file') @@ -1448,7 +1448,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert os.path.isfile(input_abspath) def test_path_normalization(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('dir1/dir2/file', size=1024 * 80) with changedir('input/dir1/dir2'): self.cmd(f'--repo={self.repository_location}', 'create', 'test', @@ -1458,7 +1458,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in(' input/dir1/dir2/file', output) def test_exclude_normalization(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('file2', size=1024 * 80) with changedir('input'): @@ -1478,13 +1478,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_repeated_files(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', 'input') def test_overwrite(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Overwriting regular files and directories should be supported os.mkdir('output/input') @@ -1503,7 +1503,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_rename(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--dry-run') @@ -1522,7 +1522,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') info_repo = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert 'All archives:' in info_repo @@ -1533,7 +1533,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info_json(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'rinfo', '--json')) repository = info_repo['repository'] @@ -1563,7 +1563,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_info_json_of_empty_archive(self): """See https://github.com/borgbackup/borg/issues/6120""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json', '--first=1')) assert info_repo["archives"] == [] info_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'info', '--json', '--last=1')) @@ -1571,7 +1571,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_comment(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--comment', 'this is the comment') self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input', '--comment', '"deleted" comment') @@ -1591,7 +1591,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_delete(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test.3', 'input') @@ -1611,7 +1611,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_delete_multiple(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test3', 'input') @@ -1624,7 +1624,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_delete_repo(self): self.create_regular_file('file1', size=1024 * 80) self.create_regular_file('dir2/file2', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'create', 'test.2', 'input') os.environ['BORG_DELETE_I_KNOW_WHAT_I_AM_DOING'] = 'no' @@ -1636,7 +1636,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assertFalse(os.path.exists(self.repository_path)) def test_delete_force(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.create_src_archive('test') with Repository(self.repository_path, exclusive=True) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1655,7 +1655,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('test', output) def test_delete_double_force(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.create_src_archive('test') with Repository(self.repository_path, exclusive=True) as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -1669,7 +1669,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('test', output) def test_corrupted_repository(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--dry-run') output = self.cmd(f'--repo={self.repository_location}', 'check', '--show-version') @@ -1684,7 +1684,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('Starting repository check', output) # --info given for root logger def test_readonly_check(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1699,7 +1699,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'check', '--verify-data', '--bypass-lock') def test_readonly_diff(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('a') self.create_src_archive('b') with self.read_only(self.repository_path): @@ -1715,7 +1715,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'diff', 'a', 'b', '--bypass-lock') def test_readonly_export_tar(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1730,7 +1730,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'test.tar', '--bypass-lock') def test_readonly_extract(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1745,7 +1745,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'extract', 'test', '--bypass-lock') def test_readonly_info(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1760,7 +1760,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'rinfo', '--bypass-lock') def test_readonly_list(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1776,7 +1776,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_readonly_mount(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('test') with self.read_only(self.repository_path): # verify that command normally doesn't work with read-only repo @@ -1797,13 +1797,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): @pytest.mark.skipif('BORG_TESTS_IGNORE_MODES' in os.environ, reason='modes unreliable') def test_umask(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') mode = os.stat(self.repository_path).st_mode self.assertEqual(stat.S_IMODE(mode), 0o700) def test_create_dry_run(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--dry-run', 'test', 'input') # Make sure no archive has been created with Repository(self.repository_path) as repository: @@ -1826,23 +1826,23 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert excinfo.value.args == (['unknown-feature'],) def test_unknown_feature_on_create(self): - print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + print(self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey')) self.add_unknown_feature(Manifest.Operation.WRITE) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', 'test', 'input']) def test_unknown_feature_on_cache_sync(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'rdelete', '--cache-only') self.add_unknown_feature(Manifest.Operation.READ) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'create', 'test', 'input']) def test_unknown_feature_on_change_passphrase(self): - print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + print(self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey')) self.add_unknown_feature(Manifest.Operation.CHECK) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'key', 'change-passphrase']) def test_unknown_feature_on_read(self): - print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + print(self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey')) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.READ) with changedir('output'): @@ -1852,13 +1852,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'info', '-a', 'test']) def test_unknown_feature_on_rename(self): - print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + print(self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey')) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.CHECK) self.cmd_raises_unknown_feature([f'--repo={self.repository_location}', 'rename', 'test', 'other']) def test_unknown_feature_on_delete(self): - print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + print(self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey')) self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.DELETE) # delete of an archive raises @@ -1869,7 +1869,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_unknown_feature_on_mount(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.add_unknown_feature(Manifest.Operation.READ) mountpoint = os.path.join(self.tmpdir, 'mountpoint') @@ -1884,7 +1884,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): else: path_prefix = '' - print(self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey')) + print(self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey')) with Repository(self.repository_path, exclusive=True) as repository: if path_prefix: @@ -1920,13 +1920,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_progress_on(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', 'test4', 'input', '--progress') self.assert_in("\r", output) def test_progress_off(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', 'test5', 'input') self.assert_not_in("\r", output) @@ -1937,7 +1937,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', 'test', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) @@ -1953,7 +1953,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', contents=b'123') time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', '--list', '--files-cache=ctime,size') # modify file1, but cheat with the mtime (and atime) and also keep same size: @@ -1970,7 +1970,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=10) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', '--files-cache=mtime,size', 'test1', 'input') # change mode of file1, no content change: @@ -1986,7 +1986,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=10) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=10) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', '--files-cache=rechunk,ctime', 'test1', 'input') # no changes here, but this mode rechunks unconditionally @@ -2003,7 +2003,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): if has_lchflags: self.create_regular_file('file3', size=1024 * 80) platform.set_flags(os.path.join(self.input_path, 'file3'), stat.UF_NODUMP) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'create', '--list', '--exclude-nodump', 'test', 'input') self.assert_in("A input/file1", output) self.assert_in("A input/file2", output) @@ -2019,7 +2019,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_json(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') create_info = json.loads(self.cmd(f'--repo={self.repository_location}', 'create', '--json', 'test', 'input')) # The usual keys @@ -2039,7 +2039,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('file1', size=1024 * 80) time.sleep(1) # file2 must have newer timestamps than file1 self.create_regular_file('file2', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # no listing by default output = self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.assert_not_in('file1', output) @@ -2069,7 +2069,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): finally: os.close(fd) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') data = b'foobar' * 1000 fifo_fn = os.path.join(self.input_path, 'fifo') @@ -2092,20 +2092,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_create_read_special_broken_symlink(self): os.symlink('somewhere does not exist', os.path.join(self.input_path, 'link')) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--read-special', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', 'test') assert 'input/link -> somewhere does not exist' in output # def test_cmdline_compatibility(self): # self.create_regular_file('file1', size=1024 * 80) - # self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + # self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # output = self.cmd('foo', self.repository_location, '--old') # self.assert_in('"--old" has been deprecated. Use "--new" instead', output) def test_prune_repository(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'test2', src_dir) # these are not really a checkpoints, but they look like some: @@ -2154,7 +2154,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # This test must match docs/misc/prune-example.txt def test_prune_repository_example(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # Archives that will be kept, per the example # Oldest archive self._create_archive_ts('test01', 2015, 1, 1) @@ -2215,7 +2215,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # With an initial and daily backup, prune daily until oldest is replaced by a monthly backup def test_prune_retain_and_expire_oldest(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # Initial backup self._create_archive_ts('original_archive', 2020, 9, 1, 11, 15) # Archive and prune daily for 30 days @@ -2238,7 +2238,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('original_archive', output) def test_prune_repository_save_space(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'test2', src_dir) output = self.cmd(f'--repo={self.repository_location}', 'prune', '--list', '--dry-run', '--keep-daily=1') @@ -2253,7 +2253,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('test2', output) def test_prune_repository_prefix(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'foo-2015-08-12-10:00', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'foo-2015-08-12-20:00', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'bar-2015-08-12-10:00', src_dir) @@ -2274,7 +2274,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('bar-2015-08-12-20:00', output) def test_prune_repository_glob(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-10:00-foo', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-20:00-foo', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', '2015-08-12-10:00-bar', src_dir) @@ -2295,7 +2295,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in('2015-08-12-20:00-bar', output) def test_list_prefix(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'something-else-than-test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', 'test-2', src_dir) @@ -2305,7 +2305,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in('something-else', output) def test_list_format(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', src_dir) output_1 = self.cmd(f'--repo={self.repository_location}', 'list', 'test') output_2 = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{mode} {user:6} {group:6} {size:8d} {mtime} {path}{extra}{NEWLINE}') @@ -2314,7 +2314,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assertNotEqual(output_1, output_3) def test_archives_format(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '--comment', 'comment 1', 'test-1', src_dir) self.cmd(f'--repo={self.repository_location}', 'create', '--comment', 'comment 2', 'test-2', src_dir) output_1 = self.cmd(f'--repo={self.repository_location}', 'rlist') @@ -2331,14 +2331,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_hash(self): self.create_regular_file('empty_file', size=0) self.create_regular_file('amb', contents=b'a' * 1000000) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{sha256} {path}{NL}') assert "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 input/amb" in output assert "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 input/empty_file" in output def test_list_consider_checkpoints(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', src_dir) # these are not really a checkpoints, but they look like some: self.cmd(f'--repo={self.repository_location}', 'create', 'test2.checkpoint', src_dir) @@ -2358,7 +2358,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(os.path.join(self.input_path, 'two_chunks'), 'wb') as fd: fd.write(b'abba' * 2000000) fd.write(b'baab' * 2000000) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{num_chunks} {unique_chunks} {path}{NL}') assert "0 0 input/empty_file" in output @@ -2366,7 +2366,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_size(self): self.create_regular_file('compressible_file', size=10000) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', '-C', 'lz4', 'test', 'input') output = self.cmd(f'--repo={self.repository_location}', 'list', 'test', '--format', '{size} {path}{NL}') size, path = output.split("\n")[1].split(" ") @@ -2374,7 +2374,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_list_json(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') list_repo = json.loads(self.cmd(f'--repo={self.repository_location}', 'rlist', '--json')) repository = list_repo['repository'] @@ -2402,7 +2402,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_log_json(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') log = self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--log-json', '--list', '--debug') messages = {} # type -> message, one of each kind for line in log.splitlines(): @@ -2420,7 +2420,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_profile(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '--debug-profile=create.prof') self.cmd('debug', 'convert-profile', 'create.prof', 'create.pyprof') stats = pstats.Stats('create.pyprof') @@ -2434,12 +2434,12 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_common_options(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') log = self.cmd(f'--repo={self.repository_location}', '--debug', 'create', 'test', 'input') assert 'security: read previous location' in log def test_change_passphrase(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') os.environ['BORG_NEW_PASSPHRASE'] = 'newpassphrase' # here we have both BORG_PASSPHRASE and BORG_NEW_PASSPHRASE set: self.cmd(f'--repo={self.repository_location}', 'key', 'change-passphrase') @@ -2447,7 +2447,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'rlist') def test_change_location_to_keyfile(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(repokey)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'keyfile') @@ -2455,7 +2455,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert '(key file)' in log def test_change_location_to_b2keyfile(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey-blake2') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey-blake2') log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(repokey BLAKE2b)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'keyfile') @@ -2463,7 +2463,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert '(key file BLAKE2b)' in log def test_change_location_to_repokey(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=keyfile') log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(key file)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') @@ -2471,7 +2471,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert '(repokey)' in log def test_change_location_to_b2repokey(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile-blake2') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=keyfile-blake2') log = self.cmd(f'--repo={self.repository_location}', 'rinfo') assert '(key file BLAKE2b)' in log self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') @@ -2479,7 +2479,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert '(repokey BLAKE2b)' in log def test_break_lock(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'break-lock') def test_usage(self): @@ -2489,9 +2489,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_help(self): assert 'Borg' in self.cmd('help') assert 'patterns' in self.cmd('help', 'patterns') - assert 'Initialize' in self.cmd('help', 'init') - assert 'positional arguments' not in self.cmd('help', 'init', '--epilog-only') - assert 'This command initializes' not in self.cmd('help', 'init', '--usage-only') + assert 'creates a new, empty repository' in self.cmd('help', 'rcreate') + assert 'positional arguments' not in self.cmd('help', 'rcreate', '--epilog-only') + assert 'creates a new, empty repository' not in self.cmd('help', 'rcreate', '--usage-only') @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse(self): @@ -2506,7 +2506,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): noatime_used = flags_noatime != flags_normal return noatime_used and atime_before == atime_after - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_test_files() have_noatime = has_noatime('input/file1') self.cmd(f'--repo={self.repository_location}', 'create', '--exclude-nodump', '--atime', 'archive', 'input') @@ -2595,7 +2595,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_versions_view(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('test', contents=b'first') if are_hardlinks_supported(): self.create_regular_file('hardlink1', contents=b'123456') @@ -2627,7 +2627,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_allow_damaged_files(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('archive') # Get rid of a chunk and repair it archive, repository = self.open_archive('archive') @@ -2652,7 +2652,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): @unittest.skipUnless(llfuse, 'llfuse not installed') def test_fuse_mount_options(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('arch11') self.create_src_archive('arch12') self.create_src_archive('arch21') @@ -2726,7 +2726,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Decorate borg.locking.Lock.migrate_lock = write_assert_data(borg.locking.Lock.migrate_lock) try: - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.create_src_archive('arch') mountpoint = os.path.join(self.tmpdir, 'mountpoint') # In order that the decoration is kept for the borg mount process, we must not spawn, but actually fork; @@ -2779,7 +2779,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_test_files() os.environ['BORG_PASSPHRASE'] = 'passphrase' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=' + method) + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=' + method) verify_uniqueness() self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') verify_uniqueness() @@ -2796,7 +2796,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_archive_items(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive-items', 'test') @@ -2806,7 +2806,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_debug_dump_repo_objs(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-repo-objs') @@ -2815,7 +2815,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert 'Done.' in output def test_debug_put_get_delete_obj(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') data = b'some data' hexkey = sha256(data).hexdigest() self.create_regular_file('file', contents=data) @@ -2838,19 +2838,19 @@ class ArchiverTestCase(ArchiverTestCaseBase): raise EOFError with patch.object(FlexiKey, 'create', raise_eof): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', exit_code=1) + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey', exit_code=1) assert not os.path.exists(self.repository_location) def test_init_requires_encryption_option(self): - self.cmd(f'--repo={self.repository_location}', 'init', exit_code=2) + self.cmd(f'--repo={self.repository_location}', 'rcreate', exit_code=2) def test_init_nested_repositories(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') if self.FORK_DEFAULT: - self.cmd(f'--repo={self.repository_location}/nested', 'init', '--encryption=repokey', exit_code=2) + self.cmd(f'--repo={self.repository_location}/nested', 'rcreate', '--encryption=repokey', exit_code=2) else: with pytest.raises(Repository.AlreadyExists): - self.cmd(f'--repo={self.repository_location}/nested', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}/nested', 'rcreate', '--encryption=repokey') def test_init_refuse_to_overwrite_keyfile(self): """BORG_KEY_FILE=something borg init should quit if "something" already exists. @@ -2858,10 +2858,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): See https://github.com/borgbackup/borg/pull/6046""" keyfile = os.path.join(self.tmpdir, 'keyfile') with environment_variable(BORG_KEY_FILE=keyfile): - self.cmd(f'--repo={self.repository_location}0', 'init', '--encryption=keyfile') + self.cmd(f'--repo={self.repository_location}0', 'rcreate', '--encryption=keyfile') with open(keyfile) as file: before = file.read() - arg = (f'--repo={self.repository_location}1', 'init', '--encryption=keyfile') + arg = (f'--repo={self.repository_location}1', 'rcreate', '--encryption=keyfile') if self.FORK_DEFAULT: self.cmd(*arg, exit_code=2) else: @@ -2893,7 +2893,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert id in seen def test_check_cache(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with self.open_repository() as repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -2905,13 +2905,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.check_cache() def test_recreate_target_rc(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'recreate', '--target=asdf', exit_code=2) assert 'Need to specify single archive' in output def test_recreate_target(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.check_cache() self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.check_cache() @@ -2931,7 +2931,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_basic(self): self.create_test_files() self.create_regular_file('dir2/file3', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', 'input/dir2', '-e', 'input/dir2/file3') self.check_cache() @@ -2961,7 +2961,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): with open(os.path.join(self.input_path, 'large_file'), 'wb') as fd: fd.write(b'a' * 280) fd.write(b'b' * 280) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test1', 'input', '--chunker-params', '7,9,8,128') self.cmd(f'--repo={self.repository_location}', 'create', 'test2', 'input', '--files-cache=disabled') list = self.cmd(f'--repo={self.repository_location}', 'list', 'test1', 'input/large_file', @@ -2978,7 +2978,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_recompress(self): self.create_regular_file('compressible', size=10000) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input', '-C', 'none') file_list = self.cmd(f'--repo={self.repository_location}', 'list', 'test', 'input/compressible', '--format', '{size} {sha256}') @@ -2993,7 +2993,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_timestamp(self): local_timezone = datetime.now(timezone(timedelta(0))).astimezone().tzinfo self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') self.cmd(f'--repo={self.repository_location}', 'recreate', 'test0', '--timestamp', "1970-01-02T00:00:00", '--comment', 'test') @@ -3005,7 +3005,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_dry_run(self): self.create_regular_file('compressible', size=10000) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') archives_before = self.cmd(f'--repo={self.repository_location}', 'list', 'test') self.cmd(f'--repo={self.repository_location}', 'recreate', '-n', '-e', 'input/compressible') @@ -3015,7 +3015,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_recreate_skips_nothing_to_do(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') info_before = self.cmd(f'--repo={self.repository_location}', 'info', '-a', 'test') self.cmd(f'--repo={self.repository_location}', 'recreate', '--chunker-params', 'default') @@ -3024,13 +3024,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert info_before == info_after # includes archive ID def test_with_lock(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') lock_path = os.path.join(self.repository_path, 'lock.exclusive') cmd = 'python3', '-c', 'import os, sys; sys.exit(42 if os.path.exists("%s") else 23)' % lock_path self.cmd(f'--repo={self.repository_location}', 'with-lock', *cmd, fork=True, exit_code=42) def test_recreate_list_output(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('file1', size=0) self.create_regular_file('file2', size=0) self.create_regular_file('file3', size=0) @@ -3060,13 +3060,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_not_in("x input/file5", output) def test_bad_filters(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'delete', '--first', '1', '--last', '1', fork=True, exit_code=2) def test_key_export_keyfile(self): export_file = self.output_path + '/exported' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'keyfile') repo_id = self._extract_repository_id(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'key', 'export', export_file) @@ -3092,7 +3092,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert key_contents2 == key_contents def test_key_import_keyfile_with_borg_key_file(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'keyfile') exported_key_file = os.path.join(self.output_path, 'exported') self.cmd(f'--repo={self.repository_location}', 'key', 'export', exported_key_file) @@ -3113,7 +3113,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_key_export_repokey(self): export_file = self.output_path + '/exported' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'repokey') repo_id = self._extract_repository_id(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'key', 'export', export_file) @@ -3144,7 +3144,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): def test_key_export_qr(self): export_file = self.output_path + '/exported.html' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'repokey') repo_id = self._extract_repository_id(self.repository_path) self.cmd(f'--repo={self.repository_location}', 'key', 'export', '--qr-html', export_file) @@ -3159,13 +3159,13 @@ class ArchiverTestCase(ArchiverTestCaseBase): export_directory = self.output_path + '/exported' os.mkdir(export_directory) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'repokey') self.cmd(f'--repo={self.repository_location}', 'key', 'export', export_directory, exit_code=EXIT_ERROR) def test_key_import_errors(self): export_file = self.output_path + '/exported' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'keyfile') self.cmd(f'--repo={self.repository_location}', 'key', 'import', export_file, exit_code=EXIT_ERROR) @@ -3191,7 +3191,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): repo_id = 'e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239' export_file = self.output_path + '/exported' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'keyfile') self._set_repository_id(self.repository_path, unhexlify(repo_id)) key_file = self.keys_path + '/' + os.listdir(self.keys_path)[0] @@ -3215,7 +3215,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_key_import_paperkey(self): repo_id = 'e294423506da4e1ea76e8dcdf1a3919624ae3ae496fddf905610c351d3f09239' - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption', 'keyfile') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption', 'keyfile') self._set_repository_id(self.repository_path, unhexlify(repo_id)) key_file = self.keys_path + '/' + os.listdir(self.keys_path)[0] @@ -3260,7 +3260,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_manifest(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') dump_file = self.output_path + '/dump' output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-manifest', dump_file) @@ -3275,7 +3275,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_debug_dump_archive(self): self.create_regular_file('file1', size=1024 * 80) - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') dump_file = self.output_path + '/dump' output = self.cmd(f'--repo={self.repository_location}', 'debug', 'dump-archive', 'test', dump_file) @@ -3288,7 +3288,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 assert '_items' in result def test_debug_refcount_obj(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'debug', 'refcount-obj', '0' * 64).strip() assert output == 'object 0000000000000000000000000000000000000000000000000000000000000000 not found [info from chunks cache].' @@ -3307,14 +3307,14 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 assert 'Python' in output def test_benchmark_crud(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') with environment_variable(_BORG_BENCHMARK_CRUD_TEST='YES'): self.cmd(f'--repo={self.repository_location}', 'benchmark', 'crud', self.input_path) def test_config(self): self.create_test_files() os.unlink('input/flagfile') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') output = self.cmd(f'--repo={self.repository_location}', 'config', '--list') self.assert_in('[repository]', output) self.assert_in('version', output) @@ -3357,7 +3357,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_export_tar(self): self.create_test_files() os.unlink('input/flagfile') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'simple.tar', '--progress', '--tar-format=GNU') with changedir('output'): @@ -3372,7 +3372,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 pytest.skip('gzip is not installed') self.create_test_files() os.unlink('input/flagfile') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') list = self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'simple.tar.gz', '--list', '--tar-format=GNU') @@ -3388,7 +3388,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 pytest.skip('gzip is not installed') self.create_test_files() os.unlink('input/flagfile') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') list = self.cmd(f'--repo={self.repository_location}', 'export-tar', 'test', 'simple.tar', '--strip-components=1', '--list', '--tar-format=GNU') @@ -3427,7 +3427,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_import_tar(self, tar_format='PAX'): self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', 'src', 'simple.tar', f'--tar-format={tar_format}') self.cmd(f'--repo={self.repository_location}', 'import-tar', 'dst', 'simple.tar') @@ -3441,7 +3441,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 pytest.skip('gzip is not installed') self.create_test_files(create_hardlinks=False) # hardlinks become separate files os.unlink('input/flagfile') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', 'src', 'simple.tgz', f'--tar-format={tar_format}') self.cmd(f'--repo={self.repository_location}', 'import-tar', 'dst', 'simple.tgz') @@ -3451,7 +3451,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_roundtrip_pax_borg(self): self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=none') self.cmd(f'--repo={self.repository_location}', 'create', 'src', 'input') self.cmd(f'--repo={self.repository_location}', 'export-tar', 'src', 'simple.tar', '--tar-format=BORG') self.cmd(f'--repo={self.repository_location}', 'import-tar', 'dst', 'simple.tar') @@ -3469,7 +3469,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.create_regular_file('file') xattr.setxattr(b'input/file', b'user.attribute%p', b'value') - self.cmd('init', self.repository_location, '-e' 'none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '-e' 'none') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): @@ -3485,7 +3485,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 os.makedirs(os.path.join(self.input_path, 'dir%p')) xattr.setxattr(b'input/dir%p', b'user.attribute', b'value') - self.cmd(f'--repo={self.repository_location}', 'init', '-e' 'none') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '-e' 'none') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') with changedir('output'): with patch.object(xattr, 'setxattr', patched_setxattr_EACCES): @@ -3504,7 +3504,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 It should be possible to retrieve the data from an archive even if both the client and the server forget the nonce""" self.create_regular_file('file1', contents=b'Hello, borg') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 @@ -3535,7 +3535,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 repo. Otherwise we can just use our own copy of the nonce. """ self.create_regular_file('file1', contents=b'Hello, borg') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cmd(f'--repo={self.repository_location}', 'create', 'test', 'input') # Oops! We have removed the repo-side memory of the nonce! # See https://github.com/borgbackup/borg/issues/5858 @@ -3547,20 +3547,20 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 def test_init_defaults_to_argon2(self): """https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') with Repository(self.repository_path) as repository: key = msgpack.unpackb(a2b_base64(repository.load_key())) assert key['algorithm'] == 'argon2 chacha20-poly1305' def test_init_with_explicit_key_algorithm(self): """https://github.com/borgbackup/borg/issues/747#issuecomment-1076160401""" - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--key-algorithm=pbkdf2') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey', '--key-algorithm=pbkdf2') with Repository(self.repository_path) as repository: key = msgpack.unpackb(a2b_base64(repository.load_key())) assert key['algorithm'] == 'sha256' def verify_change_passphrase_does_not_change_algorithm(self, given_algorithm, expected_algorithm): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--key-algorithm', given_algorithm) + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey', '--key-algorithm', given_algorithm) os.environ['BORG_NEW_PASSPHRASE'] = 'newpassphrase' self.cmd(f'--repo={self.repository_location}', 'key', 'change-passphrase') @@ -3576,7 +3576,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.verify_change_passphrase_does_not_change_algorithm('pbkdf2', 'sha256') def verify_change_location_does_not_change_algorithm(self, given_algorithm, expected_algorithm): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=keyfile', '--key-algorithm', given_algorithm) + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=keyfile', '--key-algorithm', given_algorithm) self.cmd(f'--repo={self.repository_location}', 'key', 'change-location', 'repokey') @@ -3591,7 +3591,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02 self.verify_change_location_does_not_change_algorithm('pbkdf2', 'sha256') def test_key_change_algorithm(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey', '--key-algorithm=pbkdf2') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey', '--key-algorithm=pbkdf2') self.cmd(f'--repo={self.repository_location}', 'key', 'change-algorithm', 'argon2') @@ -3650,7 +3650,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): def setUp(self): super().setUp() with patch.object(ChunkBuffer, 'BUFFER_SIZE', 10): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('archive1') self.create_src_archive('archive2') @@ -3825,7 +3825,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): def _test_verify_data(self, *init_args): shutil.rmtree(self.repository_path) - self.cmd(f'--repo={self.repository_location}', 'init', *init_args) + self.cmd(f'--repo={self.repository_location}', 'rcreate', *init_args) self.create_src_archive('archive1') archive, repository = self.open_archive('archive1') with repository: @@ -3871,7 +3871,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): repository.commit(compact=False) def test_fresh_init_tam_required(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') repository = Repository(self.repository_path, exclusive=True) with repository: manifest, key = Manifest.load(repository, Manifest.NO_OPERATION_CHECK) @@ -3886,7 +3886,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'rlist') def test_not_required(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('archive1234') repository = Repository(self.repository_path, exclusive=True) with repository: @@ -3918,7 +3918,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): self.cmd(f'--repo={self.repository_location}', 'rlist') def test_disable(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('archive1234') self.cmd(f'--repo={self.repository_location}', 'upgrade', '--disable-tam') repository = Repository(self.repository_path, exclusive=True) @@ -3926,7 +3926,7 @@ class ManifestAuthenticationTest(ArchiverTestCaseBase): assert not self.cmd(f'--repo={self.repository_location}', 'rlist') def test_disable2(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_src_archive('archive1234') repository = Repository(self.repository_path, exclusive=True) self.spoof_manifest(repository) @@ -3943,32 +3943,32 @@ class RemoteArchiverTestCase(ArchiverTestCase): def test_remote_repo_restrict_to_path(self): # restricted to repo directory itself: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', self.repository_path]): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # restricted to repo directory itself, fail for other directories with same prefix: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', self.repository_path]): with pytest.raises(PathNotAllowed): - self.cmd(f'--repo={self.repository_location}_0', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_0', 'rcreate', '--encryption=repokey') # restricted to a completely different path: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', '/foo']): with pytest.raises(PathNotAllowed): - self.cmd(f'--repo={self.repository_location}_1', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_1', 'rcreate', '--encryption=repokey') path_prefix = os.path.dirname(self.repository_path) # restrict to repo directory's parent directory: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', path_prefix]): - self.cmd(f'--repo={self.repository_location}_2', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_2', 'rcreate', '--encryption=repokey') # restrict to repo directory's parent directory and another directory: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-path', '/foo', '--restrict-to-path', path_prefix]): - self.cmd(f'--repo={self.repository_location}_3', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}_3', 'rcreate', '--encryption=repokey') def test_remote_repo_restrict_to_repository(self): # restricted to repo directory itself: with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-repository', self.repository_path]): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') parent_path = os.path.join(self.repository_path, '..') with patch.object(RemoteRepository, 'extra_test_args', ['--restrict-to-repository', parent_path]): with pytest.raises(PathNotAllowed): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') @unittest.skip('only works locally') def test_debug_put_get_delete_obj(self): @@ -3983,7 +3983,7 @@ class RemoteArchiverTestCase(ArchiverTestCase): pass def test_remote_repo_strip_components_doesnt_leak(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('dir/file', contents=b"test file contents 1") self.create_regular_file('dir/file2', contents=b"test file contents 2") self.create_regular_file('skipped-file1', contents=b"test file contents 3") @@ -4009,7 +4009,7 @@ class ArchiverCorruptionTestCase(ArchiverTestCaseBase): def setUp(self): super().setUp() self.create_test_files() - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.cache_path = json.loads(self.cmd(f'--repo={self.repository_location}', 'rinfo', '--json'))['cache']['path'] def corrupt(self, file, amount=1): @@ -4103,7 +4103,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): os.link('input/file_removed', 'input/hardlink_removed') os.link('input/file_removed2', 'input/hardlink_target_removed') - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') # Create the first snapshot self.cmd(f'--repo={self.repository_location}', 'create', 'test0', 'input') @@ -4289,7 +4289,7 @@ class DiffArchiverTestCase(ArchiverTestCaseBase): do_json_asserts(self.cmd(f'--repo={self.repository_location}', 'diff', 'test0', 'test1a', '--json-lines'), True) def test_sort_option(self): - self.cmd(f'--repo={self.repository_location}', 'init', '--encryption=repokey') + self.cmd(f'--repo={self.repository_location}', 'rcreate', '--encryption=repokey') self.create_regular_file('a_file_removed', size=8) self.create_regular_file('f_file_removed', size=16) @@ -4350,7 +4350,7 @@ def test_get_args(): assert args.restrict_to_repositories == ['/r1', '/r2'] # trying to cheat - try to execute different subcommand args = archiver.get_args(['borg', 'serve', '--restrict-to-path=/p1', '--restrict-to-path=/p2', ], - 'borg --repo=/ init --encryption=repokey') + 'borg --repo=/ rcreate --encryption=repokey') assert args.func == archiver.do_serve # Check that environment variables in the forced command don't cause issues. If the command diff --git a/src/borg/testsuite/benchmark.py b/src/borg/testsuite/benchmark.py index 0a9a4373a..7b8d93168 100644 --- a/src/borg/testsuite/benchmark.py +++ b/src/borg/testsuite/benchmark.py @@ -28,7 +28,7 @@ def repo_url(request, tmpdir, monkeypatch): @pytest.fixture(params=["none", "repokey"]) def repo(request, cmd, repo_url): - cmd(f'--repo={repo_url}', 'init', '--encryption', request.param) + cmd(f'--repo={repo_url}', 'rcreate', '--encryption', request.param) return repo_url From f578c20b22841838901603d144be45801fadd159 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 23 Jun 2022 09:50:48 +0200 Subject: [PATCH 21/21] fix benchmark tests --- src/borg/testsuite/benchmark.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/borg/testsuite/benchmark.py b/src/borg/testsuite/benchmark.py index 7b8d93168..b23a7d800 100644 --- a/src/borg/testsuite/benchmark.py +++ b/src/borg/testsuite/benchmark.py @@ -57,7 +57,7 @@ def testdata(request, tmpdir_factory): @pytest.fixture(params=['none', 'lz4']) def repo_archive(request, cmd, repo, testdata): archive = 'test' - cmd(f'--repo={repo}', 'create', f'{archive}', '--compression', request.param, testdata) + cmd(f'--repo={repo}', 'create', '--compression', request.param, archive, testdata) return repo, archive @@ -82,19 +82,19 @@ def test_extract(benchmark, cmd, repo_archive, tmpdir): def test_delete(benchmark, cmd, repo_archive): repo, archive = repo_archive - result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'delete', '--name', archive)) + result, out = benchmark.pedantic(cmd, (f'--repo={repo}', 'delete', '-a', archive)) assert result == 0 def test_list(benchmark, cmd, repo_archive): repo, archive = repo_archive - result, out = benchmark(cmd, f'--repo={repo}', 'list', '--name', archive) + result, out = benchmark(cmd, f'--repo={repo}', 'list', archive) assert result == 0 def test_info(benchmark, cmd, repo_archive): repo, archive = repo_archive - result, out = benchmark(cmd, f'--repo={repo}', 'info', '--name', archive) + result, out = benchmark(cmd, f'--repo={repo}', 'info', '-a', archive) assert result == 0