installation: Make fetching remote refs work offline

Currently flatpak_installation_fetch_remote_ref_sync() does not work
offline. It returns an error when it fails to fetch the remote's summary
in flatpak_dir_get_remote_state(). This is a problem since GNOME
Software (or at least the Endless fork) uses this library function to
display apps it finds on a USB drive (see gs_plugin_refine_item_origin()
in gs-flatpak.c) and that's something that should work even offline.

So this commit changes flatpak_dir_get_remote_state_optional() so that
it accepts the only_cached option, and updates the call sites. Also have
fetch_remote_ref_sync() use flatpak_dir_get_remote_state_optional(),
which means that when we're offline we will use the xa.cache data in the
ostree-metadata ref as a list of refs list instead of using a summary.
However since the commit checksums are not in xa.cache, we don't have
enough information to form a FlatpakRemoteRef. So also call
ostree_repo_find_remotes_async() to get the commit from any LAN or USB
sources that may be available. This may not be very performant but at
least it only happens if the ref wasn't found in a remote summary; see
https://github.com/flatpak/flatpak/issues/1862

It's sad this code is so long-winded but it's difficult to break out a
helper function that could be shared with
list_remotes_for_configured_remote() above. Longer term we could improve
the ostree_repo_find_remotes_async() API and add options to remove the
need to manually handle OstreeRepoFinder objects.

Closes: #3114
Approved by: alexlarsson
This commit is contained in:
Matthew Leeds
2019-09-18 20:02:36 -07:00
committed by Atomic Bot
parent ed766dc6db
commit d647bc105e
6 changed files with 88 additions and 15 deletions

View File

@@ -664,7 +664,7 @@ flatpak_builtin_create_usb (int argc, char **argv, GCancellable *cancellable, GE
/* Try to update the repo metadata by creating a FlatpakRemoteState object,
* but don't fail on error because we want this to work offline. */
state = flatpak_dir_get_remote_state_optional (dir, remote_name, cancellable, &local_error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, &local_error);
if (state == NULL)
{
g_printerr (_("Warning: Couldn't update repo metadata for remote %s: %s\n"),

View File

@@ -882,6 +882,7 @@ gboolean flatpak_dir_remote_make_oci_summary (FlatpakDir *self,
GError **error);
FlatpakRemoteState * flatpak_dir_get_remote_state_optional (FlatpakDir *self,
const char *remote,
gboolean only_cached,
GCancellable *cancellable,
GError **error);
FlatpakRemoteState * flatpak_dir_get_remote_state_local_only (FlatpakDir *self,

View File

@@ -4153,7 +4153,7 @@ flatpak_dir_update_appstream (FlatpakDir *self,
is_oci = flatpak_dir_get_remote_oci (self, remote);
state = flatpak_dir_get_remote_state_optional (self, remote, cancellable, error);
state = flatpak_dir_get_remote_state_optional (self, remote, FALSE, cancellable, error);
if (state == NULL)
return FALSE;
@@ -10876,10 +10876,11 @@ flatpak_dir_get_remote_state_for_summary (FlatpakDir *self,
FlatpakRemoteState *
flatpak_dir_get_remote_state_optional (FlatpakDir *self,
const char *remote,
gboolean only_cached,
GCancellable *cancellable,
GError **error)
{
return _flatpak_dir_get_remote_state (self, remote, TRUE, FALSE, FALSE, NULL, NULL, cancellable, error);
return _flatpak_dir_get_remote_state (self, remote, TRUE, FALSE, only_cached, NULL, NULL, cancellable, error);
}
@@ -10902,7 +10903,7 @@ flatpak_dir_remote_has_ref (FlatpakDir *self,
g_autoptr(GError) local_error = NULL;
g_autoptr(FlatpakRemoteState) state = NULL;
state = flatpak_dir_get_remote_state_optional (self, remote, NULL, &local_error);
state = flatpak_dir_get_remote_state_optional (self, remote, FALSE, NULL, &local_error);
if (state == NULL)
{
g_debug ("Can't get state for remote %s: %s", remote, local_error->message);
@@ -11275,7 +11276,7 @@ flatpak_dir_find_remote_refs (FlatpakDir *self,
g_autoptr(FlatpakRemoteState) state = NULL;
GPtrArray *matched_refs;
state = flatpak_dir_get_remote_state_optional (self, remote, cancellable, error);
state = flatpak_dir_get_remote_state_optional (self, remote, FALSE, cancellable, error);
if (state == NULL)
return NULL;
@@ -11372,7 +11373,7 @@ flatpak_dir_find_remote_ref (FlatpakDir *self,
g_autoptr(FlatpakRemoteState) state = NULL;
g_autoptr(GError) my_error = NULL;
state = flatpak_dir_get_remote_state_optional (self, remote, cancellable, error);
state = flatpak_dir_get_remote_state_optional (self, remote, FALSE, cancellable, error);
if (state == NULL)
return NULL;

View File

@@ -1995,7 +1995,7 @@ flatpak_installation_install_full (FlatpakInstallation *self,
return NULL;
}
state = flatpak_dir_get_remote_state_optional (dir, remote_name, cancellable, error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, error);
if (state == NULL)
return NULL;
@@ -2158,7 +2158,7 @@ flatpak_installation_update_full (FlatpakInstallation *self,
if (remote_name == NULL)
return NULL;
state = flatpak_dir_get_remote_state_optional (dir, remote_name, cancellable, error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, error);
if (state == NULL)
return NULL;
@@ -2392,7 +2392,7 @@ flatpak_installation_fetch_remote_size_sync (FlatpakInstallation *self,
if (dir == NULL)
return FALSE;
state = flatpak_dir_get_remote_state_optional (dir, remote_name, cancellable, error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, error);
if (state == NULL)
return FALSE;
@@ -2433,7 +2433,7 @@ flatpak_installation_fetch_remote_metadata_sync (FlatpakInstallation *self,
if (dir == NULL)
return NULL;
state = flatpak_dir_get_remote_state_optional (dir, remote_name, cancellable, error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, error);
if (state == NULL)
return FALSE;
@@ -2598,7 +2598,7 @@ flatpak_installation_fetch_remote_ref_sync_full (FlatpakInstallation *self,
if (dir == NULL)
return NULL;
state = flatpak_dir_get_remote_state (dir, remote_name, (flags & FLATPAK_QUERY_FLAGS_ONLY_CACHED) != 0, cancellable, error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, (flags & FLATPAK_QUERY_FLAGS_ONLY_CACHED) != 0, cancellable, error);
if (state == NULL)
return NULL;
@@ -2624,6 +2624,77 @@ flatpak_installation_fetch_remote_ref_sync_full (FlatpakInstallation *self,
coll_ref = flatpak_collection_ref_new (collection_id, ref);
checksum = g_hash_table_lookup (ht, coll_ref);
/* Check LAN/USB sources too in case we're offline */
if (checksum == NULL && collection_id != NULL && *collection_id != '\0')
{
OstreeRepo *repo;
const char * const *default_repo_finders;
g_autoptr(GAsyncResult) result = NULL;
OstreeCollectionRef ostree_coll_ref;
const OstreeCollectionRef *refs[2] = { NULL, };
OstreeRepoFinder *finders[3] = { NULL, };
guint finder_index = 0;
gsize i;
g_autoptr(GMainContextPopDefault) context = NULL;
g_autoptr(OstreeRepoFinder) finder_mount = NULL, finder_avahi = NULL;
context = flatpak_main_context_new_default ();
ostree_coll_ref.collection_id = collection_id;
ostree_coll_ref.ref_name = ref;
refs[0] = &ostree_coll_ref;
if (!flatpak_dir_ensure_repo (dir, cancellable, error))
return NULL;
repo = flatpak_dir_get_repo (dir);
default_repo_finders = ostree_repo_get_default_repo_finders (repo);
if (default_repo_finders == NULL || g_strv_contains (default_repo_finders, "mount"))
{
finder_mount = OSTREE_REPO_FINDER (ostree_repo_finder_mount_new (NULL));
finders[finder_index++] = finder_mount;
}
if (default_repo_finders == NULL || g_strv_contains (default_repo_finders, "lan"))
{
g_autoptr(GError) local_error = NULL;
finder_avahi = OSTREE_REPO_FINDER (ostree_repo_finder_avahi_new (context));
finders[finder_index++] = finder_avahi;
/* The Avahi finder may fail to start on, for example, a CI server. */
ostree_repo_finder_avahi_start (OSTREE_REPO_FINDER_AVAHI (finder_avahi), &local_error);
if (local_error != NULL)
{
finders[--finder_index] = NULL;
g_clear_object (&finder_avahi);
}
}
if (finders[0] != NULL)
{
g_auto(OstreeRepoFinderResultv) results = NULL;
ostree_repo_find_remotes_async (repo, (const OstreeCollectionRef * const *)refs,
NULL, finders, NULL, cancellable, async_result_cb, &result);
while (result == NULL)
g_main_context_iteration (context, TRUE);
results = ostree_repo_find_remotes_finish (repo, result, error);
if (finder_avahi != NULL)
ostree_repo_finder_avahi_stop (OSTREE_REPO_FINDER_AVAHI (finder_avahi));
if (results == NULL)
return NULL;
for (i = 0; results[i] != NULL; i++)
{
checksum = g_hash_table_lookup (results[i]->ref_to_checksum, &ostree_coll_ref);
if (checksum != NULL)
break;
}
}
}
/* If there was not a match, it may be because the collection ID is
* not set in the local configuration, or it is wrong, so we resort to
* trying to match just the ref name */
@@ -2814,7 +2885,7 @@ flatpak_installation_list_remote_related_refs_sync (FlatpakInstallation *self,
if (dir == NULL)
return NULL;
state = flatpak_dir_get_remote_state_optional (dir, remote_name, cancellable, error);
state = flatpak_dir_get_remote_state_optional (dir, remote_name, FALSE, cancellable, error);
if (state == NULL)
return NULL;

View File

@@ -1412,7 +1412,7 @@ flatpak_transaction_ensure_remote_state (FlatpakTransaction *self,
if (state)
return flatpak_remote_state_ref (state);
state = flatpak_dir_get_remote_state_optional (priv->dir, remote, NULL, error);
state = flatpak_dir_get_remote_state_optional (priv->dir, remote, FALSE, NULL, error);
if (state)
g_hash_table_insert (priv->remote_states, state->remote_name, flatpak_remote_state_ref (state));

View File

@@ -645,7 +645,7 @@ handle_deploy (FlatpakSystemHelper *object,
return TRUE;
}
state = flatpak_dir_get_remote_state_optional (system, arg_origin, NULL, &error);
state = flatpak_dir_get_remote_state_optional (system, arg_origin, FALSE, NULL, &error);
if (state == NULL)
{
flatpak_invocation_return_error (invocation, error, "Error getting remote state");
@@ -885,7 +885,7 @@ handle_deploy_appstream (FlatpakSystemHelper *object,
return TRUE;
}
state = flatpak_dir_get_remote_state_optional (system, arg_origin, NULL, &error);
state = flatpak_dir_get_remote_state_optional (system, arg_origin, FALSE, NULL, &error);
if (state == NULL)
{
flatpak_invocation_return_error (invocation, error, "Error getting remote state");