Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transaction: Add new flatpak_transaction_add_rebase_and_uninstall() API #5332

Merged
merged 4 commits into from
Mar 30, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
transaction: Add new flatpak_transaction_add_rebase_and_uninstall() API
This mostly replaces `flatpak_transaction_add_rebase()`. It’s necessary
because the uninstall op for an eol-rebased app needs to be linked to
the install/update op for the rebased app, otherwise one op can proceed
after the other has failed (or they can be run in the wrong order) and
result in the old app being uninstalled but the new one not installed.

The following commit will port the internal flatpak `FlatpakTransaction`
subclasses to use it. Other consumers of `FlatpakTransaction` (such as
gnome-software) will have to be ported as well.

Signed-off-by: Philip Withnall <[email protected]>

Fixes: #3991
  • Loading branch information
pwithnall committed Mar 20, 2023
commit ea0f5c7878fc9a690f1f6d20c570b48a7cafb6aa
5 changes: 2 additions & 3 deletions common/flatpak-installation.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,9 +987,8 @@ end_of_lifed_with_rebase (FlatpakTransaction *transaction,
if (rebased_to_ref == NULL || remote == NULL)
return FALSE;

/* No need to call flatpak_transaction_add_uninstall() and
* flatpak_transaction_add_rebase() here since we only care about what needs
* an update
/* No need to call flatpak_transaction_add_rebase_and_uninstall() here since
* we only care about what needs an update
*/
g_ptr_array_add (*eol_rebase_refs, g_strdup (ref));
return TRUE;
Expand Down
120 changes: 116 additions & 4 deletions common/flatpak-transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ struct _FlatpakTransactionOperation
int run_after_prio; /* Higher => run later (when it becomes runnable). Used to run related ops (runtime extensions) before deps (apps using the runtime) */
GList *run_before_ops;
gboolean run_last; /* Run this after all the other apps that are not run_last */
FlatpakTransactionOperation *fail_if_op_fails; /* main app/runtime for related extensions, runtime for apps */
FlatpakTransactionOperation *fail_if_op_fails; /* main app/runtime for related extensions, runtime for apps, install/update for uninstalls of eol-rebase apps */
/* main app/runtime for related extensions, app for runtimes; could be multiple
* related-to-ops if this op is for a runtime which is needed by multiple apps
* in the transaction: */
Expand Down Expand Up @@ -1275,9 +1275,8 @@ flatpak_transaction_class_init (FlatpakTransactionClass *klass)
* ref.
*
* If the caller wants to install the rebased ref, they should call
* flatpak_transaction_add_uninstall() on @ref,
* flatpak_transaction_add_rebase() on @rebased_to_ref, and return %TRUE.
* Otherwise %FALSE may be returned.
* flatpak_transaction_add_rebase_and_uninstall() on @rebased_to_ref and @ref,
* and return %TRUE. Otherwise %FALSE may be returned.
*
* Returns: %TRUE if the operation on this end-of-lifed ref should
* be skipped (e.g. because the rebased ref has been added to the
Expand Down Expand Up @@ -2817,6 +2816,10 @@ flatpak_transaction_add_install (FlatpakTransaction *self,
* treat @ref as the result of following an eol-rebase, and data migration from
* the refs in @previous_ids will be set up.
*
* If you want to rebase the ref and uninstall the old version of it, consider
* using flatpak_transaction_add_rebase_and_uninstall() instead. It will add
* appropriate dependencies between the rebase and uninstall operations.
*
* See flatpak_transaction_add_install() for a description of @remote.
*
* Returns: %TRUE on success; %FALSE with @error set on failure.
Expand Down Expand Up @@ -2854,6 +2857,115 @@ flatpak_transaction_add_rebase (FlatpakTransaction *self,
return flatpak_transaction_add_ref (self, remote, decomposed, subpaths, previous_ids, NULL, FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE, NULL, NULL, FALSE, NULL, error);
}

/**
* flatpak_transaction_add_rebase_and_uninstall:
* @self: a #FlatpakTransaction
* @remote: the name of the remote
* @new_ref: the ref to rebase to
* @old_ref: the ref to uninstall
* @subpaths: (nullable): the subpaths to include, or %NULL to install the complete ref
* @previous_ids: (nullable) (array zero-terminated=1): Previous ids to add to the
* given ref. These should simply be the ids, not the full ref names (e.g. org.foo.Bar,
* not org.foo.Bar/x86_64/master).
* @error: return location for a #GError
*
* Adds updating the @previous_ids of the given @new_ref to this transaction,
* via either installing the @new_ref if it was not already present or updating
* it. This will treat @new_ref as the result of following an eol-rebase, and
* data migration from the refs in @previous_ids will be set up.
*
* Also adds an operation to uninstall @old_ref to this transaction. This
* operation will only be run if the operation to install/update @new_ref
* succeeds.
*
* If @old_ref is not already installed (which can happen if requesting to
* install an EOLed app, rather than update one which is already installed), the
* uninstall operation will silently not be added, and this function will behave
* similarly to flatpak_transaction_add_rebase().
*
* See flatpak_transaction_add_install() for a description of @remote.
*
* Returns: %TRUE on success; %FALSE with @error set on failure.
* Since: 1.15.4
*/
gboolean
flatpak_transaction_add_rebase_and_uninstall (FlatpakTransaction *self,
const char *remote,
const char *new_ref,
const char *old_ref,
const char **subpaths,
const char **previous_ids,
GError **error)
{
FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self);
const char *all_paths[] = { NULL };
g_autoptr(FlatpakDecomposed) old_decomposed = NULL;
g_autoptr(FlatpakDecomposed) new_decomposed = NULL;
g_autofree char *installed_origin = NULL;
g_autoptr(GError) local_error = NULL;
FlatpakTransactionOperation *rebase_op = NULL, *uninstall_op = NULL;

g_return_val_if_fail (new_ref != NULL, FALSE);
g_return_val_if_fail (old_ref != NULL, FALSE);
g_return_val_if_fail (remote != NULL, FALSE);
/* flatpak_transaction_add_rebase_and_uninstall() without previous_ids doesn't make sense */
g_return_val_if_fail (previous_ids != NULL, FALSE);

new_decomposed = flatpak_decomposed_new_from_ref (new_ref, error);
if (new_decomposed == NULL)
return FALSE;

old_decomposed = flatpak_decomposed_new_from_ref (old_ref, error);
if (old_decomposed == NULL)
return FALSE;

/* If we install with no special args pull all subpaths */
if (subpaths == NULL)
subpaths = all_paths;

if (dir_ref_is_installed (priv->dir, new_decomposed, &installed_origin, NULL))
remote = installed_origin;

/* Add the install/update and uninstall ops. */
if (!flatpak_transaction_add_ref (self, remote, new_decomposed, subpaths,
previous_ids, NULL,
FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE,
NULL, NULL, FALSE, &rebase_op, error))
return FALSE;

if (!flatpak_transaction_add_ref (self, NULL, old_decomposed, NULL, NULL, NULL,
FLATPAK_TRANSACTION_OPERATION_UNINSTALL,
NULL, NULL, FALSE, &uninstall_op, &local_error))
{
/* If the user is trying to install an eol-rebased app from scratch, the
* @old_ref can’t be uninstalled because it’s not installed already.
* Silently ignore that. */
if (g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_NOT_INSTALLED))
{
g_clear_error (&local_error);
}
else
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
}

/* Link the ops together so that the install/update is done first, and if
* that fails then the uninstall is skipped. @uninstall_op might be %NULL even
* if the flatpak_transaction_add_ref() call succeeded above, as this might be
* a no-deploy transaction. */
if (uninstall_op != NULL)
{
uninstall_op->non_fatal = TRUE;
uninstall_op->fail_if_op_fails = rebase_op;
flatpak_transaction_operation_add_related_to_op (uninstall_op, rebase_op);
run_operation_before (rebase_op, uninstall_op, 1);
}

return TRUE;
}

/**
* flatpak_transaction_add_install_bundle:
* @self: a #FlatpakTransaction
Expand Down
8 changes: 8 additions & 0 deletions common/flatpak-transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@ gboolean flatpak_transaction_add_rebase (FlatpakTransaction *self,
const char **previous_ids,
GError **error);
FLATPAK_EXTERN
gboolean flatpak_transaction_add_rebase_and_uninstall (FlatpakTransaction *self,
const char *remote,
const char *new_ref,
const char *old_ref,
const char **subpaths,
const char **previous_ids,
GError **error);
FLATPAK_EXTERN
gboolean flatpak_transaction_add_install_bundle (FlatpakTransaction *self,
GFile *file,
GBytes *gpg_data,
Expand Down
1 change: 1 addition & 0 deletions doc/reference/flatpak-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ flatpak_transaction_add_install
flatpak_transaction_add_install_bundle
flatpak_transaction_add_install_flatpakref
flatpak_transaction_add_rebase
flatpak_transaction_add_rebase_and_uninstall
flatpak_transaction_add_update
flatpak_transaction_add_uninstall
flatpak_transaction_add_default_dependency_sources
Expand Down