Merge pull request #4487 from flatpak/dont-mask-noenumerate-main-refs

dir: Don't mask the main ref of a noenumerate remote
This commit is contained in:
Philip Withnall
2021-11-02 11:14:37 +00:00
committed by GitHub
2 changed files with 312 additions and 18 deletions

View File

@@ -12283,7 +12283,7 @@ flatpak_dir_list_all_remote_refs (FlatpakDir *self,
{
summary = var_summary_from_gvariant (subsummary);
ref_map = var_summary_get_ref_map (summary);
populate_hash_table_from_refs_map (ret_all_refs, NULL, ref_map, NULL, state);
populate_hash_table_from_refs_map (ret_all_refs, NULL, ref_map, state->collection_id, state);
}
}
else if (state->summary != NULL)
@@ -14316,17 +14316,6 @@ flatpak_dir_modify_remote (FlatpakDir *self,
return TRUE;
}
static gboolean
remove_unless_decomposed_in_hash (gpointer key,
gpointer value,
gpointer user_data)
{
GHashTable *table = user_data;
const FlatpakDecomposed *d = key;
return !g_hash_table_contains (table, d);
}
gboolean
flatpak_dir_list_remote_refs (FlatpakDir *self,
FlatpakRemoteState *state,
@@ -14348,12 +14337,15 @@ flatpak_dir_list_remote_refs (FlatpakDir *self,
g_autoptr(GHashTable) decomposed_local_refs =
g_hash_table_new_full ((GHashFunc)flatpak_decomposed_hash, (GEqualFunc)flatpak_decomposed_equal, (GDestroyNotify)flatpak_decomposed_unref, NULL);
g_autoptr(GHashTable) local_refs = NULL;
g_autoptr(FlatpakDecomposed) decomposed_main_ref = NULL;
GHashTableIter hash_iter;
gpointer key;
g_autofree char *refspec_prefix = g_strconcat (state->remote_name, ":.", NULL);
g_autofree char *remote_main_ref = NULL;
/* For noenumerate remotes, only return data for already locally
* available refs */
* available refs, or the ref set as xa.main-ref on the remote, or
* extensions of that main ref */
if (!ostree_repo_list_refs (self->repo, refspec_prefix, &local_refs,
cancellable, error))
@@ -14363,15 +14355,44 @@ flatpak_dir_list_remote_refs (FlatpakDir *self,
while (g_hash_table_iter_next (&hash_iter, &key, NULL))
{
const char *refspec = key;
g_autoptr(FlatpakDecomposed) d = flatpak_decomposed_new_from_refspec (refspec, NULL);
g_autofree char *ref = NULL;
g_autoptr(FlatpakDecomposed) d = NULL;
if (!ostree_parse_refspec (refspec, NULL, &ref, error))
return FALSE;
d = flatpak_decomposed_new_from_col_ref (ref, state->collection_id, NULL);
if (d)
g_hash_table_insert (decomposed_local_refs, g_steal_pointer (&d), NULL);
}
/* Then we remove all remote refs not in the local refs set */
g_hash_table_foreach_remove (*refs,
remove_unless_decomposed_in_hash,
decomposed_local_refs);
remote_main_ref = flatpak_dir_get_remote_main_ref (self, state->remote_name);
if (remote_main_ref != NULL && *remote_main_ref != '\0')
decomposed_main_ref = flatpak_decomposed_new_from_col_ref (remote_main_ref, state->collection_id, NULL);
/* Then we remove all remote refs not in the local refs set, not the main
* ref, and not an extension of the main ref */
GLNX_HASH_TABLE_FOREACH_IT (*refs, it, FlatpakDecomposed *, d, void *, v)
{
if (g_hash_table_contains (decomposed_local_refs, d))
continue;
if (decomposed_main_ref != NULL)
{
g_autofree char *main_ref_id = NULL;
g_autofree char *main_ref_prefix = NULL;
if (flatpak_decomposed_equal (decomposed_main_ref, d))
continue;
main_ref_id = flatpak_decomposed_dup_id (decomposed_main_ref);
main_ref_prefix = g_strconcat (main_ref_id, ".", NULL);
if (flatpak_decomposed_id_has_prefix (d, main_ref_prefix))
continue;
}
g_hash_table_iter_remove (&it);
}
}
return TRUE;

View File

@@ -1129,6 +1129,63 @@ test_list_remote_refs (void)
}
}
/* Test the xa.noenumerate option on a remote, which should mask non-installed refs */
static void
test_list_remote_refs_noenumerate (void)
{
g_autoptr(FlatpakInstallation) inst = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) refs = NULL;
g_autoptr(FlatpakRemote) remote = NULL;
g_autoptr(FlatpakInstalledRef) runtime_ref = NULL;
gboolean res;
inst = flatpak_installation_new_user (NULL, &error);
g_assert_no_error (error);
empty_installation (inst);
refs = flatpak_installation_list_remote_refs_sync (inst, repo_name, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (refs);
g_assert_cmpint (refs->len, ==, 4);
/* Install a runtime */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
runtime_ref = flatpak_installation_install (inst,
repo_name,
FLATPAK_REF_KIND_RUNTIME,
"org.test.Platform",
NULL, "master", NULL, NULL, NULL,
&error);
G_GNUC_END_IGNORE_DEPRECATIONS
g_assert_no_error (error);
g_assert_true (FLATPAK_IS_INSTALLED_REF (runtime_ref));
/* Set xa.noenumerate=true */
remote = flatpak_installation_get_remote_by_name (inst, repo_name, NULL, &error);
g_assert_no_error (error);
flatpak_remote_set_noenumerate (remote, TRUE);
res = flatpak_installation_modify_remote (inst, remote, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
/* Only the platform should be visible */
g_clear_pointer (&refs, g_ptr_array_unref);
refs = flatpak_installation_list_remote_refs_sync (inst, repo_name, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (refs);
g_assert_cmpint (refs->len, ==, 1);
empty_installation (inst);
/* Set xa.noenumerate=false */
flatpak_remote_set_noenumerate (remote, FALSE);
res = flatpak_installation_modify_remote (inst, remote, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
}
static void
test_update_installed_ref_if_missing_runtime (void)
{
@@ -2845,6 +2902,9 @@ empty_installation (FlatpakInstallation *inst)
flatpak_installation_prune_local_repo (inst, NULL, &error);
g_assert_no_error (error);
flatpak_installation_drop_caches (inst, NULL, &error);
g_assert_no_error (error);
}
static int ready_count;
@@ -3541,6 +3601,107 @@ test_transaction_flatpakref_remote_creation (void)
remove_remote_system ("test-runtime-only-repo");
}
static gboolean
ready_check_origin_remote (FlatpakTransaction *transaction)
{
g_autoptr(FlatpakInstallation) installation = NULL;
g_autoptr(FlatpakRemoteRef) remote_ref = NULL;
g_autoptr(FlatpakRemote) remote = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *app = NULL;
installation = flatpak_transaction_get_installation (transaction);
app = g_strdup_printf ("app/org.test.Hello/%s/master",
flatpak_get_default_arch ());
/* The remote should return the ref set as xa.main-ref on it despite having xa.noenumerate set */
remote = flatpak_installation_get_remote_by_name (installation, "hello-origin", NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (remote);
g_assert_true (flatpak_remote_get_noenumerate (remote));
g_assert_cmpstr (flatpak_remote_get_main_ref (remote), ==, app);
remote_ref = flatpak_installation_fetch_remote_ref_sync (installation,
"hello-origin",
FLATPAK_REF_KIND_APP,
"org.test.Hello",
flatpak_get_default_arch (),
"master",
NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (remote_ref);
/* An extension with the main ref as a prefix should also be visible */
g_clear_object (&remote_ref);
remote_ref = flatpak_installation_fetch_remote_ref_sync (installation,
"hello-origin",
FLATPAK_REF_KIND_RUNTIME,
"org.test.Hello.Plugin.fun",
flatpak_get_default_arch (),
"v1",
NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (remote_ref);
return TRUE;
}
/* Test that installing a flatpakref causes an origin remote to be created when
* the file has no SuggestRemoteName= option, and check the options set on the
* remote */
static void
test_transaction_flatpakref_origin_remote_creation (void)
{
g_autoptr(FlatpakInstallation) user_inst = NULL;
g_autoptr(FlatpakTransaction) transaction = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *s = NULL;
g_autoptr(GBytes) data = NULL;
gboolean res;
user_inst = flatpak_installation_new_user (NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (user_inst);
empty_installation (user_inst);
assert_remote_not_in_installation (user_inst, "hello-origin");
assert_remote_not_in_installation (user_inst, "test-runtime-only-repo");
transaction = flatpak_transaction_new_for_installation (user_inst, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (transaction);
s = g_strconcat ("[Flatpak Ref]\n"
"Title=Test App\n"
"Name=org.test.Hello\n"
"Branch=master\n"
"Url=http://127.0.0.1:", httpd_port, "/test-without-runtime\n"
"IsRuntime=False\n"
"RuntimeRepo=http://127.0.0.1:", httpd_port, "/test-runtime-only/test-runtime-only-repo.flatpakrepo\n",
NULL);
data = g_bytes_new (s, strlen (s));
res = flatpak_transaction_add_install_flatpakref (transaction, data, &error);
g_assert_no_error (error);
g_assert_true (res);
g_signal_connect (transaction, "add-new-remote", G_CALLBACK (add_new_remote3), NULL);
g_signal_connect (transaction, "ready", G_CALLBACK (ready_check_origin_remote), NULL);
res = flatpak_transaction_run (transaction, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
assert_remote_in_installation (user_inst, "hello-origin");
assert_remote_in_installation (user_inst, "test-runtime-only-repo");
empty_installation (user_inst);
/* note: the origin remote will be removed automatically in the above prune */
assert_remote_not_in_installation (user_inst, "hello-origin");
remove_remote_user ("test-runtime-only-repo");
}
static gboolean
check_ready1_abort (FlatpakTransaction *transaction)
{
@@ -3760,6 +3921,115 @@ test_transaction_app_runtime_same_remote (void)
remove_remote_user ("aaatest-runtime-only-repo");
}
static gboolean
ready_set_nodeps_on_remote (FlatpakTransaction *transaction)
{
g_autoptr(FlatpakInstallation) installation = NULL;
g_autoptr(FlatpakRemote) remote = NULL;
g_autoptr(GError) error = NULL;
gboolean res;
installation = flatpak_transaction_get_installation (transaction);
/* Set the nodeps option on the runtime remote */
remote = flatpak_installation_get_remote_by_name (installation, "test-runtime-only-repo", NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (remote);
g_assert_false (flatpak_remote_get_nodeps (remote));
flatpak_remote_set_nodeps (remote, TRUE);
res = flatpak_installation_modify_remote (installation, remote, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
/* Abort since this transaction is already resolved; we need a new one */
return FALSE;
}
/* Test that setting xa.nodeps=true on the remote providing the runtime causes
* app installation to fail */
static void
test_remote_nodeps_option (void)
{
g_autoptr(FlatpakInstallation) user_inst = NULL;
g_autoptr(FlatpakRemote) remote = NULL;
g_autoptr(FlatpakTransaction) transaction = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *s = NULL;
g_autoptr(GBytes) data = NULL;
gboolean res;
user_inst = flatpak_installation_new_user (NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (user_inst);
empty_installation (user_inst);
assert_remote_not_in_installation (user_inst, "hello-origin");
assert_remote_not_in_installation (user_inst, "test-runtime-only-repo");
/* Set the nodeps option on the test-repo remote */
remote = flatpak_installation_get_remote_by_name (user_inst, "test-repo", NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (remote);
g_assert_false (flatpak_remote_get_nodeps (remote));
flatpak_remote_set_nodeps (remote, TRUE);
res = flatpak_installation_modify_remote (user_inst, remote, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
transaction = flatpak_transaction_new_for_installation (user_inst, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (transaction);
s = g_strconcat ("[Flatpak Ref]\n"
"Title=Test App\n"
"Name=org.test.Hello\n"
"Branch=master\n"
"Url=http://127.0.0.1:", httpd_port, "/test-without-runtime\n"
"IsRuntime=False\n"
"RuntimeRepo=http://127.0.0.1:", httpd_port, "/test-runtime-only/test-runtime-only-repo.flatpakrepo\n",
NULL);
data = g_bytes_new (s, strlen (s));
res = flatpak_transaction_add_install_flatpakref (transaction, data, &error);
g_assert_no_error (error);
g_assert_true (res);
g_signal_connect (transaction, "add-new-remote", G_CALLBACK (add_new_remote3), NULL);
g_signal_connect (transaction, "ready", G_CALLBACK (ready_set_nodeps_on_remote), NULL);
res = flatpak_transaction_run (transaction, NULL, &error);
g_assert_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ABORTED);
g_assert_false (res);
g_clear_error (&error);
/* Make a new transaction so the runtime resolution happens again */
g_clear_object (&transaction);
transaction = flatpak_transaction_new_for_installation (user_inst, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (transaction);
res = flatpak_transaction_add_install_flatpakref (transaction, data, &error);
g_assert_no_error (error);
g_assert_true (res);
g_signal_connect (transaction, "add-new-remote", G_CALLBACK (add_new_remote3), NULL);
res = flatpak_transaction_run (transaction, NULL, &error);
g_assert_error (error, FLATPAK_ERROR, FLATPAK_ERROR_RUNTIME_NOT_FOUND);
g_assert_false (res);
g_clear_error (&error);
/* Set nodeps back to false */
flatpak_remote_set_nodeps (remote, FALSE);
res = flatpak_installation_modify_remote (user_inst, remote, NULL, &error);
g_assert_no_error (error);
g_assert_true (res);
empty_installation (user_inst);
remove_remote_user ("hello-origin");
remove_remote_user ("test-runtime-only-repo");
}
typedef struct
{
GMainLoop *loop;
@@ -4662,6 +4932,7 @@ main (int argc, char *argv[])
g_test_add_func ("/library/remote-new", test_remote_new);
g_test_add_func ("/library/remote-new-from-file", test_remote_new_from_file);
g_test_add_func ("/library/list-remote-refs", test_list_remote_refs);
g_test_add_func ("/library/list-remote-refs-noenumerate", test_list_remote_refs_noenumerate);
g_test_add_func ("/library/list-remote-related-refs", test_list_remote_related_refs);
g_test_add_func ("/library/list-remote-related-refs-for-installed", test_list_remote_related_refs_for_installed);
g_test_add_func ("/library/list-refs", test_list_refs);
@@ -4675,9 +4946,11 @@ main (int argc, char *argv[])
g_test_add_func ("/library/transaction-install-uninstall", test_transaction_install_uninstall);
g_test_add_func ("/library/transaction-install-flatpakref", test_transaction_install_flatpakref);
g_test_add_func ("/library/transaction-flatpakref-remote-creation", test_transaction_flatpakref_remote_creation);
g_test_add_func ("/library/transaction-flatpakref-origin-remote-creation", test_transaction_flatpakref_origin_remote_creation);
g_test_add_func ("/library/transaction-deps", test_transaction_deps);
g_test_add_func ("/library/transaction-install-local", test_transaction_install_local);
g_test_add_func ("/library/transaction-app-runtime-same-remote", test_transaction_app_runtime_same_remote);
g_test_add_func ("/library/remote-nodeps-option", test_remote_nodeps_option);
g_test_add_func ("/library/instance", test_instance);
g_test_add_func ("/library/update-subpaths", test_update_subpaths);
g_test_add_func ("/library/overrides", test_overrides);