treefile: Support inline postprocess element (for inheritance)

I'm trying to have a more opinionated model where custom builds
use inheritance, and currently one can only have a single
`postprocess-script`.

Further, in YAML it's very convenient to use inline vs external
data.

Closes: #1527
Approved by: jlebon
This commit is contained in:
Colin Walters 2018-09-05 10:53:03 -04:00 committed by Atomic Bot
parent 9920094cfa
commit 279e7c4f1b
4 changed files with 51 additions and 1 deletions

View File

@ -173,6 +173,16 @@ It supports the following parameters:
Note this does not alter the RPM database, so `rpm -V` will complain.
If you want to depend on network access, or tools not in the target host,
you can use the split-up `rpm-ostree compose install`
and `rpm-ostree compose postprocess/commit` commands.
* `postprocess`: array of string, optional: This is an *inline* script
variant of `postprocess-script` that is also an array, so it works
correctly with inheritance. If both `postprocess-script` and `postprocess`
are provided, then `postprocess-script` will be executed after all
other `postprocess`.
* `include`: string, optional: Path to another treefile which will be
used as an inheritance base. The semantics for inheritance are:
Non-array values in child values override parent values. Array

View File

@ -318,8 +318,12 @@ pub struct TreeComposeConfig {
// Content manipulation
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "postprocess-script")]
// This one references an external filename
pub postprocess_script: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
// This one is inline, and supports multiple (hence is useful for inheritance)
pub postprocess: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "add-files")]
pub add_files: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]

View File

@ -1721,11 +1721,40 @@ rpmostree_treefile_postprocessing (int rootfs_fd,
if (!copy_additional_files (rootfs_fd, context_directory, treefile, cancellable, error))
return FALSE;
if (json_object_has_member (treefile, "postprocess"))
{
JsonArray *postprocess_inlines = json_object_get_array_member (treefile, "postprocess");
guint len = json_array_get_length (postprocess_inlines);
for (guint i = 0; i < len; i++)
{
const char *script = _rpmostree_jsonutil_array_require_string_element (postprocess_inlines, i, error);
if (!script)
return FALSE;
g_autofree char* binpath = g_strdup_printf ("/usr/bin/rpmostree-postprocess-inline-%u", i);
const char *target_binpath = binpath + 1;
if (!glnx_file_replace_contents_with_perms_at (rootfs_fd, target_binpath,
(guint8*)script, -1,
0755, (uid_t)-1, (gid_t)-1,
GLNX_FILE_REPLACE_NODATASYNC,
cancellable, error))
return FALSE;
g_print ("Executing `postprocess` inline script '%u'\n", i);
char *child_argv[] = { binpath, NULL };
if (!run_bwrap_mutably (rootfs_fd, binpath, child_argv, unified_core_mode, cancellable, error))
return glnx_prefix_error (error, "While executing inline postprocessing script '%i'", i);
if (!glnx_unlinkat (rootfs_fd, target_binpath, 0, error))
return FALSE;
}
}
const char *postprocess_script = NULL;
if (!_rpmostree_jsonutil_object_get_optional_string_member (treefile, "postprocess-script",
&postprocess_script, error))
return FALSE;
if (postprocess_script)
{
const char *bn = glnx_basename (postprocess_script);

View File

@ -21,9 +21,16 @@ pysetjsonmember "add-files" '[["foo.txt", "/usr/etc/foo.txt"],
["baz.txt", "/usr/share/baz.txt"],
["bar.txt", "/etc/bar.txt"]]'
pysetjsonmember "postprocess-script" \"$PWD/postprocess.sh\"
pysetjsonmember "postprocess" '["""#!/bin/bash
touch /usr/share/postprocess-testing""",
"""#!/bin/bash
rm /usr/share/postprocess-testing
touch /usr/share/postprocess-testing-done"""]'
cat > postprocess.sh << EOF
#!/bin/bash
set -xeuo pipefail
# Ordering should be after postprocess
rm /usr/share/postprocess-testing-done
echo misc-tweaks-postprocess-done > /usr/share/misc-tweaks-postprocess-done.txt
cp -a /usr/etc/foo.txt /usr/share/misc-tweaks-foo.txt
EOF