diff --git a/src/app/rpmostree-compose-builtin-tree.c b/src/app/rpmostree-compose-builtin-tree.c index 31de33b6..2897bbd8 100644 --- a/src/app/rpmostree-compose-builtin-tree.c +++ b/src/app/rpmostree-compose-builtin-tree.c @@ -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; } diff --git a/src/app/rpmostree-container-builtins.c b/src/app/rpmostree-container-builtins.c index 17d98b6e..648e73d6 100644 --- a/src/app/rpmostree-container-builtins.c +++ b/src/app/rpmostree-container-builtins.c @@ -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, ¤t_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; diff --git a/src/libpriv/rpmostree-core.c b/src/libpriv/rpmostree-core.c index 727ac54d..920f8f6c 100644 --- a/src/libpriv/rpmostree-core.c +++ b/src/libpriv/rpmostree-core.c @@ -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); diff --git a/src/libpriv/rpmostree-core.h b/src/libpriv/rpmostree-core.h index 776301b8..80f82dbe 100644 --- a/src/libpriv/rpmostree-core.h +++ b/src/libpriv/rpmostree-core.h @@ -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);