org.osbuild.mkdir: support creating dirs on mounts
This allows creating new directories on mounts:
```
- type: org.osbuild.mkdir
options:
paths:
- path: mount:///boot/efi
devices:
disk: ...
mounts:
- name: boot
target: /boot
...
```
This commit is contained in:
parent
ad7c646712
commit
23f01307b2
3 changed files with 119 additions and 13 deletions
|
|
@ -3,23 +3,26 @@ import os
|
|||
import sys
|
||||
|
||||
import osbuild.api
|
||||
from osbuild.util.path import in_tree
|
||||
from osbuild.util import parsing
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
def main(args):
|
||||
options = args["options"]
|
||||
|
||||
for item in options["paths"]:
|
||||
path = item["path"]
|
||||
mode = item.get("mode", 0o777)
|
||||
parents = item.get("parents", False)
|
||||
exist_ok = item.get("exist_ok", False)
|
||||
|
||||
if not path.startswith("/"):
|
||||
print("WARNING: relative path used, this is discouraged!")
|
||||
|
||||
target = os.path.join(tree, path.lstrip("/"))
|
||||
if not in_tree(target, tree):
|
||||
raise ValueError(f"path {path} not in tree")
|
||||
if "://" not in path:
|
||||
if not path.startswith("/"):
|
||||
print("WARNING: relative path used, this is discouraged!")
|
||||
path = f"tree:///{path}"
|
||||
else:
|
||||
path = f"tree://{path}"
|
||||
|
||||
target = parsing.parse_location(path, args)
|
||||
if parents:
|
||||
os.makedirs(target, mode=mode, exist_ok=exist_ok)
|
||||
else:
|
||||
|
|
@ -33,5 +36,4 @@ def main(tree, options):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = osbuild.api.arguments()
|
||||
sys.exit(main(args["tree"], args["options"]))
|
||||
sys.exit(main(osbuild.api.arguments()))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"summary": "Create directories within the tree.",
|
||||
"summary": "Create directories within the tree or mount.",
|
||||
"description": [
|
||||
"Can create one or more directories, optionally also the",
|
||||
"intermediate directories. The stage can gracefully handle",
|
||||
|
|
@ -31,8 +31,23 @@
|
|||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"pattern": "^\\/?(?!\\.\\.)((?!\\/\\.\\.\\/).)+$"
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Target path, if a tree",
|
||||
"pattern": "^\\/?(?!\\.\\.)((?!\\/\\.\\.\\/).)+$"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Target path, if a mount",
|
||||
"pattern": "^mount://.+"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Target path, if a tree",
|
||||
"pattern": "^tree://.+"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mode": {
|
||||
"type": "number",
|
||||
|
|
|
|||
89
stages/test/test_mkdir.py
Normal file
89
stages/test/test_mkdir.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest # type: ignore
|
||||
|
||||
from osbuild.testutil import has_executable
|
||||
|
||||
STAGE_NAME = "org.osbuild.mkdir"
|
||||
|
||||
|
||||
def test_mkdir(tmp_path, stage_module):
|
||||
tree = tmp_path / "tree"
|
||||
tree.mkdir()
|
||||
|
||||
options = {
|
||||
"paths": [
|
||||
{"path": "/fake_dir"},
|
||||
{"path": "fake_relative_dir"}
|
||||
]
|
||||
}
|
||||
args = {
|
||||
"tree": f"{tree}",
|
||||
"options": options
|
||||
}
|
||||
stage_module.main(args)
|
||||
assert (tree / "fake_dir").exists()
|
||||
assert (tree / "fake_relative_dir").exists()
|
||||
|
||||
|
||||
def test_mkdir_on_a_tree(tmp_path, stage_module):
|
||||
tree = tmp_path / "tree"
|
||||
tree.mkdir()
|
||||
|
||||
options = {
|
||||
"paths": [
|
||||
{
|
||||
"path": "tree:///fake_parent/fake_dir",
|
||||
"parents": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
args = {
|
||||
"tree": f"{tree}",
|
||||
"options": options
|
||||
}
|
||||
stage_module.main(args)
|
||||
assert (tree / "fake_parent/fake_dir").exists()
|
||||
|
||||
|
||||
@pytest.mark.skipif(os.getuid() != 0, reason="needs root")
|
||||
@pytest.mark.skipif(not has_executable("mkfs.ext4"), reason="need mkfs.ext4")
|
||||
def test_mkdir_on_a_mount(tmp_path, stage_module):
|
||||
tree = tmp_path / "tree"
|
||||
tree.mkdir()
|
||||
|
||||
# Create fake EXT4 disk image
|
||||
fake_disk_path = tmp_path / "fake.img"
|
||||
with fake_disk_path.open("w") as fp:
|
||||
fp.truncate(10 * 1024 * 1024)
|
||||
subprocess.run(
|
||||
["mkfs.ext4", os.fspath(fake_disk_path)], check=True)
|
||||
|
||||
fake_disk_mnt = tmp_path / "mounts"
|
||||
fake_disk_mnt.mkdir()
|
||||
|
||||
with contextlib.ExitStack() as cm:
|
||||
subprocess.run(["mount", fake_disk_path, fake_disk_mnt], check=True)
|
||||
cm.callback(subprocess.run, ["umount", fake_disk_mnt], check=True)
|
||||
|
||||
options = {
|
||||
"paths": [
|
||||
{
|
||||
"path": "mount:///fake_parent/fake_dir",
|
||||
"parents": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
args = {
|
||||
"tree": f"{tree}",
|
||||
"options": options,
|
||||
"paths": {
|
||||
"mounts": fake_disk_mnt,
|
||||
}
|
||||
}
|
||||
stage_module.main(args)
|
||||
assert (fake_disk_mnt / "fake_parent/fake_dir").exists()
|
||||
Loading…
Add table
Add a link
Reference in a new issue