mounter: support pathlib.Path in components

Instead of supporting only string components, mount.p() now supports
strings, pathlib.Path()s, or a combination of both.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
Olivier Gayot 2024-01-19 20:09:25 +01:00
parent bcfa6b1c9c
commit cd234d416a
2 changed files with 15 additions and 9 deletions

View File

@ -56,11 +56,11 @@ class AbsolutePathError(Exception):
class _MountBase: class _MountBase:
def p(self, *args: str) -> str: def p(self, *args: Union[str, Path]) -> Path:
for a in args: for a in args:
if a.startswith("/"): if Path(a).is_absolute():
raise AbsolutePathError("no absolute paths here please") raise AbsolutePathError("no absolute paths here please")
return os.path.join(self.mountpoint, *args) return str(Path(self.mountpoint).joinpath(*args))
def write(self, path, content): def write(self, path, content):
with open(self.p(path), "w") as fp: with open(self.p(path), "w") as fp:

View File

@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import pathlib from pathlib import Path
from unittest.mock import AsyncMock, Mock, call, patch from unittest.mock import AsyncMock, Mock, call, patch
from subiquity.server.mounter import ( from subiquity.server.mounter import (
@ -40,9 +40,15 @@ class Test_MountBase(SubiTestCase):
self.assertEqual("/target/d1", mnt.p("d1")) self.assertEqual("/target/d1", mnt.p("d1"))
self.assertEqual("/target/d1/d2/d3/d4", mnt.p("d1", "d2/d3", "d4")) self.assertEqual("/target/d1/d2/d3/d4", mnt.p("d1", "d2/d3", "d4"))
# Mix of strings and paths should produce the same result.
self.assertEqual(mnt.p("d1", "d2/d3"), mnt.p("d1", Path("d2/d3")))
self.assertEqual(mnt.p("d1", "d2/d3"), mnt.p(Path("d1"), "d2/d3"))
def test_p__absolute(self): def test_p__absolute(self):
with self.assertRaises(AbsolutePathError): with self.assertRaises(AbsolutePathError):
self.mountbase.p("a", "/b") self.mountbase.p("a", "/b")
with self.assertRaises(AbsolutePathError):
self.mountbase.p("a", pathlib.Path("/b"))
class TestMounter(SubiTestCase): class TestMounter(SubiTestCase):
@ -134,7 +140,7 @@ class TestMounter(SubiTestCase):
# When we are bind mounting a directory, the destination should be # When we are bind mounting a directory, the destination should be
# created as a directory. # created as a directory.
src = self.tmp_dir() src = self.tmp_dir()
dst = pathlib.Path(self.tmp_dir()) / "dst" dst = Path(self.tmp_dir()) / "dst"
self.app.command_runner = AsyncMock() self.app.command_runner = AsyncMock()
await mounter.bind_mount_tree(src, dst) await mounter.bind_mount_tree(src, dst)
@ -144,9 +150,9 @@ class TestMounter(SubiTestCase):
mounter = Mounter(self.app) mounter = Mounter(self.app)
# When we are bind mounting a file, the destination should be created # When we are bind mounting a file, the destination should be created
# as a file. # as a file.
src = pathlib.Path(self.tmp_dir()) / "src" src = Path(self.tmp_dir()) / "src"
src.touch() src.touch()
dst = pathlib.Path(self.tmp_dir()) / "dst" dst = Path(self.tmp_dir()) / "dst"
self.app.command_runner = AsyncMock() self.app.command_runner = AsyncMock()
await mounter.bind_mount_tree(src, dst) await mounter.bind_mount_tree(src, dst)
@ -156,9 +162,9 @@ class TestMounter(SubiTestCase):
mounter = Mounter(self.app) mounter = Mounter(self.app)
# When we are mounting a device, the destination should be created # When we are mounting a device, the destination should be created
# as a directory. # as a directory.
src = pathlib.Path(self.tmp_dir()) / "src" src = Path(self.tmp_dir()) / "src"
src.touch() src.touch()
dst = pathlib.Path(self.tmp_dir()) / "dst" dst = Path(self.tmp_dir()) / "dst"
self.app.command_runner = AsyncMock() self.app.command_runner = AsyncMock()
await mounter.mount(src, dst) await mounter.mount(src, dst)