diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
index ce064eea..8b64ac09 100644
--- a/common/flatpak-dir.c
+++ b/common/flatpak-dir.c
@@ -6974,10 +6974,36 @@ flatpak_dir_remove_ref (FlatpakDir *self,
GCancellable *cancellable,
GError **error)
{
- if (!ostree_repo_set_ref_immediate (self->repo, remote_name, ref, NULL, cancellable, error))
+ if (flatpak_dir_use_system_helper (self, NULL))
+ {
+ const char *installation = flatpak_dir_get_id (self);
+ FlatpakSystemHelper *system_helper = flatpak_dir_get_system_helper (self);
+
+ /* If we don't have the system helper, we'll have to try and just remove
+ * the ref as an unprivileged user, which might fail later */
+ if (system_helper)
+ {
+ if (!flatpak_system_helper_call_remove_local_ref_sync (system_helper,
+ remote_name,
+ ref,
+ installation ? installation : "",
+ cancellable,
+ error))
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ if (!ostree_repo_set_ref_immediate (self->repo,
+ remote_name,
+ ref,
+ NULL,
+ cancellable,
+ error))
return FALSE;
- return TRUE;
+ return flatpak_dir_prune (self, cancellable, error);
}
gboolean
@@ -7033,58 +7059,6 @@ out:
return ret;
}
-static GHashTable *
-filter_out_deployed_refs (FlatpakDir *self,
- GHashTable *local_refs)
-{
- GHashTable *undeployed_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- g_autoptr(GVariant) deploy_data = NULL;
- GHashTableIter hash_iter;
- gpointer key;
-
- g_hash_table_iter_init (&hash_iter, local_refs);
- while (g_hash_table_iter_next (&hash_iter, &key, NULL))
- {
- g_autoptr(GVariant) deploy_data = flatpak_dir_get_deploy_data (self, key, NULL, NULL);
-
- if (!deploy_data)
- g_hash_table_add (undeployed_refs, g_strdup (key));
- }
-
- return undeployed_refs;
-}
-
-gboolean
-flatpak_dir_cleanup_undeployed_refs (FlatpakDir *self,
- GCancellable *cancellable,
- GError **error)
-{
- g_autoptr(GHashTable) local_refs = NULL;
- g_autoptr(GHashTable) undeployed_refs = NULL;
- GHashTableIter hash_iter;
- gpointer key;
-
- if (!ostree_repo_list_refs (self->repo, NULL, &local_refs, cancellable, error))
- return FALSE;
-
- undeployed_refs = filter_out_deployed_refs (self, local_refs);
- g_hash_table_iter_init (&hash_iter, undeployed_refs);
-
- while (g_hash_table_iter_next (&hash_iter, &key, NULL))
- {
- g_autofree gchar *remote = NULL;
- g_autofree gchar *ref = NULL;
-
- if (!ostree_parse_refspec (key, &remote, &ref, error))
- return FALSE;
-
- if (!flatpak_dir_remove_ref (self, remote, ref, cancellable, error))
- return FALSE;
- }
-
- return TRUE;
-}
-
gboolean
flatpak_dir_prune (FlatpakDir *self,
GCancellable *cancellable,
@@ -8055,6 +8029,101 @@ flatpak_dir_find_installed_ref (FlatpakDir *self,
return NULL;
}
+/* Given a list of refs in local_refspecs, remove any refs that have already
+ * been deployed and return a new GPtrArray containing only the undeployed
+ * refs. This is used by flatpak_dir_cleanup_undeployed_refs to determine
+ * which undeployed refs need to be removed from the local repository.
+ *
+ * Returns: (transfer-full): A #GPtrArray
+ */
+static GPtrArray *
+filter_out_deployed_refs (FlatpakDir *self,
+ GPtrArray *local_refspecs,
+ GError **error)
+{
+ g_autoptr(GPtrArray) undeployed_refs = g_ptr_array_new_full (local_refspecs->len, g_free);
+ gsize i;
+
+ for (i = 0; i < local_refspecs->len; ++i)
+ {
+ const gchar *refspec = g_ptr_array_index (local_refspecs, i);
+ g_autofree gchar *ref = NULL;
+ g_autoptr(GVariant) deploy_data = NULL;
+
+ if (!ostree_parse_refspec (refspec, NULL, &ref, error))
+ return FALSE;
+
+ deploy_data = flatpak_dir_get_deploy_data (self, ref, NULL, NULL);
+
+ if (!deploy_data)
+ g_ptr_array_add (undeployed_refs, g_strdup (refspec));
+ }
+
+ return g_steal_pointer (&undeployed_refs);
+}
+
+/**
+ * flatpak_dir_cleanup_undeployed_refs:
+ *
+ * Find all flatpak refs in the local repository which have not been deloyed
+ * in the dir and remove them from the repository. You might want to call this
+ * function if you pulled refs into the dir but then decided that you did
+ * not want to deploy them for some reason. Note that this does not prune
+ * objects bound to the cleaned up refs from the underlying OSTree repository,
+ * you should consider using flatpak_dir_prune to do that.
+ *
+ * @self: a #FlatpakDir
+ * @cancellable: (allow-none): a #GCancellable
+ * @error: (allow-none): a #GError
+ *
+ * Since: 0.10.0
+ * Returns: (transfer-full): %TRUE if cleaning up the refs suceeded, %FALSE
+ * otherwise
+ */
+gboolean
+flatpak_dir_cleanup_undeployed_refs (FlatpakDir *self,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GHashTable) local_refspecs = NULL;
+ g_autoptr(GPtrArray) local_flatpak_refspecs = NULL;
+ g_autoptr(GPtrArray) undeployed_refs = NULL;
+ gsize i = 0;
+
+ if (!ostree_repo_list_refs (self->repo, NULL, &local_refspecs, cancellable, error))
+ return FALSE;
+
+ local_flatpak_refspecs = find_matching_refs (local_refspecs,
+ NULL, NULL, NULL,
+ FLATPAK_KINDS_APP |
+ FLATPAK_KINDS_RUNTIME,
+ FIND_MATCHING_REFS_FLAGS_KEEP_REMOTE,
+ error);
+
+ if (!local_flatpak_refspecs)
+ return FALSE;
+
+ undeployed_refs = filter_out_deployed_refs (self, local_flatpak_refspecs, error);
+
+ if (!undeployed_refs)
+ return FALSE;
+
+ for (; i < undeployed_refs->len; ++i)
+ {
+ const char *refspec = g_ptr_array_index (undeployed_refs, i);
+ g_autofree gchar *remote = NULL;
+ g_autofree gchar *ref = NULL;
+
+ if (!ostree_parse_refspec (refspec, &remote, &ref, error))
+ return FALSE;
+
+ if (!flatpak_dir_remove_ref (self, remote, ref, cancellable, error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static FlatpakDir *
flatpak_dir_new_full (GFile *path, gboolean user, DirExtraData *extra_data)
{
diff --git a/data/org.freedesktop.Flatpak.xml b/data/org.freedesktop.Flatpak.xml
index 7136024c..267b02c9 100644
--- a/data/org.freedesktop.Flatpak.xml
+++ b/data/org.freedesktop.Flatpak.xml
@@ -111,6 +111,12 @@
+
+
+
+
+
+
diff --git a/system-helper/flatpak-system-helper.c b/system-helper/flatpak-system-helper.c
index 1f0cad9a..40576fbf 100644
--- a/system-helper/flatpak-system-helper.c
+++ b/system-helper/flatpak-system-helper.c
@@ -790,6 +790,49 @@ handle_update_remote (FlatpakSystemHelper *object,
return TRUE;
}
+static gboolean
+handle_remove_local_ref (FlatpakSystemHelper *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_remote,
+ const gchar *arg_ref,
+ const gchar *arg_installation)
+{
+ g_autoptr(FlatpakDir) system = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_debug ("RemoveLocalRef %s %s %s", arg_remote, arg_ref, arg_installation);
+
+ system = dir_get_system (arg_installation, &error);
+ if (system == NULL)
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (*arg_remote == 0 || strchr (arg_remote, '/') != NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid remote name: %s", arg_remote);
+ return TRUE;
+ }
+
+ if (!flatpak_dir_ensure_repo (system, NULL, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (!flatpak_dir_remove_ref (system, arg_remote, arg_ref, NULL, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ flatpak_system_helper_complete_remove_local_ref (object, invocation);
+
+ return TRUE;
+}
+
static gboolean
flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface,
GDBusMethodInvocation *invocation,
@@ -901,6 +944,16 @@ flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface,
action = "org.freedesktop.Flatpak.update-remote";
+ polkit_details_insert (details, "remote", remote);
+ }
+ else if (g_strcmp0 (method_name, "RemoveLocalRef") == 0)
+ {
+ const char *remote;
+
+ g_variant_get_child (parameters, 0, "&s", &remote);
+
+ action = "org.freedesktop.Flatpak.modify-repo";
+
polkit_details_insert (details, "remote", remote);
}
@@ -958,6 +1011,7 @@ on_bus_acquired (GDBusConnection *connection,
g_signal_connect (helper, "handle-install-bundle", G_CALLBACK (handle_install_bundle), NULL);
g_signal_connect (helper, "handle-configure-remote", G_CALLBACK (handle_configure_remote), NULL);
g_signal_connect (helper, "handle-update-remote", G_CALLBACK (handle_update_remote), NULL);
+ g_signal_connect (helper, "handle-remove-local-ref", G_CALLBACK (handle_remove_local_ref), NULL);
g_signal_connect (helper, "g-authorize-method",
G_CALLBACK (flatpak_authorize_method_handler),
diff --git a/system-helper/org.freedesktop.Flatpak.policy.in b/system-helper/org.freedesktop.Flatpak.policy.in
index 8c629c9f..daf8bdab 100644
--- a/system-helper/org.freedesktop.Flatpak.policy.in
+++ b/system-helper/org.freedesktop.Flatpak.policy.in
@@ -98,6 +98,21 @@
+
+
+ Update system repository
+ Authentication is required to update the system repository
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ yes
+
+
+
Install bundle
Authentication is required to install software
diff --git a/system-helper/org.freedesktop.Flatpak.rules.in b/system-helper/org.freedesktop.Flatpak.rules.in
index d2185238..c2ec6a96 100644
--- a/system-helper/org.freedesktop.Flatpak.rules.in
+++ b/system-helper/org.freedesktop.Flatpak.rules.in
@@ -2,7 +2,8 @@ polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.Flatpak.app-install" ||
action.id == "org.freedesktop.Flatpak.runtime-install"||
action.id == "org.freedesktop.Flatpak.app-uninstall" ||
- action.id == "org.freedesktop.Flatpak.runtime-uninstall") &&
+ action.id == "org.freedesktop.Flatpak.runtime-uninstall" ||
+ action.id == "org.freedesktop.Flatpak.modify-repo") &&
subject.active == true && subject.local == true &&
subject.isInGroup("@privileged_group@")) {
return polkit.Result.YES;