treecompose: Add support for an "include" key
This greatly increases the practiality of using treefiles directly instead of the old products.json.
This commit is contained in:
parent
df2b355f38
commit
6e082af2b3
@ -23,6 +23,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <glib-unix.h>
|
#include <glib-unix.h>
|
||||||
#include <json-glib/json-glib.h>
|
#include <json-glib/json-glib.h>
|
||||||
|
#include <gio/gunixoutputstream.h>
|
||||||
|
|
||||||
#include "rpmostree-builtins.h"
|
#include "rpmostree-builtins.h"
|
||||||
#include "rpmostree-postprocess.h"
|
#include "rpmostree-postprocess.h"
|
||||||
@ -33,12 +34,14 @@ static char *opt_workdir;
|
|||||||
static char *opt_cachedir;
|
static char *opt_cachedir;
|
||||||
static char *opt_proxy;
|
static char *opt_proxy;
|
||||||
static char *opt_repo;
|
static char *opt_repo;
|
||||||
|
static gboolean opt_print_only;
|
||||||
|
|
||||||
static GOptionEntry option_entries[] = {
|
static GOptionEntry option_entries[] = {
|
||||||
{ "workdir", 0, 0, G_OPTION_ARG_STRING, &opt_workdir, "Working directory", "WORKDIR" },
|
{ "workdir", 0, 0, G_OPTION_ARG_STRING, &opt_workdir, "Working directory", "WORKDIR" },
|
||||||
{ "cachedir", 0, 0, G_OPTION_ARG_STRING, &opt_cachedir, "Cached state", "CACHEDIR" },
|
{ "cachedir", 0, 0, G_OPTION_ARG_STRING, &opt_cachedir, "Cached state", "CACHEDIR" },
|
||||||
{ "repo", 'r', 0, G_OPTION_ARG_STRING, &opt_repo, "Path to OSTree repository", "REPO" },
|
{ "repo", 'r', 0, G_OPTION_ARG_STRING, &opt_repo, "Path to OSTree repository", "REPO" },
|
||||||
{ "proxy", 0, 0, G_OPTION_ARG_STRING, &opt_proxy, "HTTP proxy", "PROXY" },
|
{ "proxy", 0, 0, G_OPTION_ARG_STRING, &opt_proxy, "HTTP proxy", "PROXY" },
|
||||||
|
{ "print-only", 0, 0, G_OPTION_ARG_NONE, &opt_print_only, "Just expand any includes and print treefile", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -527,6 +530,104 @@ yuminstall (JsonObject *treedata,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
process_includes (GFile *treefile_path,
|
||||||
|
guint depth,
|
||||||
|
JsonObject *root,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
const char *include_path;
|
||||||
|
const guint maxdepth = 50;
|
||||||
|
|
||||||
|
if (depth > maxdepth)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Exceeded maximum include depth of %u", maxdepth);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!object_get_optional_string_member (root, "include", &include_path, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (include_path)
|
||||||
|
{
|
||||||
|
gs_unref_object GFile *treefile_dirpath = g_file_get_parent (treefile_path);
|
||||||
|
gs_unref_object GFile *parent_path = g_file_resolve_relative_path (treefile_dirpath, include_path);
|
||||||
|
gs_unref_object JsonParser *parent_parser = json_parser_new ();
|
||||||
|
JsonNode *parent_rootval;
|
||||||
|
JsonObject *parent_root;
|
||||||
|
GList *members;
|
||||||
|
GList *iter;
|
||||||
|
|
||||||
|
if (!json_parser_load_from_file (parent_parser,
|
||||||
|
gs_file_get_path_cached (parent_path),
|
||||||
|
error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
parent_rootval = json_parser_get_root (parent_parser);
|
||||||
|
if (!JSON_NODE_HOLDS_OBJECT (parent_rootval))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Treefile root is not an object");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
parent_root = json_node_get_object (parent_rootval);
|
||||||
|
|
||||||
|
if (!process_includes (parent_path, depth + 1, parent_root,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
members = json_object_get_members (parent_root);
|
||||||
|
for (iter = members; iter; iter = iter->next)
|
||||||
|
{
|
||||||
|
const char *name = iter->data;
|
||||||
|
JsonNode *parent_val = json_object_get_member (parent_root, name);
|
||||||
|
JsonNode *val = json_object_get_member (root, name);
|
||||||
|
|
||||||
|
g_assert (parent_val);
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
json_object_set_member (root, name, json_node_copy (parent_val));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JsonNodeType parent_type =
|
||||||
|
json_node_get_node_type (parent_val);
|
||||||
|
JsonNodeType child_type =
|
||||||
|
json_node_get_node_type (val);
|
||||||
|
if (parent_type != child_type)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Conflicting element type of '%s'",
|
||||||
|
name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (child_type == JSON_NODE_ARRAY)
|
||||||
|
{
|
||||||
|
JsonArray *parent_array = json_node_get_array (parent_val);
|
||||||
|
JsonArray *child_array = json_node_get_array (val);
|
||||||
|
JsonArray *new_child = json_array_new ();
|
||||||
|
guint i, len;
|
||||||
|
|
||||||
|
len = json_array_get_length (parent_array);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
json_array_add_element (new_child, json_node_copy (json_array_get_element (parent_array, i)));
|
||||||
|
len = json_array_get_length (child_array);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
json_array_add_element (new_child, json_node_copy (json_array_get_element (child_array, i)));
|
||||||
|
|
||||||
|
json_object_set_array_member (root, name, new_child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
rpmostree_builtin_treecompose (int argc,
|
rpmostree_builtin_treecompose (int argc,
|
||||||
char **argv,
|
char **argv,
|
||||||
@ -536,7 +637,7 @@ rpmostree_builtin_treecompose (int argc,
|
|||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GOptionContext *context = g_option_context_new ("- Run yum and commit the result to an OSTree repository");
|
GOptionContext *context = g_option_context_new ("- Run yum and commit the result to an OSTree repository");
|
||||||
const char *ref;
|
const char *ref;
|
||||||
JsonNode *treefile_root = NULL;
|
JsonNode *treefile_rootval = NULL;
|
||||||
JsonObject *treefile = NULL;
|
JsonObject *treefile = NULL;
|
||||||
JsonArray *internal_postprocessing = NULL;
|
JsonArray *internal_postprocessing = NULL;
|
||||||
JsonArray *units = NULL;
|
JsonArray *units = NULL;
|
||||||
@ -607,14 +708,31 @@ rpmostree_builtin_treecompose (int argc,
|
|||||||
error))
|
error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
treefile_root = json_parser_get_root (treefile_parser);
|
treefile_rootval = json_parser_get_root (treefile_parser);
|
||||||
if (!JSON_NODE_HOLDS_OBJECT (treefile_root))
|
if (!JSON_NODE_HOLDS_OBJECT (treefile_rootval))
|
||||||
{
|
{
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
"Treefile root is not an object");
|
"Treefile root is not an object");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
treefile = json_node_get_object (treefile_root);
|
treefile = json_node_get_object (treefile_rootval);
|
||||||
|
|
||||||
|
if (!process_includes (treefile_path, 0, treefile,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (opt_print_only)
|
||||||
|
{
|
||||||
|
gs_unref_object JsonGenerator *generator = json_generator_new ();
|
||||||
|
gs_unref_object GOutputStream *stdout = g_unix_output_stream_new (1, FALSE);
|
||||||
|
|
||||||
|
json_generator_set_pretty (generator, TRUE);
|
||||||
|
json_generator_set_root (generator, treefile_rootval);
|
||||||
|
(void) json_generator_to_stream (generator, stdout, NULL, NULL);
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
yumroot = g_file_get_child (workdir, "rootfs.tmp");
|
yumroot = g_file_get_child (workdir, "rootfs.tmp");
|
||||||
if (!gs_shutil_rm_rf (yumroot, cancellable, error))
|
if (!gs_shutil_rm_rf (yumroot, cancellable, error))
|
||||||
|
Loading…
Reference in New Issue
Block a user