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:
parent
06f5577770
commit
961a036c5b
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user