installation: Return refs as updatable if related extensions are missing

While updating, if the related extension is missing on
the installation of an installed ref (could be an app or
runtime), FlatpakTransaction tends to "repair" the ref by
automatically downloading the related extension again and
restoring the overall functionality of the ref.

The related extension concerned that are the ones associated with
`should-download` to TRUE only.

Hence, teach the libflatpak API to do that same, so that clients
like gnome-software can mark those refs as updatable, if their
related extensions is missing.
This commit is contained in:
Umang Jain
2019-11-21 12:18:55 +05:30
committed by Alexander Larsson
parent c76dca8550
commit 61f9d19eae
4 changed files with 138 additions and 1 deletions

View File

@@ -902,6 +902,10 @@ GPtrArray * flatpak_dir_find_remote_related_for_metadata (FlatpakDir *se
GKeyFile *metakey,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_check_installed_ref_missing_related_ref (FlatpakDir *self,
FlatpakRemoteState *state,
const gchar *full_ref,
GCancellable *cancellable);
GPtrArray * flatpak_dir_find_remote_related (FlatpakDir *dir,
FlatpakRemoteState *state,
const char *ref,

View File

@@ -14034,6 +14034,41 @@ flatpak_dir_find_remote_related_for_metadata (FlatpakDir *self,
return g_steal_pointer (&related);
}
gboolean
flatpak_dir_check_installed_ref_missing_related_ref (FlatpakDir *self,
FlatpakRemoteState *state,
const gchar *full_ref,
GCancellable *cancellable)
{
g_autoptr(GPtrArray) remote_related_refs = NULL;
g_autoptr(GError) local_error = NULL;
guint j;
remote_related_refs = flatpak_dir_find_remote_related (self, state, full_ref,
cancellable, &local_error);
if (remote_related_refs == NULL)
{
g_warning ("Unable to get remote related refs for %s: %s", full_ref, local_error->message);
return FALSE;
}
for (j = 0; j < remote_related_refs->len; j++)
{
FlatpakRelated *rel = g_ptr_array_index (remote_related_refs, j);
g_autoptr(GFile) deploy = NULL;
if (!rel->download || flatpak_dir_ref_is_masked (self, rel->ref))
continue;
deploy = flatpak_dir_get_if_deployed (self, rel->ref, NULL, cancellable);
/* If the related extension ref was meant to be auto-installed but was not found to be
* deployed, return TRUE. It will be pulled in via a FlatpakTransaction's update-op again. */
if (rel->download && deploy == NULL)
return TRUE;
}
return FALSE;
}
GPtrArray *
flatpak_dir_find_remote_related (FlatpakDir *self,

View File

@@ -1002,6 +1002,11 @@ _ostree_collection_ref_free0 (OstreeCollectionRef *ref)
* it can have local updates available that has not been deployed. Look
* at commit vs latest_commit on installed apps for this.
*
* This also checks if any of #FlatpakInstalledRef has a missing #FlatpakRelatedRef
* (which has `should-download` set to %TRUE). If so, it adds the ref to the
* returning #GPtrArray to pull in the #FlatpakRelatedRef again via an update
* operation in #FlatpakTransaction.
*
* Returns: (transfer container) (element-type FlatpakInstalledRef): a GPtrArray of
* #FlatpakInstalledRef instances, or %NULL on error
*/
@@ -1079,6 +1084,7 @@ flatpak_installation_list_installed_refs_for_update (FlatpakInstallation *self,
for (i = 0; i < installed->len; i++)
{
g_autoptr(FlatpakRemoteState) state = NULL;
FlatpakInstalledRef *installed_ref = g_ptr_array_index (installed, i);
const char *remote_name = flatpak_installed_ref_get_origin (installed_ref);
g_autofree char *full_ref = flatpak_ref_format_ref (FLATPAK_REF (installed_ref));
@@ -1092,7 +1098,28 @@ flatpak_installation_list_installed_refs_for_update (FlatpakInstallation *self,
/* Note: local_commit may be NULL here */
if (remote_commit != NULL &&
g_strcmp0 (remote_commit, local_commit) != 0)
g_ptr_array_add (updates, g_object_ref (installed_ref));
{
g_ptr_array_add (updates, g_object_ref (installed_ref));
/* Don't check further, as we already added the installed_ref to @updates. */
continue;
}
/* Check if all "should-download" related refs for the ref are installed.
* If not, add the ref in @updates array so that it can be installed via
* FlatpakTransaction's update-op.
*
* This makes sure that the ref (maybe an app or runtime) remains in usable
* state and fixes itself through an update.
*/
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, error);
if (state == NULL)
continue;
if (flatpak_dir_check_installed_ref_missing_related_ref (dir, state, full_ref, cancellable))
{
g_ptr_array_add (updates, g_object_ref (installed_ref));
}
}
collection_refs = g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_collection_ref_free0);

View File

@@ -1073,6 +1073,76 @@ test_list_remote_refs (void)
}
}
static void
test_update_related_refs (void)
{
g_autoptr(FlatpakInstallation) inst = NULL;
g_autoptr(FlatpakTransaction) transaction = NULL;
g_autoptr(GPtrArray) updatable_refs = NULL;
g_autoptr(GPtrArray) related_refs = NULL;
g_autoptr(GError) error = NULL;
FlatpakInstalledRef *iref = NULL;
g_autoptr(FlatpakInstalledRef) runtime_ref = NULL;
gboolean res;
g_autofree char *app = NULL;
app = g_strdup_printf ("app/org.test.Hello/%s/master",
flatpak_get_default_arch ());
inst = flatpak_installation_new_user (NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (inst);
empty_installation (inst);
/* Install a runtime */
runtime_ref = flatpak_installation_install (inst,
repo_name,
FLATPAK_REF_KIND_RUNTIME,
"org.test.Platform",
NULL, "master", NULL, NULL, NULL,
&error);
g_assert_no_error (error);
g_assert (FLATPAK_IS_INSTALLED_REF (runtime_ref));
iref = flatpak_installation_install (inst,
repo_name,
FLATPAK_REF_KIND_APP,
"org.test.Hello",
NULL, "master", NULL, NULL, NULL,
&error);
g_assert_no_error (error);
g_assert (FLATPAK_IS_INSTALLED_REF (iref));
iref = NULL;
/* We expect no installed related refs (i.e. org.test.Hello.Locale) at this point */
related_refs = flatpak_installation_list_installed_related_refs_sync (inst, repo_name, app, NULL, &error);
g_assert_cmpint (related_refs->len, ==, 0);
updatable_refs = flatpak_installation_list_installed_refs_for_update (inst, NULL, &error);
g_assert_cmpint (updatable_refs->len, ==, 1);
iref = g_ptr_array_index (updatable_refs, 0);
g_assert_cmpstr (flatpak_ref_get_name (FLATPAK_REF (iref)), ==, "org.test.Hello");
/* Prepare an update transaction to update org.test.Hello. The missing related .Locale
extension should automatically be installed with it. */
transaction = flatpak_transaction_new_for_installation (inst, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (transaction);
res = flatpak_transaction_add_update (transaction, app, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
res = flatpak_transaction_run (transaction, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
iref = flatpak_installation_get_installed_ref (inst, FLATPAK_REF_KIND_RUNTIME, "org.test.Hello.Locale", NULL, NULL, NULL, &error);
g_assert_nonnull (iref);
g_assert_no_error (error);
}
static void
test_list_remote_related_refs (void)
{
@@ -3947,6 +4017,7 @@ main (int argc, char *argv[])
g_test_add_func ("/library/install-bundle", test_install_bundle);
g_test_add_func ("/library/install-flatpakref", test_install_flatpakref);
g_test_add_func ("/library/list-installed-related-refs", test_list_installed_related_refs);
g_test_add_func ("/library/update-related-refs", test_update_related_refs);
g_test_add_func ("/library/no-deploy", test_no_deploy);
g_test_add_func ("/library/bad-remote-name", test_bad_remote_name);
g_test_add_func ("/library/transaction-no-runtime", test_transaction_no_runtime);