Skip to content

Commit c63d6b4

Browse files
committed
ngclient: Create directories as needed
Make sure ngclient creates metadata and artifact directories when needed. This was not useful when caller needed to populate the metadata dir with the initial root anyway, but now with boostrap argument it becomes a usability improvement. Signed-off-by: Jussi Kukkonen <jkukkonen@google.com>
1 parent 8df9f0f commit c63d6b4

File tree

3 files changed

+9
-13
lines changed

3 files changed

+9
-13
lines changed

examples/client/client

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ def init_tofu(base_url: str) -> bool:
3838

3939
metadata_dir = build_metadata_dir(base_url)
4040

41-
if not os.path.isdir(metadata_dir):
42-
os.makedirs(metadata_dir)
43-
4441
response = urllib3.request("GET", f"{base_url}/metadata/1.root.json")
4542
if response.status != 200:
4643
print(f"Failed to download initial root {base_url}/metadata/1.root.json")
@@ -81,9 +78,6 @@ def download(base_url: str, target: str) -> bool:
8178

8279
print(f"Using trusted root in {metadata_dir}")
8380

84-
if not os.path.isdir(DOWNLOAD_DIR):
85-
os.mkdir(DOWNLOAD_DIR)
86-
8781
try:
8882
# NOTE: initial root should be provided with ``bootstrap`` argument:
8983
# This examples uses unsafe Trust-On-First-Use initialization so it is

tests/test_updater_top_level_update.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import tempfile
1313
import unittest
1414
from datetime import timezone
15+
from pathlib import Path
1516
from typing import TYPE_CHECKING
1617
from unittest.mock import MagicMock, call, patch
1718

@@ -57,8 +58,6 @@ def setUp(self) -> None:
5758
self.temp_dir = tempfile.TemporaryDirectory()
5859
self.metadata_dir = os.path.join(self.temp_dir.name, "metadata")
5960
self.targets_dir = os.path.join(self.temp_dir.name, "targets")
60-
os.mkdir(self.metadata_dir)
61-
os.mkdir(self.targets_dir)
6261

6362
self.sim = RepositorySimulator()
6463

@@ -134,7 +133,8 @@ def test_cached_root_missing_without_bootstrap(self) -> None:
134133
self._run_refresh(skip_bootstrap=True)
135134

136135
# Metadata dir is empty
137-
self.assertFalse(os.listdir(self.metadata_dir))
136+
with self.assertRaises(FileNotFoundError):
137+
os.listdir(self.metadata_dir)
138138

139139
def test_trusted_root_expired(self) -> None:
140140
# Create an expired root version
@@ -166,6 +166,7 @@ def test_trusted_root_expired(self) -> None:
166166

167167
def test_trusted_root_unsigned_without_bootstrap(self) -> None:
168168
# Cached root is not signed, bootstrap root is not used
169+
Path(self.metadata_dir).mkdir(parents=True)
169170
root_path = os.path.join(self.metadata_dir, "root.json")
170171
md_root = Metadata.from_bytes(self.sim.signed_roots[0])
171172
md_root.signatures.clear()

tuf/ngclient/updater.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import os
5959
import shutil
6060
import tempfile
61+
from pathlib import Path
6162
from typing import TYPE_CHECKING, cast
6263
from urllib import parse
6364

@@ -267,6 +268,7 @@ def download_target(
267268

268269
if filepath is None:
269270
filepath = self._generate_target_file_path(targetinfo)
271+
Path(filepath).parent.mkdir(exist_ok=True, parents=True)
270272

271273
if target_base_url is None:
272274
if self._target_base_url is None:
@@ -332,10 +334,9 @@ def _persist_root(self, version: int, data: bytes) -> None:
332334
The metadata is stored with version prefix (e.g.
333335
"root_history/1.root.json").
334336
"""
335-
rootdir = os.path.join(self._dir, "root_history")
336-
with contextlib.suppress(FileExistsError):
337-
os.mkdir(rootdir)
338-
self._persist_file(os.path.join(rootdir, f"{version}.root.json"), data)
337+
rootdir = Path(self._dir, "root_history")
338+
rootdir.mkdir(exist_ok=True, parents=True)
339+
self._persist_file(str(rootdir / f"{version}.root.json"), data)
339340

340341
def _persist_file(self, filename: str, data: bytes) -> None:
341342
"""Write a file to disk atomically to avoid data loss."""

0 commit comments

Comments
 (0)