summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2023-11-21 11:13:16 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2023-11-21 11:15:25 +0100
commitcd6cbe8792f038fc7a27d37c0804afa0a244eca9 (patch)
tree57fc96cefdf5b814db447ede3f9b8972c50b3d67
parentarchiver: New (diff)
downloadrtems-central-cd6cbe8792f038fc7a27d37c0804afa0a244eca9.tar.bz2
runactions: New
-rw-r--r--rtemsspec/packagebuildfactory.py2
-rw-r--r--rtemsspec/runactions.py314
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/output/run-actions.yml13
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/package-build.yml2
-rw-r--r--rtemsspec/tests/spec-packagebuild/qdp/steps/run-actions.yml282
-rw-r--r--rtemsspec/tests/test_packagebuild.py14
-rw-r--r--rtemsspec/util.py42
-rw-r--r--spec-qdp/spec/qdp-action-copy-and-substitute.yml42
-rw-r--r--spec-qdp/spec/qdp-action-create-ini-file.yml35
-rw-r--r--spec-qdp/spec/qdp-action-directory-state-add-files.yml34
-rw-r--r--spec-qdp/spec/qdp-action-directory-state-add-tarfile-members.yml43
-rw-r--r--spec-qdp/spec/qdp-action-directory-state-add-tree.yml49
-rw-r--r--spec-qdp/spec/qdp-action-directory-state-clear.yml26
-rw-r--r--spec-qdp/spec/qdp-action-directory-state-copy-tree.yml49
-rw-r--r--spec-qdp/spec/qdp-action-directory-state-move-tree.yml49
-rw-r--r--spec-qdp/spec/qdp-action-list.yml16
-rw-r--r--spec-qdp/spec/qdp-action-mkdir.yml35
-rw-r--r--spec-qdp/spec/qdp-action-remove-empty-directories.yml28
-rw-r--r--spec-qdp/spec/qdp-action-remove-glob.yml38
-rw-r--r--spec-qdp/spec/qdp-action-remove-tree.yml30
-rw-r--r--spec-qdp/spec/qdp-action-remove.yml31
-rw-r--r--spec-qdp/spec/qdp-action-subprocess-env-list.yml16
-rw-r--r--spec-qdp/spec/qdp-action-subprocess-env.yml33
-rw-r--r--spec-qdp/spec/qdp-action-subprocess.yml42
-rw-r--r--spec-qdp/spec/qdp-action-touch.yml30
-rw-r--r--spec-qdp/spec/qdp-action.yml26
-rw-r--r--spec-qdp/spec/qdp-ini-file-key-value-pair-list.yml16
-rw-r--r--spec-qdp/spec/qdp-ini-file-key-value-pair.yml31
-rw-r--r--spec-qdp/spec/qdp-ini-file-section-list.yml16
-rw-r--r--spec-qdp/spec/qdp-ini-file-section.yml29
-rw-r--r--spec-qdp/spec/qdp-run-actions.yml31
31 files changed, 1442 insertions, 2 deletions
diff --git a/rtemsspec/packagebuildfactory.py b/rtemsspec/packagebuildfactory.py
index ef4a950b..600c58de 100644
--- a/rtemsspec/packagebuildfactory.py
+++ b/rtemsspec/packagebuildfactory.py
@@ -27,12 +27,14 @@
from rtemsspec.archiver import Archiver
from rtemsspec.directorystate import DirectoryState
from rtemsspec.packagebuild import BuildItemFactory, PackageVariant
+from rtemsspec.runactions import RunActions
def create_build_item_factory() -> BuildItemFactory:
""" Creates the default build item factory. """
factory = BuildItemFactory()
factory.add_constructor("qdp/build-step/archive", Archiver)
+ factory.add_constructor("qdp/build-step/run-actions", RunActions)
factory.add_constructor("qdp/directory-state/generic", DirectoryState)
factory.add_constructor("qdp/directory-state/repository", DirectoryState)
factory.add_constructor("qdp/directory-state/unpacked-archive",
diff --git a/rtemsspec/runactions.py b/rtemsspec/runactions.py
new file mode 100644
index 00000000..1da507cd
--- /dev/null
+++ b/rtemsspec/runactions.py
@@ -0,0 +1,314 @@
+# SPDX-License-Identifier: BSD-2-Clause
+""" This module provides a build step to run actions. """
+
+# Copyright (C) 2022, 2023 embedded brains GmbH (http://www.embedded-brains.de)
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import copy
+import os
+import logging
+from pathlib import Path
+import shutil
+import subprocess
+from typing import Any, Dict, List, Optional, Union
+
+from rtemsspec.directorystate import DirectoryState
+from rtemsspec.items import Item, ItemGetValueContext, is_enabled
+from rtemsspec.packagebuild import BuildItem, PackageBuildDirector
+from rtemsspec.util import copy_and_substitute, remove_empty_directories
+
+
+def _env_clear(item: "RunActions", env: Dict, _action: Dict[str, str]) -> None:
+ logging.info("%s: env: clear", item.uid)
+ env.clear()
+
+
+def _env_path_append(item: "RunActions", env: Dict, action: Dict[str,
+ str]) -> None:
+ name = action["name"]
+ value = action["value"]
+ logging.info("%s: env: append '%s' to %s", item.uid, value, name)
+ env[name] = f"{env[name]}:{value}"
+
+
+def _env_path_prepend(item: "RunActions", env: Dict,
+ action: Dict[str, str]) -> None:
+ name = action["name"]
+ value = action["value"]
+ logging.info("%s: env: prepend '%s' to %s", item.uid, value, name)
+ env[name] = f"{value}:{env[name]}"
+
+
+def _env_set(item: "RunActions", env: Dict, action: Dict[str, str]) -> None:
+ name = action["name"]
+ value = action["value"]
+ logging.info("%s: env: %s = '%s'", item.uid, name, value)
+ env[name] = value
+
+
+def _env_unset(item: "RunActions", env: Dict, action: Dict[str, str]) -> None:
+ name = action["name"]
+ logging.info("%s: env: unset %s", item.uid, name)
+ del env[name]
+
+
+_ENV_ACTIONS = {
+ "clear": _env_clear,
+ "path-append": _env_path_append,
+ "path-prepend": _env_path_prepend,
+ "set": _env_set,
+ "unset": _env_unset
+}
+
+
+def _get_host_processor_count(_ctx: ItemGetValueContext) -> str:
+ count = os.cpu_count()
+ return str(count if count is not None else 1)
+
+
+class RunActions(BuildItem):
+ """ Runs actions. """
+
+ def __init__(self, director: PackageBuildDirector, item: Item):
+ super().__init__(director, item)
+ self.mapper.add_get_value(f"{self.item.type}:/host-processor-count",
+ _get_host_processor_count)
+
+ def run(self):
+ for index, action in enumerate(self["actions"]):
+ action_type = action["action"]
+ logging.info("%s: run action %i: %s", self.uid, index, action_type)
+ if is_enabled(self.enabled_set, action["enabled-by"]):
+ output_name = action.get("output-name", None)
+ if output_name is None:
+ output = None
+ else:
+ try:
+ output = self.output(output_name)
+ except ValueError:
+ continue
+ RunActions._ACTIONS[action_type](self, action, output)
+
+ def _copy_and_substitute(self, action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ assert isinstance(output, DirectoryState)
+ input_state = self.input(action["input-name"])
+ assert isinstance(input_state, DirectoryState)
+ source = action["source"]
+ source_base = input_state.directory
+ target_base = output.directory
+ if source is None:
+ prefix = action["target"]
+ if prefix is None:
+ prefix = "."
+ targets: List[str] = []
+ for source_file in input_state:
+ tail = os.path.relpath(source_file, source_base)
+ target_file = os.path.join(target_base, prefix, tail)
+ targets.append(tail)
+ copy_and_substitute(source_file, target_file, self.mapper,
+ self.uid)
+ output.add_files(targets)
+ else:
+ source_file = os.path.join(source_base, source)
+ target = action["target"]
+ if target is None:
+ target_file = output.file
+ else:
+ output.add_files([target])
+ target_file = os.path.join(target_base, target)
+ copy_and_substitute(source_file, target_file, self.mapper,
+ self.uid)
+
+ def _create_ini_file(self, action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ assert isinstance(output, DirectoryState)
+ target = action["target"]
+ if target is None:
+ target = output.file
+ else:
+ output.add_files([target])
+ target = os.path.join(output.directory, target)
+ logging.info("%s: create: %s", self.uid, target)
+ os.makedirs(os.path.dirname(target), exist_ok=True)
+ with open(target, "w", encoding="utf-8") as dst:
+ for section in action["sections"]:
+ if not is_enabled(self.enabled_set, section["enabled-by"]):
+ continue
+ dst.write(f"[{section['name']}]\n")
+ for key_value in section["key-value-pairs"]:
+ if not is_enabled(self.enabled_set,
+ key_value["enabled-by"]):
+ continue
+ dst.write(f"{key_value['key']} = {key_value['value']}\n")
+
+ def _directory_state_clear(self, _action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ assert isinstance(output, DirectoryState)
+ output.clear()
+
+ def _directory_state_add_files(self, action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ assert isinstance(output, DirectoryState)
+ root = Path(action["path"]).absolute()
+ pattern = action["pattern"]
+ logging.info("%s: add files matching '%s' in: %s", self.uid, pattern,
+ root)
+ base = output.directory
+ output.add_files(
+ [os.path.relpath(path, base) for path in root.glob(pattern)])
+
+ def _directory_state_add_tarfile_members(
+ self, action: Dict, output: Optional[DirectoryState]) -> None:
+ assert isinstance(output, DirectoryState)
+ root = Path(action["search-path"])
+ pattern = action["pattern"]
+ logging.info("%s: search for tarfiles matching '%s' in: %s", self.uid,
+ pattern, root)
+ for path in root.glob(pattern):
+ output.add_tarfile_members(path, action["prefix-path"],
+ action["extract"])
+
+ def _directory_state_tree_op(self, action: Dict,
+ output: Optional[DirectoryState],
+ tree_op: Any) -> None:
+ assert isinstance(output, DirectoryState)
+ root = Path(action["root"]).absolute()
+ prefix = action["prefix"]
+ if prefix is None:
+ prefix = "."
+ tree_op(output, root, prefix, action["excludes"])
+
+ def _directory_state_add_tree(self, action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ self._directory_state_tree_op(action, output, DirectoryState.add_tree)
+
+ def _directory_state_copy_tree(self, action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ self._directory_state_tree_op(action, output, DirectoryState.copy_tree)
+
+ def _directory_state_move_tree(self, action: Dict,
+ output: Optional[DirectoryState]) -> None:
+ self._directory_state_tree_op(action, output, DirectoryState.move_tree)
+
+ def _process(self, action: Dict,
+ _output: Optional[DirectoryState]) -> None:
+ env: Union[Dict, None] = None
+ env_actions = action["env"]
+ if env_actions:
+ logging.info("%s: env: modify", self.uid)
+ env = copy.deepcopy(os.environ.copy())
+ for env_action in env_actions:
+ _ENV_ACTIONS[env_action["action"]](self, env, env_action)
+ cmd = action["command"]
+ cwd = action["working-directory"]
+ logging.info("%s: run in '%s': %s", self.uid, cwd,
+ " ".join(f"'{i}'" for i in cmd))
+ status = subprocess.run(cmd, env=env, check=False, cwd=cwd)
+ expected_return_code = action["expected-return-code"]
+ if expected_return_code is not None:
+ assert status.returncode == expected_return_code
+
+ def _mkdir(self, action: Dict, _output: Optional[DirectoryState]) -> None:
+ path = Path(action["path"])
+ logging.info("%s: make directory: %s", self.uid, path)
+ path.mkdir(parents=action["parents"], exist_ok=action["exist-ok"])
+
+ def _remove_path(self, path: Path) -> None:
+ if path.is_dir():
+ logging.info("%s: remove directory: %s", self.uid, path)
+ path.rmdir()
+ else:
+ logging.info("%s: unlink file: %s", self.uid, path)
+ path.unlink()
+
+ def _remove(self, action: Dict, _output: Optional[DirectoryState]) -> None:
+ path = Path(action["path"])
+ if action["missing-ok"]:
+ try:
+ self._remove_path(path)
+ except FileNotFoundError:
+ pass
+ else:
+ self._remove_path(path)
+
+ def _remove_empty_directories(self, action: Dict,
+ _output: Optional[DirectoryState]) -> None:
+ remove_empty_directories(self.uid, action["path"])
+
+ def _remove_glob(self, action: Dict,
+ _output: Optional[DirectoryState]) -> None:
+ root = Path(action["path"])
+ for pattern in action["patterns"]:
+ logging.info(
+ "%s: remove files and directories matching with '%s' in: %s",
+ self.uid, pattern, root)
+ for path in root.glob(pattern):
+ if path.is_dir():
+ if action["remove-tree"]:
+ logging.info("%s: remove directory tree: %s", self.uid,
+ path)
+ shutil.rmtree(path)
+ else:
+ logging.info("%s: remove directory: %s", self.uid,
+ path)
+ path.rmdir()
+ else:
+ logging.info("%s: remove file: %s", self.uid, path)
+ path.unlink()
+
+ def _remove_tree(self, action: Dict,
+ _output: Optional[DirectoryState]) -> None:
+ path = action["path"]
+ logging.info("%s: remove directory tree: %s", self.uid, path)
+ if action["missing-ok"]:
+ try:
+ shutil.rmtree(path)
+ except FileNotFoundError:
+ pass
+ else:
+ shutil.rmtree(path)
+
+ def _touch(self, action: Dict, _output: Optional[DirectoryState]) -> None:
+ path = Path(action["path"])
+ logging.info("%s: touch file: %s", self.uid, path)
+ path.touch(exist_ok=action["exist-ok"])
+
+ _ACTIONS = {
+ "copy-and-substitute": _copy_and_substitute,
+ "create-ini-file": _create_ini_file,
+ "directory-state-add-files": _directory_state_add_files,
+ "directory-state-add-tarfile-members":
+ _directory_state_add_tarfile_members,
+ "directory-state-add-tree": _directory_state_add_tree,
+ "directory-state-clear": _directory_state_clear,
+ "directory-state-copy-tree": _directory_state_copy_tree,
+ "directory-state-move-tree": _directory_state_move_tree,
+ "mkdir": _mkdir,
+ "remove": _remove,
+ "remove-empty-directories": _remove_empty_directories,
+ "remove-glob": _remove_glob,
+ "remove-tree": _remove_tree,
+ "subprocess": _process,
+ "touch": _touch
+ }
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/output/run-actions.yml b/rtemsspec/tests/spec-packagebuild/qdp/output/run-actions.yml
new file mode 100644
index 00000000..b5dd5ddb
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/output/run-actions.yml
@@ -0,0 +1,13 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+copyrights-by-license: {}
+directory: ${../variant:/prefix-directory}
+directory-state-type: generic
+enabled-by: true
+files: []
+hash: null
+links: []
+patterns: []
+qdp-type: directory-state
+type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml b/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
index 4e72be8b..1d7a18c8 100644
--- a/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
+++ b/rtemsspec/tests/spec-packagebuild/qdp/package-build.yml
@@ -10,6 +10,8 @@ links:
- role: build-step
uid: steps/c
- role: build-step
+ uid: steps/run-actions
+- role: build-step
uid: steps/archive
qdp-type: package-build
type: qdp
diff --git a/rtemsspec/tests/spec-packagebuild/qdp/steps/run-actions.yml b/rtemsspec/tests/spec-packagebuild/qdp/steps/run-actions.yml
new file mode 100644
index 00000000..505acbdd
--- /dev/null
+++ b/rtemsspec/tests/spec-packagebuild/qdp/steps/run-actions.yml
@@ -0,0 +1,282 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- action: mkdir
+ enabled-by: true
+ exist-ok: false
+ parents: true
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: touch
+ enabled-by: false
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: touch
+ enabled-by: true
+ exist-ok: true
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove
+ enabled-by: true
+ missing-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove
+ enabled-by: true
+ missing-ok: true
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove
+ enabled-by: true
+ missing-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: remove
+ enabled-by: true
+ missing-ok: true
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: mkdir
+ enabled-by: true
+ exist-ok: false
+ parents: false
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove-empty-directories
+ enabled-by: true
+ path: ${../variant:/build-directory}/some
+- action: remove
+ enabled-by: true
+ missing-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove-empty-directories
+ enabled-by: true
+ path: ${../variant:/build-directory}/some
+- action: mkdir
+ enabled-by: true
+ exist-ok: false
+ parents: true
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove-tree
+ enabled-by: true
+ missing-ok: true
+ path: ${../variant:/build-directory}/some/more
+- action: remove-tree
+ enabled-by: true
+ missing-ok: true
+ path: ${../variant:/build-directory}/some/more
+- action: remove-tree
+ enabled-by: true
+ missing-ok: false
+ path: ${../variant:/build-directory}/some
+- action: mkdir
+ enabled-by: true
+ exist-ok: false
+ parents: true
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove-glob
+ enabled-by: true
+ remove-tree: false
+ path: ${../variant:/build-directory}/some/more/dirs
+ patterns:
+ - foobar
+- action: remove-glob
+ enabled-by: true
+ remove-tree: false
+ path: ${../variant:/build-directory}/some/more/dirs
+ patterns:
+ - file
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: remove-glob
+ enabled-by: true
+ remove-tree: true
+ path: ${../variant:/build-directory}/some
+ patterns:
+ - more
+- action: remove-glob
+ enabled-by: true
+ remove-tree: false
+ path: ${../variant:/build-directory}
+ patterns:
+ - some
+- action: directory-state-clear
+ enabled-by: true
+ output-name: destination
+- action: directory-state-clear
+ enabled-by: true
+ output-name: disabled
+- action: directory-state-add-tarfile-members
+ enabled-by: true
+ extract: true
+ output-name: destination
+ prefix-path: ${../variant:/deployment-directory}
+ search-path: ${../variant:/prefix-directory}
+ pattern: archive.tar.xz
+- action: directory-state-clear
+ enabled-by: true
+ output-name: destination
+- action: mkdir
+ enabled-by: true
+ exist-ok: false
+ parents: true
+ path: ${../variant:/build-directory}/some/more/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../variant:/build-directory}/some/more/dirs/file
+- action: directory-state-add-files
+ enabled-by: true
+ output-name: destination
+ path: ${../variant:/prefix-directory}
+ pattern: archive.tar.xz
+- action: directory-state-add-tree
+ enabled-by: true
+ excludes: []
+ output-name: destination
+ prefix: null
+ root: ${../variant:/build-directory}/some/more
+- action: mkdir
+ enabled-by: true
+ exist-ok: false
+ parents: true
+ path: ${../output/run-actions:/directory}/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../output/run-actions:/directory}/dirs/file
+- action: directory-state-copy-tree
+ enabled-by: true
+ excludes: []
+ output-name: destination
+ prefix: "u"
+ root: ${../variant:/build-directory}/some/more
+- action: directory-state-move-tree
+ enabled-by: true
+ excludes: []
+ output-name: destination
+ prefix: "v"
+ root: ${../output/run-actions:/directory}/u/dirs
+- action: touch
+ enabled-by: true
+ exist-ok: false
+ path: ${../output/run-actions:/directory}/u/dirs/file
+- action: create-ini-file
+ enabled-by: true
+ output-name: destination
+ sections:
+ - enabled-by: true
+ key-value-pairs:
+ - enabled-by: true
+ key: KA
+ value: VA
+ - enabled-by: false
+ key: KB
+ value: VB
+ name: AA
+ - enabled-by: false
+ key-value-pairs: []
+ name: SB
+ target: null
+- action: create-ini-file
+ enabled-by: true
+ output-name: destination
+ sections: []
+ target: foo.ini
+- action: copy-and-substitute
+ enabled-by: true
+ input-name: source
+ output-name: destination
+ source: null
+ target: null
+- action: copy-and-substitute
+ enabled-by: true
+ input-name: source
+ output-name: destination
+ source: dir/subdir/c.txt
+ target: null
+- action: copy-and-substitute
+ enabled-by: true
+ input-name: source
+ output-name: destination
+ source: null
+ target: some/other
+- action: copy-and-substitute
+ enabled-by: true
+ input-name: source
+ output-name: destination
+ source: dir/subdir/c.txt
+ target: some/other/file.txt
+- action: subprocess
+ command:
+ - git
+ - foobar
+ enabled-by: true
+ env: []
+ expected-return-code: null
+ working-directory: ${../variant:/build-directory}
+- action: subprocess
+ command:
+ - git
+ - status
+ enabled-by: true
+ env:
+ - action: clear
+ name: PATH
+ value: null
+ - action: set
+ name: FOOBAR
+ value: foo
+ - action: path-append
+ name: FOOBAR
+ value: bar
+ - action: path-prepend
+ name: FOOBAR
+ value: ${.:/host-processor-count}
+ - action: unset
+ name: FOOBAR
+ value: null
+ expected-return-code: null
+ working-directory: ${../variant:/build-directory}
+- action: subprocess
+ command:
+ - git
+ - status
+ enabled-by: true
+ env: []
+ expected-return-code: 0
+ working-directory: ${../variant:/build-directory}
+build-step-type: run-actions
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+description: Description.
+enabled-by: run-actions
+links:
+- hash: null
+ name: variant
+ role: input
+ uid: ../variant
+- hash: null
+ name: source
+ role: input
+ uid: ../source/a
+- name: destination
+ role: output
+ uid: ../output/run-actions
+- name: disabled
+ role: output
+ uid: ../output/b
+params: {}
+qdp-type: build-step
+type: qdp
+
diff --git a/rtemsspec/tests/test_packagebuild.py b/rtemsspec/tests/test_packagebuild.py
index 436c6f29..fc4ae327 100644
--- a/rtemsspec/tests/test_packagebuild.py
+++ b/rtemsspec/tests/test_packagebuild.py
@@ -101,6 +101,8 @@ def test_packagebuild(caplog, tmpdir):
director.clear()
variant = director["/qdp/variant"]
prefix_dir = Path(variant["prefix-directory"])
+ status = run_command(["git", "init"], str(prefix_dir))
+ assert status == 0
director.build_package(None, None)
log = get_and_clear_log(caplog)
@@ -199,3 +201,15 @@ def test_packagebuild(caplog, tmpdir):
"dir/subdir/c.txt\t663049a20dfea6b8da28b2eb90eddd10ccf28ef2519563310b9bde25b7268444014c48c4384ee5c5a54e7830e45fcd87df7910a7fda77b68c2efdd75f8de25e8",
"dir/subdir/d.txt\t48fb10b15f3d44a09dc82d02b06581e0c0c69478c9fd2cf8f9093659019a1687baecdbb38c9e72b12169dc4148690f87467f9154f5931c5df665c6496cbfd5f5"
]
+
+ # Test RunActions
+ variant["enabled"] = ["run-actions"]
+ director.build_package(None, None)
+ log = get_and_clear_log(caplog)
+ assert f"/qdp/steps/run-actions: make directory: {tmp_dir}/pkg/build/some/more/dirs" in log
+ assert f"/qdp/steps/run-actions: remove empty directory: {tmp_dir}/pkg/build/some/more/dirs" in log
+ assert f"/qdp/steps/run-actions: remove empty directory: {tmp_dir}/pkg/build/some/more" in log
+ assert f"/qdp/steps/run-actions: remove empty directory: {tmp_dir}/pkg/build/some" in log
+ assert f"/qdp/steps/run-actions: remove directory tree: {tmp_dir}/pkg/build/some" in log
+ assert f"/qdp/steps/run-actions: run in '{tmp_dir}/pkg/build': 'git' 'foobar'" in log
+ assert f"/qdp/steps/run-actions: run in '{tmp_dir}/pkg/build': 'git' 'status'" in log
diff --git a/rtemsspec/util.py b/rtemsspec/util.py
index 2e491244..a1f46372 100644
--- a/rtemsspec/util.py
+++ b/rtemsspec/util.py
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: BSD-2-Clause
""" This module provides utility functions. """
-# Copyright (C) 2020, 2021 embedded brains GmbH & Co. KG
+# Copyright (C) 2020, 2023 embedded brains GmbH & Co. KG
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -33,9 +33,11 @@ import os
from pathlib import Path
import shutil
import subprocess
-from typing import Any, List, Optional, Union
+from typing import Any, List, Optional, Set, Union
import yaml
+from rtemsspec.items import ItemMapper
+
def base64_to_hex(data: str) -> str:
""" Converts the data from base64 to hex. """
@@ -79,6 +81,42 @@ def copy_files(src_dir: str, dst_dir: str, files: List[str],
shutil.copy2(src_file, dst_file)
+def copy_and_substitute(src_file: str, dst_file: str, mapper: ItemMapper,
+ log_context: str) -> None:
+ """
+ Copies the file from the source to the destination path and performs a
+ variable substitution on the file content using the item mapper.
+ """
+ logging.info("%s: read: %s", log_context, src_file)
+ with open(src_file, "r", encoding="utf-8") as src:
+ logging.info("%s: substitute using mapper of item %s", log_context,
+ mapper.item.uid)
+ content = mapper.substitute(src.read())
+ logging.info("%s: write: %s", log_context, dst_file)
+ os.makedirs(os.path.dirname(dst_file), exist_ok=True)
+ with open(dst_file, "w+", encoding="utf-8") as dst:
+ dst.write(content)
+
+
+def remove_empty_directories(scope: str, base: str) -> None:
+ """
+ Recursively removes all empty subdirectories of base and base itself if it
+ gets empty.
+
+ The scope is used for log messages.
+ """
+ removed: Set[str] = set()
+ for root, subdirs, files in os.walk(base, topdown=False):
+ if files:
+ continue
+ if any(subdir for subdir in subdirs
+ if os.path.join(root, subdir) not in removed):
+ continue
+ logging.info("%s: remove empty directory: %s", scope, root)
+ os.rmdir(root)
+ removed.add(root)
+
+
def load_config(config_filename: str) -> Any:
""" Loads the configuration file with recursive includes. """
diff --git a/spec-qdp/spec/qdp-action-copy-and-substitute.yml b/spec-qdp/spec/qdp-action-copy-and-substitute.yml
new file mode 100644
index 00000000..9b1d1527
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-copy-and-substitute.yml
@@ -0,0 +1,42 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: copy-and-substitute
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ input-name:
+ description: |
+ It shall be name of the input directory state.
+ spec-type: str
+ output-name:
+ description: |
+ It shall be name of the output directory state.
+ spec-type: str
+ source:
+ description: |
+ If the value is present, then it shall be the source file relative to
+ the base directory of the input directory state, otherwise the
+ source file is the first file of the input directory state.
+ spec-type: optional-str
+ target:
+ description: |
+ If the value is present, then it shall be the target file relative to
+ the base directory of the output directory state, otherwise the
+ target file is the first file of the output directory state.
+ spec-type: optional-str
+ description: |
+ This set of attributes specifies a copy and substitute action.
+ mandatory-attributes: all
+spec-name: Copy and Substitute Action
+spec-type: qdp-action-copy-and-substitute
+type: spec
diff --git a/spec-qdp/spec/qdp-action-create-ini-file.yml b/spec-qdp/spec/qdp-action-create-ini-file.yml
new file mode 100644
index 00000000..269a22b8
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-create-ini-file.yml
@@ -0,0 +1,35 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: create-ini-file
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ output-name:
+ description: |
+ It shall be name of the output directory state.
+ spec-type: str
+ sections:
+ description: null
+ spec-type: qdp-ini-file-section-list
+ target:
+ description: |
+ If the value is present, then it shall be the target file relative to
+ the base directory of the output directory state, otherwise the
+ target file is the first file of the output directory state.
+ spec-type: optional-str
+ description: |
+ This set of attributes specifies a create INI file action.
+ mandatory-attributes: all
+spec-name: Create INI File Action
+spec-type: qdp-action-create-ini-file
+type: spec
diff --git a/spec-qdp/spec/qdp-action-directory-state-add-files.yml b/spec-qdp/spec/qdp-action-directory-state-add-files.yml
new file mode 100644
index 00000000..ef6dd05d
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-directory-state-add-files.yml
@@ -0,0 +1,34 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: directory-state-add-files
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ output-name:
+ description: |
+ It shall be name of the output directory state.
+ spec-type: str
+ pattern:
+ description: |
+ It shall be the pattern to match the files.
+ spec-type: str
+ path:
+ description: |
+ It shall be the path to start the search for files.
+ spec-type: str
+ description: |
+ This set of attributes specifies a directory state add files action.
+ mandatory-attributes: all
+spec-name: Directory State Add Files Action
+spec-type: qdp-action-directory-state-add-files
+type: spec
diff --git a/spec-qdp/spec/qdp-action-directory-state-add-tarfile-members.yml b/spec-qdp/spec/qdp-action-directory-state-add-tarfile-members.yml
new file mode 100644
index 00000000..27b8b69d
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-directory-state-add-tarfile-members.yml
@@ -0,0 +1,43 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: directory-state-add-tarfile-members
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ extract:
+ description: |
+ It shall be true, to extract the archive file.
+ spec-type: bool
+ output-name:
+ description: |
+ It shall be name of the output directory state.
+ spec-type: str
+ pattern:
+ description: |
+ It shall be the pattern to match the tarfiles.
+ spec-type: str
+ prefix-path:
+ description: |
+ It shall be prefix path for tarfile members.
+ spec-type: str
+ search-path:
+ description: |
+ It shall be the path to start the search for tarfiles.
+ spec-type: str
+ description: |
+ This set of attributes specifies a directory state add tarfile members
+ action.
+ mandatory-attributes: all
+spec-name: Directory State Add Tarfile Members Action
+spec-type: qdp-action-directory-state-add-tarfile-members
+type: spec
diff --git a/spec-qdp/spec/qdp-action-directory-state-add-tree.yml b/spec-qdp/spec/qdp-action-directory-state-add-tree.yml
new file mode 100644
index 00000000..6a237d6c
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-directory-state-add-tree.yml
@@ -0,0 +1,49 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: directory-state-add-tree
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ excludes:
+ description: |
+ It shall be a list of Python ``fnmatch`` patterns. If a file path
+ matches with the pattern, then the file is not added to the directory
+ state. The file paths are absolute paths relative to the base
+ directory of the directory state. For example, if the directory
+ state has a base of ``/base`` and a file to include has the path
+ ``/base/abc``, then the file path ``/abc`` is used to match with the
+ exclude patterns.
+ spec-type: list-str
+ output-name:
+ description: |
+ It shall be the name of the output directory state.
+ spec-type: str
+ root:
+ description: |
+ It shall be the root directory of the directory tree to add.
+ spec-type: str
+ prefix:
+ description: |
+ If the value is present, then it shall be the prefix path.
+ spec-type: optional-str
+ description: |
+ This set of attributes specifies a directory state add tree action. The
+ files of the directory tree starting at the root directory are added to
+ the file set of the directory state. The added file path is relative to
+ the root directory. The prefix is prepended to the file path for each
+ file before it is added to the directory state. The files are not copied
+ or moved.
+ mandatory-attributes: all
+spec-name: Directory State Add Tree Action
+spec-type: qdp-action-directory-state-add-tree
+type: spec
diff --git a/spec-qdp/spec/qdp-action-directory-state-clear.yml b/spec-qdp/spec/qdp-action-directory-state-clear.yml
new file mode 100644
index 00000000..289e10cc
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-directory-state-clear.yml
@@ -0,0 +1,26 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: directory-state-clear
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ output-name:
+ description: |
+ It shall be name of the output directory state.
+ spec-type: str
+ description: |
+ This set of attributes specifies a directory state clear action.
+ mandatory-attributes: all
+spec-name: Directory State Clear Action
+spec-type: qdp-action-directory-state-clear
+type: spec
diff --git a/spec-qdp/spec/qdp-action-directory-state-copy-tree.yml b/spec-qdp/spec/qdp-action-directory-state-copy-tree.yml
new file mode 100644
index 00000000..b2876579
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-directory-state-copy-tree.yml
@@ -0,0 +1,49 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: directory-state-copy-tree
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ excludes:
+ description: |
+ It shall be a list of Python ``fnmatch`` patterns. If a file path
+ matches with the pattern, then the file is not added to the directory
+ state. The file paths are absolute paths relative to the base
+ directory of the directory state. For example, if the directory
+ state has a base of ``/base`` and a file to include has the path
+ ``/base/abc``, then the file path ``/abc`` is used to match with the
+ exclude patterns.
+ spec-type: list-str
+ output-name:
+ description: |
+ It shall be the name of the output directory state.
+ spec-type: str
+ root:
+ description: |
+ It shall be the root directory of the directory tree to add and copy.
+ spec-type: str
+ prefix:
+ description: |
+ If the value is present, then it shall be the prefix path.
+ spec-type: optional-str
+ description: |
+ This set of attributes specifies a directory state add and copy tree
+ action. The files of the directory tree starting at the root directory
+ are added to the file set of the directory state. The added file path is
+ relative to the root directory. The prefix is prepended to the file path
+ for each file before it is added to the directory state. The files are
+ copied.
+ mandatory-attributes: all
+spec-name: Directory State Add and Copy Tree Action
+spec-type: qdp-action-directory-state-copy-tree
+type: spec
diff --git a/spec-qdp/spec/qdp-action-directory-state-move-tree.yml b/spec-qdp/spec/qdp-action-directory-state-move-tree.yml
new file mode 100644
index 00000000..250b6a78
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-directory-state-move-tree.yml
@@ -0,0 +1,49 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: directory-state-move-tree
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ excludes:
+ description: |
+ It shall be a list of Python ``fnmatch`` patterns. If a file path
+ matches with the pattern, then the file is not added to the directory
+ state. The file paths are absolute paths relative to the base
+ directory of the directory state. For example, if the directory
+ state has a base of ``/base`` and a file to include has the path
+ ``/base/abc``, then the file path ``/abc`` is used to match with the
+ exclude patterns.
+ spec-type: list-str
+ output-name:
+ description: |
+ It shall be the name of the output directory state.
+ spec-type: str
+ root:
+ description: |
+ It shall be the root directory of the directory tree to add and move.
+ spec-type: str
+ prefix:
+ description: |
+ If the value is present, then it shall be the prefix path.
+ spec-type: optional-str
+ description: |
+ This set of attributes specifies a directory state add and move tree
+ action. The files of the directory tree starting at the root directory
+ are added to the file set of the directory state. The added file path is
+ relative to the root directory. The prefix is prepended to the file path
+ for each file before it is added to the directory state. The files are
+ moved.
+ mandatory-attributes: all
+spec-name: Directory State Add and Move Tree Action
+spec-type: qdp-action-directory-state-move-tree
+type: spec
diff --git a/spec-qdp/spec/qdp-action-list.yml b/spec-qdp/spec/qdp-action-list.yml
new file mode 100644
index 00000000..95398756
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-list.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ list:
+ description: null
+ spec-type: qdp-action
+spec-name: Action List
+spec-type: qdp-action-list
+type: spec
diff --git a/spec-qdp/spec/qdp-action-mkdir.yml b/spec-qdp/spec/qdp-action-mkdir.yml
new file mode 100644
index 00000000..624b9985
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-mkdir.yml
@@ -0,0 +1,35 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: mkdir
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ exist-ok:
+ description: |
+ It shall be true, if the directory may already exist, otherwise false.
+ spec-type: bool
+ parents:
+ description: |
+ It shall be true, if missing parent directories shall be created,
+ otherwise false.
+ spec-type: bool
+ path:
+ description: |
+ It shall be the path to the directory to make.
+ spec-type: str
+ description: |
+ This set of attributes specifies a make directory action.
+ mandatory-attributes: all
+spec-name: Make Directory Action
+spec-type: qdp-action-mkdir
+type: spec
diff --git a/spec-qdp/spec/qdp-action-remove-empty-directories.yml b/spec-qdp/spec/qdp-action-remove-empty-directories.yml
new file mode 100644
index 00000000..dd6afa6f
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-remove-empty-directories.yml
@@ -0,0 +1,28 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: remove-empty-directories
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ path:
+ description: |
+ It shall be the path to the base directory of the removal action.
+ spec-type: str
+ description: |
+ This set of attributes specifies a removal of empty directories action.
+ The action recursively removes all empty subdirectories of the base
+ directory and the base directory itself if it gets empty.
+ mandatory-attributes: all
+spec-name: Remove Empty Directories Action
+spec-type: qdp-action-remove-empty-directories
+type: spec
diff --git a/spec-qdp/spec/qdp-action-remove-glob.yml b/spec-qdp/spec/qdp-action-remove-glob.yml
new file mode 100644
index 00000000..b1ba517c
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-remove-glob.yml
@@ -0,0 +1,38 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: remove-glob
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ path:
+ description: |
+ It shall be the path to start the search for files and directories to
+ remove.
+ spec-type: str
+ patterns:
+ description: |
+ It shall be the list of patterns to match the files and directories
+ to remove.
+ spec-type: list-str
+ remove-tree:
+ description: |
+ It shall be true, if matching directories shall be removed as a
+ directory tree, otherwise false.
+ spec-type: bool
+ description: |
+ This set of attributes specifies a pattern based removal of files and
+ directories action.
+ mandatory-attributes: all
+spec-name: Remove Matching Files and Directories Action
+spec-type: qdp-action-remove-glob
+type: spec
diff --git a/spec-qdp/spec/qdp-action-remove-tree.yml b/spec-qdp/spec/qdp-action-remove-tree.yml
new file mode 100644
index 00000000..4a659e8a
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-remove-tree.yml
@@ -0,0 +1,30 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: remove-tree
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ missing-ok:
+ description: |
+ It shall be true, if the directory may be missing, otherwise false.
+ spec-type: bool
+ path:
+ description: |
+ It shall be the path to the directory tree to remove.
+ spec-type: str
+ description: |
+ This set of attributes specifies a removal of a directory tree action.
+ mandatory-attributes: all
+spec-name: Remove Directory Tree Action
+spec-type: qdp-action-remove-tree
+type: spec
diff --git a/spec-qdp/spec/qdp-action-remove.yml b/spec-qdp/spec/qdp-action-remove.yml
new file mode 100644
index 00000000..6722af9f
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-remove.yml
@@ -0,0 +1,31 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: remove
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ missing-ok:
+ description: |
+ It shall be true, if the file or directory may be missing, otherwise
+ false.
+ spec-type: bool
+ path:
+ description: |
+ It shall be the path to the file or directory to remove.
+ spec-type: str
+ description: |
+ This set of attributes specifies a file or directory remove action.
+ mandatory-attributes: all
+spec-name: Remove File or Directory Action
+spec-type: qdp-action-remove
+type: spec
diff --git a/spec-qdp/spec/qdp-action-subprocess-env-list.yml b/spec-qdp/spec/qdp-action-subprocess-env-list.yml
new file mode 100644
index 00000000..cfb3370e
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-subprocess-env-list.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ list:
+ description: null
+ spec-type: qdp-action-subprocess-env
+spec-name: Action Subprocess Environment List
+spec-type: qdp-action-subprocess-env-list
+type: spec
diff --git a/spec-qdp/spec/qdp-action-subprocess-env.yml b/spec-qdp/spec/qdp-action-subprocess-env.yml
new file mode 100644
index 00000000..1e24c20c
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-subprocess-env.yml
@@ -0,0 +1,33 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ action:
+ description: |
+ It shall be the action execution environment modification action.
+ spec-type: str
+ name:
+ description: |
+ If the value is present, then it shall be the environment variable
+ name.
+ spec-type: optional-str
+ value:
+ description: |
+ If the value is present, then it shall be the environment variable
+ value.
+ spec-type: optional-str
+ description: |
+ This set of attributes specifies an action to alter the action execution
+ environment.
+ mandatory-attributes: all
+spec-name: Subprocess Action Environment Action
+spec-type: qdp-action-subprocess-env
+type: spec
diff --git a/spec-qdp/spec/qdp-action-subprocess.yml b/spec-qdp/spec/qdp-action-subprocess.yml
new file mode 100644
index 00000000..3b19a570
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-subprocess.yml
@@ -0,0 +1,42 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: subprocess
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ command:
+ description: |
+ It shall be the command and argument list to run as a subprocess. A
+ variable substitution is performed on the list elements. For
+ example, you can use
+ ``$${/variant:/build-directory}/some/path/to/build/file`` or
+ ``$${/variant:/deployment-directory}/some/path/to/deployment/file``.
+ spec-type: list-str
+ env:
+ description: null
+ spec-type: qdp-action-subprocess-env-list
+ expected-return-code:
+ description: |
+ If the value is present, then it shall be the expected return code of
+ the command.
+ spec-type: optional-int
+ working-directory:
+ description: |
+ It shall be the working directory to run the command.
+ spec-type: str
+ description: |
+ This set of attributes specifies a subprocess action.
+ mandatory-attributes: all
+spec-name: Subprocess Action
+spec-type: qdp-action-subprocess
+type: spec
diff --git a/spec-qdp/spec/qdp-action-touch.yml b/spec-qdp/spec/qdp-action-touch.yml
new file mode 100644
index 00000000..f6aa8fdf
--- /dev/null
+++ b/spec-qdp/spec/qdp-action-touch.yml
@@ -0,0 +1,30 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: action
+ spec-value: touch
+ uid: qdp-action
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ exist-ok:
+ description: |
+ It shall be true, if the file may already exist, otherwise false.
+ spec-type: bool
+ path:
+ description: |
+ It shall be the path to the file to touch.
+ spec-type: str
+ description: |
+ This set of attributes specifies a touch file action.
+ mandatory-attributes: all
+spec-name: Touch File Action
+spec-type: qdp-action-touch
+type: spec
diff --git a/spec-qdp/spec/qdp-action.yml b/spec-qdp/spec/qdp-action.yml
new file mode 100644
index 00000000..52e5344a
--- /dev/null
+++ b/spec-qdp/spec/qdp-action.yml
@@ -0,0 +1,26 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ action:
+ description: |
+ It shall be the action type.
+ spec-type: name
+ enabled-by:
+ description: |
+ It shall define the conditions under which the action is enabled.
+ spec-type: enabled-by
+ description: |
+ This set of attributes specifies a action.
+ mandatory-attributes: all
+spec-name: Action
+spec-type: qdp-action
+type: spec
diff --git a/spec-qdp/spec/qdp-ini-file-key-value-pair-list.yml b/spec-qdp/spec/qdp-ini-file-key-value-pair-list.yml
new file mode 100644
index 00000000..34891e96
--- /dev/null
+++ b/spec-qdp/spec/qdp-ini-file-key-value-pair-list.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ list:
+ description: null
+ spec-type: qdp-ini-file-key-value-pair
+spec-name: INI File Key Value Pair List
+spec-type: qdp-ini-file-key-value-pair-list
+type: spec
diff --git a/spec-qdp/spec/qdp-ini-file-key-value-pair.yml b/spec-qdp/spec/qdp-ini-file-key-value-pair.yml
new file mode 100644
index 00000000..8cf815a6
--- /dev/null
+++ b/spec-qdp/spec/qdp-ini-file-key-value-pair.yml
@@ -0,0 +1,31 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ enabled-by:
+ description: |
+ It shall define the conditions under which the key-value pair is
+ enabled.
+ spec-type: enabled-by
+ key:
+ description: |
+ It shall be the name of the key.
+ spec-type: str
+ value:
+ description: |
+ It shall be the value associated with the key.
+ spec-type: str
+ description: |
+ This set of attributes specifies an INI file key-value pair.
+ mandatory-attributes: all
+spec-name: INI File Key-Value Pair
+spec-type: qdp-ini-file-key-value-pair
+type: spec
diff --git a/spec-qdp/spec/qdp-ini-file-section-list.yml b/spec-qdp/spec/qdp-ini-file-section-list.yml
new file mode 100644
index 00000000..422a6df2
--- /dev/null
+++ b/spec-qdp/spec/qdp-ini-file-section-list.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ list:
+ description: null
+ spec-type: qdp-ini-file-section
+spec-name: INI File Section List
+spec-type: qdp-ini-file-section-list
+type: spec
diff --git a/spec-qdp/spec/qdp-ini-file-section.yml b/spec-qdp/spec/qdp-ini-file-section.yml
new file mode 100644
index 00000000..0772b6da
--- /dev/null
+++ b/spec-qdp/spec/qdp-ini-file-section.yml
@@ -0,0 +1,29 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2023 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ enabled-by:
+ description: |
+ It shall define the conditions under which the section is enabled.
+ spec-type: enabled-by
+ key-value-pairs:
+ description: null
+ spec-type: qdp-ini-file-key-value-pair-list
+ name:
+ description: |
+ It shall be the name of the section.
+ spec-type: str
+ description: |
+ This set of attributes specifies an INI file section.
+ mandatory-attributes: all
+spec-name: INI File Section
+spec-type: qdp-ini-file-section
+type: spec
diff --git a/spec-qdp/spec/qdp-run-actions.yml b/spec-qdp/spec/qdp-run-actions.yml
new file mode 100644
index 00000000..f72ae596
--- /dev/null
+++ b/spec-qdp/spec/qdp-run-actions.yml
@@ -0,0 +1,31 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH & Co. KG
+enabled-by: true
+links:
+- role: spec-member
+ uid: root
+- role: spec-refinement
+ spec-key: build-step-type
+ spec-value: run-actions
+ uid: qdp-build-step
+spec-description: null
+spec-example: null
+spec-info:
+ dict:
+ attributes:
+ actions:
+ description: |
+ It shall be the list of actions to run as a subprocess.
+ spec-type: qdp-action-list
+ params:
+ description: |
+ It shall be an optional set of parameters which may be used for
+ variable subsitution.
+ spec-type: any
+ description: |
+ This set of attributes specifies actions to run as a subprocess.
+ mandatory-attributes: all
+spec-name: Run Actions Item Type
+spec-type: qdp-run-actions
+type: spec