install: Support RuntimeRepo= key in flatpakref files

This allows an app to point to the repo where the runtime it uses
comes from, and the user will be asked to add that if its not
already configured.
This commit is contained in:
Alexander Larsson
2016-12-02 16:30:15 +01:00
parent 3eb9fa0ee6
commit bb6e1d535f
4 changed files with 205 additions and 7 deletions

View File

@@ -36,13 +36,6 @@
#include "flatpak-utils.h"
#include "flatpak-chain-input-stream.h"
#define FLATPAK_REPO_GROUP "Flatpak Repo"
#define FLATPAK_REPO_URL_KEY "Url"
#define FLATPAK_REPO_TITLE_KEY "Title"
#define FLATPAK_REPO_DEFAULT_BRANCH_KEY "DefaultBranch"
#define FLATPAK_REPO_GPGKEY_KEY "GPGKey"
#define FLATPAK_REPO_NODEPS_KEY "NoDeps"
static gboolean opt_no_gpg_verify;
static gboolean opt_do_gpg_verify;
static gboolean opt_do_enumerate;

View File

@@ -144,6 +144,96 @@ install_bundle (FlatpakDir *dir,
return TRUE;
}
static gboolean
handle_runtime_repo_deps (FlatpakDir *dir, GBytes *data, GError **error)
{
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
g_autoptr(GKeyFile) dep_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;
g_autofree char *new_remote = NULL;
g_autofree char *basename = NULL;
g_autoptr(SoupURI) uri = NULL;
g_auto(GStrv) remotes = NULL;
g_autoptr(GKeyFile) config = NULL;
g_autoptr(GBytes) gpg_key = NULL;
g_autofree char *group = NULL;
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)
return TRUE;
dep_data = download_uri (dep_url, error);
if (dep_data == NULL)
{
g_prefix_error (error, "Can't load dependent file %s", dep_url);
return FALSE;
}
uri = soup_uri_new (dep_url);
basename = g_path_get_basename (soup_uri_get_path (uri));
/* Strip suffix */
t = strchr (basename, '.');
if (t != NULL)
*t = 0;
/* Find a free remote name */
remotes = flatpak_dir_list_remotes (dir, NULL, NULL);
i = 0;
do
{
g_clear_pointer (&new_remote, g_free);
if (i == 0)
new_remote = g_strdup (basename);
else
new_remote = g_strdup_printf ("%s-%d", basename, i);
i++;
}
while (remotes != NULL && g_strv_contains ((const char * const*)remotes, new_remote));
config = flatpak_dir_parse_repofile (dir, new_remote, dep_data, &gpg_key, NULL, error);
if (config == NULL)
{
g_prefix_error (error, "Can't parse dependent file %s", dep_url);
return FALSE;
}
/* See if it already exists */
group = g_strdup_printf ("remote \"%s\"", new_remote);
runtime_url = g_key_file_get_string (config, group, "url", NULL);
g_assert (runtime_url != NULL);
old_remote = flatpak_dir_find_remote_by_uri (dir, runtime_url);
if (old_remote == NULL && flatpak_dir_is_user (dir))
{
g_autoptr(FlatpakDir) system_dir = flatpak_dir_get_system ();
old_remote = flatpak_dir_find_remote_by_uri (system_dir, runtime_url);
}
if (old_remote != NULL)
return TRUE;
if (flatpak_yes_no_prompt (_("This application depends on runtimes from:\n %s\nConfigure this as new remote '%s'"),
runtime_url, new_remote))
{
if (!flatpak_dir_modify_remote (dir, new_remote, config, gpg_key, NULL, error))
return FALSE;
if (!flatpak_dir_recreate_repo (dir, NULL, error))
return FALSE;
}
return TRUE;
}
static gboolean
install_from (FlatpakDir *dir,
@@ -194,6 +284,9 @@ 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))
return FALSE;
if (!flatpak_dir_create_remote_for_ref_file (dir, file_data, &remote, &ref, error))
return FALSE;

View File

@@ -897,6 +897,16 @@ flatpak_dir_ensure_path (FlatpakDir *self,
return flatpak_mkdir_p (self->basedir, cancellable, error);
}
/* Warning: This is not threadsafe, don't use in libflatpak */
gboolean
flatpak_dir_recreate_repo (FlatpakDir *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(OstreeRepo) old_repo = g_steal_pointer (&self->repo);
return flatpak_dir_ensure_repo (self, cancellable, error);
}
gboolean
flatpak_dir_ensure_repo (FlatpakDir *self,
GCancellable *cancellable,
@@ -5643,6 +5653,91 @@ flatpak_dir_create_origin_remote (FlatpakDir *self,
return g_steal_pointer (&remote);
}
GKeyFile *
flatpak_dir_parse_repofile (FlatpakDir *self,
const char *remote_name,
GBytes *data,
GBytes **gpg_data_out,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
g_autofree char *remote = NULL;
g_autoptr(GError) local_error = NULL;
g_autoptr(GBytes) gpg_data = NULL;
g_autofree char *uri = NULL;
g_autofree char *title = NULL;
g_autofree char *gpg_key = NULL;
g_autofree char *default_branch = NULL;
gboolean nodeps;
GKeyFile *config = g_key_file_new ();
g_autofree char *group = g_strdup_printf ("remote \"%s\"", remote_name);
if (!g_key_file_load_from_data (keyfile,
g_bytes_get_data (data, NULL),
g_bytes_get_size (data),
0, &local_error))
{
flatpak_fail (error, "Invalid .flatpakref: %s\n", local_error->message);
return NULL;
}
if (!g_key_file_has_group (keyfile, FLATPAK_REPO_GROUP))
{
flatpak_fail (error, "Invalid .flatpakref\n");
return NULL;
}
uri = g_key_file_get_string (keyfile, FLATPAK_REPO_GROUP,
FLATPAK_REPO_URL_KEY, NULL);
if (uri == NULL)
{
flatpak_fail (error, "Invalid .flatpakref\n");
return NULL;
}
g_key_file_set_string (config, group, "url", uri);
title = g_key_file_get_locale_string (keyfile, FLATPAK_REPO_GROUP,
FLATPAK_REPO_TITLE_KEY, NULL, NULL);
if (title != NULL)
g_key_file_set_string (config, group, "xa.title", title);
default_branch = g_key_file_get_locale_string (keyfile, FLATPAK_REPO_GROUP,
FLATPAK_REPO_DEFAULT_BRANCH_KEY, NULL, NULL);
if (default_branch != NULL)
g_key_file_set_string (config, group, "xa.default-branch", default_branch);
nodeps = g_key_file_get_boolean (keyfile, FLATPAK_REPO_GROUP,
FLATPAK_REPO_NODEPS_KEY, NULL);
if (nodeps)
g_key_file_set_boolean (config, group, "xa.nodeps", TRUE);
gpg_key = g_key_file_get_string (keyfile, FLATPAK_REPO_GROUP,
FLATPAK_REPO_GPGKEY_KEY, NULL);
if (gpg_key != NULL)
{
guchar *decoded;
gsize decoded_len;
gpg_key = g_strstrip (gpg_key);
decoded = g_base64_decode (gpg_key, &decoded_len);
if (decoded_len < 10) /* Check some minimal size so we don't get crap */
{
flatpak_fail (error, "Invalid gpg key\n");
return NULL;
}
gpg_data = g_bytes_new_take (decoded, decoded_len);
g_key_file_set_boolean (config, group, "gpg-verify", TRUE);
g_key_file_set_boolean (config, group, "gpg-verify-summary", TRUE);
}
*gpg_data_out = g_steal_pointer (&gpg_data);
return g_steal_pointer (&config);
}
static gboolean
parse_ref_file (GBytes *data,
char **name_out,

View File

@@ -39,12 +39,20 @@ GType flatpak_deploy_get_type (void);
#define FLATPAK_REF_GROUP "Flatpak Ref"
#define FLATPAK_REF_URL_KEY "Url"
#define FLATPAK_REF_RUNTIME_REPO_KEY "RuntimeRepo"
#define FLATPAK_REF_TITLE_KEY "Title"
#define FLATPAK_REF_GPGKEY_KEY "GPGKey"
#define FLATPAK_REF_IS_RUNTIME_KEY "IsRuntime"
#define FLATPAK_REF_NAME_KEY "Name"
#define FLATPAK_REF_BRANCH_KEY "Branch"
#define FLATPAK_REPO_GROUP "Flatpak Repo"
#define FLATPAK_REPO_URL_KEY "Url"
#define FLATPAK_REPO_TITLE_KEY "Title"
#define FLATPAK_REPO_DEFAULT_BRANCH_KEY "DefaultBranch"
#define FLATPAK_REPO_GPGKEY_KEY "GPGKey"
#define FLATPAK_REPO_NODEPS_KEY "NoDeps"
typedef struct
{
char *ref;
@@ -223,6 +231,9 @@ gboolean flatpak_dir_ensure_path (FlatpakDir *self,
gboolean flatpak_dir_use_child_repo (FlatpakDir *self);
gboolean flatpak_dir_ensure_system_child_repo (FlatpakDir *self,
GError **error);
gboolean flatpak_dir_recreate_repo (FlatpakDir *self,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_ensure_repo (FlatpakDir *self,
GCancellable *cancellable,
GError **error);
@@ -423,6 +434,12 @@ gboolean flatpak_dir_create_remote_for_ref_file (FlatpakDir *self,
char **remote_name_out,
char **ref_out,
GError **error);
GKeyFile * flatpak_dir_parse_repofile (FlatpakDir *self,
const char *remote_name,
GBytes *data,
GBytes **gpg_data_out,
GCancellable *cancellable,
GError **error);
char *flatpak_dir_find_remote_by_uri (FlatpakDir *self,
const char *uri);