Skip to content

Commit a44e259

Browse files
Merge pull request #8914 from ThomasWaldmann/pathlib
refactor: use pathlib.Path
2 parents 9a65d52 + 6a565c8 commit a44e259

15 files changed

Lines changed: 142 additions & 128 deletions

File tree

src/borg/archiver/compact_cmd.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import argparse
2-
import os
2+
from pathlib import Path
33

44
from ._common import with_repository
55
from ..archive import Archive
@@ -83,8 +83,8 @@ def cleanup_files_cache(self):
8383
"""
8484
logger.info("Cleaning up files cache...")
8585

86-
cache_dir = os.path.join(get_cache_dir(), self.repository.id_str)
87-
if not os.path.exists(cache_dir):
86+
cache_dir = Path(get_cache_dir()) / self.repository.id_str
87+
if not cache_dir.exists():
8888
logger.debug("Cache directory does not exist, skipping files cache cleanup")
8989
return
9090

@@ -104,9 +104,9 @@ def cleanup_files_cache(self):
104104
unused_files_cache_names = files_cache_names - used_files_cache_names
105105

106106
for cache_filename in unused_files_cache_names:
107-
cache_path = os.path.join(cache_dir, cache_filename)
107+
cache_path = cache_dir / cache_filename
108108
try:
109-
os.unlink(cache_path)
109+
cache_path.unlink()
110110
except (FileNotFoundError, PermissionError) as e:
111111
logger.warning(f"Could not access cache file: {e}")
112112
logger.info(f"Removed {len(unused_files_cache_names)} unused files cache files.")

src/borg/cache.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import stat
66
from collections import namedtuple
77
from datetime import datetime, timezone, timedelta
8+
from pathlib import Path
89
from time import perf_counter
910

1011
from borgstore.backends.errors import PermissionDenied
@@ -63,7 +64,7 @@ def discover_files_cache_names(path, files_cache_name="files"):
6364
:param files_cache_name: base name of the files cache files
6465
:return: list of files cache file names
6566
"""
66-
return [fn for fn in os.listdir(path) if fn.startswith(files_cache_name + ".")]
67+
return [p.name for p in path.iterdir() if p.name.startswith(files_cache_name + ".")]
6768

6869

6970
# chunks is a list of ChunkListEntry
@@ -92,34 +93,33 @@ class SecurityManager:
9293

9394
def __init__(self, repository):
9495
self.repository = repository
95-
self.dir = get_security_dir(repository.id_str, legacy=(repository.version == 1))
96-
self.cache_dir = cache_dir(repository)
97-
self.key_type_file = os.path.join(self.dir, "key-type")
98-
self.location_file = os.path.join(self.dir, "location")
99-
self.manifest_ts_file = os.path.join(self.dir, "manifest-timestamp")
96+
self.dir = Path(get_security_dir(repository.id_str, legacy=(repository.version == 1)))
97+
self.key_type_file = self.dir / "key-type"
98+
self.location_file = self.dir / "location"
99+
self.manifest_ts_file = self.dir / "manifest-timestamp"
100100

101101
@staticmethod
102102
def destroy(repository, path=None):
103103
"""destroy the security dir for ``repository`` or at ``path``"""
104104
path = path or get_security_dir(repository.id_str, legacy=(repository.version == 1))
105-
if os.path.exists(path):
105+
if Path(path).exists():
106106
shutil.rmtree(path)
107107

108108
def known(self):
109-
return all(os.path.exists(f) for f in (self.key_type_file, self.location_file, self.manifest_ts_file))
109+
return all(f.exists() for f in (self.key_type_file, self.location_file, self.manifest_ts_file))
110110

111111
def key_matches(self, key):
112112
if not self.known():
113113
return False
114114
try:
115-
with open(self.key_type_file) as fd:
115+
with self.key_type_file.open() as fd:
116116
type = fd.read()
117117
return type == str(key.TYPE)
118118
except OSError as exc:
119119
logger.warning("Could not read/parse key type file: %s", exc)
120120

121121
def save(self, manifest, key):
122-
logger.debug("security: saving state for %s to %s", self.repository.id_str, self.dir)
122+
logger.debug("security: saving state for %s to %s", self.repository.id_str, str(self.dir))
123123
current_location = self.repository._location.canonical_path()
124124
logger.debug("security: current location %s", current_location)
125125
logger.debug("security: key type %s", str(key.TYPE))
@@ -134,7 +134,7 @@ def save(self, manifest, key):
134134
def assert_location_matches(self):
135135
# Warn user before sending data to a relocated repository
136136
try:
137-
with open(self.location_file) as fd:
137+
with self.location_file.open() as fd:
138138
previous_location = fd.read()
139139
logger.debug("security: read previous location %r", previous_location)
140140
except FileNotFoundError:
@@ -167,7 +167,7 @@ def assert_location_matches(self):
167167

168168
def assert_no_manifest_replay(self, manifest, key):
169169
try:
170-
with open(self.manifest_ts_file) as fd:
170+
with self.manifest_ts_file.open() as fd:
171171
timestamp = fd.read()
172172
logger.debug("security: read manifest timestamp %r", timestamp)
173173
except FileNotFoundError:
@@ -235,15 +235,15 @@ def assert_secure(repository, manifest):
235235

236236

237237
def cache_dir(repository, path=None):
238-
return path or os.path.join(get_cache_dir(), repository.id_str)
238+
return Path(path) if path else Path(get_cache_dir()) / repository.id_str
239239

240240

241241
class CacheConfig:
242242
def __init__(self, repository, path=None):
243243
self.repository = repository
244244
self.path = cache_dir(repository, path)
245245
logger.debug("Using %s as cache", self.path)
246-
self.config_path = os.path.join(self.path, "config")
246+
self.config_path = self.path / "config"
247247

248248
def __enter__(self):
249249
self.open()
@@ -253,7 +253,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
253253
self.close()
254254

255255
def exists(self):
256-
return os.path.exists(self.config_path)
256+
return self.config_path.exists()
257257

258258
def create(self):
259259
assert not self.exists()
@@ -272,7 +272,7 @@ def open(self):
272272

273273
def load(self):
274274
self._config = configparser.ConfigParser(interpolation=None)
275-
with open(self.config_path) as fd:
275+
with self.config_path.open() as fd:
276276
self._config.read_file(fd)
277277
self._check_upgrade(self.config_path)
278278
self.id = self._config.get("cache", "repository")
@@ -361,10 +361,10 @@ def break_lock(repository, path=None):
361361
@staticmethod
362362
def destroy(repository, path=None):
363363
"""destroy the cache for ``repository`` or at ``path``"""
364-
path = path or os.path.join(get_cache_dir(), repository.id_str)
365-
config = os.path.join(path, "config")
366-
if os.path.exists(config):
367-
os.remove(config) # kill config first
364+
path = cache_dir(repository, path)
365+
config = path / "config"
366+
if config.exists():
367+
config.unlink() # kill config first
368368
shutil.rmtree(path)
369369

370370
def __new__(
@@ -540,7 +540,7 @@ def _read_files_cache(self):
540540
msg = None
541541
try:
542542
with IntegrityCheckedFile(
543-
path=os.path.join(self.path, self.files_cache_name()),
543+
path=str(self.path / self.files_cache_name()),
544544
write=False,
545545
integrity_data=self.cache_config.integrity.get(self.files_cache_name()),
546546
) as fd:
@@ -583,7 +583,7 @@ def _write_files_cache(self, files):
583583
ttl = int(os.environ.get("BORG_FILES_CACHE_TTL", 2))
584584
files_cache_logger.debug("FILES-CACHE-SAVE: starting...")
585585
# TODO: use something like SaveFile here, but that didn't work due to SyncFile missing .seek().
586-
with IntegrityCheckedFile(path=os.path.join(self.path, self.files_cache_name()), write=True) as fd:
586+
with IntegrityCheckedFile(path=str(self.path / self.files_cache_name()), write=True) as fd:
587587
entries = 0
588588
age_discarded = 0
589589
race_discarded = 0
@@ -983,7 +983,7 @@ def __init__(
983983
self.cache_config = CacheConfig(self.repository, self.path)
984984

985985
# Warn user before sending data to a never seen before unencrypted repository
986-
if not os.path.exists(self.path):
986+
if not self.path.exists():
987987
self.security_manager.assert_access_unknown(warn_if_unencrypted, manifest, self.key)
988988
self.create()
989989

@@ -1009,13 +1009,13 @@ def __exit__(self, exc_type, exc_val, exc_tb):
10091009

10101010
def create(self):
10111011
"""Create a new empty cache at `self.path`"""
1012-
os.makedirs(self.path)
1013-
with open(os.path.join(self.path, "README"), "w") as fd:
1012+
self.path.mkdir(parents=True, exist_ok=True)
1013+
with open(self.path / "README", "w") as fd:
10141014
fd.write(CACHE_README)
10151015
self.cache_config.create()
10161016

10171017
def open(self):
1018-
if not os.path.isdir(self.path):
1018+
if not self.path.is_dir():
10191019
raise Exception("%s Does not look like a Borg cache" % self.path)
10201020
self.cache_config.open()
10211021
self.cache_config.load()

src/borg/crypto/file_integrity.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import hashlib
22
import io
33
import json
4-
import os
54
from hmac import compare_digest
65
from collections.abc import Callable
6+
from pathlib import Path
77

88
from ..helpers import IntegrityError
99
from ..logger import create_logger
@@ -162,7 +162,7 @@ def hash_filename(self, filename=None):
162162
# Changing the name however imbues a change of context that is not permissible.
163163
# While Borg does not use anything except ASCII in these file names, it's important to use
164164
# the same encoding everywhere for portability. Using os.fsencode() would be wrong.
165-
filename = os.path.basename(filename or self.path)
165+
filename = Path(filename or self.path).name
166166
self.hasher.update(("%10d" % len(filename)).encode())
167167
self.hasher.update(filename.encode())
168168

@@ -219,17 +219,17 @@ def store_integrity_data(self, data: str):
219219
class DetachedIntegrityCheckedFile(IntegrityCheckedFile):
220220
def __init__(self, path, write, filename=None, override_fd=None):
221221
super().__init__(path, write, filename, override_fd)
222-
filename = filename or os.path.basename(path)
223-
output_dir = os.path.dirname(path)
224-
self.output_integrity_file = self.integrity_file_path(os.path.join(output_dir, filename))
222+
path_obj = Path(path)
223+
filename = filename or path_obj.name
224+
self.output_integrity_file = self.integrity_file_path(path_obj.parent / filename)
225225

226226
def load_integrity_data(self, path, integrity_data):
227227
assert not integrity_data, "Cannot pass explicit integrity_data to DetachedIntegrityCheckedFile"
228228
return self.read_integrity_file(self.path)
229229

230230
@staticmethod
231231
def integrity_file_path(path):
232-
return path + ".integrity"
232+
return Path(str(path) + ".integrity")
233233

234234
@classmethod
235235
def read_integrity_file(cls, path):
@@ -243,5 +243,5 @@ def read_integrity_file(cls, path):
243243
raise FileIntegrityError(path)
244244

245245
def store_integrity_data(self, data: str):
246-
with open(self.output_integrity_file, "w") as fd:
246+
with self.output_integrity_file.open("w") as fd:
247247
fd.write(data)

src/borg/crypto/key.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import textwrap
55
from hashlib import sha256, pbkdf2_hmac
6+
from pathlib import Path
67
from typing import Literal, ClassVar
78
from collections.abc import Callable
89

@@ -642,11 +643,11 @@ def get_existing_or_new_target(self, args):
642643

643644
def _find_key_in_keys_dir(self):
644645
id = self.repository.id
645-
keys_dir = get_keys_dir()
646-
for name in os.listdir(keys_dir):
647-
filename = os.path.join(keys_dir, name)
646+
keys_path = Path(get_keys_dir())
647+
for entry in keys_path.iterdir():
648+
filename = keys_path / entry.name
648649
try:
649-
return self.sanity_check(filename, id)
650+
return self.sanity_check(str(filename), id)
650651
except (KeyfileInvalidError, KeyfileMismatchError):
651652
pass
652653

@@ -668,12 +669,12 @@ def _find_key_file_from_environment(self):
668669

669670
def _get_new_target_in_keys_dir(self, args):
670671
filename = args.location.to_key_filename()
671-
path = filename
672+
path = Path(filename)
672673
i = 1
673-
while os.path.exists(path):
674+
while path.exists():
674675
i += 1
675-
path = filename + ".%d" % i
676-
return path
676+
path = Path(filename + ".%d" % i)
677+
return str(path)
677678

678679
def load(self, target, passphrase):
679680
if self.STORAGE == KeyBlobStorage.KEYFILE:

0 commit comments

Comments
 (0)