lib: Add xdg_app_installation_install_bundle

tingping/wmclass
Alexander Larsson 2016-02-25 16:05:13 +01:00
parent cd13e9e21d
commit 382ae396b3
7 changed files with 186 additions and 28 deletions

View File

@ -122,7 +122,6 @@ install_bundle (XdgAppDir *dir,
OstreeRepo *repo;
g_auto(GLnxLockFile) lock = GLNX_LOCK_FILE_INIT;
g_autoptr(GVariant) metadata = NULL;
g_autoptr(GVariant) gpg_value = NULL;
g_autofree char *basename = NULL;
if (argc < 2)
@ -132,30 +131,16 @@ install_bundle (XdgAppDir *dir,
repo = xdg_app_dir_get_repo (dir);
if (!xdg_app_supports_bundles (repo))
return xdg_app_fail (error, "Your version of ostree is too old to support single-file bundles");
file = g_file_new_for_commandline_arg (filename);
metadata = xdg_app_bundle_load (file, &to_checksum, error);
metadata = xdg_app_bundle_load (file, &to_checksum,
&ref,
&origin,
&gpg_data,
error);
if (metadata == NULL)
return FALSE;
if (!g_variant_lookup (metadata, "ref", "s", &ref))
return xdg_app_fail (error, "Invalid bundle, no ref in metadata");
if (!g_variant_lookup (metadata, "origin", "s", &origin))
origin = NULL;
gpg_value = g_variant_lookup_value (metadata, "gpg-keys", G_VARIANT_TYPE("ay"));
if (gpg_value)
{
gsize n_elements;
const char *data = g_variant_get_fixed_array (gpg_value, &n_elements, 1);
gpg_data = g_bytes_new (data, n_elements);
}
if (opt_gpg_file != NULL)
{
/* Override gpg_data from file */

View File

@ -875,7 +875,7 @@ xdg_app_dir_pull_from_bundle (XdgAppDir *self,
if (!xdg_app_supports_bundles (self->repo))
return xdg_app_fail (error, "Your version of ostree is too old to support single-file bundles");
metadata = xdg_app_bundle_load (file, &to_checksum, error);
metadata = xdg_app_bundle_load (file, &to_checksum, NULL, NULL, NULL, error);
if (metadata == NULL)
return FALSE;

View File

@ -2335,6 +2335,9 @@ xdg_app_xml_parse (GInputStream *in,
GVariant *
xdg_app_bundle_load (GFile *file,
char **commit,
char **ref,
char **origin,
GBytes **gpg_keys,
GError **error)
{
g_autoptr(GVariant) delta = NULL;
@ -2362,6 +2365,35 @@ xdg_app_bundle_load (GFile *file,
metadata = g_variant_get_child_value (delta, 0);
if (ref != NULL)
{
if (!g_variant_lookup (metadata, "ref", "s", ref))
{
xdg_app_fail (error, "Invalid bundle, no ref in metadata");
return NULL;
}
}
if (origin != NULL)
{
if (!g_variant_lookup (metadata, "origin", "s", origin))
*origin = NULL;
}
if (gpg_keys != NULL)
{
g_autoptr(GVariant) gpg_value = g_variant_lookup_value (metadata, "gpg-keys",
G_VARIANT_TYPE("ay"));
if (gpg_value)
{
gsize n_elements;
const char *data = g_variant_get_fixed_array (gpg_value, &n_elements, 1);
*gpg_keys = g_bytes_new (data, n_elements);
}
else
*gpg_keys = NULL;
}
/* Make a copy of the data so we can return it after freeing the file */
return g_variant_new_from_bytes (g_variant_get_type (metadata),
g_bytes_new (g_variant_get_data (metadata),

View File

@ -186,6 +186,9 @@ gboolean xdg_app_repo_generate_appstream (OstreeRepo *repo,
GVariant * xdg_app_bundle_load (GFile *file,
char **commit,
char **ref,
char **origin,
GBytes **gpg_keys,
GError **error);

View File

@ -163,16 +163,10 @@ xdg_app_bundle_ref_new (GFile *file,
g_autofree char *full_ref = NULL;
g_autofree char *metadata_contents = NULL;
metadata = xdg_app_bundle_load (file, &commit, error);
metadata = xdg_app_bundle_load (file, &commit, &full_ref, NULL, NULL, error);
if (metadata == NULL)
return NULL;
if (!g_variant_lookup (metadata, "ref", "s", &full_ref))
{
xdg_app_fail (error, "Invalid bundle, no ref in metadata");
return NULL;
}
parts = xdg_app_decompose_ref (full_ref, error);
if (parts == NULL)
return NULL;

View File

@ -715,6 +715,144 @@ progress_cb (OstreeAsyncProgress *progress, gpointer user_data)
g_string_free (buf, TRUE);
}
/**
* xdg_app_installation_install_bundle:
* @self: a #XdgAppInstallation
* @file: a #GFile that is an xdg-app bundle
* @progress: (scope call): progress callback
* @progress_data: user data passed to @progress
* @cancellable: (nullable): a #GCancellable
* @error: return location for a #GError
*
* Install a new ref from a bundle.
*
* Returns: (transfer full): The ref for the newly installed app or %NULL on failure
*/
XdgAppInstalledRef *
xdg_app_installation_install_bundle (XdgAppInstallation *self,
GFile *file,
XdgAppProgressCallback progress,
gpointer progress_data,
GCancellable *cancellable,
GError **error)
{
XdgAppInstallationPrivate *priv = xdg_app_installation_get_instance_private (self);
g_autofree char *ref = NULL;
gboolean created_deploy_base = FALSE;
gboolean added_remote = FALSE;
g_autoptr(GFile) deploy_base = NULL;
g_autoptr(XdgAppDir) dir_clone = NULL;
XdgAppInstalledRef *result = NULL;
g_autoptr(GError) local_error = NULL;
g_auto(GLnxLockFile) lock = GLNX_LOCK_FILE_INIT;
g_autoptr(GVariant) metadata = NULL;
g_autofree char *origin = NULL;
g_auto(GStrv) parts = NULL;
g_autofree char *basename = NULL;
g_autoptr(GBytes) gpg_data = NULL;
g_autofree char *to_checksum = NULL;
g_autofree char *remote = NULL;
metadata = xdg_app_bundle_load (file, &to_checksum,
&ref,
&origin,
&gpg_data,
error);
if (metadata == NULL)
return FALSE;
parts = xdg_app_decompose_ref (ref, error);
if (parts == NULL)
return FALSE;
deploy_base = xdg_app_dir_get_deploy_dir (priv->dir, ref);
if (g_file_query_exists (deploy_base, cancellable))
{
g_set_error (error,
XDG_APP_ERROR, XDG_APP_ERROR_ALREADY_INSTALLED,
"%s branch %s already installed", parts[1], parts[3]);
return NULL;
}
/* Add a remote for later updates */
basename = g_file_get_basename (file);
remote = xdg_app_dir_create_origin_remote (priv->dir,
origin,
parts[1],
basename,
gpg_data,
cancellable,
error);
if (remote == NULL)
return FALSE;
/* From here we need to goto out on error, to clean up */
added_remote = TRUE;
/* Pull, prune, etc are not threadsafe, so we work on a copy */
dir_clone = xdg_app_dir_clone (priv->dir);
if (!xdg_app_dir_pull_from_bundle (dir_clone,
file,
remote,
ref,
gpg_data != NULL,
cancellable,
error))
goto out;
if (!xdg_app_dir_lock (dir_clone, &lock,
cancellable, error))
goto out;
if (!g_file_make_directory_with_parents (deploy_base, cancellable, &local_error))
{
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
g_set_error (error,
XDG_APP_ERROR, XDG_APP_ERROR_ALREADY_INSTALLED,
"%s branch %s already installed", parts[1], parts[3]);
else
g_propagate_error (error, g_steal_pointer (&local_error));
goto out;
}
created_deploy_base = TRUE;
if (!xdg_app_dir_set_origin (dir_clone, ref, remote, cancellable, error))
goto out;
if (!xdg_app_dir_deploy (dir_clone, ref, NULL, cancellable, error))
goto out;
if (strcmp (parts[0], "app") == 0)
{
if (!xdg_app_dir_make_current_ref (dir_clone, ref, cancellable, error))
goto out;
if (!xdg_app_dir_update_exports (dir_clone, parts[1], cancellable, error))
goto out;
}
result = get_ref (self, ref, cancellable);
glnx_release_lock_file (&lock);
xdg_app_dir_cleanup_removed (dir_clone, cancellable, NULL);
if (!xdg_app_dir_mark_changed (dir_clone, error))
goto out;
out:
if (created_deploy_base && result == NULL)
gs_shutil_rm_rf (deploy_base, cancellable, NULL);
if (added_remote && result == NULL)
ostree_repo_remote_delete (xdg_app_dir_get_repo (priv->dir), remote, NULL, NULL);
return result;
}
/**
* xdg_app_installation_install:
* @self: a #XdgAppInstallation

View File

@ -142,6 +142,12 @@ XDG_APP_EXTERN XdgAppInstalledRef * xdg_app_installation_update
gpointer progress_data,
GCancellable *cancellable,
GError **error);
XDG_APP_EXTERN XdgAppInstalledRef * xdg_app_installation_install_bundle (XdgAppInstallation *self,
GFile *file,
XdgAppProgressCallback progress,
gpointer progress_data,
GCancellable *cancellable,
GError **error);
XDG_APP_EXTERN gboolean xdg_app_installation_uninstall (XdgAppInstallation *self,
XdgAppRefKind kind,
const char *name,