bundles: Support dependencies and runtime-repo

If the bundle contains an origin link we can now install related
things from it, such as locale data.

You can also build the bundle with --runtime-repo=URL, where the url
points to a flatpakrepo file for a repo with runtimes. This works
similar to the RuntimeRepo= feature in flatpakref files.
tingping/wmclass
Alexander Larsson 2016-12-20 16:24:13 +01:00
parent 54d65aabc5
commit f20e5f7823
16 changed files with 418 additions and 181 deletions

View File

@ -44,6 +44,7 @@
static char *opt_arch;
static char *opt_repo_url;
static char *opt_runtime_repo;
static gboolean opt_runtime = FALSE;
static char **opt_gpg_file;
static gboolean opt_oci = FALSE;
@ -52,6 +53,7 @@ static GOptionEntry options[] = {
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, N_("Export runtime instead of app"), NULL },
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, N_("Arch to bundle for"), N_("ARCH") },
{ "repo-url", 0, 0, G_OPTION_ARG_STRING, &opt_repo_url, N_("Url for repo"), N_("URL") },
{ "runtime-repo", 0, 0, G_OPTION_ARG_STRING, &opt_runtime_repo, N_("Url for runtime flatpakrepo file"), N_("URL") },
{ "gpg-keys", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_gpg_file, N_("Add GPG key from FILE (- for stdin)"), N_("FILE") },
{ "oci", 0, 0, G_OPTION_ARG_NONE, &opt_oci, N_("Export oci image instead of flatpak bundle"), NULL },
@ -222,6 +224,9 @@ build_bundle (OstreeRepo *repo, GFile *file,
if (opt_repo_url)
g_variant_builder_add (&metadata_builder, "{sv}", "origin", g_variant_new_string (opt_repo_url));
if (opt_runtime_repo)
g_variant_builder_add (&metadata_builder, "{sv}", "runtime-repo", g_variant_new_string (opt_runtime_repo));
if (opt_gpg_file != NULL)
{
gpg_data = read_gpg_data (cancellable, error);

View File

@ -108,10 +108,8 @@ import_bundle (OstreeRepo *repo, GFile *file,
metadata = flatpak_bundle_load (file, &to_checksum,
&bundle_ref,
NULL,
NULL,
NULL,
error);
NULL, NULL, NULL,
NULL, NULL, error);
if (metadata == NULL)
return NULL;

View File

@ -112,49 +112,8 @@ read_gpg_data (GCancellable *cancellable,
}
static gboolean
install_bundle (FlatpakDir *dir,
GOptionContext *context,
int argc, char **argv,
GCancellable *cancellable,
GError **error)
handle_runtime_repo_deps (FlatpakDir *dir, const char *dep_url, GError **error)
{
g_autoptr(GFile) file = NULL;
const char *filename;
g_autoptr(GBytes) gpg_data = NULL;
if (argc < 2)
return usage_error (context, _("Bundle filename must be specified"), error);
if (argc > 2)
return usage_error (context, _("Too many arguments"), error);
filename = argv[1];
file = g_file_new_for_commandline_arg (filename);
if (!g_file_is_native (file))
return flatpak_fail (error, _("Remote bundles are not supported"));
if (opt_gpg_file != NULL)
{
/* Override gpg_data from file */
gpg_data = read_gpg_data (cancellable, error);
if (gpg_data == NULL)
return FALSE;
}
if (!flatpak_dir_install_bundle (dir, file, gpg_data, NULL,
cancellable, error))
return FALSE;
return TRUE;
}
static gboolean
handle_runtime_repo_deps (FlatpakDir *dir, GBytes *data, GError **error)
{
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
g_autofree char *dep_url = NULL;
g_autoptr(GBytes) dep_data = NULL;
g_autofree char *runtime_url = NULL;
g_autofree char *old_remote = NULL;
@ -168,13 +127,7 @@ handle_runtime_repo_deps (FlatpakDir *dir, GBytes *data, GError **error)
char *t;
int i;
if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (data, NULL), g_bytes_get_size (data),
0, error))
return FALSE;
dep_url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP,
FLATPAK_REF_RUNTIME_REPO_KEY, NULL);
if (dep_url == NULL)
if (opt_no_deps)
return TRUE;
dep_data = download_uri (dep_url, error);
@ -256,6 +209,101 @@ handle_runtime_repo_deps (FlatpakDir *dir, GBytes *data, GError **error)
return TRUE;
}
static gboolean
handle_runtime_repo_deps_from_bundle (FlatpakDir *dir, GFile *file, GError **error)
{
g_autofree char *dep_url = NULL;
g_autoptr(GVariant) metadata = NULL;
if (opt_no_deps)
return TRUE;
metadata = flatpak_bundle_load (file, NULL,
NULL,
NULL,
&dep_url,
NULL,
NULL,
NULL,
NULL);
if (metadata == NULL || dep_url == NULL)
return TRUE;
return handle_runtime_repo_deps (dir, dep_url, error);
}
static gboolean
install_bundle (FlatpakDir *dir,
GOptionContext *context,
int argc, char **argv,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GFile) file = NULL;
const char *filename;
g_autoptr(GBytes) gpg_data = NULL;
g_autoptr(FlatpakTransaction) transaction = NULL;
if (argc < 2)
return usage_error (context, _("Bundle filename must be specified"), error);
if (argc > 2)
return usage_error (context, _("Too many arguments"), error);
filename = argv[1];
file = g_file_new_for_commandline_arg (filename);
if (!g_file_is_native (file))
return flatpak_fail (error, _("Remote bundles are not supported"));
if (opt_gpg_file != NULL)
{
/* Override gpg_data from file */
gpg_data = read_gpg_data (cancellable, error);
if (gpg_data == NULL)
return FALSE;
}
if (!handle_runtime_repo_deps_from_bundle (dir, file, error))
return FALSE;
if (!flatpak_dir_ensure_repo (dir, cancellable, error))
return FALSE;
transaction = flatpak_transaction_new (dir, opt_yes, opt_no_pull, opt_no_deploy,
!opt_no_deps, !opt_no_related);
if (!flatpak_transaction_add_install_bundle (transaction, file, gpg_data, error))
return FALSE;
if (!flatpak_transaction_run (transaction, TRUE, cancellable, error))
return FALSE;
return TRUE;
}
static gboolean
handle_runtime_repo_deps_from_keyfile (FlatpakDir *dir, GBytes *data, GError **error)
{
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
g_autofree char *dep_url = NULL;
if (opt_no_deps)
return TRUE;
if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (data, NULL), g_bytes_get_size (data),
0, error))
return FALSE;
dep_url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP,
FLATPAK_REF_RUNTIME_REPO_KEY, NULL);
if (dep_url == NULL)
return TRUE;
return handle_runtime_repo_deps (dir, dep_url, error);
}
static gboolean
install_from (FlatpakDir *dir,
GOptionContext *context,
@ -303,7 +351,7 @@ install_from (FlatpakDir *dir,
file_data = g_bytes_new_take (g_steal_pointer (&data), data_len);
}
if (!handle_runtime_repo_deps (dir, file_data, error))
if (!handle_runtime_repo_deps_from_keyfile (dir, file_data, error))
return FALSE;
if (!flatpak_dir_create_remote_for_ref_file (dir, file_data, &remote, &ref, error))

View File

@ -30,13 +30,20 @@
typedef struct FlatpakTransactionOp FlatpakTransactionOp;
typedef enum {
FLATPAK_TRANSACTION_OP_KIND_INSTALL,
FLATPAK_TRANSACTION_OP_KIND_UPDATE,
FLATPAK_TRANSACTION_OP_KIND_INSTALL_OR_UPDATE,
FLATPAK_TRANSACTION_OP_KIND_BUNDLE
} FlatpakTransactionOpKind;
struct FlatpakTransactionOp {
char *remote;
char *ref;
char **subpaths;
char *commit;
gboolean update;
gboolean install;
GFile *bundle;
FlatpakTransactionOpKind kind;
gboolean non_fatal;
};
@ -117,8 +124,8 @@ flatpak_transaction_operation_new (const char *remote,
const char *ref,
const char **subpaths,
const char *commit,
gboolean install,
gboolean update)
GFile *bundle,
FlatpakTransactionOpKind kind)
{
FlatpakTransactionOp *self = g_new0 (FlatpakTransactionOp, 1);
@ -126,8 +133,9 @@ flatpak_transaction_operation_new (const char *remote,
self->ref = g_strdup (ref);
self->subpaths = g_strdupv ((char **)subpaths);
self->commit = g_strdup (commit);
self->update = update;
self->install = install;
if (bundle)
self->bundle = g_object_ref (bundle);
self->kind = kind;
return self;
}
@ -139,6 +147,7 @@ flatpak_transaction_operation_free (FlatpakTransactionOp *self)
g_free (self->ref);
g_free (self->commit);
g_strfreev (self->subpaths);
g_clear_object (&self->bundle);
g_free (self);
}
@ -212,31 +221,38 @@ subpaths_to_string (const char **subpaths)
return g_string_free (s, FALSE);
}
static const char *
kind_to_str (FlatpakTransactionOpKind kind)
{
switch (kind)
{
case FLATPAK_TRANSACTION_OP_KIND_INSTALL:
return "install";
case FLATPAK_TRANSACTION_OP_KIND_UPDATE:
return "update";
case FLATPAK_TRANSACTION_OP_KIND_INSTALL_OR_UPDATE:
return "install/update";
case FLATPAK_TRANSACTION_OP_KIND_BUNDLE:
return "install bundle";
}
return "unknown";
}
FlatpakTransactionOp *
flatpak_transaction_add_op (FlatpakTransaction *self,
const char *remote,
const char *ref,
const char **subpaths,
const char *commit,
gboolean install,
gboolean update)
GFile *bundle,
FlatpakTransactionOpKind kind)
{
FlatpakTransactionOp *op;
g_autofree char *subpaths_str = NULL;
const char *opname;
if (install)
{
if (update)
opname = "install/update";
else
opname = "install";
}
else
opname = "update";
subpaths_str = subpaths_to_string (subpaths);
g_debug ("Transaction: %s %s:%s%s%s%s",
opname, remote, ref,
kind_to_str (kind), remote, ref,
commit != NULL ? "@" : "",
commit != NULL ? commit : "",
subpaths_str);
@ -255,7 +271,7 @@ flatpak_transaction_add_op (FlatpakTransaction *self,
return op;
}
op = flatpak_transaction_operation_new (remote, ref, subpaths, commit, install, update);
op = flatpak_transaction_operation_new (remote, ref, subpaths, commit, bundle, kind);
g_hash_table_insert (self->refs, g_strdup (ref), op);
self->ops = g_list_prepend (self->ops, op);
@ -329,7 +345,8 @@ add_related (FlatpakTransaction *self,
op = flatpak_transaction_add_op (self, remote, rel->ref,
(const char **)rel->subpaths,
NULL, TRUE, TRUE);
NULL, NULL,
FLATPAK_TRANSACTION_OP_KIND_INSTALL_OR_UPDATE);
op->non_fatal = TRUE;
}
}
@ -394,14 +411,16 @@ add_deps (FlatpakTransaction *self,
"The Application %s requires the runtime %s which is not installed",
pref, runtime_ref);
flatpak_transaction_add_op (self, runtime_remote, full_runtime_ref, NULL, NULL, TRUE, TRUE);
flatpak_transaction_add_op (self, runtime_remote, full_runtime_ref, NULL, NULL, NULL,
FLATPAK_TRANSACTION_OP_KIND_INSTALL_OR_UPDATE);
}
else
{
/* Update if in same dir */
if (dir_ref_is_installed (self->dir, full_runtime_ref, &runtime_remote))
{
flatpak_transaction_add_op (self, runtime_remote, full_runtime_ref, NULL, NULL, FALSE, TRUE);
flatpak_transaction_add_op (self, runtime_remote, full_runtime_ref, NULL, NULL, NULL,
FLATPAK_TRANSACTION_OP_KIND_UPDATE);
}
}
}
@ -419,17 +438,19 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
const char *ref,
const char **subpaths,
const char *commit,
gboolean is_update,
FlatpakTransactionOpKind kind,
GFile *bundle,
const char *metadata,
GError **error)
{
g_autofree char *origin = NULL;
const char *pref;
g_autofree char *metadata = NULL;
g_autofree char *remote_metadata = NULL;
g_autoptr(GKeyFile) metakey = NULL;
pref = strchr (ref, '/') + 1;
if (is_update)
if (kind == FLATPAK_TRANSACTION_OP_KIND_UPDATE)
{
if (!dir_ref_is_installed (self->dir, ref, &origin))
{
@ -456,7 +477,11 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
}
}
if (flatpak_dir_fetch_ref_cache (self->dir, remote, ref, NULL, NULL, &metadata, NULL, NULL))
if (metadata == NULL && remote != NULL &&
flatpak_dir_fetch_ref_cache (self->dir, remote, ref, NULL, NULL, &remote_metadata, NULL, NULL))
metadata = remote_metadata;
if (metadata)
{
metakey = g_key_file_new ();
if (!g_key_file_load_from_data (metakey, metadata, -1, 0, NULL))
@ -487,7 +512,7 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
return FALSE;
}
flatpak_transaction_add_op (self, remote, ref, subpaths, commit, !is_update, is_update);
flatpak_transaction_add_op (self, remote, ref, subpaths, commit, bundle, kind);
if (!add_related (self, remote, ref, error))
return FALSE;
@ -508,7 +533,30 @@ flatpak_transaction_add_install (FlatpakTransaction *self,
if (subpaths == NULL)
subpaths = all_paths;
return flatpak_transaction_add_ref (self, remote, ref, subpaths, NULL, FALSE, error);
return flatpak_transaction_add_ref (self, remote, ref, subpaths, NULL, FLATPAK_TRANSACTION_OP_KIND_INSTALL, NULL, NULL, error);
}
gboolean
flatpak_transaction_add_install_bundle (FlatpakTransaction *self,
GFile *file,
GBytes *gpg_data,
GError **error)
{
g_autofree char *remote = NULL;
g_autofree char *ref = NULL;
g_autofree char *metadata = NULL;
gboolean created_remote;
remote = flatpak_dir_ensure_bundle_remote (self->dir, file, gpg_data,
&ref, &metadata, &created_remote,
NULL, error);
if (remote == NULL)
return FALSE;
if (!flatpak_dir_recreate_repo (self->dir, NULL, error))
return FALSE;
return flatpak_transaction_add_ref (self, remote, ref, NULL, NULL, FLATPAK_TRANSACTION_OP_KIND_BUNDLE, file, metadata, error);
}
gboolean
@ -557,7 +605,7 @@ flatpak_transaction_add_install_oci (FlatpakTransaction *self,
id = g_strdup_printf ("oci-%s", parts[1]);
remote = flatpak_dir_create_origin_remote (self->dir, NULL,
id, title,
id, title,
ref, uri, tag, NULL,
NULL, error);
if (remote == NULL)
@ -568,7 +616,7 @@ flatpak_transaction_add_install_oci (FlatpakTransaction *self,
g_debug ("Added OCI origin remote %s", remote);
return flatpak_transaction_add_ref (self, remote, ref, all_paths, checksum, FALSE, error);
return flatpak_transaction_add_ref (self, remote, ref, all_paths, checksum, FLATPAK_TRANSACTION_OP_KIND_INSTALL, NULL, NULL, error);
}
gboolean
@ -578,7 +626,7 @@ flatpak_transaction_add_update (FlatpakTransaction *self,
const char *commit,
GError **error)
{
return flatpak_transaction_add_ref (self, NULL, ref, subpaths, commit, TRUE, error);
return flatpak_transaction_add_ref (self, NULL, ref, subpaths, commit, FLATPAK_TRANSACTION_OP_KIND_UPDATE, NULL, NULL, error);
}
gboolean
@ -599,18 +647,20 @@ flatpak_transaction_run (FlatpakTransaction *self,
gboolean res;
const char *pref;
const char *opname;
FlatpakTransactionOpKind kind;
if (op->install && op->update)
kind = op->kind;
if (kind == FLATPAK_TRANSACTION_OP_KIND_INSTALL_OR_UPDATE)
{
if (dir_ref_is_installed (self->dir, op->ref, NULL))
op->install = FALSE;
kind = FLATPAK_TRANSACTION_OP_KIND_UPDATE;
else
op->update = FALSE;
kind = FLATPAK_TRANSACTION_OP_KIND_INSTALL;
}
pref = strchr (op->ref, '/') + 1;
if (op->install)
if (kind == FLATPAK_TRANSACTION_OP_KIND_INSTALL)
{
opname = _("install");
g_print (_("Installing: %s from %s\n"), pref, op->remote);
@ -622,7 +672,7 @@ flatpak_transaction_run (FlatpakTransaction *self,
NULL,
cancellable, &local_error);
}
else /* update */
else if (kind == FLATPAK_TRANSACTION_OP_KIND_UPDATE)
{
opname = _("update");
g_print (_("Updating: %s from %s\n"), pref, op->remote);
@ -651,6 +701,17 @@ flatpak_transaction_run (FlatpakTransaction *self,
g_clear_error (&local_error);
}
}
else if (kind == FLATPAK_TRANSACTION_OP_KIND_BUNDLE)
{
g_autofree char *bundle_basename = g_file_get_basename (op->bundle);
opname = _("install bundle");
g_print (_("Installing: %s from bundle %s\n"), pref, bundle_basename);
res = flatpak_dir_install_bundle (self->dir, op->bundle,
op->remote, NULL,
cancellable, &local_error);
}
else
g_assert_not_reached ();
if (!res)
{

View File

@ -48,6 +48,10 @@ gboolean flatpak_transaction_add_install_oci (FlatpakTransaction *se
const char *uri,
const char *tag,
GError **error);
gboolean flatpak_transaction_add_install_bundle (FlatpakTransaction *self,
GFile *file,
GBytes *gpg_data,
GError **error);
gboolean flatpak_transaction_add_update (FlatpakTransaction *self,
const char *ref,
const char **subpaths,

View File

@ -4310,45 +4310,125 @@ flatpak_dir_install (FlatpakDir *self,
return TRUE;
}
gboolean
flatpak_dir_install_bundle (FlatpakDir *self,
GFile *file,
GBytes *extra_gpg_data,
char **out_ref,
GCancellable *cancellable,
GError **error)
char *
flatpak_dir_ensure_bundle_remote (FlatpakDir *self,
GFile *file,
GBytes *extra_gpg_data,
char **out_ref,
char **out_metadata,
gboolean *out_created_remote,
GCancellable *cancellable,
GError **error)
{
g_autofree char *ref = NULL;
gboolean added_remote = FALSE;
gboolean created_remote = FALSE;
g_autoptr(GVariant) deploy_data = NULL;
g_autoptr(GVariant) metadata = NULL;
g_autofree char *origin = NULL;
g_autofree char *fp_metadata = NULL;
g_auto(GStrv) parts = NULL;
g_autofree char *basename = NULL;
g_autoptr(GBytes) included_gpg_data = NULL;
GBytes *gpg_data = NULL;
g_autofree char *to_checksum = NULL;
g_autofree char *remote = NULL;
gboolean ret = FALSE;
if (!flatpak_dir_ensure_repo (self, cancellable, error))
return NULL;
metadata = flatpak_bundle_load (file, &to_checksum,
&ref,
&origin,
NULL, &fp_metadata, NULL,
&included_gpg_data,
error);
if (metadata == NULL)
return NULL;
gpg_data = extra_gpg_data ? extra_gpg_data : included_gpg_data;
parts = flatpak_decompose_ref (ref, error);
if (parts == NULL)
return NULL;
deploy_data = flatpak_dir_get_deploy_data (self, ref, cancellable, NULL);
if (deploy_data != NULL)
{
remote = g_strdup (flatpak_deploy_data_get_origin (deploy_data));
/* We need to import any gpg keys because otherwise the pull will fail */
if (gpg_data != NULL)
{
g_autoptr(GKeyFile) new_config = NULL;
new_config = ostree_repo_copy_config (flatpak_dir_get_repo (self));
if (!flatpak_dir_modify_remote (self, remote, new_config,
gpg_data, cancellable, error))
return NULL;
}
}
else
{
/* Add a remote for later updates */
basename = g_file_get_basename (file);
remote = flatpak_dir_create_origin_remote (self,
origin,
parts[1],
basename,
ref,
NULL, NULL,
gpg_data,
cancellable,
error);
if (remote == NULL)
return NULL;
/* From here we need to goto out on error, to clean up */
created_remote = TRUE;
}
if (out_created_remote)
*out_created_remote = created_remote;
if (out_ref)
*out_ref = g_steal_pointer (&ref);
if (out_metadata)
*out_metadata = g_steal_pointer (&fp_metadata);
return g_steal_pointer (&remote);
}
gboolean
flatpak_dir_install_bundle (FlatpakDir *self,
GFile *file,
const char *remote,
char **out_ref,
GCancellable *cancellable,
GError **error)
{
g_autofree char *ref = NULL;
g_autoptr(GVariant) deploy_data = NULL;
g_autoptr(GVariant) metadata = NULL;
g_autofree char *origin = NULL;
g_auto(GStrv) parts = NULL;
g_autofree char *to_checksum = NULL;
gboolean gpg_verify;
if (flatpak_dir_use_system_helper (self))
{
FlatpakSystemHelper *system_helper;
g_autoptr(GVariant) gpg_data_v = NULL;
const char *installation = flatpak_dir_get_id (self);
system_helper = flatpak_dir_get_system_helper (self);
g_assert (system_helper != NULL);
if (gpg_data != NULL)
gpg_data_v = variant_new_ay_bytes (gpg_data);
else
gpg_data_v = g_variant_ref_sink (g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL));
g_debug ("Calling system helper: InstallBundle");
if (!flatpak_system_helper_call_install_bundle_sync (system_helper,
flatpak_file_get_path_cached (file),
0, gpg_data_v,
0, remote,
installation ? installation : "",
&ref,
cancellable,
@ -4367,14 +4447,12 @@ flatpak_dir_install_bundle (FlatpakDir *self,
metadata = flatpak_bundle_load (file, &to_checksum,
&ref,
&origin,
NULL,
&included_gpg_data,
NULL, NULL,
NULL, NULL,
error);
if (metadata == NULL)
return FALSE;
gpg_data = extra_gpg_data ? extra_gpg_data : included_gpg_data;
parts = flatpak_decompose_ref (ref, error);
if (parts == NULL)
return FALSE;
@ -4388,51 +4466,27 @@ flatpak_dir_install_bundle (FlatpakDir *self,
_("This version of %s is already installed"), parts[1]);
return FALSE;
}
remote = g_strdup (flatpak_deploy_data_get_origin (deploy_data));
/* We need to import any gpg keys because otherwise the pull will fail */
if (gpg_data != NULL)
if (strcmp (remote, flatpak_deploy_data_get_origin (deploy_data)) != 0)
{
g_autoptr(GInputStream) input_stream = g_memory_input_stream_new_from_bytes (gpg_data);
guint imported = 0;
if (!ostree_repo_remote_gpg_import (self->repo, remote, input_stream,
NULL, &imported, cancellable, error))
return FALSE;
/* XXX If we ever add internationalization, use ngettext() here. */
g_debug ("Imported %u GPG key%s to remote \"%s\"",
imported, (imported == 1) ? "" : "s", remote);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
_("Can't change remote during bundle install"));
return FALSE;
}
}
else
{
/* Add a remote for later updates */
basename = g_file_get_basename (file);
remote = flatpak_dir_create_origin_remote (self,
origin,
parts[1],
basename,
ref,
NULL, NULL,
gpg_data,
cancellable,
error);
if (remote == NULL)
return FALSE;
/* From here we need to goto out on error, to clean up */
added_remote = TRUE;
}
if (!ostree_repo_remote_get_gpg_verify (self->repo, remote,
&gpg_verify, error))
return FALSE;
if (!flatpak_pull_from_bundle (self->repo,
file,
remote,
ref,
gpg_data != NULL,
gpg_verify,
cancellable,
error))
goto out;
return FALSE;
if (deploy_data != NULL)
{
@ -4466,24 +4520,18 @@ flatpak_dir_install_bundle (FlatpakDir *self,
if (deploy_data)
{
if (!flatpak_dir_deploy_update (self, ref, NULL, NULL, cancellable, error))
goto out;
return FALSE;
}
else
{
if (!flatpak_dir_deploy_install (self, ref, remote, NULL, cancellable, error))
goto out;
return FALSE;
}
if (out_ref)
*out_ref = g_steal_pointer (&ref);
ret = TRUE;
out:
if (added_remote && !ret)
ostree_repo_remote_delete (self->repo, remote, NULL, NULL);
return ret;
return TRUE;
}
static gboolean
@ -6340,6 +6388,7 @@ create_origin_remote_config (OstreeRepo *repo,
const char *main_ref,
const char *oci_uri,
const char *oci_tag,
gboolean gpg_verify,
GKeyFile *new_config)
{
g_autofree char *remote = NULL;
@ -6370,8 +6419,16 @@ create_origin_remote_config (OstreeRepo *repo,
g_key_file_set_string (new_config, group, "xa.title", title);
g_key_file_set_string (new_config, group, "xa.noenumerate", "true");
g_key_file_set_string (new_config, group, "xa.prio", "0");
g_key_file_set_string (new_config, group, "gpg-verify", "true");
g_key_file_set_string (new_config, group, "gpg-verify-summary", "true");
if (gpg_verify)
{
g_key_file_set_string (new_config, group, "gpg-verify", "true");
g_key_file_set_string (new_config, group, "gpg-verify-summary", "true");
}
else
{
g_key_file_set_string (new_config, group, "gpg-verify", "false");
g_key_file_set_string (new_config, group, "gpg-verify-summary", "false");
}
if (main_ref)
g_key_file_set_string (new_config, group, "xa.main-ref", main_ref);
if (oci_uri)
@ -6397,7 +6454,7 @@ flatpak_dir_create_origin_remote (FlatpakDir *self,
g_autoptr(GKeyFile) new_config = g_key_file_new ();
g_autofree char *remote = NULL;
remote = create_origin_remote_config (self->repo, url, id, title, main_ref, oci_uri, oci_tag, new_config);
remote = create_origin_remote_config (self->repo, url, id, title, main_ref, oci_uri, oci_tag, gpg_data != NULL, new_config);
if (!flatpak_dir_modify_remote (self, remote, new_config,
gpg_data, cancellable, error))

View File

@ -370,9 +370,17 @@ gboolean flatpak_dir_install (FlatpakDir *self,
OstreeAsyncProgress *progress,
GCancellable *cancellable,
GError **error);
char *flatpak_dir_ensure_bundle_remote (FlatpakDir *self,
GFile *file,
GBytes *extra_gpg_data,
char **out_ref,
char **out_metadata,
gboolean *out_created_remote,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_install_bundle (FlatpakDir *self,
GFile *file,
GBytes *extra_gpg_data,
const char *remote,
char **out_ref,
GCancellable *cancellable,
GError **error);

View File

@ -3878,6 +3878,8 @@ flatpak_bundle_load (GFile *file,
char **commit,
char **ref,
char **origin,
char **runtime_repo,
char **app_metadata,
guint64 *installed_size,
GBytes **gpg_keys,
GError **error)
@ -3947,6 +3949,18 @@ flatpak_bundle_load (GFile *file,
*origin = NULL;
}
if (runtime_repo != NULL)
{
if (!g_variant_lookup (metadata, "runtime-repo", "s", runtime_repo))
*runtime_repo = NULL;
}
if (app_metadata != NULL)
{
if (!g_variant_lookup (metadata, "metadata", "s", app_metadata))
*runtime_repo = NULL;
}
if (gpg_keys != NULL)
{
g_autoptr(GVariant) gpg_value = g_variant_lookup_value (metadata, "gpg-keys",
@ -3991,12 +4005,10 @@ flatpak_pull_from_bundle (OstreeRepo *repo,
g_autoptr(GVariant) metadata = NULL;
gboolean metadata_valid;
metadata = flatpak_bundle_load (file, &to_checksum, NULL, NULL, NULL, NULL, error);
metadata = flatpak_bundle_load (file, &to_checksum, NULL, NULL, NULL, &metadata_contents, NULL, NULL, error);
if (metadata == NULL)
return FALSE;
g_variant_lookup (metadata, "metadata", "s", &metadata_contents);
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
return FALSE;

View File

@ -295,6 +295,8 @@ GVariant * flatpak_bundle_load (GFile *file,
char **commit,
char **ref,
char **origin,
char **runtime_repo,
char **app_metadata,
guint64 *installed_size,
GBytes **gpg_keys,
GError **error);

View File

@ -84,9 +84,7 @@
<method name="InstallBundle">
<arg type='ay' name='bundle_path' direction='in'/>
<arg type='u' name='flags' direction='in'/>
<arg type='ay' name='gpg_key' direction='in'>
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
</arg>
<arg type='s' name='remote' direction='in'/>
<arg type='s' name='installation' direction='in'/>
<arg type='s' name='ref' direction='out'/>
</method>

View File

@ -98,6 +98,16 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--runtime-repo=URL</option></term>
<listitem><para>
The URL for a .flatpakrepo file that contains
the information about the repository that supplies
the runtimes required by the app.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--gpg-keys=FILE</option></term>

View File

@ -32,6 +32,7 @@ struct _FlatpakBundleRefPrivate
{
GFile *file;
char *origin;
char *runtime_repo;
GBytes *metadata;
GBytes *appstream;
GBytes *icon_64;
@ -60,6 +61,7 @@ flatpak_bundle_ref_finalize (GObject *object)
g_bytes_unref (priv->icon_64);
g_bytes_unref (priv->icon_128);
g_free (priv->origin);
g_free (priv->runtime_repo);
G_OBJECT_CLASS (flatpak_bundle_ref_parent_class)->finalize (object);
}
@ -221,6 +223,25 @@ flatpak_bundle_ref_get_origin (FlatpakBundleRef *self)
return g_strdup (priv->origin);
}
/**
* flatpak_bundle_ref_get_runtime_repo:
* @self: a #FlatpakBundleRef
*
* Get the runtime flatpakrepo url stored in the bundle (if any)
*
* Returns: (transfer full) : an url string, or %NULL
*
* Since: 0.8.0
*/
char *
flatpak_bundle_ref_get_runtime_repo_url (FlatpakBundleRef *self)
{
FlatpakBundleRefPrivate *priv = flatpak_bundle_ref_get_instance_private (self);
return g_strdup (priv->runtime_repo);
}
/**
* flatpak_bundle_ref_get_installed_size:
* @self: a FlatpakBundleRef
@ -259,13 +280,14 @@ flatpak_bundle_ref_new (GFile *file,
g_autofree char *commit = NULL;
g_autofree char *full_ref = NULL;
g_autofree char *origin = NULL;
g_autofree char *runtime_repo = NULL;
g_autofree char *metadata_contents = NULL;
g_autoptr(GVariant) appstream = NULL;
g_autoptr(GVariant) icon_64 = NULL;
g_autoptr(GVariant) icon_128 = NULL;
guint64 installed_size;
metadata = flatpak_bundle_load (file, &commit, &full_ref, &origin, &installed_size,
metadata = flatpak_bundle_load (file, &commit, &full_ref, &origin, &runtime_repo, &metadata_contents, &installed_size,
NULL, error);
if (metadata == NULL)
return NULL;
@ -274,9 +296,6 @@ flatpak_bundle_ref_new (GFile *file,
if (parts == NULL)
return NULL;
if (!g_variant_lookup (metadata, "metadata", "s", &metadata_contents))
metadata_contents = NULL;
if (strcmp (parts[0], "app") != 0)
kind = FLATPAK_REF_KIND_RUNTIME;
@ -310,6 +329,7 @@ flatpak_bundle_ref_new (GFile *file,
priv->installed_size = installed_size;
priv->origin = g_steal_pointer (&origin);
priv->runtime_repo = g_steal_pointer (&runtime_repo);
return ref;
}

View File

@ -55,6 +55,7 @@ FLATPAK_EXTERN GBytes *flatpak_bundle_ref_get_icon (FlatpakBundleRef *s
int size);
FLATPAK_EXTERN char *flatpak_bundle_ref_get_origin (FlatpakBundleRef *self);
FLATPAK_EXTERN guint64 flatpak_bundle_ref_get_installed_size (FlatpakBundleRef *self);
FLATPAK_EXTERN char *flatpak_bundle_ref_get_runtime_repo_url (FlatpakBundleRef *self);
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC

View File

@ -1225,14 +1225,22 @@ flatpak_installation_install_bundle (FlatpakInstallation *self,
g_autoptr(FlatpakDir) dir = flatpak_installation_get_dir (self);
g_autoptr(FlatpakDir) dir_clone = NULL;
g_autofree char *ref = NULL;
g_autofree char *remote = NULL;
FlatpakInstalledRef *result = NULL;
remote = flatpak_dir_ensure_bundle_remote (dir, file, NULL, &ref, NULL, NULL, cancellable, error);
if (remote == NULL)
return NULL;
/* Make sure we pick up the new config */
flatpak_installation_drop_caches (self, NULL, NULL);
/* Pull, prune, etc are not threadsafe, so we work on a copy */
dir_clone = flatpak_dir_clone (dir);
if (!flatpak_dir_ensure_repo (dir_clone, cancellable, error))
return NULL;
if (!flatpak_dir_install_bundle (dir_clone, file, NULL, &ref,
if (!flatpak_dir_install_bundle (dir_clone, file, remote, NULL,
cancellable, error))
return NULL;

View File

@ -428,16 +428,15 @@ handle_install_bundle (FlatpakSystemHelper *object,
GDBusMethodInvocation *invocation,
const gchar *arg_bundle_path,
guint32 arg_flags,
GVariant *arg_gpg_key,
const gchar *arg_remote,
const gchar *arg_installation)
{
g_autoptr(FlatpakDir) system = NULL;
g_autoptr(GFile) path = g_file_new_for_path (arg_bundle_path);
g_autoptr(GError) error = NULL;
g_autoptr(GBytes) gpg_data = NULL;
g_autofree char *ref = NULL;
g_debug ("InstallBundle %s %u %p %s", arg_bundle_path, arg_flags, arg_gpg_key, arg_installation);
g_debug ("InstallBundle %s %u %s %s", arg_bundle_path, arg_flags, arg_remote, arg_installation);
system = dir_get_system (arg_installation, &error);
if (system == NULL)
@ -460,10 +459,7 @@ handle_install_bundle (FlatpakSystemHelper *object,
return TRUE;
}
if (g_variant_get_size (arg_gpg_key) > 0)
gpg_data = g_variant_get_data_as_bytes (arg_gpg_key);
if (!flatpak_dir_install_bundle (system, path, gpg_data, &ref, NULL, &error))
if (!flatpak_dir_install_bundle (system, path, arg_remote, &ref, NULL, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;

View File

@ -26,17 +26,22 @@ skip_without_user_xattrs
echo "1..6"
mkdir bundles
setup_repo
${FLATPAK} build-bundle repo --repo-url=file://`pwd`/repo --gpg-keys=${FL_GPG_HOMEDIR}/pubring.gpg hello.flatpak org.test.Hello
assert_has_file hello.flatpak
${FLATPAK} build-bundle repo --repo-url=file://`pwd`/repo --gpg-keys=${FL_GPG_HOMEDIR}/pubring.gpg bundles/hello.flatpak org.test.Hello
assert_has_file bundles/hello.flatpak
${FLATPAK} build-bundle repo --runtime --repo-url=file://`pwd`/repo --gpg-keys=${FL_GPG_HOMEDIR}/pubring.gpg platform.flatpak org.test.Platform
assert_has_file platform.flatpak
${FLATPAK} build-bundle repo --runtime --repo-url=file://`pwd`/repo --gpg-keys=${FL_GPG_HOMEDIR}/pubring.gpg bundles/platform.flatpak org.test.Platform
assert_has_file bundles/platform.flatpak
echo "ok create bundles"
${FLATPAK} install ${U} --bundle hello.flatpak
${FLATPAK} install ${U} -y --bundle bundles/hello.flatpak
# This should have installed the runtime dependency too
assert_has_file $FL_DIR/repo/refs/remotes/test-repo/runtime/org.test.Platform/$ARCH/master
assert_has_file $FL_DIR/repo/refs/remotes/org.test.Hello-origin/app/org.test.Hello/$ARCH/master
APP_COMMIT=`cat $FL_DIR/repo/refs/remotes/org.test.Hello-origin/app/org.test.Hello/$ARCH/master`
@ -80,7 +85,11 @@ assert_has_file $FL_DIR/repo/org.test.Hello-origin.trustedkeys.gpg
echo "ok install app bundle"
${FLATPAK} install ${U} --bundle platform.flatpak
${FLATPAK} uninstall ${U} org.test.Platform
assert_not_has_file $FL_DIR/repo/refs/remotes/org.test.Platform-origin/runtime/org.test.Platform/$ARCH/master
${FLATPAK} install ${U} --bundle bundles/platform.flatpak
assert_has_file $FL_DIR/repo/refs/remotes/org.test.Platform-origin/runtime/org.test.Platform/$ARCH/master
RUNTIME_COMMIT=`cat $FL_DIR/repo/refs/remotes/org.test.Platform-origin/runtime/org.test.Platform/$ARCH/master`