diff --git a/docs/usage/tar.rst b/docs/usage/tar.rst index 63a3aff0d..05070c50d 100644 --- a/docs/usage/tar.rst +++ b/docs/usage/tar.rst @@ -34,7 +34,7 @@ Outputs a script that copies all archives from repo1 to repo2: :: - for A T in `borg list --format='{archive} {time:%Y-%m-%dT%H:%M:%S}{LF}'` + for A T in `borg list --format='{archive} {time:%Y-%m-%dT%H:%M:%S}{NL}'` do echo "borg -r repo1 export-tar --tar-format=BORG $A - | borg -r repo2 import-tar --timestamp=$T $A -" done diff --git a/src/borg/archiver/create_cmd.py b/src/borg/archiver/create_cmd.py index 4db61bbd5..855357401 100644 --- a/src/borg/archiver/create_cmd.py +++ b/src/borg/archiver/create_cmd.py @@ -28,6 +28,7 @@ from ..helpers import sig_int, ignore_sigint from ..helpers import iter_separated from ..manifest import Manifest from ..patterns import PatternMatcher +from ..platform import is_win32 from ..platform import get_flags from ..platform import uid2user, gid2group @@ -68,7 +69,9 @@ class CreateMixIn: if not dry_run: try: try: - proc = subprocess.Popen(args.paths, stdout=subprocess.PIPE, preexec_fn=ignore_sigint) + proc = subprocess.Popen( + args.paths, stdout=subprocess.PIPE, preexec_fn=None if is_win32 else ignore_sigint + ) except (FileNotFoundError, PermissionError) as e: self.print_error("Failed to execute command: %s", e) return self.exit_code @@ -89,7 +92,9 @@ class CreateMixIn: paths_sep = eval_escapes(args.paths_delimiter) if args.paths_delimiter is not None else "\n" if args.paths_from_command: try: - proc = subprocess.Popen(args.paths, stdout=subprocess.PIPE, preexec_fn=ignore_sigint) + proc = subprocess.Popen( + args.paths, stdout=subprocess.PIPE, preexec_fn=None if is_win32 else ignore_sigint + ) except (FileNotFoundError, PermissionError) as e: self.print_error("Failed to execute command: %s", e) return self.exit_code diff --git a/src/borg/archiver/key_cmds.py b/src/borg/archiver/key_cmds.py index fa89d1da9..abb9d1ee2 100644 --- a/src/borg/archiver/key_cmds.py +++ b/src/borg/archiver/key_cmds.py @@ -101,6 +101,8 @@ class KeysMixIn: manager.export_paperkey(args.path) else: try: + if os.path.isdir(args.path): + raise IsADirectoryError if args.qr: manager.export_qr(args.path) else: diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index f28d23dd9..686431931 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -593,8 +593,8 @@ class BaseFormatter: "TAB": "\t", "CR": "\r", "NUL": "\0", - "NEWLINE": os.linesep, - "NL": os.linesep, + "NEWLINE": "\n", + "NL": "\n", # \n is automatically converted to os.linesep on write } def get_item_data(self, item): diff --git a/src/borg/helpers/process.py b/src/borg/helpers/process.py index 3d6de7aef..5877b8b42 100644 --- a/src/borg/helpers/process.py +++ b/src/borg/helpers/process.py @@ -341,7 +341,7 @@ def create_filter_process(cmd, stream, stream_close, inbound=True): stdin=filter_stream, log_prefix="filter-process: ", env=env, - preexec_fn=ignore_sigint, + preexec_fn=None if is_win32 else ignore_sigint, ) else: proc = popen_with_error_handling( @@ -350,7 +350,7 @@ def create_filter_process(cmd, stream, stream_close, inbound=True): stdout=filter_stream, log_prefix="filter-process: ", env=env, - preexec_fn=ignore_sigint, + preexec_fn=None if is_win32 else ignore_sigint, ) if not proc: raise Error(f"filter {cmd}: process creation failed") diff --git a/src/borg/platform/windows.pyx b/src/borg/platform/windows.pyx index e0c82da4e..3c627e45f 100644 --- a/src/borg/platform/windows.pyx +++ b/src/borg/platform/windows.pyx @@ -16,22 +16,22 @@ cdef extern from 'windows.h': @lru_cache(maxsize=None) def uid2user(uid, default=None): - return default + return "root" @lru_cache(maxsize=None) def user2uid(user, default=None): - return default + return 0 @lru_cache(maxsize=None) def gid2group(gid, default=None): - return default + return "root" @lru_cache(maxsize=None) def group2gid(group, default=None): - return default + return 0 def getosusername(): diff --git a/src/borg/testsuite/archiver/__init__.py b/src/borg/testsuite/archiver/__init__.py index a9a5da6d3..0b6e137ba 100644 --- a/src/borg/testsuite/archiver/__init__.py +++ b/src/borg/testsuite/archiver/__init__.py @@ -28,6 +28,7 @@ from ...repository import Repository from .. import has_lchflags from .. import BaseTestCase, changedir, environment_variable from .. import are_symlinks_supported, are_hardlinks_supported, are_fifos_supported +from ..platform import is_win32 RK_ENCRYPTION = "--encryption=repokey-aes-ocb" KF_ENCRYPTION = "--encryption=keyfile-chacha20-poly1305" @@ -230,23 +231,27 @@ class ArchiverTestCaseBase(BaseTestCase): os.mkfifo(os.path.join(self.input_path, "fifo1")) if has_lchflags: platform.set_flags(os.path.join(self.input_path, "flagfile"), stat.UF_NODUMP) - try: - # Block device - os.mknod("input/bdev", 0o600 | stat.S_IFBLK, os.makedev(10, 20)) - # Char device - os.mknod("input/cdev", 0o600 | stat.S_IFCHR, os.makedev(30, 40)) - # File owner - os.chown("input/file1", 100, 200) # raises OSError invalid argument on cygwin - # File mode - os.chmod("input/dir2", 0o555) # if we take away write perms, we need root to remove contents - have_root = True # we have (fake)root - except PermissionError: - have_root = False - except OSError as e: - # Note: ENOSYS "Function not implemented" happens as non-root on Win 10 Linux Subsystem. - if e.errno not in (errno.EINVAL, errno.ENOSYS): - raise + + if is_win32: have_root = False + else: + try: + # Block device + os.mknod("input/bdev", 0o600 | stat.S_IFBLK, os.makedev(10, 20)) + # Char device + os.mknod("input/cdev", 0o600 | stat.S_IFCHR, os.makedev(30, 40)) + # File owner + os.chown("input/file1", 100, 200) # raises OSError invalid argument on cygwin + # File mode + os.chmod("input/dir2", 0o555) # if we take away write perms, we need root to remove contents + have_root = True # we have (fake)root + except PermissionError: + have_root = False + except OSError as e: + # Note: ENOSYS "Function not implemented" happens as non-root on Win 10 Linux Subsystem. + if e.errno not in (errno.EINVAL, errno.ENOSYS): + raise + have_root = False time.sleep(1) # "empty" must have newer timestamp than other files self.create_regular_file("empty", size=0) return have_root diff --git a/src/borg/testsuite/archiver/check_cmd.py b/src/borg/testsuite/archiver/check_cmd.py index 61936460d..b7f74247c 100644 --- a/src/borg/testsuite/archiver/check_cmd.py +++ b/src/borg/testsuite/archiver/check_cmd.py @@ -71,7 +71,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): 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", "archive1", "--format={health}#{path}{LF}", exit_code=0 + f"--repo={self.repository_location}", "list", "archive1", "--format={health}#{path}{NL}", 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 @@ -104,7 +104,7 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase): self.fail("should not happen") # list is also all-healthy again output = self.cmd( - f"--repo={self.repository_location}", "list", "archive1", "--format={health}#{path}{LF}", exit_code=0 + f"--repo={self.repository_location}", "list", "archive1", "--format={health}#{path}{NL}", exit_code=0 ) self.assert_not_in("broken#", output) diff --git a/src/borg/testsuite/archiver/config_cmd.py b/src/borg/testsuite/archiver/config_cmd.py index c16f17576..f7b675822 100644 --- a/src/borg/testsuite/archiver/config_cmd.py +++ b/src/borg/testsuite/archiver/config_cmd.py @@ -24,17 +24,17 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.assert_in("No option ", output) 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" + assert output == "123" + os.linesep output = self.cmd(f"--repo={self.repository_location}", "config", "--list") self.assert_in("last_segment_checked", output) 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(f"--repo={self.repository_location}", "config", cfg_key) - assert output == "0" + "\n" + assert output == "0" + os.linesep 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" + assert output == cfg_value + os.linesep self.cmd(f"--repo={self.repository_location}", "config", "--delete", cfg_key) self.cmd(f"--repo={self.repository_location}", "config", cfg_key, exit_code=1) diff --git a/src/borg/testsuite/archiver/corruption.py b/src/borg/testsuite/archiver/corruption.py index 3ee429992..ef933eab9 100644 --- a/src/borg/testsuite/archiver/corruption.py +++ b/src/borg/testsuite/archiver/corruption.py @@ -60,7 +60,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}", "rlist", "--format={id}{LF}").strip() + target_id = self.cmd(f"--repo={self.repository_location}", "rlist", "--format={id}{NL}").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 diff --git a/src/borg/testsuite/archiver/create_cmd.py b/src/borg/testsuite/archiver/create_cmd.py index 74b77be90..76e9a0209 100644 --- a/src/borg/testsuite/archiver/create_cmd.py +++ b/src/borg/testsuite/archiver/create_cmd.py @@ -13,7 +13,7 @@ import pytest from ... import platform from ...constants import * # NOQA from ...manifest import Manifest -from ...platform import is_cygwin +from ...platform import is_cygwin, is_win32 from ...repository import Repository from .. import has_lchflags from .. import changedir @@ -119,6 +119,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # we have all fs items exactly once! assert sorted(paths) == ["input", "input/a", "input/a/hardlink", "input/b", "input/b/hardlink"] + @pytest.mark.skipif(is_win32, reason="unix sockets not available on windows") def test_unix_socket(self): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) try: @@ -204,14 +205,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): "exit 73;", exit_code=2, ) - assert output.endswith("Command 'sh' exited with status 73\n") + assert output.endswith("Command 'sh' exited with status 73" + os.linesep) 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): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) output = self.cmd(f"--repo={self.repository_location}", "create", "test", "--content-from-command", exit_code=2) - assert output.endswith("No command given.\n") + assert output.endswith("No command given." + os.linesep) def test_create_paths_from_stdin(self): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) @@ -242,9 +243,20 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file("file4", size=1024 * 80) input_data = "input/file1\ninput/file2\ninput/file3" + if is_win32: + with open("filenames.cmd", "w") as script: + for filename in input_data.splitlines(): + script.write(f"@echo {filename}\n") self.cmd( - f"--repo={self.repository_location}", "create", "--paths-from-command", "test", "--", "echo", input_data + f"--repo={self.repository_location}", + "create", + "--paths-from-command", + "test", + "--", + "filenames.cmd" if is_win32 else "echo", + input_data, ) + 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"] @@ -262,14 +274,14 @@ class ArchiverTestCase(ArchiverTestCaseBase): "exit 73;", exit_code=2, ) - assert output.endswith("Command 'sh' exited with status 73\n") + assert output.endswith("Command 'sh' exited with status 73" + os.linesep) 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): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) output = self.cmd(f"--repo={self.repository_location}", "create", "test", "--paths-from-command", exit_code=2) - assert output.endswith("No command given.\n") + assert output.endswith("No command given." + os.linesep) def test_create_without_root(self): """test create without a root""" @@ -500,6 +512,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f"--repo={self.repository_location}", "create", "test", "input", "input") @pytest.mark.skipif("BORG_TESTS_IGNORE_MODES" in os.environ, reason="modes unreliable") + @pytest.mark.skipif(is_win32, reason="modes unavailable on Windows") def test_umask(self): self.create_regular_file("file1", size=1024 * 80) self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) @@ -545,6 +558,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): # https://borgbackup.readthedocs.org/en/latest/faq.html#i-am-seeing-a-added-status-for-a-unchanged-file self.assert_in("A input/file2", output) + @pytest.mark.skipif( + is_win32, reason="ctime attribute is file creation time on Windows" + ) # see https://docs.python.org/3/library/os.html#os.stat_result.st_ctime def test_file_status_cs_cache_mode(self): """test that a changed file with faked "previous" mtime still gets backed up in ctime,size cache_mode""" self.create_regular_file("file1", contents=b"123") @@ -740,6 +756,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): extracted_data = f.read() assert extracted_data == data + @pytest.mark.skipif(not are_symlinks_supported(), reason="symlinks not supported") 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}", "rcreate", RK_ENCRYPTION) @@ -784,7 +801,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Test case set up: create a repository and a file self.cmd(f"--repo={self.repository_location}", "rcreate", "--encryption=none") - self.create_regular_file("testfile", contents=randbytes(15000000)) # more data might be needed for faster CPUs + self.create_regular_file("testfile", contents=randbytes(50000000)) # Archive result = self.cmd(f"--repo={self.repository_location}", "create", "--stats", "test_archive", self.input_path) hashing_time = extract_hashing_time(result) @@ -802,7 +819,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Test case set up: create a repository and a file self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) - self.create_regular_file("testfile", contents=randbytes(10000000)) + self.create_regular_file("testfile", contents=randbytes(50000000)) # Archive result = self.cmd(f"--repo={self.repository_location}", "create", "--stats", "test_archive", self.input_path) chunking_time = extract_chunking_time(result) diff --git a/src/borg/testsuite/archiver/debug_cmds.py b/src/borg/testsuite/archiver/debug_cmds.py index c7fce5bec..3fc8278d9 100644 --- a/src/borg/testsuite/archiver/debug_cmds.py +++ b/src/borg/testsuite/archiver/debug_cmds.py @@ -107,7 +107,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Invalid IDs do not abort or return an error 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." + assert output == "object id 124 is invalid." + os.linesep + "object id xyza is invalid." def test_debug_info(self): output = self.cmd("debug", "info") diff --git a/src/borg/testsuite/archiver/diff_cmd.py b/src/borg/testsuite/archiver/diff_cmd.py index cb0a8a867..d8015f512 100644 --- a/src/borg/testsuite/archiver/diff_cmd.py +++ b/src/borg/testsuite/archiver/diff_cmd.py @@ -5,6 +5,7 @@ import unittest from ...constants import * # NOQA from .. import are_symlinks_supported, are_hardlinks_supported +from ..platform import is_win32 from . import ArchiverTestCaseBase, RemoteArchiverTestCaseBase, ArchiverTestCaseBinaryBase, RK_ENCRYPTION, BORG_EXES @@ -79,7 +80,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert "input/file_unchanged" not in output # Directory replaced with a regular file - if "BORG_TESTS_IGNORE_MODES" not in os.environ: + if "BORG_TESTS_IGNORE_MODES" not in os.environ and not is_win32: assert "[drwxr-xr-x -> -rwxr-xr-x] input/dir_replaced_with_file" in output # Basic directory cases @@ -153,7 +154,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert not any(get_changes("input/file_unchanged", joutput)) # Directory replaced with a regular file - if "BORG_TESTS_IGNORE_MODES" not in os.environ: + if "BORG_TESTS_IGNORE_MODES" not in os.environ and not is_win32: assert {"type": "mode", "old_mode": "drwxr-xr-x", "new_mode": "-rwxr-xr-x"} in get_changes( "input/dir_replaced_with_file", joutput ) diff --git a/src/borg/testsuite/archiver/extract_cmd.py b/src/borg/testsuite/archiver/extract_cmd.py index b948e7a5e..9e223599a 100644 --- a/src/borg/testsuite/archiver/extract_cmd.py +++ b/src/borg/testsuite/archiver/extract_cmd.py @@ -309,19 +309,18 @@ class ArchiverTestCase(ArchiverTestCaseBase): 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.create_regular_file("aa:something", size=1024 * 80) # Create while excluding using mixed pattern styles with open(self.exclude_file_path, "wb") as fd: fd.write(b"re:input/file4$\n") - fd.write(b"fm:*aa:*thing\n") + fd.write(b"fm:*file3*\n") 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", "test") - self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2", "file3", "file333"]) + self.assert_equal(sorted(os.listdir("output/input")), ["file1", "file2"]) shutil.rmtree("output/input") # Exclude using regular expression @@ -346,7 +345,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd( f"--repo={self.repository_location}", "extract", "test", "--exclude-from=" + self.exclude_file_path ) - self.assert_equal(sorted(os.listdir("output/input")), ["file3"]) + self.assert_equal(sorted(os.listdir("output/input")), []) def test_extract_with_pattern(self): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) diff --git a/src/borg/testsuite/archiver/info_cmd.py b/src/borg/testsuite/archiver/info_cmd.py index eb960dff2..c6af865b0 100644 --- a/src/borg/testsuite/archiver/info_cmd.py +++ b/src/borg/testsuite/archiver/info_cmd.py @@ -1,4 +1,5 @@ import json +import os import unittest from ...constants import * # NOQA @@ -18,9 +19,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) self.cmd(f"--repo={self.repository_location}", "create", "test", "input") info_archive = self.cmd(f"--repo={self.repository_location}", "info", "-a", "test") - assert "Archive name: test\n" in info_archive + assert "Archive name: test" + os.linesep in info_archive info_archive = self.cmd(f"--repo={self.repository_location}", "info", "--first", "1") - assert "Archive name: test\n" in info_archive + assert "Archive name: test" + os.linesep in info_archive def test_info_json(self): self.create_regular_file("file1", size=1024 * 80) diff --git a/src/borg/testsuite/archiver/key_cmds.py b/src/borg/testsuite/archiver/key_cmds.py index c866fc3ae..94dadcab0 100644 --- a/src/borg/testsuite/archiver/key_cmds.py +++ b/src/borg/testsuite/archiver/key_cmds.py @@ -163,6 +163,16 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f"--repo={self.repository_location}", "key", "export", export_directory, exit_code=EXIT_ERROR) + def test_key_export_qr_directory(self): + export_directory = self.output_path + "/exported" + os.mkdir(export_directory) + + self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) + + self.cmd( + f"--repo={self.repository_location}", "key", "export", "--qr-html", 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}", "rcreate", KF_ENCRYPTION) diff --git a/src/borg/testsuite/archiver/recreate_cmd.py b/src/borg/testsuite/archiver/recreate_cmd.py index 67cc13843..435cafb2b 100644 --- a/src/borg/testsuite/archiver/recreate_cmd.py +++ b/src/borg/testsuite/archiver/recreate_cmd.py @@ -265,7 +265,7 @@ 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", "-a", "test1") + assert "Comment: " + os.linesep 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") @@ -274,7 +274,7 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.cmd(f"--repo={self.repository_location}", "recreate", "-a", "test4", "12345") 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: " + os.linesep 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") diff --git a/src/borg/testsuite/archiver/rlist_cmd.py b/src/borg/testsuite/archiver/rlist_cmd.py index f4ceff626..7ee7ab58b 100644 --- a/src/borg/testsuite/archiver/rlist_cmd.py +++ b/src/borg/testsuite/archiver/rlist_cmd.py @@ -1,4 +1,5 @@ import json +import os import unittest from ...constants import * # NOQA @@ -34,10 +35,10 @@ class ArchiverTestCase(ArchiverTestCaseBase): ) self.assertEqual(output_1, output_2) output_1 = self.cmd(f"--repo={self.repository_location}", "rlist", "--short") - self.assertEqual(output_1, "test-1\ntest-2\n") + self.assertEqual(output_1, "test-1" + os.linesep + "test-2" + os.linesep) 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) + self.assert_in("test-1 comment 1" + os.linesep, output_3) + self.assert_in("test-2 comment 2" + os.linesep, output_3) def test_rlist_consider_checkpoints(self): self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) diff --git a/src/borg/testsuite/archiver/transfer_cmd.py b/src/borg/testsuite/archiver/transfer_cmd.py index acc978101..b0a520266 100644 --- a/src/borg/testsuite/archiver/transfer_cmd.py +++ b/src/borg/testsuite/archiver/transfer_cmd.py @@ -7,6 +7,7 @@ import unittest from ...constants import * # NOQA from ...helpers.time import parse_timestamp +from ..platform import is_win32 from . import ArchiverTestCaseBase, RemoteArchiverTestCaseBase, ArchiverTestCaseBinaryBase, RK_ENCRYPTION, BORG_EXES @@ -151,6 +152,11 @@ class ArchiverTestCase(ArchiverTestCaseBase): # Note: size == 0 for all items without a size or chunks list (like e.g. directories) # Note: healthy == True indicates the *absence* of the additional chunks_healthy list del g["hlid"] + + if e["type"] == "b" and is_win32: + # The S_IFBLK macro is broken on MINGW + del e["type"], g["type"] + del e["mode"], g["mode"] assert g == e if name == "archive1": @@ -250,7 +256,9 @@ class ArchiverTestCase(ArchiverTestCaseBase): assert item.group in ("root", "wheel") assert "hlid" not in item elif item.path.endswith("bdev_12_34"): - assert stat.S_ISBLK(item.mode) + if not is_win32: + # The S_IFBLK macro is broken on MINGW + assert stat.S_ISBLK(item.mode) # looks like we can't use os.major/minor with data coming from another platform, # thus we only do a rather rough check here: assert "rdev" in item and item.rdev != 0