1520 lines
66 KiB
Diff
1520 lines
66 KiB
Diff
|
From 67165cf06b31da919cfcb9162b7d54704bc5ace4 Mon Sep 17 00:00:00 2001
|
|||
|
From: Kalev Lember <klember@redhat.com>
|
|||
|
Date: Tue, 16 Apr 2024 12:18:59 +0200
|
|||
|
Subject: [PATCH 1/3] Add initial support for preinstalling flatpaks
|
|||
|
|
|||
|
This adds new FlatpakTransaction API, and a new top level CLI command to
|
|||
|
preinstall flatpaks, that is to install flatpaks that are considered
|
|||
|
part of the operating system.
|
|||
|
|
|||
|
A new drop-in directory /etc/flatpak/preinstall.d/ allows configuring
|
|||
|
what apps should be preinstalled, and a new flatpak preinstall command
|
|||
|
installs and removes apps based on the current configuration.
|
|||
|
|
|||
|
A drop-in loupe.preinstall file can look something like this:
|
|||
|
|
|||
|
[Flatpak Preinstall]
|
|||
|
Name=org.gnome.Loupe
|
|||
|
Branch=stable
|
|||
|
IsRuntime=false
|
|||
|
|
|||
|
The corresponding API is flatpak_transaction_add_sync_preinstalled()
|
|||
|
which can be implemented by GUI clients to drive the actual installs
|
|||
|
on system startup.
|
|||
|
|
|||
|
Resolves: https://github.com/flatpak/flatpak/issues/5579
|
|||
|
---
|
|||
|
app/flatpak-builtins-preinstall.c | 160 +++++++++++++++
|
|||
|
app/flatpak-builtins.h | 1 +
|
|||
|
app/flatpak-main.c | 1 +
|
|||
|
app/meson.build | 1 +
|
|||
|
common/flatpak-dir-private.h | 18 +-
|
|||
|
common/flatpak-dir.c | 175 ++++++++++++++++-
|
|||
|
common/flatpak-installation.c | 2 +-
|
|||
|
common/flatpak-transaction.c | 166 ++++++++++++++--
|
|||
|
common/flatpak-transaction.h | 3 +
|
|||
|
doc/flatpak-docs.xml.in | 1 +
|
|||
|
doc/flatpak-preinstall.xml | 273 ++++++++++++++++++++++++++
|
|||
|
doc/meson.build | 1 +
|
|||
|
po/POTFILES.in | 1 +
|
|||
|
system-helper/flatpak-system-helper.c | 5 +-
|
|||
|
14 files changed, 785 insertions(+), 23 deletions(-)
|
|||
|
create mode 100644 app/flatpak-builtins-preinstall.c
|
|||
|
create mode 100644 doc/flatpak-preinstall.xml
|
|||
|
|
|||
|
diff --git a/app/flatpak-builtins-preinstall.c b/app/flatpak-builtins-preinstall.c
|
|||
|
new file mode 100644
|
|||
|
index 0000000..4ac6c4d
|
|||
|
--- /dev/null
|
|||
|
+++ b/app/flatpak-builtins-preinstall.c
|
|||
|
@@ -0,0 +1,160 @@
|
|||
|
+/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
|
|||
|
+ * Copyright © 2024 Red Hat, Inc
|
|||
|
+ *
|
|||
|
+ * This program is free software; you can redistribute it and/or
|
|||
|
+ * modify it under the terms of the GNU Lesser General Public
|
|||
|
+ * License as published by the Free Software Foundation; either
|
|||
|
+ * version 2.1 of the License, or (at your option) any later version.
|
|||
|
+ *
|
|||
|
+ * This library is distributed in the hope that it will be useful,
|
|||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
+ * Lesser General Public License for more details.
|
|||
|
+ *
|
|||
|
+ * You should have received a copy of the GNU Lesser General Public
|
|||
|
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
+ *
|
|||
|
+ * Authors:
|
|||
|
+ * Kalev Lember <klember@redhat.com>
|
|||
|
+ */
|
|||
|
+
|
|||
|
+#include "config.h"
|
|||
|
+
|
|||
|
+#include <locale.h>
|
|||
|
+#include <stdlib.h>
|
|||
|
+#include <unistd.h>
|
|||
|
+#include <string.h>
|
|||
|
+
|
|||
|
+#include <glib/gi18n.h>
|
|||
|
+
|
|||
|
+#include <gio/gunixinputstream.h>
|
|||
|
+
|
|||
|
+#include "libglnx.h"
|
|||
|
+
|
|||
|
+#include "flatpak-builtins.h"
|
|||
|
+#include "flatpak-builtins-utils.h"
|
|||
|
+#include "flatpak-transaction-private.h"
|
|||
|
+#include "flatpak-cli-transaction.h"
|
|||
|
+#include "flatpak-quiet-transaction.h"
|
|||
|
+#include "flatpak-utils-http-private.h"
|
|||
|
+#include "flatpak-utils-private.h"
|
|||
|
+#include "flatpak-error.h"
|
|||
|
+#include "flatpak-chain-input-stream-private.h"
|
|||
|
+
|
|||
|
+static char **opt_sideload_repos;
|
|||
|
+static gboolean opt_no_pull;
|
|||
|
+static gboolean opt_no_deploy;
|
|||
|
+static gboolean opt_no_related;
|
|||
|
+static gboolean opt_no_deps;
|
|||
|
+static gboolean opt_no_static_deltas;
|
|||
|
+static gboolean opt_include_sdk;
|
|||
|
+static gboolean opt_include_debug;
|
|||
|
+static gboolean opt_yes;
|
|||
|
+static gboolean opt_reinstall;
|
|||
|
+static gboolean opt_noninteractive;
|
|||
|
+
|
|||
|
+static GOptionEntry options[] = {
|
|||
|
+ { "no-pull", 0, 0, G_OPTION_ARG_NONE, &opt_no_pull, N_("Don't pull, only install from local cache"), NULL },
|
|||
|
+ { "no-deploy", 0, 0, G_OPTION_ARG_NONE, &opt_no_deploy, N_("Don't deploy, only download to local cache"), NULL },
|
|||
|
+ { "no-related", 0, 0, G_OPTION_ARG_NONE, &opt_no_related, N_("Don't install related refs"), NULL },
|
|||
|
+ { "no-deps", 0, 0, G_OPTION_ARG_NONE, &opt_no_deps, N_("Don't verify/install runtime dependencies"), NULL },
|
|||
|
+ { "no-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_no_static_deltas, N_("Don't use static deltas"), NULL },
|
|||
|
+ { "include-sdk", 0, 0, G_OPTION_ARG_NONE, &opt_include_sdk, N_("Additionally install the SDK used to build the given refs") },
|
|||
|
+ { "include-debug", 0, 0, G_OPTION_ARG_NONE, &opt_include_debug, N_("Additionally install the debug info for the given refs and their dependencies") },
|
|||
|
+ { "assumeyes", 'y', 0, G_OPTION_ARG_NONE, &opt_yes, N_("Automatically answer yes for all questions"), NULL },
|
|||
|
+ { "reinstall", 0, 0, G_OPTION_ARG_NONE, &opt_reinstall, N_("Uninstall first if already installed"), NULL },
|
|||
|
+ { "noninteractive", 0, 0, G_OPTION_ARG_NONE, &opt_noninteractive, N_("Produce minimal output and don't ask questions"), NULL },
|
|||
|
+ /* Translators: A sideload is when you install from a local USB drive rather than the Internet. */
|
|||
|
+ { "sideload-repo", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_sideload_repos, N_("Use this local repo for sideloads"), N_("PATH") },
|
|||
|
+ { NULL }
|
|||
|
+};
|
|||
|
+
|
|||
|
+gboolean
|
|||
|
+flatpak_builtin_preinstall (int argc, char **argv, GCancellable *cancellable, GError **error)
|
|||
|
+{
|
|||
|
+ g_autoptr(GOptionContext) context = NULL;
|
|||
|
+ g_autoptr(GPtrArray) dirs = NULL;
|
|||
|
+ g_autoptr(FlatpakDir) dir = NULL;
|
|||
|
+ g_autoptr(FlatpakTransaction) transaction = NULL;
|
|||
|
+
|
|||
|
+ context = g_option_context_new (_("- Install flatpaks that are part of the operating system"));
|
|||
|
+ g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
|||
|
+
|
|||
|
+ if (!flatpak_option_context_parse (context, options, &argc, &argv,
|
|||
|
+ FLATPAK_BUILTIN_FLAG_ALL_DIRS | FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO,
|
|||
|
+ &dirs, cancellable, error))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ /* Use the default dir */
|
|||
|
+ dir = g_object_ref (g_ptr_array_index (dirs, 0));
|
|||
|
+
|
|||
|
+ if (opt_noninteractive)
|
|||
|
+ opt_yes = TRUE; /* Implied */
|
|||
|
+
|
|||
|
+ if (!opt_noninteractive)
|
|||
|
+ g_print (_("Syncing preinstalled flatpaks…\n"));
|
|||
|
+
|
|||
|
+ if (opt_noninteractive)
|
|||
|
+ transaction = flatpak_quiet_transaction_new (dir, error);
|
|||
|
+ else
|
|||
|
+ transaction = flatpak_cli_transaction_new (dir, opt_yes, TRUE, FALSE, error);
|
|||
|
+ if (transaction == NULL)
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ flatpak_transaction_set_no_pull (transaction, opt_no_pull);
|
|||
|
+ flatpak_transaction_set_no_deploy (transaction, opt_no_deploy);
|
|||
|
+ flatpak_transaction_set_disable_static_deltas (transaction, opt_no_static_deltas);
|
|||
|
+ flatpak_transaction_set_disable_dependencies (transaction, opt_no_deps);
|
|||
|
+ flatpak_transaction_set_disable_related (transaction, opt_no_related);
|
|||
|
+ flatpak_transaction_set_reinstall (transaction, opt_reinstall);
|
|||
|
+ flatpak_transaction_set_auto_install_sdk (transaction, opt_include_sdk);
|
|||
|
+ flatpak_transaction_set_auto_install_debug (transaction, opt_include_debug);
|
|||
|
+
|
|||
|
+ for (int i = 0; opt_sideload_repos != NULL && opt_sideload_repos[i] != NULL; i++)
|
|||
|
+ flatpak_transaction_add_sideload_repo (transaction, opt_sideload_repos[i]);
|
|||
|
+
|
|||
|
+ if (!flatpak_transaction_add_sync_preinstalled (transaction, error))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ if (flatpak_transaction_is_empty (transaction))
|
|||
|
+ {
|
|||
|
+ g_print ("\n");
|
|||
|
+ g_print (_("Nothing to do.\n"));
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (!flatpak_transaction_run (transaction, cancellable, error))
|
|||
|
+ {
|
|||
|
+ if (g_error_matches (*error, FLATPAK_ERROR, FLATPAK_ERROR_ABORTED))
|
|||
|
+ g_clear_error (error); /* Don't report on stderr */
|
|||
|
+
|
|||
|
+ return FALSE;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+gboolean
|
|||
|
+flatpak_complete_preinstall (FlatpakCompletion *completion)
|
|||
|
+{
|
|||
|
+ g_autoptr(GOptionContext) context = NULL;
|
|||
|
+ g_autoptr(GPtrArray) dirs = NULL;
|
|||
|
+
|
|||
|
+ context = g_option_context_new ("");
|
|||
|
+ if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
|
|||
|
+ FLATPAK_BUILTIN_FLAG_ONE_DIR | FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO,
|
|||
|
+ &dirs, NULL, NULL))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ switch (completion->argc)
|
|||
|
+ {
|
|||
|
+ default: /* REF */
|
|||
|
+ flatpak_complete_options (completion, global_entries);
|
|||
|
+ flatpak_complete_options (completion, options);
|
|||
|
+ flatpak_complete_options (completion, user_entries);
|
|||
|
+ break;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
diff --git a/app/flatpak-builtins.h b/app/flatpak-builtins.h
|
|||
|
index 32a9c95..20eb227 100644
|
|||
|
--- a/app/flatpak-builtins.h
|
|||
|
+++ b/app/flatpak-builtins.h
|
|||
|
@@ -127,6 +127,7 @@ BUILTINPROTO (repair)
|
|||
|
BUILTINPROTO (create_usb)
|
|||
|
BUILTINPROTO (kill)
|
|||
|
BUILTINPROTO (history)
|
|||
|
+BUILTINPROTO (preinstall)
|
|||
|
|
|||
|
#undef BUILTINPROTO
|
|||
|
|
|||
|
diff --git a/app/flatpak-main.c b/app/flatpak-main.c
|
|||
|
index 4549889..d5794d9 100644
|
|||
|
--- a/app/flatpak-main.c
|
|||
|
+++ b/app/flatpak-main.c
|
|||
|
@@ -89,6 +89,7 @@ static FlatpakCommand commands[] = {
|
|||
|
{ "config", N_("Configure flatpak"), flatpak_builtin_config, flatpak_complete_config },
|
|||
|
{ "repair", N_("Repair flatpak installation"), flatpak_builtin_repair, flatpak_complete_repair },
|
|||
|
{ "create-usb", N_("Put applications or runtimes onto removable media"), flatpak_builtin_create_usb, flatpak_complete_create_usb },
|
|||
|
+ { "preinstall", N_("Install flatpaks that are part of the operating system"), flatpak_builtin_preinstall, flatpak_complete_preinstall },
|
|||
|
|
|||
|
/* translators: please keep the leading newline and space */
|
|||
|
{ N_("\n Find applications and runtimes") },
|
|||
|
diff --git a/app/meson.build b/app/meson.build
|
|||
|
index 258d582..8e6ef1d 100644
|
|||
|
--- a/app/meson.build
|
|||
|
+++ b/app/meson.build
|
|||
|
@@ -100,6 +100,7 @@ sources = [
|
|||
|
'flatpak-builtins-permission-set.c',
|
|||
|
'flatpak-builtins-permission-show.c',
|
|||
|
'flatpak-builtins-pin.c',
|
|||
|
+ 'flatpak-builtins-preinstall.c',
|
|||
|
'flatpak-builtins-ps.c',
|
|||
|
'flatpak-builtins-remote-add.c',
|
|||
|
'flatpak-builtins-remote-delete.c',
|
|||
|
diff --git a/common/flatpak-dir-private.h b/common/flatpak-dir-private.h
|
|||
|
index 871f40b..a10a202 100644
|
|||
|
--- a/common/flatpak-dir-private.h
|
|||
|
+++ b/common/flatpak-dir-private.h
|
|||
|
@@ -180,6 +180,7 @@ typedef enum {
|
|||
|
FLATPAK_HELPER_DEPLOY_FLAGS_APP_HINT = 1 << 5,
|
|||
|
FLATPAK_HELPER_DEPLOY_FLAGS_INSTALL_HINT = 1 << 6,
|
|||
|
FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PINNED = 1 << 7,
|
|||
|
+ FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PREINSTALLED = 1 << 8,
|
|||
|
} FlatpakHelperDeployFlags;
|
|||
|
|
|||
|
#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE | \
|
|||
|
@@ -189,18 +190,21 @@ typedef enum {
|
|||
|
FLATPAK_HELPER_DEPLOY_FLAGS_NO_INTERACTION | \
|
|||
|
FLATPAK_HELPER_DEPLOY_FLAGS_APP_HINT | \
|
|||
|
FLATPAK_HELPER_DEPLOY_FLAGS_INSTALL_HINT | \
|
|||
|
- FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PINNED)
|
|||
|
+ FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PINNED | \
|
|||
|
+ FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PREINSTALLED)
|
|||
|
|
|||
|
typedef enum {
|
|||
|
FLATPAK_HELPER_UNINSTALL_FLAGS_NONE = 0,
|
|||
|
FLATPAK_HELPER_UNINSTALL_FLAGS_KEEP_REF = 1 << 0,
|
|||
|
FLATPAK_HELPER_UNINSTALL_FLAGS_FORCE_REMOVE = 1 << 1,
|
|||
|
FLATPAK_HELPER_UNINSTALL_FLAGS_NO_INTERACTION = 1 << 2,
|
|||
|
+ FLATPAK_HELPER_UNINSTALL_FLAGS_UPDATE_PREINSTALLED = 1 << 3,
|
|||
|
} FlatpakHelperUninstallFlags;
|
|||
|
|
|||
|
#define FLATPAK_HELPER_UNINSTALL_FLAGS_ALL (FLATPAK_HELPER_UNINSTALL_FLAGS_KEEP_REF | \
|
|||
|
FLATPAK_HELPER_UNINSTALL_FLAGS_FORCE_REMOVE | \
|
|||
|
- FLATPAK_HELPER_UNINSTALL_FLAGS_NO_INTERACTION)
|
|||
|
+ FLATPAK_HELPER_UNINSTALL_FLAGS_NO_INTERACTION | \
|
|||
|
+ FLATPAK_HELPER_UNINSTALL_FLAGS_UPDATE_PREINSTALLED)
|
|||
|
|
|||
|
typedef enum {
|
|||
|
FLATPAK_HELPER_CONFIGURE_REMOTE_FLAGS_NONE = 0,
|
|||
|
@@ -364,6 +368,14 @@ gboolean flatpak_remove_override_keyfile (const char *app_id,
|
|||
|
gboolean user,
|
|||
|
GError **error);
|
|||
|
|
|||
|
+char ** flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
+ GError **error);
|
|||
|
+gboolean flatpak_parse_preinstall_config_file (const char *file_path,
|
|||
|
+ const char *default_arch,
|
|||
|
+ FlatpakDecomposed **ref_out,
|
|||
|
+ char **collection_id_out,
|
|||
|
+ GError **error);
|
|||
|
+
|
|||
|
int flatpak_deploy_data_get_version (GBytes *deploy_data);
|
|||
|
const char * flatpak_deploy_data_get_origin (GBytes *deploy_data);
|
|||
|
const char * flatpak_deploy_data_get_commit (GBytes *deploy_data);
|
|||
|
@@ -679,6 +691,7 @@ gboolean flatpak_dir_deploy_install (Fla
|
|||
|
const char **previous_ids,
|
|||
|
gboolean reinstall,
|
|||
|
gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy,
|
|||
|
GCancellable *cancellable,
|
|||
|
GError **error);
|
|||
|
gboolean flatpak_dir_install (FlatpakDir *self,
|
|||
|
@@ -688,6 +701,7 @@ gboolean flatpak_dir_install (Fla
|
|||
|
gboolean reinstall,
|
|||
|
gboolean app_hint,
|
|||
|
gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy,
|
|||
|
FlatpakRemoteState *state,
|
|||
|
FlatpakDecomposed *ref,
|
|||
|
const char *opt_commit,
|
|||
|
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
|
|||
|
index 6936d45..295f610 100644
|
|||
|
--- a/common/flatpak-dir.c
|
|||
|
+++ b/common/flatpak-dir.c
|
|||
|
@@ -84,6 +84,15 @@
|
|||
|
#define FLATPAK_REMOTES_DIR "remotes.d"
|
|||
|
#define FLATPAK_REMOTES_FILE_EXT ".flatpakrepo"
|
|||
|
|
|||
|
+#define FLATPAK_PREINSTALL_DIR "preinstall.d"
|
|||
|
+#define FLATPAK_PREINSTALL_FILE_EXT ".preinstall"
|
|||
|
+
|
|||
|
+#define FLATPAK_PREINSTALL_GROUP "Flatpak Preinstall"
|
|||
|
+#define FLATPAK_PREINSTALL_IS_RUNTIME_KEY "IsRuntime"
|
|||
|
+#define FLATPAK_PREINSTALL_NAME_KEY "Name"
|
|||
|
+#define FLATPAK_PREINSTALL_BRANCH_KEY "Branch"
|
|||
|
+#define FLATPAK_PREINSTALL_COLLECTION_ID_KEY "CollectionID"
|
|||
|
+
|
|||
|
#define SIDELOAD_REPOS_DIR_NAME "sideload-repos"
|
|||
|
|
|||
|
#define FLATPAK_TRIGGERS_DIR "triggers"
|
|||
|
@@ -1899,6 +1908,151 @@ get_system_locations (GCancellable *cancellable,
|
|||
|
return g_steal_pointer (&locations);
|
|||
|
}
|
|||
|
|
|||
|
+char **
|
|||
|
+flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
+ GError **error)
|
|||
|
+{
|
|||
|
+ g_autoptr(GPtrArray) paths = NULL;
|
|||
|
+ g_autoptr(GFile) conf_dir = NULL;
|
|||
|
+ g_autoptr(GFileEnumerator) dir_enum = NULL;
|
|||
|
+ g_autoptr(GError) my_error = NULL;
|
|||
|
+ g_autofree char *config_dir = NULL;
|
|||
|
+
|
|||
|
+ paths = g_ptr_array_new_with_free_func (g_free);
|
|||
|
+ config_dir = g_strdup_printf ("%s/%s",
|
|||
|
+ get_config_dir_location (),
|
|||
|
+ FLATPAK_PREINSTALL_DIR);
|
|||
|
+
|
|||
|
+ if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR))
|
|||
|
+ {
|
|||
|
+ g_info ("Skipping missing preinstall config directory %s", config_dir);
|
|||
|
+ goto out;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ conf_dir = g_file_new_for_path (config_dir);
|
|||
|
+ dir_enum = g_file_enumerate_children (conf_dir,
|
|||
|
+ G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
|||
|
+ G_FILE_QUERY_INFO_NONE,
|
|||
|
+ cancellable, &my_error);
|
|||
|
+ if (my_error != NULL)
|
|||
|
+ {
|
|||
|
+ g_info ("Unexpected error retrieving preinstalls from %s: %s",
|
|||
|
+ config_dir, my_error->message);
|
|||
|
+ g_propagate_error (error, g_steal_pointer (&my_error));
|
|||
|
+ return NULL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ while (TRUE)
|
|||
|
+ {
|
|||
|
+ GFileInfo *file_info;
|
|||
|
+ GFile *path;
|
|||
|
+ const char *name;
|
|||
|
+ guint32 type;
|
|||
|
+
|
|||
|
+ if (!g_file_enumerator_iterate (dir_enum, &file_info, &path,
|
|||
|
+ cancellable, &my_error))
|
|||
|
+ {
|
|||
|
+ g_info ("Unexpected error reading file in %s: %s",
|
|||
|
+ config_dir, my_error->message);
|
|||
|
+ g_propagate_error (error, g_steal_pointer (&my_error));
|
|||
|
+ return NULL;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ if (file_info == NULL)
|
|||
|
+ break;
|
|||
|
+
|
|||
|
+ name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
|
|||
|
+ type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
|
|||
|
+
|
|||
|
+ if (type == G_FILE_TYPE_REGULAR && g_str_has_suffix (name, FLATPAK_PREINSTALL_FILE_EXT))
|
|||
|
+ {
|
|||
|
+ g_autofree char *path_str = g_file_get_path (path);
|
|||
|
+ g_ptr_array_add (paths, g_steal_pointer (&path_str));
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+out:
|
|||
|
+ g_ptr_array_add (paths, NULL);
|
|||
|
+ return (char **) g_ptr_array_free (g_steal_pointer (&paths), FALSE);
|
|||
|
+}
|
|||
|
+
|
|||
|
+static gboolean
|
|||
|
+parse_preinstall_keyfile (GKeyFile *keyfile,
|
|||
|
+ char **name_out,
|
|||
|
+ char **branch_out,
|
|||
|
+ gboolean *is_runtime_out,
|
|||
|
+ char **collection_id_out,
|
|||
|
+ GError **error)
|
|||
|
+{
|
|||
|
+ g_autofree char *name = NULL;
|
|||
|
+ g_autofree char *branch = NULL;
|
|||
|
+ gboolean is_runtime = FALSE;
|
|||
|
+ g_autofree char *collection_id = NULL;
|
|||
|
+
|
|||
|
+ *name_out = NULL;
|
|||
|
+ *branch_out = NULL;
|
|||
|
+ *is_runtime_out = FALSE;
|
|||
|
+ *collection_id_out = NULL;
|
|||
|
+
|
|||
|
+ if (!g_key_file_has_group (keyfile, FLATPAK_PREINSTALL_GROUP))
|
|||
|
+ return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Invalid file format, no %s group"), FLATPAK_PREINSTALL_GROUP);
|
|||
|
+
|
|||
|
+ name = g_key_file_get_string (keyfile, FLATPAK_PREINSTALL_GROUP,
|
|||
|
+ FLATPAK_PREINSTALL_NAME_KEY, NULL);
|
|||
|
+ if (name == NULL)
|
|||
|
+ return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Invalid file format, no %s specified"), FLATPAK_PREINSTALL_NAME_KEY);
|
|||
|
+
|
|||
|
+ branch = g_key_file_get_string (keyfile, FLATPAK_PREINSTALL_GROUP,
|
|||
|
+ FLATPAK_PREINSTALL_BRANCH_KEY, NULL);
|
|||
|
+ if (branch == NULL)
|
|||
|
+ branch = g_strdup ("master");
|
|||
|
+
|
|||
|
+ is_runtime = g_key_file_get_boolean (keyfile, FLATPAK_PREINSTALL_GROUP,
|
|||
|
+ FLATPAK_PREINSTALL_IS_RUNTIME_KEY, NULL);
|
|||
|
+
|
|||
|
+ collection_id = flatpak_keyfile_get_string_non_empty (keyfile, FLATPAK_PREINSTALL_GROUP,
|
|||
|
+ FLATPAK_PREINSTALL_COLLECTION_ID_KEY);
|
|||
|
+
|
|||
|
+ *name_out = g_steal_pointer (&name);
|
|||
|
+ *branch_out = g_steal_pointer (&branch);
|
|||
|
+ *is_runtime_out = is_runtime;
|
|||
|
+ *collection_id_out = g_steal_pointer (&collection_id);
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+gboolean
|
|||
|
+flatpak_parse_preinstall_config_file (const char *file_path,
|
|||
|
+ const char *default_arch,
|
|||
|
+ FlatpakDecomposed **ref_out,
|
|||
|
+ char **collection_id_out,
|
|||
|
+ GError **error)
|
|||
|
+{
|
|||
|
+ g_autofree char *name = NULL;
|
|||
|
+ g_autofree char *branch = NULL;
|
|||
|
+ gboolean is_runtime = FALSE;
|
|||
|
+ g_autofree char *collection_id = NULL;
|
|||
|
+ g_autoptr(FlatpakDecomposed) ref = NULL;
|
|||
|
+ g_autoptr(GKeyFile) keyfile = NULL;
|
|||
|
+
|
|||
|
+ keyfile = g_key_file_new ();
|
|||
|
+
|
|||
|
+ if (!g_key_file_load_from_file (keyfile, file_path, G_KEY_FILE_NONE, error))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ if (!parse_preinstall_keyfile (keyfile, &name, &branch, &is_runtime, &collection_id, error))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ ref = flatpak_decomposed_new_from_parts (is_runtime ? FLATPAK_KINDS_RUNTIME : FLATPAK_KINDS_APP,
|
|||
|
+ name, default_arch, branch, error);
|
|||
|
+ if (ref == NULL)
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ *ref_out = g_steal_pointer (&ref);
|
|||
|
+ *collection_id_out = g_steal_pointer (&collection_id);
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
GPtrArray *
|
|||
|
flatpak_get_system_base_dir_locations (GCancellable *cancellable,
|
|||
|
GError **error)
|
|||
|
@@ -9168,6 +9322,7 @@ flatpak_dir_deploy_install (FlatpakDir *self,
|
|||
|
const char **previous_ids,
|
|||
|
gboolean reinstall,
|
|||
|
gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy,
|
|||
|
GCancellable *cancellable,
|
|||
|
GError **error)
|
|||
|
{
|
|||
|
@@ -9273,6 +9428,14 @@ flatpak_dir_deploy_install (FlatpakDir *self,
|
|||
|
TRUE, NULL, error))
|
|||
|
goto out;
|
|||
|
|
|||
|
+ /* Save preinstalled refs to keep the data on what is user installed and what
|
|||
|
+ * is automatically installed. */
|
|||
|
+ if (update_preinstalled_on_deploy &&
|
|||
|
+ !flatpak_dir_config_append_pattern (self, "preinstalled",
|
|||
|
+ flatpak_decomposed_get_ref (ref),
|
|||
|
+ FALSE, NULL, error))
|
|||
|
+ goto out;
|
|||
|
+
|
|||
|
ret = TRUE;
|
|||
|
|
|||
|
commit = flatpak_dir_read_active (self, ref, cancellable);
|
|||
|
@@ -9873,6 +10036,7 @@ flatpak_dir_install (FlatpakDir *self,
|
|||
|
gboolean reinstall,
|
|||
|
gboolean app_hint,
|
|||
|
gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy,
|
|||
|
FlatpakRemoteState *state,
|
|||
|
FlatpakDecomposed *ref,
|
|||
|
const char *opt_commit,
|
|||
|
@@ -10085,6 +10249,9 @@ flatpak_dir_install (FlatpakDir *self,
|
|||
|
if (pin_on_deploy)
|
|||
|
helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PINNED;
|
|||
|
|
|||
|
+ if (update_preinstalled_on_deploy)
|
|||
|
+ helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PREINSTALLED;
|
|||
|
+
|
|||
|
helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_INSTALL_HINT;
|
|||
|
|
|||
|
if (!flatpak_dir_system_helper_call_deploy (self,
|
|||
|
@@ -10122,6 +10289,7 @@ flatpak_dir_install (FlatpakDir *self,
|
|||
|
{
|
|||
|
if (!flatpak_dir_deploy_install (self, ref, state->remote_name, opt_subpaths,
|
|||
|
opt_previous_ids, reinstall, pin_on_deploy,
|
|||
|
+ update_preinstalled_on_deploy,
|
|||
|
cancellable, error))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
@@ -10412,7 +10580,7 @@ flatpak_dir_install_bundle (FlatpakDir *self,
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
- if (!flatpak_dir_deploy_install (self, ref, remote, NULL, NULL, FALSE, FALSE, cancellable, error))
|
|||
|
+ if (!flatpak_dir_deploy_install (self, ref, remote, NULL, NULL, FALSE, FALSE, FALSE, cancellable, error))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
@@ -10842,6 +11010,7 @@ flatpak_dir_uninstall (FlatpakDir *self,
|
|||
|
g_autoptr(GBytes) deploy_data = NULL;
|
|||
|
gboolean keep_ref = flags & FLATPAK_HELPER_UNINSTALL_FLAGS_KEEP_REF;
|
|||
|
gboolean force_remove = flags & FLATPAK_HELPER_UNINSTALL_FLAGS_FORCE_REMOVE;
|
|||
|
+ gboolean update_preinstalled = flags & FLATPAK_HELPER_UNINSTALL_FLAGS_UPDATE_PREINSTALLED;
|
|||
|
|
|||
|
name = flatpak_decomposed_dup_id (ref);
|
|||
|
|
|||
|
@@ -10948,6 +11117,10 @@ flatpak_dir_uninstall (FlatpakDir *self,
|
|||
|
if (!flatpak_dir_mark_changed (self, error))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
+ if (update_preinstalled &&
|
|||
|
+ !flatpak_dir_config_remove_pattern (self, "preinstalled", flatpak_decomposed_get_ref (ref), error))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
if (!was_deployed)
|
|||
|
{
|
|||
|
const char *branch = flatpak_decomposed_get_branch (ref);
|
|||
|
diff --git a/common/flatpak-installation.c b/common/flatpak-installation.c
|
|||
|
index c7d2e1d..38d4e8d 100644
|
|||
|
--- a/common/flatpak-installation.c
|
|||
|
+++ b/common/flatpak-installation.c
|
|||
|
@@ -1929,7 +1929,7 @@ flatpak_installation_install_full (FlatpakInstallation *self,
|
|||
|
(flags & FLATPAK_INSTALL_FLAGS_NO_PULL) != 0,
|
|||
|
(flags & FLATPAK_INSTALL_FLAGS_NO_DEPLOY) != 0,
|
|||
|
(flags & FLATPAK_INSTALL_FLAGS_NO_STATIC_DELTAS) != 0,
|
|||
|
- FALSE, FALSE, FALSE, state,
|
|||
|
+ FALSE, FALSE, FALSE, FALSE, state,
|
|||
|
ref, NULL, (const char **) subpaths, NULL, NULL, NULL, NULL,
|
|||
|
progress, cancellable, error))
|
|||
|
return NULL;
|
|||
|
diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c
|
|||
|
index 7339aca..e4de909 100644
|
|||
|
--- a/common/flatpak-transaction.c
|
|||
|
+++ b/common/flatpak-transaction.c
|
|||
|
@@ -111,6 +111,7 @@ struct _FlatpakTransactionOperation
|
|||
|
gboolean skip;
|
|||
|
gboolean update_only_deploy;
|
|||
|
gboolean pin_on_deploy;
|
|||
|
+ gboolean update_preinstalled_on_deploy;
|
|||
|
|
|||
|
gboolean resolved;
|
|||
|
char *resolved_commit;
|
|||
|
@@ -650,7 +651,8 @@ flatpak_transaction_operation_new (const char *remote,
|
|||
|
const char *commit,
|
|||
|
GFile *bundle,
|
|||
|
FlatpakTransactionOperationType kind,
|
|||
|
- gboolean pin_on_deploy)
|
|||
|
+ gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy)
|
|||
|
{
|
|||
|
FlatpakTransactionOperation *self;
|
|||
|
|
|||
|
@@ -665,6 +667,7 @@ flatpak_transaction_operation_new (const char *remote,
|
|||
|
self->bundle = g_object_ref (bundle);
|
|||
|
self->kind = kind;
|
|||
|
self->pin_on_deploy = pin_on_deploy;
|
|||
|
+ self->update_preinstalled_on_deploy = update_preinstalled_on_deploy;
|
|||
|
|
|||
|
return self;
|
|||
|
}
|
|||
|
@@ -2115,7 +2118,8 @@ flatpak_transaction_add_op (FlatpakTransaction *self,
|
|||
|
const char *commit,
|
|||
|
GFile *bundle,
|
|||
|
FlatpakTransactionOperationType kind,
|
|||
|
- gboolean pin_on_deploy)
|
|||
|
+ gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy)
|
|||
|
{
|
|||
|
FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self);
|
|||
|
FlatpakTransactionOperation *op;
|
|||
|
@@ -2145,7 +2149,8 @@ flatpak_transaction_add_op (FlatpakTransaction *self,
|
|||
|
}
|
|||
|
|
|||
|
op = flatpak_transaction_operation_new (remote, ref, subpaths, previous_ids,
|
|||
|
- commit, bundle, kind, pin_on_deploy);
|
|||
|
+ commit, bundle, kind, pin_on_deploy,
|
|||
|
+ update_preinstalled_on_deploy);
|
|||
|
g_hash_table_insert (priv->last_op_for_ref, flatpak_decomposed_ref (ref), op);
|
|||
|
|
|||
|
priv->ops = g_list_prepend (priv->ops, op);
|
|||
|
@@ -2253,7 +2258,7 @@ add_related (FlatpakTransaction *self,
|
|||
|
related_op = flatpak_transaction_add_op (self, rel->remote, rel->ref,
|
|||
|
NULL, NULL, NULL, NULL,
|
|||
|
FLATPAK_TRANSACTION_OPERATION_UNINSTALL,
|
|||
|
- FALSE);
|
|||
|
+ FALSE, FALSE);
|
|||
|
related_op->non_fatal = TRUE;
|
|||
|
related_op->fail_if_op_fails = op;
|
|||
|
flatpak_transaction_operation_add_related_to_op (related_op, op);
|
|||
|
@@ -2282,7 +2287,7 @@ add_related (FlatpakTransaction *self,
|
|||
|
(const char **) rel->subpaths,
|
|||
|
NULL, NULL, NULL,
|
|||
|
FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE,
|
|||
|
- FALSE);
|
|||
|
+ FALSE, FALSE);
|
|||
|
related_op->non_fatal = TRUE;
|
|||
|
related_op->fail_if_op_fails = op;
|
|||
|
flatpak_transaction_operation_add_related_to_op (related_op, op);
|
|||
|
@@ -2513,7 +2518,7 @@ add_new_dep_op (FlatpakTransaction *self,
|
|||
|
return FALSE;
|
|||
|
|
|||
|
*dep_op = flatpak_transaction_add_op (self, dep_remote, dep_ref, NULL, NULL, NULL, NULL,
|
|||
|
- FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE, FALSE);
|
|||
|
+ FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE, FALSE, FALSE);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
@@ -2523,7 +2528,7 @@ add_new_dep_op (FlatpakTransaction *self,
|
|||
|
g_info ("Updating dependency %s of %s", flatpak_decomposed_get_pref (dep_ref),
|
|||
|
flatpak_decomposed_get_pref (op->ref));
|
|||
|
*dep_op = flatpak_transaction_add_op (self, dep_remote, dep_ref, NULL, NULL, NULL, NULL,
|
|||
|
- FLATPAK_TRANSACTION_OPERATION_UPDATE, FALSE);
|
|||
|
+ FLATPAK_TRANSACTION_OPERATION_UPDATE, FALSE, FALSE);
|
|||
|
(*dep_op)->non_fatal = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
@@ -2618,6 +2623,7 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
|
|||
|
GFile *bundle,
|
|||
|
const char *external_metadata,
|
|||
|
gboolean pin_on_deploy,
|
|||
|
+ gboolean update_preinstalled_on_deploy,
|
|||
|
FlatpakTransactionOperation **out_op,
|
|||
|
GError **error)
|
|||
|
{
|
|||
|
@@ -2741,7 +2747,8 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
|
|||
|
}
|
|||
|
|
|||
|
op = flatpak_transaction_add_op (self, remote, ref, subpaths, previous_ids,
|
|||
|
- commit, bundle, kind, pin_on_deploy);
|
|||
|
+ commit, bundle, kind, pin_on_deploy,
|
|||
|
+ update_preinstalled_on_deploy);
|
|||
|
|
|||
|
if (external_metadata)
|
|||
|
op->external_metadata = g_bytes_new (external_metadata, strlen (external_metadata));
|
|||
|
@@ -2796,7 +2803,7 @@ flatpak_transaction_add_install (FlatpakTransaction *self,
|
|||
|
|
|||
|
if (!flatpak_transaction_add_ref (self, remote, decomposed, subpaths, NULL, NULL,
|
|||
|
FLATPAK_TRANSACTION_OPERATION_INSTALL,
|
|||
|
- NULL, NULL, pin_on_deploy, NULL, error))
|
|||
|
+ NULL, NULL, pin_on_deploy, FALSE, NULL, error))
|
|||
|
return FALSE;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
@@ -2856,7 +2863,7 @@ flatpak_transaction_add_rebase (FlatpakTransaction *self,
|
|||
|
if (dir_ref_is_installed (priv->dir, decomposed, &installed_origin, NULL))
|
|||
|
remote = installed_origin;
|
|||
|
|
|||
|
- return flatpak_transaction_add_ref (self, remote, decomposed, subpaths, previous_ids, NULL, FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE, NULL, NULL, FALSE, NULL, error);
|
|||
|
+ return flatpak_transaction_add_ref (self, remote, decomposed, subpaths, previous_ids, NULL, FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE, NULL, NULL, FALSE, FALSE, NULL, error);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
@@ -2932,12 +2939,12 @@ flatpak_transaction_add_rebase_and_uninstall (FlatpakTransaction *self,
|
|||
|
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))
|
|||
|
+ NULL, NULL, FALSE, 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))
|
|||
|
+ NULL, NULL, FALSE, 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.
|
|||
|
@@ -3024,6 +3031,125 @@ flatpak_transaction_add_install_flatpakref (FlatpakTransaction *self,
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
+/**
|
|||
|
+ * flatpak_transaction_add_sync_preinstalled:
|
|||
|
+ * @self: a #FlatpakTransaction
|
|||
|
+ * @error: return location for a #GError
|
|||
|
+ *
|
|||
|
+ * Adds preinstall operations to this transaction. This can involve both
|
|||
|
+ * installing and removing refs, based on /etc/preinstall.d contents and what
|
|||
|
+ * the system had preinstalled before.
|
|||
|
+ *
|
|||
|
+ * Returns: %TRUE on success; %FALSE with @error set on failure.
|
|||
|
+ */
|
|||
|
+gboolean
|
|||
|
+flatpak_transaction_add_sync_preinstalled (FlatpakTransaction *self,
|
|||
|
+ GError **error)
|
|||
|
+{
|
|||
|
+ FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self);
|
|||
|
+ g_autoptr(GPtrArray) install_refs = g_ptr_array_new_with_free_func (g_free);
|
|||
|
+ g_autoptr(GPtrArray) preinstalled_refs = NULL;
|
|||
|
+ g_auto(GStrv) remotes = NULL;
|
|||
|
+ g_auto(GStrv) preinstall_paths = NULL;
|
|||
|
+
|
|||
|
+ remotes = flatpak_dir_list_remotes (priv->dir, NULL, error);
|
|||
|
+ if (remotes == NULL)
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ preinstalled_refs = flatpak_dir_get_config_patterns (priv->dir, "preinstalled");
|
|||
|
+
|
|||
|
+ preinstall_paths = flatpak_get_preinstall_config_file_paths (NULL, error);
|
|||
|
+ if (preinstall_paths == NULL)
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ /* Find preinstalls that should get installed */
|
|||
|
+ for (int i = 0; preinstall_paths[i] != NULL; i++)
|
|||
|
+ {
|
|||
|
+ const char *path = preinstall_paths[i];
|
|||
|
+ g_autoptr(FlatpakDecomposed) decomposed = NULL;
|
|||
|
+ g_autofree char *collection_id = NULL;
|
|||
|
+
|
|||
|
+ if (!flatpak_parse_preinstall_config_file (path, priv->default_arch, &decomposed, &collection_id, error))
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ g_info ("Found preinstall ref %s from config file %s", flatpak_decomposed_get_ref (decomposed), path);
|
|||
|
+
|
|||
|
+ /* Store for later */
|
|||
|
+ g_ptr_array_add (install_refs, flatpak_decomposed_dup_ref (decomposed));
|
|||
|
+
|
|||
|
+ /* Skip over if it's listed as previously preinstalled - it's now under
|
|||
|
+ * user's control and we no longer install it again, even if the user
|
|||
|
+ * manually removes it. */
|
|||
|
+ if (!priv->reinstall &&
|
|||
|
+ flatpak_g_ptr_array_contains_string (preinstalled_refs, flatpak_decomposed_get_ref (decomposed)))
|
|||
|
+ {
|
|||
|
+ g_info ("Preinstall ref %s is marked as already preinstalled; skipping", flatpak_decomposed_get_ref (decomposed));
|
|||
|
+ continue;
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ for (int j = 0; remotes[j] != NULL; j++)
|
|||
|
+ {
|
|||
|
+ const char *remote = remotes[j];
|
|||
|
+ g_autoptr(GError) local_error = NULL;
|
|||
|
+ g_autofree char *remote_collection_id = NULL;
|
|||
|
+
|
|||
|
+ if (flatpak_dir_get_remote_disabled (priv->dir, remote))
|
|||
|
+ continue;
|
|||
|
+
|
|||
|
+ remote_collection_id = flatpak_dir_get_remote_collection_id (priv->dir, remote);
|
|||
|
+
|
|||
|
+ /* Choose the first match if the collection ID was not specified */
|
|||
|
+ if (collection_id != NULL &&
|
|||
|
+ g_strcmp0 (remote_collection_id, collection_id) != 0)
|
|||
|
+ continue;
|
|||
|
+
|
|||
|
+ g_info ("Adding preinstall of %s from remote %s", flatpak_decomposed_get_ref (decomposed), remote);
|
|||
|
+
|
|||
|
+ if (!flatpak_transaction_add_ref (self, remote, decomposed, NULL, NULL, NULL,
|
|||
|
+ FLATPAK_TRANSACTION_OPERATION_INSTALL,
|
|||
|
+ NULL, NULL, FALSE, TRUE, NULL,
|
|||
|
+ &local_error))
|
|||
|
+ g_info ("Failed to add preinstall ref %s: %s", flatpak_decomposed_get_ref (decomposed),
|
|||
|
+ local_error->message);
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ /* Find previously preinstalled refs that are no longer in the preinstall
|
|||
|
+ * list and should now get uninstalled */
|
|||
|
+ for (guint i = 0; i < preinstalled_refs->len; i++)
|
|||
|
+ {
|
|||
|
+ const char *ref = g_ptr_array_index (preinstalled_refs, i);
|
|||
|
+
|
|||
|
+ /* No longer in the preinstall.d list, so uninstall */
|
|||
|
+ if (!flatpak_g_ptr_array_contains_string (install_refs, ref))
|
|||
|
+ {
|
|||
|
+ g_autoptr(GError) local_error = NULL;
|
|||
|
+ g_autoptr(FlatpakDecomposed) decomposed = NULL;
|
|||
|
+
|
|||
|
+ decomposed = flatpak_decomposed_new_from_ref (ref, error);
|
|||
|
+ if (decomposed == NULL)
|
|||
|
+ return FALSE;
|
|||
|
+
|
|||
|
+ g_info ("Preinstalled ref %s is no longer listed as wanted in preinstall.d config; uninstalling", flatpak_decomposed_get_ref (decomposed));
|
|||
|
+
|
|||
|
+ if (!flatpak_transaction_add_ref (self, NULL, decomposed, NULL, NULL, NULL, FLATPAK_TRANSACTION_OPERATION_UNINSTALL, NULL, NULL, FALSE, TRUE, NULL, &local_error))
|
|||
|
+ {
|
|||
|
+ 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;
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+ }
|
|||
|
+
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
/**
|
|||
|
* flatpak_transaction_add_update:
|
|||
|
* @self: a #FlatpakTransaction
|
|||
|
@@ -3059,7 +3185,7 @@ flatpak_transaction_add_update (FlatpakTransaction *self,
|
|||
|
return FALSE;
|
|||
|
|
|||
|
/* Note: we implement the merge when subpaths == NULL in flatpak_transaction_add_ref() */
|
|||
|
- return flatpak_transaction_add_ref (self, NULL, decomposed, subpaths, NULL, commit, FLATPAK_TRANSACTION_OPERATION_UPDATE, NULL, NULL, FALSE, NULL, error);
|
|||
|
+ return flatpak_transaction_add_ref (self, NULL, decomposed, subpaths, NULL, commit, FLATPAK_TRANSACTION_OPERATION_UPDATE, NULL, NULL, FALSE, FALSE, NULL, error);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
@@ -3086,7 +3212,7 @@ flatpak_transaction_add_uninstall (FlatpakTransaction *self,
|
|||
|
if (decomposed == NULL)
|
|||
|
return FALSE;
|
|||
|
|
|||
|
- return flatpak_transaction_add_ref (self, NULL, decomposed, NULL, NULL, NULL, FLATPAK_TRANSACTION_OPERATION_UNINSTALL, NULL, NULL, FALSE, NULL, error);
|
|||
|
+ return flatpak_transaction_add_ref (self, NULL, decomposed, NULL, NULL, NULL, FLATPAK_TRANSACTION_OPERATION_UNINSTALL, NULL, NULL, FALSE, FALSE, NULL, error);
|
|||
|
}
|
|||
|
|
|||
|
static gboolean
|
|||
|
@@ -3198,7 +3324,7 @@ flatpak_transaction_add_auto_install (FlatpakTransaction *self,
|
|||
|
|
|||
|
if (!flatpak_transaction_add_ref (self, remote, auto_install_ref, NULL, NULL, NULL,
|
|||
|
FLATPAK_TRANSACTION_OPERATION_INSTALL_OR_UPDATE,
|
|||
|
- NULL, NULL, FALSE, NULL,
|
|||
|
+ NULL, NULL, FALSE, FALSE, NULL,
|
|||
|
&local_error))
|
|||
|
g_info ("Failed to add auto-install ref %s: %s", flatpak_decomposed_get_ref (auto_install_ref),
|
|||
|
local_error->message);
|
|||
|
@@ -4701,7 +4827,7 @@ flatpak_transaction_resolve_bundles (FlatpakTransaction *self,
|
|||
|
|
|||
|
if (!flatpak_transaction_add_ref (self, remote, ref, NULL, NULL, commit,
|
|||
|
FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE,
|
|||
|
- data->file, metadata, FALSE, NULL, error))
|
|||
|
+ data->file, metadata, FALSE, FALSE, NULL, error))
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
@@ -4773,6 +4899,7 @@ _run_op_kind (FlatpakTransaction *self,
|
|||
|
priv->reinstall,
|
|||
|
priv->max_op >= APP_UPDATE,
|
|||
|
op->pin_on_deploy,
|
|||
|
+ op->update_preinstalled_on_deploy,
|
|||
|
remote_state, op->ref,
|
|||
|
op->resolved_commit,
|
|||
|
(const char **) op->subpaths,
|
|||
|
@@ -4811,7 +4938,7 @@ _run_op_kind (FlatpakTransaction *self,
|
|||
|
if (flatpak_decomposed_is_app (op->ref))
|
|||
|
*out_needs_triggers = TRUE;
|
|||
|
|
|||
|
- if (op->pin_on_deploy)
|
|||
|
+ if (op->pin_on_deploy|| op->update_preinstalled_on_deploy)
|
|||
|
*out_needs_cache_drop = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
@@ -4915,6 +5042,9 @@ _run_op_kind (FlatpakTransaction *self,
|
|||
|
if (priv->force_uninstall)
|
|||
|
flags |= FLATPAK_HELPER_UNINSTALL_FLAGS_FORCE_REMOVE;
|
|||
|
|
|||
|
+ if (op->update_preinstalled_on_deploy)
|
|||
|
+ flags |= FLATPAK_HELPER_UNINSTALL_FLAGS_UPDATE_PREINSTALLED;
|
|||
|
+
|
|||
|
emit_new_op (self, op, progress);
|
|||
|
|
|||
|
res = flatpak_dir_uninstall (priv->dir, op->ref, flags,
|
|||
|
@@ -5095,7 +5225,7 @@ add_uninstall_unused_ops (FlatpakTransaction *self,
|
|||
|
uninstall_op = flatpak_transaction_add_op (self, origin, unused_ref,
|
|||
|
NULL, NULL, NULL, NULL,
|
|||
|
FLATPAK_TRANSACTION_OPERATION_UNINSTALL,
|
|||
|
- FALSE);
|
|||
|
+ FALSE, FALSE);
|
|||
|
run_operation_last (uninstall_op);
|
|||
|
}
|
|||
|
}
|
|||
|
diff --git a/common/flatpak-transaction.h b/common/flatpak-transaction.h
|
|||
|
index 0b8f2de..6e67a7b 100644
|
|||
|
--- a/common/flatpak-transaction.h
|
|||
|
+++ b/common/flatpak-transaction.h
|
|||
|
@@ -330,6 +330,9 @@ gboolean flatpak_transaction_add_install_flatpakref (FlatpakTransacti
|
|||
|
GBytes *flatpakref_data,
|
|||
|
GError **error);
|
|||
|
FLATPAK_EXTERN
|
|||
|
+gboolean flatpak_transaction_add_sync_preinstalled (FlatpakTransaction *self,
|
|||
|
+ GError **error);
|
|||
|
+FLATPAK_EXTERN
|
|||
|
gboolean flatpak_transaction_add_update (FlatpakTransaction *self,
|
|||
|
const char *ref,
|
|||
|
const char **subpaths,
|
|||
|
diff --git a/doc/flatpak-docs.xml.in b/doc/flatpak-docs.xml.in
|
|||
|
index 581bf68..4de8d1f 100644
|
|||
|
--- a/doc/flatpak-docs.xml.in
|
|||
|
+++ b/doc/flatpak-docs.xml.in
|
|||
|
@@ -52,6 +52,7 @@
|
|||
|
<xi:include href="@srcdir@/flatpak-permission-show.xml"/>
|
|||
|
<xi:include href="@srcdir@/flatpak-permission-reset.xml"/>
|
|||
|
<xi:include href="@srcdir@/flatpak-permission-set.xml"/>
|
|||
|
+ <xi:include href="@srcdir@/flatpak-preinstall.xml"/>
|
|||
|
<xi:include href="@srcdir@/flatpak-ps.xml"/>
|
|||
|
<xi:include href="@srcdir@/flatpak-remote-add.xml"/>
|
|||
|
<xi:include href="@srcdir@/flatpak-remote-delete.xml"/>
|
|||
|
diff --git a/doc/flatpak-preinstall.xml b/doc/flatpak-preinstall.xml
|
|||
|
new file mode 100644
|
|||
|
index 0000000..cbbe095
|
|||
|
--- /dev/null
|
|||
|
+++ b/doc/flatpak-preinstall.xml
|
|||
|
@@ -0,0 +1,273 @@
|
|||
|
+<?xml version='1.0'?> <!--*-nxml-*-->
|
|||
|
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|||
|
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|||
|
+
|
|||
|
+<refentry id="flatpak-preinstall">
|
|||
|
+
|
|||
|
+ <refentryinfo>
|
|||
|
+ <title>flatpak preinstall</title>
|
|||
|
+ <productname>flatpak</productname>
|
|||
|
+
|
|||
|
+ <authorgroup>
|
|||
|
+ <author>
|
|||
|
+ <contrib>Developer</contrib>
|
|||
|
+ <firstname>Kalev</firstname>
|
|||
|
+ <surname>Lember</surname>
|
|||
|
+ <email>klember@redhat.com</email>
|
|||
|
+ </author>
|
|||
|
+ </authorgroup>
|
|||
|
+ </refentryinfo>
|
|||
|
+
|
|||
|
+ <refmeta>
|
|||
|
+ <refentrytitle>flatpak preinstall</refentrytitle>
|
|||
|
+ <manvolnum>1</manvolnum>
|
|||
|
+ </refmeta>
|
|||
|
+
|
|||
|
+ <refnamediv>
|
|||
|
+ <refname>flatpak-preinstall</refname>
|
|||
|
+ <refpurpose>Install flatpaks that are part of the operating system</refpurpose>
|
|||
|
+ </refnamediv>
|
|||
|
+
|
|||
|
+ <refsynopsisdiv>
|
|||
|
+ <cmdsynopsis>
|
|||
|
+ <command>flatpak preinstall</command>
|
|||
|
+ <arg choice="opt" rep="repeat">OPTION</arg>
|
|||
|
+ </cmdsynopsis>
|
|||
|
+ </refsynopsisdiv>
|
|||
|
+
|
|||
|
+ <refsect1>
|
|||
|
+ <title>Description</title>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ This command manages flatpaks that are part of the operating system. If no options are given, running <command>flatpak preinstall</command> will synchronize (install and remove) flatpaks to match the set that the OS vendor has chosen.
|
|||
|
+ </para>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ Preinstalled flatpaks are defined by dropping .preinstall files into <filename>/etc/flatpak/preinstall.d/</filename> directory. Each .preinstall file defines one flatpak to install. The OS runs <command>flatpak preinstall -y</command> (or its GUI equivalent) on system startup, which then does the actual installation.
|
|||
|
+ </para>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ This system allows the OS vendor to define the list of flatpaks that are installed together with the OS, and also makes it possible for the OS vendor to make changes to the list in the future, which is then applied once <command>flatpak preinstall</command> is run next time.
|
|||
|
+
|
|||
|
+ Users can opt out of preinstalled flatpaks by simply removing them, at which point they won't get automatically reinstalled again.
|
|||
|
+ </para>
|
|||
|
+ </refsect1>
|
|||
|
+
|
|||
|
+ <refsect1>
|
|||
|
+ <title>File format</title>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ The .preinstall file is using the same .ini file format that is used for
|
|||
|
+ systemd unit files or application .desktop files.
|
|||
|
+ </para>
|
|||
|
+
|
|||
|
+ <refsect2>
|
|||
|
+ <title>[Flatpak Preinstall]</title>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ All the information is contained in the [Flatpak Preinstall] group.
|
|||
|
+ </para>
|
|||
|
+ <para>
|
|||
|
+ The following keys can be present in this group:
|
|||
|
+ </para>
|
|||
|
+ <variablelist>
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>Name</option> (string)</term>
|
|||
|
+ <listitem><para>The fully qualified name of the runtime or application. This key is mandatory.</para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>Branch</option> (string)</term>
|
|||
|
+ <listitem><para>The name of the branch from which to install the application or runtime. If this key is not specified, the "master" branch is used.</para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>IsRuntime</option> (boolean)</term>
|
|||
|
+ <listitem><para>Whether this file refers to a runtime. If this key is not specified, the file is assumed to refer to an application.</para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>CollectionID</option> (string)</term>
|
|||
|
+ <listitem><para>
|
|||
|
+ The collection ID of the remote to use, if it has one.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+ </variablelist>
|
|||
|
+ </refsect2>
|
|||
|
+ </refsect1>
|
|||
|
+
|
|||
|
+ <refsect1>
|
|||
|
+ <title>Example</title>
|
|||
|
+<programlisting>
|
|||
|
+[Flatpak Preinstall]
|
|||
|
+Name=org.gnome.Loupe
|
|||
|
+Branch=stable
|
|||
|
+IsRuntime=false
|
|||
|
+</programlisting>
|
|||
|
+ </refsect1>
|
|||
|
+
|
|||
|
+ <refsect1>
|
|||
|
+ <title>Options</title>
|
|||
|
+
|
|||
|
+ <para>The following options are understood:</para>
|
|||
|
+
|
|||
|
+ <variablelist>
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>-h</option></term>
|
|||
|
+ <term><option>--help</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Show help options and exit.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--reinstall</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Uninstall first if already installed.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>-u</option></term>
|
|||
|
+ <term><option>--user</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Install the application or runtime in a per-user installation.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--system</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Install the application or runtime in the default system-wide installation.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--installation=NAME</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Install the application or runtime in a system-wide installation
|
|||
|
+ specified by <arg choice="plain">NAME</arg> among those defined in
|
|||
|
+ <filename>/etc/flatpak/installations.d/</filename>. Using
|
|||
|
+ <option>--installation=default</option> is equivalent to using
|
|||
|
+ <option>--system</option>.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--no-deploy</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Download the latest version, but don't deploy it.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--no-pull</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Don't download the latest version, deploy whatever is locally available.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--no-related</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Don't download related extensions, such as the locale data.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--no-deps</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Don't verify runtime dependencies when installing.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--sideload-repo=PATH</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Adds an extra local ostree repo as a source for installation. This is equivalent
|
|||
|
+ to using the <filename>sideload-repos</filename> directories (see
|
|||
|
+ <citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>),
|
|||
|
+ but can be done on a per-command basis. Any path added here is used in addition
|
|||
|
+ to ones in those directories.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--include-sdk</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ For each app being installed, also installs the SDK that was used to build it.
|
|||
|
+ Implies <option>--or-update</option>; incompatible with <option>--no-deps</option>.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--include-debug</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ For each ref being installed, as well as all dependencies, also installs its
|
|||
|
+ debug info. Implies <option>--or-update</option>; incompatible with
|
|||
|
+ <option>--no-deps</option>.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>-y</option></term>
|
|||
|
+ <term><option>--assumeyes</option></term>
|
|||
|
+ <listitem><para>
|
|||
|
+ Automatically answer yes to all questions (or pick the most prioritized answer). This is useful for automation.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--noninteractive</option></term>
|
|||
|
+ <listitem><para>
|
|||
|
+ Produce minimal output and avoid most questions. This is suitable for use in
|
|||
|
+ non-interactive situations, e.g. in a build script.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>-v</option></term>
|
|||
|
+ <term><option>--verbose</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Print debug information during command processing.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+
|
|||
|
+ <varlistentry>
|
|||
|
+ <term><option>--ostree-verbose</option></term>
|
|||
|
+
|
|||
|
+ <listitem><para>
|
|||
|
+ Print OSTree debug information during command processing.
|
|||
|
+ </para></listitem>
|
|||
|
+ </varlistentry>
|
|||
|
+ </variablelist>
|
|||
|
+ </refsect1>
|
|||
|
+
|
|||
|
+ <refsect1>
|
|||
|
+ <title>Examples</title>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ <command>$ flatpak preinstall</command>
|
|||
|
+ </para>
|
|||
|
+ </refsect1>
|
|||
|
+
|
|||
|
+ <refsect1>
|
|||
|
+ <title>See also</title>
|
|||
|
+
|
|||
|
+ <para>
|
|||
|
+ <citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
|||
|
+ </para>
|
|||
|
+
|
|||
|
+ </refsect1>
|
|||
|
+
|
|||
|
+</refentry>
|
|||
|
diff --git a/doc/meson.build b/doc/meson.build
|
|||
|
index a4cedfb..9ef8eee 100644
|
|||
|
--- a/doc/meson.build
|
|||
|
+++ b/doc/meson.build
|
|||
|
@@ -26,6 +26,7 @@ man1 = [
|
|||
|
'flatpak-config',
|
|||
|
'flatpak-update',
|
|||
|
'flatpak-uninstall',
|
|||
|
+ 'flatpak-preinstall',
|
|||
|
'flatpak-mask',
|
|||
|
'flatpak-pin',
|
|||
|
'flatpak-list',
|
|||
|
diff --git a/po/POTFILES.in b/po/POTFILES.in
|
|||
|
index b3cb79c..52600ab 100644
|
|||
|
--- a/po/POTFILES.in
|
|||
|
+++ b/po/POTFILES.in
|
|||
|
@@ -30,6 +30,7 @@ app/flatpak-builtins-permission-reset.c
|
|||
|
app/flatpak-builtins-permission-set.c
|
|||
|
app/flatpak-builtins-permission-show.c
|
|||
|
app/flatpak-builtins-pin.c
|
|||
|
+app/flatpak-builtins-preinstall.c
|
|||
|
app/flatpak-builtins-ps.c
|
|||
|
app/flatpak-builtins-remote-add.c
|
|||
|
app/flatpak-builtins-remote-delete.c
|
|||
|
diff --git a/system-helper/flatpak-system-helper.c b/system-helper/flatpak-system-helper.c
|
|||
|
index a58ab2c..c39d0d7 100644
|
|||
|
--- a/system-helper/flatpak-system-helper.c
|
|||
|
+++ b/system-helper/flatpak-system-helper.c
|
|||
|
@@ -403,6 +403,7 @@ handle_deploy (FlatpakSystemHelper *object,
|
|||
|
gboolean local_pull;
|
|||
|
gboolean reinstall;
|
|||
|
gboolean update_pinned;
|
|||
|
+ gboolean update_preinstalled;
|
|||
|
g_autofree char *url = NULL;
|
|||
|
g_autoptr(OngoingPull) ongoing_pull = NULL;
|
|||
|
g_autofree gchar *src_dir = NULL;
|
|||
|
@@ -488,6 +489,7 @@ handle_deploy (FlatpakSystemHelper *object,
|
|||
|
local_pull = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL) != 0;
|
|||
|
reinstall = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL) != 0;
|
|||
|
update_pinned = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PINNED) != 0;
|
|||
|
+ update_preinstalled = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE_PREINSTALLED) != 0;
|
|||
|
|
|||
|
deploy_dir = flatpak_dir_get_if_deployed (system, ref, NULL, NULL);
|
|||
|
|
|||
|
@@ -704,7 +706,8 @@ handle_deploy (FlatpakSystemHelper *object,
|
|||
|
if (!flatpak_dir_deploy_install (system, ref, arg_origin,
|
|||
|
(const char **) arg_subpaths,
|
|||
|
(const char **) arg_previous_ids,
|
|||
|
- reinstall, update_pinned, NULL, &error))
|
|||
|
+ reinstall, update_pinned, update_preinstalled,
|
|||
|
+ NULL, &error))
|
|||
|
{
|
|||
|
flatpak_invocation_return_error (invocation, error, "Error deploying");
|
|||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
|||
|
|
|||
|
From 46878bfa88f8e10a799fd75f698535718aefa8b1 Mon Sep 17 00:00:00 2001
|
|||
|
From: Kalev Lember <klember@redhat.com>
|
|||
|
Date: Wed, 6 Nov 2024 15:40:52 +0100
|
|||
|
Subject: [PATCH 2/3] dir: Search for preinstall config files in both /etc and
|
|||
|
/usr/share
|
|||
|
|
|||
|
---
|
|||
|
common/flatpak-dir.c | 59 +++++++++++++++++++++++++++++++++-----------
|
|||
|
1 file changed, 44 insertions(+), 15 deletions(-)
|
|||
|
|
|||
|
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
|
|||
|
index 295f610..e7d6e9d 100644
|
|||
|
--- a/common/flatpak-dir.c
|
|||
|
+++ b/common/flatpak-dir.c
|
|||
|
@@ -1908,25 +1908,20 @@ get_system_locations (GCancellable *cancellable,
|
|||
|
return g_steal_pointer (&locations);
|
|||
|
}
|
|||
|
|
|||
|
-char **
|
|||
|
-flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
- GError **error)
|
|||
|
+static gboolean
|
|||
|
+scan_preinstall_config_files (const char *config_dir,
|
|||
|
+ GHashTable *config_file_map,
|
|||
|
+ GCancellable *cancellable,
|
|||
|
+ GError **error)
|
|||
|
{
|
|||
|
- g_autoptr(GPtrArray) paths = NULL;
|
|||
|
g_autoptr(GFile) conf_dir = NULL;
|
|||
|
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
|||
|
g_autoptr(GError) my_error = NULL;
|
|||
|
- g_autofree char *config_dir = NULL;
|
|||
|
-
|
|||
|
- paths = g_ptr_array_new_with_free_func (g_free);
|
|||
|
- config_dir = g_strdup_printf ("%s/%s",
|
|||
|
- get_config_dir_location (),
|
|||
|
- FLATPAK_PREINSTALL_DIR);
|
|||
|
|
|||
|
if (!g_file_test (config_dir, G_FILE_TEST_IS_DIR))
|
|||
|
{
|
|||
|
g_info ("Skipping missing preinstall config directory %s", config_dir);
|
|||
|
- goto out;
|
|||
|
+ return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
conf_dir = g_file_new_for_path (config_dir);
|
|||
|
@@ -1939,7 +1934,7 @@ flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
g_info ("Unexpected error retrieving preinstalls from %s: %s",
|
|||
|
config_dir, my_error->message);
|
|||
|
g_propagate_error (error, g_steal_pointer (&my_error));
|
|||
|
- return NULL;
|
|||
|
+ return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
while (TRUE)
|
|||
|
@@ -1955,7 +1950,7 @@ flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
g_info ("Unexpected error reading file in %s: %s",
|
|||
|
config_dir, my_error->message);
|
|||
|
g_propagate_error (error, g_steal_pointer (&my_error));
|
|||
|
- return NULL;
|
|||
|
+ return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (file_info == NULL)
|
|||
|
@@ -1966,11 +1961,45 @@ flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
|
|||
|
if (type == G_FILE_TYPE_REGULAR && g_str_has_suffix (name, FLATPAK_PREINSTALL_FILE_EXT))
|
|||
|
{
|
|||
|
- g_autofree char *path_str = g_file_get_path (path);
|
|||
|
- g_ptr_array_add (paths, g_steal_pointer (&path_str));
|
|||
|
+ /* already found in another directory */
|
|||
|
+ if (g_hash_table_contains (config_file_map, name))
|
|||
|
+ continue;
|
|||
|
+
|
|||
|
+ g_hash_table_insert (config_file_map, g_strdup (name), g_object_ref (path));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
+ return TRUE;
|
|||
|
+}
|
|||
|
+
|
|||
|
+char **
|
|||
|
+flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
+ GError **error)
|
|||
|
+{
|
|||
|
+ g_autoptr(GHashTable) config_file_map = NULL;
|
|||
|
+ g_autoptr(GPtrArray) paths = NULL;
|
|||
|
+ g_autofree char *config_dir = NULL;
|
|||
|
+
|
|||
|
+ config_file_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
|||
|
+ paths = g_ptr_array_new_with_free_func (g_free);
|
|||
|
+ config_dir = g_strdup_printf ("%s/%s",
|
|||
|
+ get_config_dir_location (),
|
|||
|
+ FLATPAK_PREINSTALL_DIR);
|
|||
|
+
|
|||
|
+ /* scan directories in priority order */
|
|||
|
+ if (!scan_preinstall_config_files (config_dir,
|
|||
|
+ config_file_map, cancellable, error))
|
|||
|
+ goto out;
|
|||
|
+ if (!scan_preinstall_config_files (FLATPAK_BASEDIR "/" FLATPAK_PREINSTALL_DIR,
|
|||
|
+ config_file_map, cancellable, error))
|
|||
|
+ goto out;
|
|||
|
+
|
|||
|
+ GLNX_HASH_TABLE_FOREACH_KV (config_file_map, const char *, name, GFile *, path)
|
|||
|
+ {
|
|||
|
+ g_autofree char *path_str = g_file_get_path (path);
|
|||
|
+ g_ptr_array_add (paths, g_steal_pointer (&path_str));
|
|||
|
+ }
|
|||
|
+
|
|||
|
out:
|
|||
|
g_ptr_array_add (paths, NULL);
|
|||
|
return (char **) g_ptr_array_free (g_steal_pointer (&paths), FALSE);
|
|||
|
|
|||
|
From d2792d319088d4f8f57fb2781428258a1e8d624b Mon Sep 17 00:00:00 2001
|
|||
|
From: Kalev Lember <klember@redhat.com>
|
|||
|
Date: Wed, 6 Nov 2024 15:53:11 +0100
|
|||
|
Subject: [PATCH 3/3] fixup! Add initial support for preinstalling flatpaks
|
|||
|
|
|||
|
---
|
|||
|
common/flatpak-dir.c | 14 ++++++++------
|
|||
|
1 file changed, 8 insertions(+), 6 deletions(-)
|
|||
|
|
|||
|
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
|
|||
|
index e7d6e9d..fe3d145 100644
|
|||
|
--- a/common/flatpak-dir.c
|
|||
|
+++ b/common/flatpak-dir.c
|
|||
|
@@ -1956,8 +1956,8 @@ scan_preinstall_config_files (const char *config_dir,
|
|||
|
if (file_info == NULL)
|
|||
|
break;
|
|||
|
|
|||
|
- name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
|
|||
|
- type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
|
|||
|
+ name = g_file_info_get_name (file_info);
|
|||
|
+ type = g_file_info_get_file_type (file_info);
|
|||
|
|
|||
|
if (type == G_FILE_TYPE_REGULAR && g_str_has_suffix (name, FLATPAK_PREINSTALL_FILE_EXT))
|
|||
|
{
|
|||
|
@@ -1982,9 +1982,7 @@ flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
|
|||
|
config_file_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
|||
|
paths = g_ptr_array_new_with_free_func (g_free);
|
|||
|
- config_dir = g_strdup_printf ("%s/%s",
|
|||
|
- get_config_dir_location (),
|
|||
|
- FLATPAK_PREINSTALL_DIR);
|
|||
|
+ config_dir = g_build_filename (get_config_dir_location (), FLATPAK_PREINSTALL_DIR, NULL);
|
|||
|
|
|||
|
/* scan directories in priority order */
|
|||
|
if (!scan_preinstall_config_files (config_dir,
|
|||
|
@@ -2024,7 +2022,11 @@ parse_preinstall_keyfile (GKeyFile *keyfile,
|
|||
|
*collection_id_out = NULL;
|
|||
|
|
|||
|
if (!g_key_file_has_group (keyfile, FLATPAK_PREINSTALL_GROUP))
|
|||
|
- return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Invalid file format, no %s group"), FLATPAK_PREINSTALL_GROUP);
|
|||
|
+ {
|
|||
|
+ /* empty files are allowed and expected, in order to allow overriding
|
|||
|
+ /usr configuration in /etc */
|
|||
|
+ return TRUE;
|
|||
|
+ }
|
|||
|
|
|||
|
name = g_key_file_get_string (keyfile, FLATPAK_PREINSTALL_GROUP,
|
|||
|
FLATPAK_PREINSTALL_NAME_KEY, NULL);
|
|||
|
From 72e418793ff28299a834b81abfb0d9bdc943b67e Mon Sep 17 00:00:00 2001
|
|||
|
From: Sebastian Wick <sebastian.wick@redhat.com>
|
|||
|
Date: Fri, 10 Jan 2025 14:06:44 +0100
|
|||
|
Subject: fixup! dir: Search for preinstall config files in both /etc and
|
|||
|
/usr/share
|
|||
|
|
|||
|
|
|||
|
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c
|
|||
|
index fe3d1458..fe423b7a 100644
|
|||
|
--- a/common/flatpak-dir.c
|
|||
|
+++ b/common/flatpak-dir.c
|
|||
|
@@ -1979,16 +1979,19 @@ flatpak_get_preinstall_config_file_paths (GCancellable *cancellable,
|
|||
|
g_autoptr(GHashTable) config_file_map = NULL;
|
|||
|
g_autoptr(GPtrArray) paths = NULL;
|
|||
|
g_autofree char *config_dir = NULL;
|
|||
|
+ g_autofree char *data_dir = NULL;
|
|||
|
|
|||
|
config_file_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
|||
|
paths = g_ptr_array_new_with_free_func (g_free);
|
|||
|
- config_dir = g_build_filename (get_config_dir_location (), FLATPAK_PREINSTALL_DIR, NULL);
|
|||
|
|
|||
|
/* scan directories in priority order */
|
|||
|
+ config_dir = g_build_filename (get_config_dir_location (), FLATPAK_PREINSTALL_DIR, NULL);
|
|||
|
if (!scan_preinstall_config_files (config_dir,
|
|||
|
config_file_map, cancellable, error))
|
|||
|
goto out;
|
|||
|
- if (!scan_preinstall_config_files (FLATPAK_BASEDIR "/" FLATPAK_PREINSTALL_DIR,
|
|||
|
+
|
|||
|
+ data_dir = g_build_filename (get_data_dir_location (), FLATPAK_PREINSTALL_DIR, NULL);
|
|||
|
+ if (!scan_preinstall_config_files (data_dir,
|
|||
|
config_file_map, cancellable, error))
|
|||
|
goto out;
|
|||
|
|
|||
|
From 9ef338d2508002a88e913a48f2b01c09e33b4312 Mon Sep 17 00:00:00 2001
|
|||
|
From: Sebastian Wick <sebastian.wick@redhat.com>
|
|||
|
Date: Fri, 10 Jan 2025 14:15:57 +0100
|
|||
|
Subject: fixup! Add initial support for preinstalling flatpaks
|
|||
|
|
|||
|
|
|||
|
diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c
|
|||
|
index e4de9091..9b777c38 100644
|
|||
|
--- a/common/flatpak-transaction.c
|
|||
|
+++ b/common/flatpak-transaction.c
|
|||
|
@@ -2949,15 +2949,12 @@ flatpak_transaction_add_rebase_and_uninstall (FlatpakTransaction *self,
|
|||
|
/* 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
|
|||
|
+ if (!g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_NOT_INSTALLED))
|
|||
|
{
|
|||
|
g_propagate_error (error, g_steal_pointer (&local_error));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
+ g_clear_error (&local_error);
|
|||
|
}
|
|||
|
|
|||
|
/* Link the ops together so that the install/update is done first, and if
|
|||
|
@@ -3116,7 +3113,7 @@ flatpak_transaction_add_sync_preinstalled (FlatpakTransaction *self,
|
|||
|
|
|||
|
/* Find previously preinstalled refs that are no longer in the preinstall
|
|||
|
* list and should now get uninstalled */
|
|||
|
- for (guint i = 0; i < preinstalled_refs->len; i++)
|
|||
|
+ for (int i = 0; i < preinstalled_refs->len; i++)
|
|||
|
{
|
|||
|
const char *ref = g_ptr_array_index (preinstalled_refs, i);
|
|||
|
|
|||
|
@@ -3134,15 +3131,12 @@ flatpak_transaction_add_sync_preinstalled (FlatpakTransaction *self,
|
|||
|
|
|||
|
if (!flatpak_transaction_add_ref (self, NULL, decomposed, NULL, NULL, NULL, FLATPAK_TRANSACTION_OPERATION_UNINSTALL, NULL, NULL, FALSE, TRUE, NULL, &local_error))
|
|||
|
{
|
|||
|
- if (g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_NOT_INSTALLED))
|
|||
|
- {
|
|||
|
- g_clear_error (&local_error);
|
|||
|
- }
|
|||
|
- else
|
|||
|
+ if (!g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_NOT_INSTALLED))
|
|||
|
{
|
|||
|
g_propagate_error (error, g_steal_pointer (&local_error));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
+ g_clear_error (&local_error);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|