diff --git a/src/app/rpmostree-compose-builtin-tree.c b/src/app/rpmostree-compose-builtin-tree.c index 5c319692..ac3bce3a 100644 --- a/src/app/rpmostree-compose-builtin-tree.c +++ b/src/app/rpmostree-compose-builtin-tree.c @@ -213,6 +213,7 @@ set_keyfile_string_array_from_json (GKeyFile *keyfile, static gboolean install_packages_in_root (RpmOstreeTreeComposeContext *self, + RpmOstreeContext *ctx, JsonObject *treedata, GFile *yumroot, char **packages, @@ -225,7 +226,6 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self, guint progress_sigid; GFile *contextdir = self->treefile_context_dirs->pdata[0]; g_autoptr(RpmOstreeInstall) hifinstall = { 0, }; - g_autoptr(RpmOstreeContext) ctx = NULL; HifContext *hifctx; gs_free char *ret_new_inputhash = NULL; g_autoptr(GKeyFile) treespec = g_key_file_new (); @@ -245,9 +245,6 @@ install_packages_in_root (RpmOstreeTreeComposeContext *self, } #endif - ctx = rpmostree_context_new_unprivileged (self->cachedir_dfd, cancellable, error); - if (!ctx) - goto out; hifctx = rpmostree_context_get_hif (ctx); if (opt_proxy) hif_context_set_http_proxy (hifctx, opt_proxy); @@ -577,6 +574,8 @@ rpmostree_compose_builtin_tree (int argc, gs_unref_object JsonParser *treefile_parser = NULL; gs_unref_variant_builder GVariantBuilder *metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_autoptr(RpmOstreeContext) corectx = NULL; + g_autoptr(GHashTable) varsubsts = NULL; gboolean workdir_is_tmp = FALSE; self->treefile_context_dirs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); @@ -676,6 +675,12 @@ rpmostree_compose_builtin_tree (int argc, goto out; } + corectx = rpmostree_context_new_unprivileged (self->cachedir_dfd, cancellable, error); + if (!corectx) + goto out; + + varsubsts = rpmostree_context_get_varsubsts (corectx); + treefile_parser = json_parser_new (); if (!json_parser_load_from_file (treefile_parser, gs_file_get_path_cached (treefile_path), @@ -708,9 +713,13 @@ rpmostree_compose_builtin_tree (int argc, goto out; } - self->ref = g_strdup (_rpmostree_jsonutil_object_require_string_member (treefile, "ref", error)); - if (!self->ref) - goto out; + { const char *input_ref = _rpmostree_jsonutil_object_require_string_member (treefile, "ref", error); + if (!input_ref) + goto out; + self->ref = _rpmostree_varsubst_string (input_ref, varsubsts, error); + if (!self->ref) + goto out; + } if (!ostree_repo_read_commit (repo, self->ref, &previous_root, &previous_checksum, cancellable, &temp_error)) @@ -809,7 +818,7 @@ rpmostree_compose_builtin_tree (int argc, { gboolean unmodified = FALSE; - if (!install_packages_in_root (self, treefile, yumroot, + if (!install_packages_in_root (self, corectx, treefile, yumroot, (char**)packages->pdata, opt_force_nocache ? NULL : &unmodified, &new_inputhash, diff --git a/src/libpriv/rpmostree-core.c b/src/libpriv/rpmostree-core.c index 08c3530e..65ff2e74 100644 --- a/src/libpriv/rpmostree-core.c +++ b/src/libpriv/rpmostree-core.c @@ -404,6 +404,16 @@ rpmostree_treespec_to_variant (RpmOstreeTreespec *spec) return g_variant_ref (spec->spec); } +GHashTable * +rpmostree_context_get_varsubsts (RpmOstreeContext *context) +{ + GHashTable *r = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + g_hash_table_insert (r, g_strdup ("basearch"), g_strdup (hif_context_get_base_arch (context->hifctx))); + + return r; +} + static gboolean enable_one_repo (RpmOstreeContext *context, GPtrArray *sources, diff --git a/src/libpriv/rpmostree-core.h b/src/libpriv/rpmostree-core.h index 3afabaa6..54de1eb8 100644 --- a/src/libpriv/rpmostree-core.h +++ b/src/libpriv/rpmostree-core.h @@ -50,6 +50,8 @@ RpmOstreeTreespec *rpmostree_treespec_new_from_keyfile (GKeyFile *keyfile, GErro RpmOstreeTreespec *rpmostree_treespec_new_from_path (const char *path, GError **error); RpmOstreeTreespec *rpmostree_treespec_new (GVariant *variant); +GHashTable *rpmostree_context_get_varsubsts (RpmOstreeContext *context); + GVariant *rpmostree_treespec_to_variant (RpmOstreeTreespec *spec); const char *rpmostree_treespec_get_ref (RpmOstreeTreespec *spec); diff --git a/src/libpriv/rpmostree-util.c b/src/libpriv/rpmostree-util.c index eb12de44..457a67a7 100644 --- a/src/libpriv/rpmostree-util.c +++ b/src/libpriv/rpmostree-util.c @@ -121,6 +121,70 @@ rpmostree_mkdtemp (const char *template, return ret; } +/* Given a string of the form + * "bla blah ${foo} blah ${bar}" + * and a hash table of variables, substitute the variable values. + */ +char * +_rpmostree_varsubst_string (const char *instr, + GHashTable *substitutions, + GError **error) +{ + const char *s; + const char *p; + /* Acts as a reusable buffer space */ + g_autoptr(GString) varnamebuf = g_string_new (""); + g_autoptr(GString) result = g_string_new (""); + + s = instr; + while ((p = strstr (s, "${")) != NULL) + { + const char *varstart = p + 2; + const char *varend = strchr (varstart, '}'); + const char *value; + if (!varend) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unclosed variable reference starting at %u bytes", + (guint)(p - instr)); + return NULL; + } + + /* Append leading bytes */ + g_string_append_len (result, s, p - s); + + /* Get a NUL-terminated copy of the variable name */ + g_string_truncate (varnamebuf, 0); + g_string_append_len (varnamebuf, varstart, varend - varstart); + + value = g_hash_table_lookup (substitutions, varnamebuf->str); + if (!value) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unknown variable reference ${%s}", + varnamebuf->str); + return NULL; + } + /* Append the replaced value */ + g_string_append (result, value); + + /* On to the next */ + s = varend+1; + } + + if (s != instr) + { + char *r; + g_string_append_len (result, s, p - s); + /* Steal the C string, NULL out the GString since we freed it */ + r = g_string_free (result, FALSE); + result = NULL; + return r; + } + else + return g_strdup (instr); +} + gboolean _rpmostree_util_enumerate_directory_allow_noent (GFile *dirpath, const char *queryargs, diff --git a/src/libpriv/rpmostree-util.h b/src/libpriv/rpmostree-util.h index 0adfa50a..76eb2217 100644 --- a/src/libpriv/rpmostree-util.h +++ b/src/libpriv/rpmostree-util.h @@ -47,6 +47,11 @@ gboolean rpmostree_mkdtemp (const char *template, int *out_tmpdir_dfd, /* allow-none */ GError **error); +char * +_rpmostree_varsubst_string (const char *instr, + GHashTable *substitutions, + GError **error); + gboolean _rpmostree_util_enumerate_directory_allow_noent (GFile *dirpath, const char *queryargs, diff --git a/tests/compose/test-repo.json b/tests/compose/test-repo.json index 83e7e90a..714e1d57 100644 --- a/tests/compose/test-repo.json +++ b/tests/compose/test-repo.json @@ -1,5 +1,5 @@ { - "ref": "fedora/test", + "ref": "fedora/${basearch}/test", "repos": ["test-repo"], diff --git a/tests/test-compose.sh b/tests/test-compose.sh index 037ddcd4..0f3082ae 100755 --- a/tests/test-compose.sh +++ b/tests/test-compose.sh @@ -27,7 +27,12 @@ check_root_test # Remove once it doesn't happen anymore. unset G_DEBUG -(arch | grep -q x86_64) || { echo 1>&2 "$0 can be run only on x86_64"; echo "1..0" ; exit 77; } +arch=$(arch) +if ! test "${arch}" = x86_64; then + echo 1>&2 "$0 can be run only on x86_64"; echo "1..0" ; exit 77 +fi + +testref=fedora/${arch}/test echo "1..4" @@ -44,7 +49,7 @@ echo "ok dry run" rpm-ostree --repo=repo compose tree $SRCDIR/test-repo.json ostree --repo=repo refs >refs.txt -assert_file_has_content refs.txt fedora/test +assert_file_has_content refs.txt ${testref} echo "ok compose"