Introduce "treespec" concept as GKeyFile

I debated config file formats a lot.  JSON is fairly awkward for
humans to write, and really painful to parse from C.  YAML is nice,
but also painful from C.

Both are fairly overpowered for what we really need.  Keyfiles
(desktop spec, `GKeyFile`) have a lot of limitations, but at least
it's used by systemd and `.desktop` files, and we already have a
parser.

We still parse the JSON treefiles, but internally convert them to
`GKeyFile` (which is in turn converted to `GVariant` for a canonical
form).
This commit is contained in:
Colin Walters 2016-02-10 09:25:58 +01:00
parent 06f5577770
commit 961a036c5b
4 changed files with 369 additions and 164 deletions

View File

@ -89,6 +89,7 @@ typedef struct {
GFile *workdir;
int workdir_dfd;
OstreeRepo *repo;
char *ref;
char *previous_checksum;
GBytes *serialized_treefile;
@ -137,6 +138,36 @@ on_hifstate_percentage_changed (HifState *hifstate,
glnx_console_progress_text_percent (text, percentage);
}
static gboolean
set_keyfile_string_array_from_json (GKeyFile *keyfile,
const char *keyfile_group,
const char *keyfile_key,
JsonArray *a,
GError **error)
{
gboolean ret = FALSE;
guint len = json_array_get_length (a);
guint i;
g_autoptr(GPtrArray) instlangs_v = g_ptr_array_new ();
for (i = 0; i < len; i++)
{
const char *elt = _rpmostree_jsonutil_array_require_string_element (a, i, error);
if (!elt)
goto out;
g_ptr_array_add (instlangs_v, (char*)elt);
}
g_key_file_set_string_list (keyfile, keyfile_group, keyfile_key,
(const char*const*)instlangs_v->pdata, instlangs_v->len);
ret = TRUE;
out:
return ret;
}
static gboolean
install_packages_in_root (RpmOstreeTreeComposeContext *self,
JsonObject *treedata,
@ -154,6 +185,8 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
g_autoptr(RpmOstreeContext) ctx = NULL;
HifContext *hifctx;
gs_free char *ret_new_inputhash = NULL;
g_autoptr(GKeyFile) treespec = g_key_file_new ();
JsonArray *enable_repos = NULL;
ctx = rpmostree_context_new_unprivileged (self->workdir_dfd, cancellable, error);
if (!ctx)
@ -164,66 +197,32 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
hif_context_set_repo_dir (hifctx, gs_file_get_path_cached (contextdir));
{ JsonNode *install_langs_n =
json_object_get_member (treedata, "install-langs");
g_key_file_set_string (treespec, "tree", "ref", self->ref);
g_key_file_set_string_list (treespec, "tree", "packages", (const char *const*)packages, g_strv_length (packages));
if (install_langs_n != NULL)
{
JsonArray *instlangs_a = json_node_get_array (install_langs_n);
guint len = json_array_get_length (instlangs_a);
guint i;
GString *opt = g_string_new ("");
for (i = 0; i < len; i++)
{
g_string_append (opt, json_array_get_string_element (instlangs_a, i));
if (i < len - 1)
g_string_append_c (opt, ':');
}
hif_context_set_rpm_macro (hifctx, "_install_langs", opt->str);
g_string_free (opt, TRUE);
}
}
if (!rpmostree_context_setup (ctx, gs_file_get_path_cached (yumroot),
cancellable, error))
goto out;
/* Some awful code to translate between JSON and GKeyFile */
if (json_object_has_member (treedata, "install-langs"))
{
JsonArray *a = json_object_get_array_member (treedata, "install-langs");
if (!set_keyfile_string_array_from_json (treespec, "tree", "install-langs", a, error))
goto out;
}
/* Bind the json \"repos\" member to the hif state, which looks at the
* enabled= member of the repos file. By default we forcibly enable
* only repos which are specified, ignoring the enabled= flag.
*/
{
JsonArray *enable_repos = NULL;
g_autoptr(GPtrArray) enable_repos_strv = g_ptr_array_new ();
guint i;
guint n;
if (!json_object_has_member (treedata, "repos"))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Treefile is missing required \"repos\" member");
goto out;
}
enable_repos = json_object_get_array_member (treedata, "repos");
n = json_array_get_length (enable_repos);
for (i = 0; i < n; i++)
{
const char *reponame = _rpmostree_jsonutil_array_require_string_element (enable_repos, i, error);
if (!reponame)
goto out;
g_ptr_array_add (enable_repos_strv, (char*)reponame);
}
g_ptr_array_add (enable_repos_strv, NULL);
if (!rpmostree_context_repos_enable_only (ctx,
(const char *const*)enable_repos_strv->pdata,
error))
if (!json_object_has_member (treedata, "repos"))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Treefile is missing required \"repos\" member");
goto out;
}
}
enable_repos = json_object_get_array_member (treedata, "repos");
if (!set_keyfile_string_array_from_json (treespec, "tree", "repos", enable_repos, error))
goto out;
{ gboolean docs = TRUE;
@ -234,16 +233,23 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self,
goto out;
if (!docs)
hif_transaction_set_flags (hif_context_get_transaction (hifctx),
HIF_TRANSACTION_FLAG_NODOCS);
g_key_file_set_boolean (treespec, "tree", "documentation", FALSE);
}
{ g_autoptr(GError) tmp_error = NULL;
g_autoptr(RpmOstreeTreespec) treespec_value = rpmostree_treespec_new_from_keyfile (treespec, &tmp_error);
g_assert_no_error (tmp_error);
if (!rpmostree_context_setup (ctx, gs_file_get_path_cached (yumroot), treespec_value,
cancellable, error))
goto out;
}
/* --- Downloading metadata --- */
if (!rpmostree_context_download_metadata (ctx, cancellable, error))
goto out;
if (!rpmostree_context_prepare_install (ctx, (const char *const*)packages,
&hifinstall, cancellable, error))
if (!rpmostree_context_prepare_install (ctx, &hifinstall, cancellable, error))
goto out;
/* FIXME - just do a depsolve here before we compute download requirements */
@ -485,7 +491,6 @@ rpmostree_compose_builtin_tree (int argc,
int exit_status = EXIT_FAILURE;
GError *temp_error = NULL;
GOptionContext *context = g_option_context_new ("TREEFILE - Run yum and commit the result to an OSTree repository");
const char *ref;
RpmOstreeTreeComposeContext selfdata = { NULL, };
RpmOstreeTreeComposeContext *self = &selfdata;
JsonNode *treefile_rootval = NULL;
@ -626,17 +631,17 @@ rpmostree_compose_builtin_tree (int argc,
goto out;
}
ref = _rpmostree_jsonutil_object_require_string_member (treefile, "ref", error);
if (!ref)
self->ref = g_strdup (_rpmostree_jsonutil_object_require_string_member (treefile, "ref", error));
if (!self->ref)
goto out;
if (!ostree_repo_read_commit (repo, ref, &previous_root, &previous_checksum,
if (!ostree_repo_read_commit (repo, self->ref, &previous_root, &previous_checksum,
cancellable, &temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_print ("No previous commit for %s\n", ref);
g_print ("No previous commit for %s\n", self->ref);
}
else
{
@ -781,7 +786,7 @@ rpmostree_compose_builtin_tree (int argc,
error))
goto out;
if (!rpmostree_commit (yumroot, repo, ref, metadata, gpgkey, selinux,
if (!rpmostree_commit (yumroot, repo, self->ref, metadata, gpgkey, selinux,
cancellable, error))
goto out;
}

View File

@ -105,6 +105,8 @@ roc_context_init (ROContainerContext *rocctx,
static gboolean
roc_context_prepare_for_root (ROContainerContext *rocctx,
const char *target,
RpmOstreeTreespec *treespec,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
@ -119,10 +121,10 @@ roc_context_prepare_for_root (ROContainerContext *rocctx,
if (!rocctx->ctx)
goto out;
if (!rpmostree_context_setup (rocctx->ctx, abs_instroot_tmp, NULL, error))
if (!rpmostree_context_setup (rocctx->ctx, abs_instroot_tmp, treespec, cancellable, error))
goto out;
if (!glnx_shutil_rm_rf_at (AT_FDCWD, abs_instroot_tmp, NULL, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, abs_instroot_tmp, cancellable, error))
goto out;
ret = TRUE;
@ -243,11 +245,12 @@ rpmostree_container_builtin_assemble (int argc,
g_auto(ROContainerContext) rocctx_data = RO_CONTAINER_CONTEXT_INIT;
ROContainerContext *rocctx = &rocctx_data;
g_autoptr(RpmOstreeInstall) install = {0,};
const char *name;
const char *specpath;
struct stat stbuf;
g_autofree char**pkgnames = NULL;
const char *name;
g_autofree char *commit = NULL;
const char *target_rootdir;
g_autoptr(RpmOstreeTreespec) treespec = NULL;
if (!rpmostree_option_context_parse (context,
assemble_option_entries,
@ -260,23 +263,16 @@ rpmostree_container_builtin_assemble (int argc,
if (argc < 1)
{
rpmostree_usage_error (context, "NAME must be specified", error);
rpmostree_usage_error (context, "SPEC must be specified", error);
goto out;
}
name = argv[1];
{ g_autoptr(GPtrArray) pkgnamesv = g_ptr_array_new_with_free_func (NULL);
if (argc == 2)
g_ptr_array_add (pkgnamesv, argv[1]);
else
{
guint i;
for (i = 2; i < argc; i++)
g_ptr_array_add (pkgnamesv, argv[i]);
}
g_ptr_array_add (pkgnamesv, NULL);
pkgnames = (char**)g_ptr_array_free (pkgnamesv, FALSE);
}
specpath = argv[1];
treespec = rpmostree_treespec_new_from_path (specpath, error);
if (!treespec)
goto out;
name = rpmostree_treespec_get_ref (treespec);
if (!roc_context_init (rocctx, error))
goto out;
@ -298,7 +294,7 @@ rpmostree_container_builtin_assemble (int argc,
goto out;
}
if (!roc_context_prepare_for_root (rocctx, target_rootdir, error))
if (!roc_context_prepare_for_root (rocctx, target_rootdir, treespec, cancellable, error))
goto out;
/* --- Downloading metadata --- */
@ -306,8 +302,7 @@ rpmostree_container_builtin_assemble (int argc,
goto out;
/* --- Resolving dependencies --- */
if (!rpmostree_context_prepare_install (rocctx->ctx, (const char*const*)pkgnames,
&install, cancellable, error))
if (!rpmostree_context_prepare_install (rocctx->ctx, &install, cancellable, error))
goto out;
/* --- Download and import as necessary --- */
@ -419,16 +414,15 @@ rpmostree_container_builtin_upgrade (int argc, char **argv, GCancellable *cancel
ROContainerContext *rocctx = &rocctx_data;
g_autoptr(RpmOstreeInstall) install = NULL;
const char *name;
const char *const*pkgnames;
g_autofree char *commit_checksum = NULL;
g_autofree char *new_commit_checksum = NULL;
g_autoptr(GVariant) commit = NULL;
g_autoptr(GVariant) metadata = NULL;
g_autoptr(GVariant) input_packages_v = NULL;
g_autoptr(GVariant) input_goal_sha512_v = NULL;
g_autoptr(RpmOstreeTreespec) treespec = NULL;
guint current_version;
guint new_version;
g_autofree char *previous_goal_sha512 = NULL;
g_autofree char *previous_state_sha512 = NULL;
const char *target_current_root;
const char *target_new_root;
@ -462,24 +456,9 @@ rpmostree_container_builtin_upgrade (int argc, char **argv, GCancellable *cancel
if (!parse_app_version (target_current_root, &current_version, error))
goto out;
new_version = current_version == 0 ? 1 : 0;
/* Yeah, I'm being mildly clever here indexing into the constant
* array which is a pointless micro-optimization avoiding
* g_strdup_printf().
*/
if (new_version == 0)
target_new_root = glnx_strjoina (name, ".0");
else
target_new_root = glnx_strjoina (name, ".1");
if (!roc_context_prepare_for_root (rocctx, name, error))
goto out;
/* --- Downloading metadata --- */
if (!rpmostree_context_download_metadata (rocctx->ctx, cancellable, error))
goto out;
{ g_autoptr(GVariantDict) metadata_dict = NULL;
g_autoptr(GVariant) spec_v = NULL;
g_autoptr(GVariant) previous_sha512_v = NULL;
if (!ostree_repo_resolve_rev (rocctx->repo, name, FALSE, &commit_checksum, error))
goto out;
@ -491,29 +470,43 @@ rpmostree_container_builtin_upgrade (int argc, char **argv, GCancellable *cancel
metadata = g_variant_get_child_value (commit, 0);
metadata_dict = g_variant_dict_new (metadata);
input_packages_v = _rpmostree_vardict_lookup_value_required (metadata_dict, "rpmostree.input-packages",
(GVariantType*)"as", error);
if (!input_packages_v)
spec_v = _rpmostree_vardict_lookup_value_required (metadata_dict, "rpmostree.spec",
(GVariantType*)"a{sv}", error);
if (!spec_v)
goto out;
pkgnames = g_variant_get_strv (input_packages_v, NULL);
treespec = rpmostree_treespec_new (spec_v);
input_goal_sha512_v = _rpmostree_vardict_lookup_value_required (metadata_dict, "rpmostree.nevras-sha512",
(GVariantType*)"s", error);
if (!input_goal_sha512_v)
previous_sha512_v = _rpmostree_vardict_lookup_value_required (metadata_dict,
"rpmostree.state-sha512",
(GVariantType*)"s", error);
if (!previous_sha512_v)
goto out;
previous_goal_sha512 = g_variant_dup_string (input_goal_sha512_v, NULL);
previous_state_sha512 = g_variant_dup_string (previous_sha512_v, NULL);
}
new_version = current_version == 0 ? 1 : 0;
if (new_version == 0)
target_new_root = glnx_strjoina (name, ".0");
else
target_new_root = glnx_strjoina (name, ".1");
if (!roc_context_prepare_for_root (rocctx, name, treespec, cancellable, error))
goto out;
/* --- Downloading metadata --- */
if (!rpmostree_context_download_metadata (rocctx->ctx, cancellable, error))
goto out;
/* --- Resolving dependencies --- */
if (!rpmostree_context_prepare_install (rocctx->ctx, pkgnames, &install,
if (!rpmostree_context_prepare_install (rocctx->ctx, &install,
cancellable, error))
goto out;
{ g_autofree char *new_goal_sha512 = rpmostree_hif_checksum_goal (G_CHECKSUM_SHA512, hif_context_get_goal (rpmostree_context_get_hif (rocctx->ctx)));
{ g_autofree char *new_state_sha512 = rpmostree_context_get_state_sha512 (rocctx->ctx);
if (strcmp (new_goal_sha512, previous_goal_sha512) == 0)
if (strcmp (new_state_sha512, previous_state_sha512) == 0)
{
g_print ("No changes in inputs to %s (%s)\n", name, commit_checksum);
exit_status = EXIT_SUCCESS;

View File

@ -44,6 +44,7 @@
struct _RpmOstreeContext {
GObject parent;
RpmOstreeTreespec *spec;
HifContext *hifctx;
OstreeRepo *ostreerepo;
};
@ -65,6 +66,15 @@ struct _RpmOstreeInstall {
G_DEFINE_TYPE (RpmOstreeInstall, rpmostree_install, G_TYPE_OBJECT)
struct _RpmOstreeTreespec {
GObject parent;
GVariant *spec;
GVariantDict *dict;
};
G_DEFINE_TYPE (RpmOstreeTreespec, rpmostree_treespec, G_TYPE_OBJECT)
static void
rpmostree_context_finalize (GObject *object)
{
@ -95,7 +105,7 @@ rpmostree_install_finalize (GObject *object)
g_clear_pointer (&self->packages_to_download, g_ptr_array_unref);
g_clear_pointer (&self->packages_requested, g_ptr_array_unref);
G_OBJECT_CLASS (rpmostree_context_parent_class)->finalize (object);
G_OBJECT_CLASS (rpmostree_install_parent_class)->finalize (object);
}
static void
@ -110,6 +120,29 @@ rpmostree_install_init (RpmOstreeInstall *self)
{
}
static void
rpmostree_treespec_finalize (GObject *object)
{
RpmOstreeTreespec *self = RPMOSTREE_TREESPEC (object);
g_clear_pointer (&self->spec, g_variant_unref);
g_clear_pointer (&self->dict, g_variant_dict_unref);
G_OBJECT_CLASS (rpmostree_treespec_parent_class)->finalize (object);
}
static void
rpmostree_treespec_class_init (RpmOstreeTreespecClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = rpmostree_treespec_finalize;
}
static void
rpmostree_treespec_init (RpmOstreeTreespec *self)
{
}
RpmOstreeContext *
rpmostree_context_new_system (GCancellable *cancellable,
GError **error)
@ -147,7 +180,6 @@ rpmostree_context_new_system (GCancellable *cancellable,
}
RpmOstreeContext *
rpmostree_context_new_unprivileged (int userroot_dfd,
GCancellable *cancellable,
GError **error)
@ -205,31 +237,129 @@ rpmostree_context_get_hif (RpmOstreeContext *self)
return self->hifctx;
}
gboolean
rpmostree_context_setup (RpmOstreeContext *self,
const char *installroot,
GCancellable *cancellable,
GError **error)
static int
qsort_cmpstr (const void*ap, const void *bp, gpointer data)
{
gboolean ret = FALSE;
GPtrArray *repos = NULL;
hif_context_set_install_root (self->hifctx, installroot);
const char *a = *((const char *const*) ap);
const char *b = *((const char *const*) bp);
return strcmp (a, b);
}
if (!hif_context_setup (self->hifctx, cancellable, error))
goto out;
static gboolean
add_canonicalized_string_array (GVariantBuilder *builder,
const char *key,
const char *notfound_key,
GKeyFile *keyfile,
GError **error)
{
g_auto(GStrv) input = NULL;
g_autoptr(GHashTable) set = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autofree char **sorted = NULL;
guint count;
char **iter;
g_autoptr(GError) temp_error = NULL;
repos = hif_context_get_repos (self->hifctx);
if (repos->len == 0)
input = g_key_file_get_string_list (keyfile, "tree", key, NULL, &temp_error);
if (!(input && *input))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No enabled repositories");
goto out;
if (notfound_key)
{
g_variant_builder_add (builder, "{sv}", notfound_key, g_variant_new_boolean (TRUE));
return TRUE;
}
else
{
g_propagate_error (error, g_steal_pointer (&temp_error));
return FALSE;
}
}
ret = TRUE;
out:
return ret;
for (iter = input; iter && *iter; iter++)
{
g_autofree char *stripped = g_strdup (*iter);
g_strchug (g_strchomp (stripped));
g_hash_table_add (set, g_steal_pointer (&stripped));
}
sorted = (char**)g_hash_table_get_keys_as_array (set, &count);
g_qsort_with_data (sorted, count, sizeof (void*), qsort_cmpstr, NULL);
g_variant_builder_add (builder, "{sv}", key,
g_variant_new_strv ((const char*const*)sorted, g_strv_length (sorted)));
return TRUE;
}
RpmOstreeTreespec *
rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile,
GError **error)
{
g_autoptr(RpmOstreeTreespec) ret = g_object_new (RPMOSTREE_TYPE_TREESPEC, NULL);
g_auto(GVariantBuilder) builder;
g_variant_builder_init (&builder, (GVariantType*)"a{sv}");
{ g_autofree char *ref = g_key_file_get_string (keyfile, "tree", "ref", error);
if (!ref)
return NULL;
g_variant_builder_add (&builder, "{sv}", "ref", g_variant_new_string (ref));
}
if (!add_canonicalized_string_array (&builder, "packages", NULL, keyfile, error))
return FALSE;
if (!add_canonicalized_string_array (&builder, "repos", NULL, keyfile, error))
return FALSE;
if (!add_canonicalized_string_array (&builder, "instlangs", "instlangs-all", keyfile, error))
return FALSE;
{ gboolean documentation = TRUE;
g_autofree char *value = g_key_file_get_value (keyfile, "tree", "documentation", NULL);
if (value)
documentation = g_key_file_get_boolean (keyfile, "tree", "documentation", NULL);
g_variant_builder_add (&builder, "{sv}", "documentation", g_variant_new_boolean (documentation));
}
ret->spec = g_variant_builder_end (&builder);
ret->dict = g_variant_dict_new (ret->spec);
return g_steal_pointer (&ret);
}
RpmOstreeTreespec *
rpmostree_treespec_new_from_path (const char *path, GError **error)
{
g_autoptr(GKeyFile) specdata = g_key_file_new();
if (!g_key_file_load_from_file (specdata, path, 0, error))
return NULL;
return rpmostree_treespec_new_from_keyfile (specdata, error);
}
RpmOstreeTreespec *
rpmostree_treespec_new (GVariant *variant)
{
g_autoptr(RpmOstreeTreespec) ret = g_object_new (RPMOSTREE_TYPE_TREESPEC, NULL);
ret->spec = g_variant_ref (variant);
ret->dict = g_variant_dict_new (ret->spec);
return g_steal_pointer (&ret);
}
const char *
rpmostree_treespec_get_ref (RpmOstreeTreespec *spec)
{
const char *r;
g_variant_dict_lookup (spec->dict, "ref", "&s", &r);
g_assert (r);
return r;
}
GVariant *
rpmostree_treespec_to_variant (RpmOstreeTreespec *spec)
{
return g_variant_ref (spec->spec);
}
static gboolean
@ -268,10 +398,10 @@ enable_one_repo (RpmOstreeContext *context,
return ret;
}
gboolean
rpmostree_context_repos_enable_only (RpmOstreeContext *context,
const char *const *enabled_repos,
GError **error)
static gboolean
context_repos_enable_only (RpmOstreeContext *context,
const char *const *enabled_repos,
GError **error)
{
gboolean ret = FALSE;
guint i;
@ -296,6 +426,71 @@ rpmostree_context_repos_enable_only (RpmOstreeContext *context,
out:
return ret;
}
gboolean
rpmostree_context_setup (RpmOstreeContext *self,
const char *installroot,
RpmOstreeTreespec *spec,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GPtrArray *repos = NULL;
char **enabled_repos = NULL;
char **instlangs = NULL;
hif_context_set_install_root (self->hifctx, installroot);
if (!hif_context_setup (self->hifctx, cancellable, error))
goto out;
self->spec = g_object_ref (spec);
g_assert (g_variant_dict_lookup (self->spec->dict, "repos", "^a&s", &enabled_repos));
if (!context_repos_enable_only (self, (const char *const*)enabled_repos, error))
goto out;
repos = hif_context_get_repos (self->hifctx);
if (repos->len == 0)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No enabled repositories");
goto out;
}
if (g_variant_dict_lookup (self->spec->dict, "instlangs", "^a&s", &instlangs))
{
GString *opt = g_string_new ("");
char **iter;
gboolean first = TRUE;
for (iter = instlangs; iter && *iter; iter++)
{
const char *v = *iter;
if (!first)
g_string_append_c (opt, ':');
else
first = FALSE;
g_string_append (opt, v);
}
hif_context_set_rpm_macro (self->hifctx, "_install_langs", opt->str);
g_string_free (opt, TRUE);
}
{ gboolean docs;
g_variant_dict_lookup (self->spec->dict, "documentation", "b", &docs);
if (!docs)
hif_transaction_set_flags (hif_context_get_transaction (self->hifctx),
HIF_TRANSACTION_FLAG_NODOCS);
}
ret = TRUE;
out:
return ret;
}
static void
on_hifstate_percentage_changed (HifState *hifstate,
@ -484,17 +679,20 @@ get_packages_to_download (HifContext *hifctx,
gboolean
rpmostree_context_prepare_install (RpmOstreeContext *self,
const char *const *pkgnames,
RpmOstreeInstall **out_install,
GCancellable *cancellable,
GError **error)
RpmOstreeInstall **out_install,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
HifContext *hifctx = self->hifctx;
char **pkgnames = NULL;
g_autoptr(RpmOstreeInstall) ret_install = g_object_new (RPMOSTREE_TYPE_INSTALL, NULL);
g_assert (g_variant_dict_lookup (self->spec->dict, "packages", "^a&s", &pkgnames));
ret_install->packages_requested = g_ptr_array_new_with_free_func (g_free);
{ const char *const*strviter = pkgnames;
{ const char *const*strviter = (const char *const*)pkgnames;
for (; strviter && *strviter; strviter++)
{
const char *pkgname = *strviter;
@ -620,7 +818,7 @@ ptrarray_sort_compare_strings (gconstpointer ap,
*/
void
rpmostree_hif_add_checksum_goal (GChecksum *checksum,
HyGoal goal)
HyGoal goal)
{
g_autoptr(GPtrArray) pkglist = NULL;
guint i;
@ -644,11 +842,14 @@ rpmostree_hif_add_checksum_goal (GChecksum *checksum,
}
char *
rpmostree_hif_checksum_goal (GChecksumType ctype, HyGoal goal)
rpmostree_context_get_state_sha512 (RpmOstreeContext *self)
{
g_autoptr(GChecksum) checksum = g_checksum_new (ctype);
rpmostree_hif_add_checksum_goal (checksum, goal);
return g_strdup (g_checksum_get_string (checksum));
g_autoptr(GChecksum) state_checksum = g_checksum_new (G_CHECKSUM_SHA512);
g_checksum_update (state_checksum, g_variant_get_data (self->spec->spec),
g_variant_get_size (self->spec->spec));
rpmostree_hif_add_checksum_goal (state_checksum, hif_context_get_goal (self->hifctx));
return g_strdup (g_checksum_get_string (state_checksum));
}
/**
@ -1333,18 +1534,19 @@ rpmostree_context_assemble_commit (RpmOstreeContext *self,
{ glnx_unref_object OstreeMutableTree *mtree = NULL;
g_autoptr(GFile) root = NULL;
g_auto(GVariantBuilder) metadata_builder;
g_autofree char *goal_checksum = NULL;
g_autofree char *state_checksum = NULL;
OstreeRepoCommitModifier *commit_modifier = ostree_repo_commit_modifier_new (OSTREE_REPO_COMMIT_MODIFIER_FLAGS_NONE, NULL, NULL, NULL);
g_autoptr(GVariant) spec_v = g_variant_ref_sink (rpmostree_treespec_to_variant (self->spec));
g_variant_builder_init (&metadata_builder, (GVariantType*)"a{sv}");
g_variant_builder_add (&metadata_builder, "{sv}",
"rpmostree.input-packages", g_variant_new_strv ((const char *const*)install->packages_requested->pdata,
install->packages_requested->len));
g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.spec", spec_v);
state_checksum = rpmostree_context_get_state_sha512 (self);
goal_checksum = rpmostree_hif_checksum_goal (G_CHECKSUM_SHA512, hif_context_get_goal (hifctx));
g_variant_builder_add (&metadata_builder, "{sv}",
"rpmostree.nevras-sha512", g_variant_new_string (goal_checksum));
"rpmostree.state-sha512",
g_variant_new_string (state_checksum));
ostree_repo_commit_modifier_set_devino_cache (commit_modifier, devino_cache);

View File

@ -31,6 +31,9 @@
#define RPMOSTREE_TYPE_CONTEXT (rpmostree_context_get_type ())
G_DECLARE_FINAL_TYPE (RpmOstreeContext, rpmostree_context, RPMOSTREE, CONTEXT, GObject)
#define RPMOSTREE_TYPE_TREESPEC (rpmostree_treespec_get_type ())
G_DECLARE_FINAL_TYPE (RpmOstreeTreespec, rpmostree_treespec, RPMOSTREE, TREESPEC, GObject)
#define RPMOSTREE_TYPE_INSTALL (rpmostree_install_get_type ())
G_DECLARE_FINAL_TYPE (RpmOstreeInstall, rpmostree_install, RPMOSTREE, INSTALL, GObject)
@ -43,18 +46,21 @@ RpmOstreeContext *rpmostree_context_new_unprivileged (int basedir_dfd,
HifContext * rpmostree_context_get_hif (RpmOstreeContext *self);
gboolean
rpmostree_context_repos_enable_only (RpmOstreeContext *context,
const char *const *enabled_repos,
GError **error);
RpmOstreeTreespec *rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile, GError **error);
RpmOstreeTreespec *rpmostree_treespec_new_from_path (const char *path, GError **error);
RpmOstreeTreespec *rpmostree_treespec_new (GVariant *variant);
GVariant *rpmostree_treespec_to_variant (RpmOstreeTreespec *spec);
const char *rpmostree_treespec_get_ref (RpmOstreeTreespec *spec);
gboolean rpmostree_context_setup (RpmOstreeContext *self,
const char *install_root,
RpmOstreeTreespec *treespec,
GCancellable *cancellable,
GError **error);
GError **error);
void rpmostree_hif_add_checksum_goal (GChecksum *checksum, HyGoal goal);
char * rpmostree_hif_checksum_goal (GChecksumType type, HyGoal goal);
char *rpmostree_context_get_state_sha512 (RpmOstreeContext *self);
char *rpmostree_get_cache_branch_header (Header hdr);
char *rpmostree_get_cache_branch_pkg (HifPackage *pkg);
@ -65,7 +71,6 @@ gboolean rpmostree_context_download_metadata (RpmOstreeContext *context,
/* This API allocates an install context, use with one of the later ones */
gboolean rpmostree_context_prepare_install (RpmOstreeContext *self,
const char *const *packages,
RpmOstreeInstall **out_install,
GCancellable *cancellable,
GError **error);