diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f2649cca5..148757435e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,21 +66,6 @@ jobs: fail-fast: true matrix: include: - - os: ubuntu-22.04 - python-version: '3.10' - toxenv: mypy - - os: ubuntu-22.04 - python-version: '3.11' - toxenv: docs - - os: ubuntu-22.04 - python-version: '3.10' - toxenv: py310-fuse2 - - os: ubuntu-22.04 - python-version: '3.11' - toxenv: py311-fuse3 - - os: ubuntu-24.04 - python-version: '3.12' - toxenv: py312-fuse3 - os: ubuntu-24.04 python-version: '3.13' toxenv: py313-fuse3 @@ -199,7 +184,7 @@ jobs: macOS: - needs: linux + if: false # enable/disable macOS build strategy: fail-fast: true matrix: @@ -271,10 +256,9 @@ jobs: windows: - if: false # can be used to temporarily disable the build + if: true # can be used to temporarily disable the build runs-on: windows-latest timeout-minutes: 120 - needs: linux env: PY_COLORS: 1 diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index 5f051d0eca..1168469e0a 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -18,6 +18,7 @@ from string import Formatter from ..logger import create_logger +from ..platformflags import is_windows logger = create_logger() @@ -455,8 +456,9 @@ class Location: (?P.+) """ - # abs_path must start with a slash. - abs_path_re = r"(?P/.+)" + abs_path_re_posix = r"(?P/.+)" # abs path must start with a slash. + abs_path_re_win = r"(?P[a-zA-Z]:/.+)" # abs path must start with drive : slash. + abs_path_re = abs_path_re_win if is_windows else abs_path_re_posix # path may or may not start with a slash. abs_or_rel_path_re = r"(?P.+)" @@ -495,7 +497,8 @@ class Location: rclone_re = re.compile(r"(?Prclone):(?P(.*))", re.VERBOSE) - file_or_socket_re = re.compile(r"(?P(file|socket))://" + abs_path_re, re.VERBOSE) + sep = r"/" if is_windows else r"" # on windows, an addtl. slash is needed + file_or_socket_re = re.compile(r"(?P(file|socket))://" + sep + abs_path_re, re.VERBOSE) local_re = re.compile(local_path_re, re.VERBOSE) diff --git a/src/borg/legacyrepository.py b/src/borg/legacyrepository.py index 719f947f17..e94b2ecf3b 100644 --- a/src/borg/legacyrepository.py +++ b/src/borg/legacyrepository.py @@ -1,4 +1,6 @@ import errno +from pathlib import Path + import mmap import os import shutil @@ -192,7 +194,7 @@ class PathPermissionDenied(Error): def __init__(self, path, create=False, exclusive=False, lock_wait=None, lock=True, send_log_cb=None): self.path = os.path.abspath(path) - self._location = Location("file://%s" % self.path) + self._location = Location(Path(self.path).as_uri()) self.version = None # long-running repository methods which emit log or progress output are responsible for calling # the ._send_log method periodically to get log and progress output transferred to the borg client diff --git a/src/borg/platformflags.py b/src/borg/platformflags.py index da4e5f6feb..25917a1333 100644 --- a/src/borg/platformflags.py +++ b/src/borg/platformflags.py @@ -8,6 +8,8 @@ is_win32 = sys.platform.startswith("win32") is_cygwin = sys.platform.startswith("cygwin") +is_msys = sys.platform.startswith("msys") +is_windows = is_win32 or is_cygwin or is_msys is_linux = sys.platform.startswith("linux") is_freebsd = sys.platform.startswith("freebsd") diff --git a/src/borg/repository.py b/src/borg/repository.py index 42405c09fa..080691530c 100644 --- a/src/borg/repository.py +++ b/src/borg/repository.py @@ -1,5 +1,6 @@ import os import time +from pathlib import Path from borgstore.store import Store from borgstore.store import ObjectNotFound as StoreObjectNotFound @@ -105,11 +106,11 @@ def __init__( if isinstance(path_or_location, Location): location = path_or_location if location.proto == "file": - url = f"file://{location.path}" # frequently users give without file:// prefix + url = Path(location.path).absolute().as_uri() # frequently users give without file:// prefix else: url = location.processed # location as given by user, processed placeholders else: - url = "file://%s" % os.path.abspath(path_or_location) + url = Path(path_or_location).absolute().as_uri() location = Location(url) self._location = location self.url = url diff --git a/src/borg/testsuite/archiver/lock_cmds_test.py b/src/borg/testsuite/archiver/lock_cmds_test.py index 139fb0770c..9f97f85bd5 100644 --- a/src/borg/testsuite/archiver/lock_cmds_test.py +++ b/src/borg/testsuite/archiver/lock_cmds_test.py @@ -18,7 +18,7 @@ def test_break_lock(archivers, request): def test_with_lock(tmp_path): repo_path = tmp_path / "repo" env = os.environ.copy() - env["BORG_REPO"] = "file://" + str(repo_path) + env["BORG_REPO"] = repo_path.as_uri() command0 = "python3", "-m", "borg", "repo-create", "--encryption=none" # Timings must be adjusted so that command1 keeps running while command2 tries to get the lock, # so that lock acquisition for command2 fails as the test expects it. diff --git a/src/borg/testsuite/storelocking_test.py b/src/borg/testsuite/storelocking_test.py index ea091a83ba..7e1d95f996 100644 --- a/src/borg/testsuite/storelocking_test.py +++ b/src/borg/testsuite/storelocking_test.py @@ -1,4 +1,5 @@ import time +from pathlib import Path import pytest @@ -12,7 +13,7 @@ @pytest.fixture() def lockstore(tmpdir): - store = Store("file://" + str(tmpdir / "lockstore"), levels={"locks/": [0]}) + store = Store(Path(tmpdir / "lockstore").as_uri(), levels={"locks/": [0]}) store.create() with store: yield store