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 sys
|
||||||
|
|
||||||
import osbuild.api
|
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"]:
|
for item in options["paths"]:
|
||||||
path = item["path"]
|
path = item["path"]
|
||||||
mode = item.get("mode", 0o777)
|
mode = item.get("mode", 0o777)
|
||||||
parents = item.get("parents", False)
|
parents = item.get("parents", False)
|
||||||
exist_ok = item.get("exist_ok", False)
|
exist_ok = item.get("exist_ok", False)
|
||||||
|
|
||||||
if not path.startswith("/"):
|
if "://" not in path:
|
||||||
print("WARNING: relative path used, this is discouraged!")
|
if not path.startswith("/"):
|
||||||
|
print("WARNING: relative path used, this is discouraged!")
|
||||||
target = os.path.join(tree, path.lstrip("/"))
|
path = f"tree:///{path}"
|
||||||
if not in_tree(target, tree):
|
else:
|
||||||
raise ValueError(f"path {path} not in tree")
|
path = f"tree://{path}"
|
||||||
|
|
||||||
|
target = parsing.parse_location(path, args)
|
||||||
if parents:
|
if parents:
|
||||||
os.makedirs(target, mode=mode, exist_ok=exist_ok)
|
os.makedirs(target, mode=mode, exist_ok=exist_ok)
|
||||||
else:
|
else:
|
||||||
|
|
@ -33,5 +36,4 @@ def main(tree, options):
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
args = osbuild.api.arguments()
|
sys.exit(main(osbuild.api.arguments()))
|
||||||
sys.exit(main(args["tree"], args["options"]))
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"summary": "Create directories within the tree.",
|
"summary": "Create directories within the tree or mount.",
|
||||||
"description": [
|
"description": [
|
||||||
"Can create one or more directories, optionally also the",
|
"Can create one or more directories, optionally also the",
|
||||||
"intermediate directories. The stage can gracefully handle",
|
"intermediate directories. The stage can gracefully handle",
|
||||||
|
|
@ -31,8 +31,23 @@
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"path": {
|
"path": {
|
||||||
"type": "string",
|
"anyOf": [
|
||||||
"pattern": "^\\/?(?!\\.\\.)((?!\\/\\.\\.\\/).)+$"
|
{
|
||||||
|
"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": {
|
"mode": {
|
||||||
"type": "number",
|
"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