mirror of
https://github.com/flatpak/flatpak.git
synced 2026-10-21 07:05:25 -04:00
update/install: Install/Update runtime dependencies as needed
When an application requires a runtime that is not installed, search for it and prompt for permissions to install it. Also, update required runtimes when the app is being updated.
This commit is contained in:
1 parent
b2af78fb6f
commit
28261d839e
13 files changed
+892
-311
No files matched your search
@@ -5,6 +5,10 @@ bin_PROGRAMS += \
|
||||
flatpak_SOURCES = \
|
||||
app/flatpak-main.c \
|
||||
app/flatpak-builtins.h \
|
||||
app/flatpak-builtins-utils.h \
|
||||
app/flatpak-builtins-utils.c \
|
||||
app/flatpak-transaction.h \
|
||||
app/flatpak-transaction.c \
|
||||
app/flatpak-builtins-add-remote.c \
|
||||
app/flatpak-builtins-delete-remote.c \
|
||||
app/flatpak-builtins-list-remotes.c \
|
||||
|
||||
+25
-139
@@ -32,6 +32,8 @@
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include "flatpak-builtins.h"
|
||||
#include "flatpak-builtins-utils.h"
|
||||
#include "flatpak-transaction.h"
|
||||
#include "flatpak-utils.h"
|
||||
#include "lib/flatpak-error.h"
|
||||
#include "flatpak-chain-input-stream.h"
|
||||
@@ -53,7 +55,7 @@ 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 runtime dependencies"), NULL },
|
||||
{ "no-deps", 0, 0, G_OPTION_ARG_NONE, &opt_no_deps, N_("Don't verify/install runtime dependencies"), NULL },
|
||||
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, N_("Look for runtime with the specified name"), NULL },
|
||||
{ "app", 0, 0, G_OPTION_ARG_NONE, &opt_app, N_("Look for app with the specified name"), NULL },
|
||||
{ "bundle", 0, 0, G_OPTION_ARG_NONE, &opt_bundle, N_("Install from local bundle file"), NULL },
|
||||
@@ -142,78 +144,6 @@ install_bundle (FlatpakDir *dir,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_install (FlatpakDir *dir,
|
||||
gboolean no_pull,
|
||||
gboolean no_deploy,
|
||||
const char *ref,
|
||||
const char *remote_name,
|
||||
const char **opt_subpaths,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) related = NULL;
|
||||
const char *slash;
|
||||
int i;
|
||||
|
||||
slash = strchr (ref, '/');
|
||||
g_print (_("Installing: %s\n"), slash + 1);
|
||||
|
||||
if (!flatpak_dir_install (dir,
|
||||
opt_no_pull,
|
||||
opt_no_deploy,
|
||||
ref, remote_name,
|
||||
(const char **)opt_subpaths,
|
||||
NULL,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!opt_no_related)
|
||||
{
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
if (opt_no_pull)
|
||||
related = flatpak_dir_find_local_related (dir, ref, remote_name, NULL, &local_error);
|
||||
else
|
||||
related = flatpak_dir_find_remote_related (dir, ref, remote_name, NULL, &local_error);
|
||||
if (related == NULL)
|
||||
{
|
||||
g_printerr (_("Warning: Problem looking for related refs: %s\n"), local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < related->len; i++)
|
||||
{
|
||||
FlatpakRelated *rel = g_ptr_array_index (related, i);
|
||||
g_auto(GStrv) parts = NULL;
|
||||
|
||||
if (!rel->download)
|
||||
continue;
|
||||
|
||||
parts = g_strsplit (rel->ref, "/", 0);
|
||||
|
||||
g_print (_("Installing related: %s\n"), parts[1]);
|
||||
|
||||
if (!flatpak_dir_install_or_update (dir,
|
||||
opt_no_pull,
|
||||
opt_no_deploy,
|
||||
rel->ref, remote_name,
|
||||
(const char **)rel->subpaths,
|
||||
NULL,
|
||||
cancellable, &local_error))
|
||||
{
|
||||
if (!g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED))
|
||||
g_printerr (_("Warning: Failed to install related ref %s: %s\n"),
|
||||
rel->ref, local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
install_from (FlatpakDir *dir,
|
||||
@@ -232,6 +162,7 @@ install_from (FlatpakDir *dir,
|
||||
g_auto(GStrv) parts = NULL;
|
||||
const char *slash;
|
||||
FlatpakDir *clone;
|
||||
g_autoptr(FlatpakTransaction) transaction = NULL;
|
||||
|
||||
if (argc < 2)
|
||||
return usage_error (context, _("Filename must be specified"), error);
|
||||
@@ -259,30 +190,13 @@ install_from (FlatpakDir *dir,
|
||||
slash = strchr (ref, '/');
|
||||
g_print (_("Installing: %s\n"), slash + 1);
|
||||
|
||||
if (!do_install (clone,
|
||||
opt_no_pull,
|
||||
opt_no_deploy,
|
||||
ref, remote,
|
||||
(const char **)opt_subpaths,
|
||||
cancellable, error))
|
||||
transaction = flatpak_transaction_new (dir, opt_no_pull, opt_no_deploy,
|
||||
!opt_no_deps, !opt_no_related);
|
||||
|
||||
if (!flatpak_transaction_add_install (transaction, remote, ref, (const char **)opt_subpaths, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
looks_like_branch (const char *branch)
|
||||
{
|
||||
/* In particular, / is not a valid branch char, so
|
||||
this lets us distinguish full or partial refs as
|
||||
non-branches. */
|
||||
if (!flatpak_is_valid_branch (branch, NULL))
|
||||
return FALSE;
|
||||
|
||||
/* Dots are allowed in branches, but not really used much, while
|
||||
they are required for app ids, so thats a good check to
|
||||
distinguish the two */
|
||||
if (strchr (branch, '.') != NULL)
|
||||
if (!flatpak_transaction_run (transaction, TRUE, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
@@ -293,16 +207,17 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
{
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(FlatpakDir) dir = NULL;
|
||||
const char *repository;
|
||||
const char *remote;
|
||||
char **prefs = NULL;
|
||||
int i, n_prefs;
|
||||
g_autofree char *target_branch = NULL;
|
||||
g_autofree char *default_branch = NULL;
|
||||
FlatpakKinds kinds;
|
||||
g_autoptr(FlatpakTransaction) transaction = NULL;
|
||||
g_autoptr(GPtrArray) refs = NULL;
|
||||
g_autoptr(GHashTable) refs_hash = NULL;
|
||||
|
||||
context = g_option_context_new (_("REPOSITORY REF... - Install applications or runtimes"));
|
||||
context = g_option_context_new (_("REMOTE REF... - Install applications or runtimes"));
|
||||
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
||||
|
||||
if (!flatpak_option_context_parse (context, options, &argc, &argv, 0, &dir, cancellable, error))
|
||||
@@ -315,24 +230,25 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
return install_from (dir, context, argc, argv, cancellable, error);
|
||||
|
||||
if (argc < 3)
|
||||
return usage_error (context, _("REPOSITORY and REF must be specified"), error);
|
||||
return usage_error (context, _("REMOTE and REF must be specified"), error);
|
||||
|
||||
repository = argv[1];
|
||||
remote = argv[1];
|
||||
prefs = &argv[2];
|
||||
n_prefs = argc - 2;
|
||||
|
||||
/* Backwards compat for old "REPOSITORY NAME [BRANCH]" argument version */
|
||||
/* Backwards compat for old "REMOTE NAME [BRANCH]" argument version */
|
||||
if (argc == 4 && looks_like_branch (argv[3]))
|
||||
{
|
||||
target_branch = g_strdup (argv[3]);
|
||||
n_prefs = 1;
|
||||
}
|
||||
|
||||
default_branch = flatpak_dir_get_remote_default_branch (dir, repository);
|
||||
default_branch = flatpak_dir_get_remote_default_branch (dir, remote);
|
||||
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
|
||||
|
||||
refs = g_ptr_array_new_with_free_func (g_free);
|
||||
refs_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
transaction = flatpak_transaction_new (dir, opt_no_pull, opt_no_deploy,
|
||||
!opt_no_deps, !opt_no_related);
|
||||
|
||||
for (i = 0; i < n_prefs; i++)
|
||||
{
|
||||
const char *pref = prefs[i];
|
||||
@@ -342,54 +258,24 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
g_autofree char *branch = NULL;
|
||||
FlatpakKinds kind;
|
||||
g_autofree char *ref = NULL;
|
||||
g_autofree char *metadata = NULL;
|
||||
g_autoptr(GKeyFile) metakey = NULL;
|
||||
g_autofree char *runtime_ref = NULL;
|
||||
|
||||
if (!flatpak_split_partial_ref_arg (pref, kinds, opt_arch, target_branch,
|
||||
&matched_kinds, &id, &arch, &branch, error))
|
||||
return FALSE;
|
||||
|
||||
ref = flatpak_dir_find_remote_ref (dir, repository, id, branch, default_branch, arch,
|
||||
ref = flatpak_dir_find_remote_ref (dir, remote, id, branch, default_branch, arch,
|
||||
matched_kinds, &kind, cancellable, error);
|
||||
if (ref == NULL)
|
||||
return FALSE;
|
||||
|
||||
metakey = g_key_file_new ();
|
||||
if (!opt_no_deps &&
|
||||
flatpak_dir_fetch_ref_cache (dir, repository, ref, NULL, NULL, &metadata, cancellable, NULL) &&
|
||||
g_key_file_load_from_data (metakey, metadata, -1, 0, NULL))
|
||||
{
|
||||
g_autofree char *runtime_ref = NULL;
|
||||
g_autofree char *full_runtime_ref = NULL;
|
||||
runtime_ref = g_key_file_get_string (metakey, "Application", "runtime", NULL);
|
||||
full_runtime_ref = g_strconcat ("runtime/", runtime_ref, NULL);
|
||||
if (runtime_ref && !g_hash_table_lookup_extended (refs_hash, full_runtime_ref, NULL, NULL))
|
||||
{
|
||||
g_autoptr(FlatpakDeploy) deploy = flatpak_find_deploy_for_ref (full_runtime_ref, NULL, NULL);
|
||||
|
||||
if (deploy == NULL)
|
||||
return flatpak_fail (error,
|
||||
"The Application %s requires the runtime %s which is not installed",
|
||||
id, runtime_ref);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_hash_table_insert (refs_hash, g_strdup (ref), NULL))
|
||||
g_ptr_array_add (refs, g_steal_pointer (&ref));
|
||||
}
|
||||
|
||||
for (i = 0; i < refs->len; i++)
|
||||
{
|
||||
const char *ref = g_ptr_array_index (refs, i);
|
||||
if (!do_install (dir,
|
||||
opt_no_pull,
|
||||
opt_no_deploy,
|
||||
ref, repository,
|
||||
(const char **)opt_subpaths,
|
||||
cancellable, error))
|
||||
if (!flatpak_transaction_add_install (transaction, remote, ref, (const char **)opt_subpaths, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!flatpak_transaction_run (transaction, TRUE, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include "flatpak-builtins.h"
|
||||
#include "flatpak-builtins-utils.h"
|
||||
#include "flatpak-utils.h"
|
||||
|
||||
static char *opt_arch;
|
||||
@@ -49,24 +50,6 @@ static GOptionEntry options[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static gboolean
|
||||
looks_like_branch (const char *branch)
|
||||
{
|
||||
/* In particular, / is not a valid branch char, so
|
||||
this lets us distinguish full or partial refs as
|
||||
non-branches. */
|
||||
if (!flatpak_is_valid_branch (branch, NULL))
|
||||
return FALSE;
|
||||
|
||||
/* Dots are allowed in branches, but not really used much, while
|
||||
they are required for app ids, so thats a good check to
|
||||
distinguish the two */
|
||||
if (strchr (branch, '.') != NULL)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_builtin_uninstall (int argc, char **argv, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
|
||||
+15
-154
@@ -30,6 +30,8 @@
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include "flatpak-builtins.h"
|
||||
#include "flatpak-builtins-utils.h"
|
||||
#include "flatpak-transaction.h"
|
||||
#include "flatpak-utils.h"
|
||||
#include "flatpak-error.h"
|
||||
|
||||
@@ -40,6 +42,7 @@ static gboolean opt_force_remove;
|
||||
static gboolean opt_no_pull;
|
||||
static gboolean opt_no_deploy;
|
||||
static gboolean opt_no_related;
|
||||
static gboolean opt_no_deps;
|
||||
static gboolean opt_runtime;
|
||||
static gboolean opt_app;
|
||||
static gboolean opt_appstream;
|
||||
@@ -51,6 +54,7 @@ static GOptionEntry options[] = {
|
||||
{ "no-pull", 0, 0, G_OPTION_ARG_NONE, &opt_no_pull, N_("Don't pull, only update 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 update related refs"), NULL},
|
||||
{ "no-deps", 0, 0, G_OPTION_ARG_NONE, &opt_no_deps, N_("Don't verify/install runtime dependencies"), NULL },
|
||||
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, N_("Look for runtime with the specified name"), NULL },
|
||||
{ "app", 0, 0, G_OPTION_ARG_NONE, &opt_app, N_("Look for app with the specified name"), NULL },
|
||||
{ "appstream", 0, 0, G_OPTION_ARG_NONE, &opt_appstream, N_("Update appstream for remote"), NULL },
|
||||
@@ -96,138 +100,6 @@ update_appstream (FlatpakDir *dir, const char *remote, GCancellable *cancellable
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_update (FlatpakDir * dir,
|
||||
const char *ref,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_auto(GStrv) parts = flatpak_decompose_ref (ref, error);
|
||||
g_autofree char *repository = NULL;
|
||||
g_autoptr(GPtrArray) related = NULL;
|
||||
g_autoptr(GError) update_error = NULL;
|
||||
int i;
|
||||
|
||||
if (parts == NULL)
|
||||
return FALSE;
|
||||
|
||||
repository = flatpak_dir_get_origin (dir, ref, cancellable, error);
|
||||
if (repository == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (strcmp (parts[0], "app") == 0)
|
||||
g_print (_("Updating application %s, branch %s\n"), parts[1], parts[3]);
|
||||
else
|
||||
g_print (_("Updating runtime %s, branch %s\n"), parts[1], parts[3]);
|
||||
|
||||
if (flatpak_dir_get_remote_disabled (dir, repository))
|
||||
{
|
||||
g_print (_("Remote %s disabled\n"), repository);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!flatpak_dir_update (dir,
|
||||
opt_no_pull,
|
||||
opt_no_deploy,
|
||||
ref, repository, opt_commit, (const char **)opt_subpaths,
|
||||
NULL,
|
||||
cancellable, &update_error))
|
||||
{
|
||||
if (g_error_matches (update_error, FLATPAK_ERROR,
|
||||
FLATPAK_ERROR_ALREADY_INSTALLED))
|
||||
g_print (_("No updates.\n"));
|
||||
else
|
||||
g_printerr ("Error updating: %s\n", update_error->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GVariant) deploy_data = NULL;
|
||||
g_autofree char *commit = NULL;
|
||||
deploy_data = flatpak_dir_get_deploy_data (dir, ref, NULL, NULL);
|
||||
commit = g_strndup (flatpak_deploy_data_get_commit (deploy_data), 12);
|
||||
g_print (_("Now at %s.\n"), commit);
|
||||
}
|
||||
|
||||
|
||||
if (!opt_no_related)
|
||||
{
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
if (opt_no_pull)
|
||||
related = flatpak_dir_find_local_related (dir, ref, repository, NULL,
|
||||
&local_error);
|
||||
else
|
||||
related = flatpak_dir_find_remote_related (dir, ref, repository, NULL,
|
||||
&local_error);
|
||||
if (related == NULL)
|
||||
{
|
||||
g_printerr (_("Warning: Problem looking for related refs: %s\n"),
|
||||
local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < related->len; i++)
|
||||
{
|
||||
FlatpakRelated *rel = g_ptr_array_index (related, i);
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
g_auto(GStrv) parts = NULL;
|
||||
|
||||
if (!rel->download)
|
||||
continue;
|
||||
|
||||
parts = g_strsplit (rel->ref, "/", 0);
|
||||
|
||||
g_print (_("Updating related: %s\n"), parts[1]);
|
||||
|
||||
if (!flatpak_dir_install_or_update (dir,
|
||||
opt_no_pull,
|
||||
opt_no_deploy,
|
||||
rel->ref, repository,
|
||||
(const char **)rel->subpaths,
|
||||
NULL,
|
||||
cancellable, &local_error))
|
||||
{
|
||||
if (g_error_matches (local_error, FLATPAK_ERROR,
|
||||
FLATPAK_ERROR_ALREADY_INSTALLED))
|
||||
g_print (_("No updates.\n"));
|
||||
else
|
||||
g_printerr ("Error updating: %s\n", local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GVariant) deploy_data = NULL;
|
||||
g_autofree char *commit = NULL;
|
||||
deploy_data = flatpak_dir_get_deploy_data (dir, rel->ref, NULL, NULL);
|
||||
commit = g_strndup (flatpak_deploy_data_get_commit (deploy_data), 12);
|
||||
g_print (_("Now at %s.\n"), commit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
looks_like_branch (const char *branch)
|
||||
{
|
||||
/* In particular, / is not a valid branch char, so
|
||||
this lets us distinguish full or partial refs as
|
||||
non-branches. */
|
||||
if (!flatpak_is_valid_branch (branch, NULL))
|
||||
return FALSE;
|
||||
|
||||
/* Dots are allowed in branches, but not really used much, while
|
||||
they are required for app ids, so thats a good check to
|
||||
distinguish the two */
|
||||
if (strchr (branch, '.') != NULL)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_builtin_update (int argc,
|
||||
char **argv,
|
||||
@@ -239,10 +111,8 @@ flatpak_builtin_update (int argc,
|
||||
char **prefs = NULL;
|
||||
int i, j, n_prefs;
|
||||
const char *default_branch = NULL;
|
||||
gboolean failed = FALSE;
|
||||
FlatpakKinds kinds;
|
||||
g_autoptr(GHashTable) update_refs_hash = NULL;
|
||||
g_autoptr(GPtrArray) update_refs = NULL;
|
||||
g_autoptr(FlatpakTransaction) transaction = NULL;
|
||||
|
||||
context = g_option_context_new (_("[REF...] - Update applications or runtimes"));
|
||||
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
||||
@@ -263,10 +133,12 @@ flatpak_builtin_update (int argc,
|
||||
n_prefs = 1;
|
||||
}
|
||||
|
||||
update_refs = g_ptr_array_new_with_free_func (g_free);
|
||||
update_refs_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
transaction = flatpak_transaction_new (dir, opt_no_pull, opt_no_deploy,
|
||||
!opt_no_deps, !opt_no_related);
|
||||
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
|
||||
|
||||
g_print ("Looking for updates...\n");
|
||||
|
||||
for (j = 0; j == 0 || j < n_prefs; j++)
|
||||
{
|
||||
const char *pref = NULL;
|
||||
@@ -313,8 +185,8 @@ flatpak_builtin_update (int argc,
|
||||
continue;
|
||||
|
||||
found = TRUE;
|
||||
if (g_hash_table_insert (update_refs_hash, g_strdup (refs[i]), NULL))
|
||||
g_ptr_array_add (update_refs, g_strdup (refs[i]));
|
||||
if (!flatpak_transaction_add_update (transaction, refs[i], (const char **)opt_subpaths, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +216,8 @@ flatpak_builtin_update (int argc,
|
||||
continue;
|
||||
|
||||
found = TRUE;
|
||||
if (g_hash_table_insert (update_refs_hash, g_strdup (refs[i]), NULL))
|
||||
g_ptr_array_add (update_refs, g_strdup (refs[i]));
|
||||
if (!flatpak_transaction_add_update (transaction, refs[i], (const char **)opt_subpaths, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,19 +229,8 @@ flatpak_builtin_update (int argc,
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < update_refs->len; i++)
|
||||
{
|
||||
const char *ref = (char *)g_ptr_array_index (update_refs, i);
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
if (!do_update (dir, ref, cancellable, &local_error))
|
||||
{
|
||||
g_printerr (_("Error updating: %s\n"), local_error->message);
|
||||
failed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed)
|
||||
return flatpak_fail (error, _("One or more updates failed"));
|
||||
if (!flatpak_transaction_run (transaction, FALSE, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright © 2014 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:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "flatpak-builtins-utils.h"
|
||||
#include "flatpak-utils.h"
|
||||
|
||||
|
||||
gboolean
|
||||
looks_like_branch (const char *branch)
|
||||
{
|
||||
/* In particular, / is not a valid branch char, so
|
||||
this lets us distinguish full or partial refs as
|
||||
non-branches. */
|
||||
if (!flatpak_is_valid_branch (branch, NULL))
|
||||
return FALSE;
|
||||
|
||||
/* Dots are allowed in branches, but not really used much, while
|
||||
they are required for app ids, so thats a good check to
|
||||
distinguish the two */
|
||||
if (strchr (branch, '.') != NULL)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright © 2014 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:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __FLATPAK_BUILTINS_UTILS_H__
|
||||
#define __FLATPAK_BUILTINS_UTILS_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
gboolean looks_like_branch (const char *branch);
|
||||
|
||||
#endif /* __FLATPAK_BUILTINS_UTILS_H__ */
|
||||
@@ -0,0 +1,546 @@
|
||||
/*
|
||||
* Copyright © 2016 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:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "flatpak-transaction.h"
|
||||
#include "flatpak-utils.h"
|
||||
#include "flatpak-builtins-utils.h"
|
||||
#include "flatpak-error.h"
|
||||
|
||||
typedef struct FlatpakTransactionOp FlatpakTransactionOp;
|
||||
|
||||
struct FlatpakTransactionOp {
|
||||
char *remote;
|
||||
char *ref;
|
||||
char **subpaths;
|
||||
char *commit; /* TODO: handle */
|
||||
gboolean update;
|
||||
gboolean install;
|
||||
gboolean non_fatal;
|
||||
};
|
||||
|
||||
struct FlatpakTransaction {
|
||||
FlatpakDir *dir;
|
||||
GHashTable *refs;
|
||||
GList *ops;
|
||||
|
||||
gboolean no_pull;
|
||||
gboolean no_deploy;
|
||||
gboolean add_deps;
|
||||
gboolean add_related;
|
||||
};
|
||||
|
||||
|
||||
static gboolean
|
||||
ref_is_installed (const char *ref)
|
||||
{
|
||||
g_autoptr(FlatpakDeploy) deploy = NULL;
|
||||
deploy = flatpak_find_deploy_for_ref (ref, NULL, NULL);
|
||||
return deploy != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dir_ref_is_installed (FlatpakDir *dir, const char *ref, char **remote_out)
|
||||
{
|
||||
g_autoptr(GVariant) deploy_data = NULL;
|
||||
|
||||
deploy_data = flatpak_dir_get_deploy_data (dir, ref, NULL, NULL);
|
||||
if (deploy_data == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (remote_out)
|
||||
*remote_out = g_strdup (flatpak_deploy_data_get_origin (deploy_data));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
transaction_fetch_runtime_ref (FlatpakDir *dir, const char *remote, const char *ref)
|
||||
{
|
||||
g_autofree char *metadata = NULL;
|
||||
g_autoptr(GKeyFile) metakey = NULL;
|
||||
g_autofree char *runtime_ref = NULL;
|
||||
|
||||
if (!g_str_has_prefix (ref, "app/"))
|
||||
return NULL;
|
||||
|
||||
if (!flatpak_dir_fetch_ref_cache (dir, remote, ref, NULL, NULL, &metadata, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
metakey = g_key_file_new ();
|
||||
if (!g_key_file_load_from_data (metakey, metadata, -1, 0, NULL))
|
||||
return NULL;
|
||||
|
||||
runtime_ref = g_key_file_get_string (metakey, "Application", "runtime", NULL);
|
||||
|
||||
return g_steal_pointer (&runtime_ref);
|
||||
}
|
||||
|
||||
|
||||
static FlatpakTransactionOp *
|
||||
flatpak_transaction_operation_new (const char *remote,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
gboolean install,
|
||||
gboolean update)
|
||||
{
|
||||
FlatpakTransactionOp *self = g_new0 (FlatpakTransactionOp, 1);
|
||||
|
||||
self->remote = g_strdup (remote);
|
||||
self->ref = g_strdup (ref);
|
||||
self->subpaths = g_strdupv ((char **)subpaths);
|
||||
self->update = update;
|
||||
self->install = install;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
flatpak_transaction_operation_free (FlatpakTransactionOp *self)
|
||||
{
|
||||
g_free (self->remote);
|
||||
g_free (self->ref);
|
||||
g_free (self->commit);
|
||||
g_strfreev (self->subpaths);
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
FlatpakTransaction *
|
||||
flatpak_transaction_new (FlatpakDir *dir,
|
||||
gboolean no_pull,
|
||||
gboolean no_deploy,
|
||||
gboolean add_deps,
|
||||
gboolean add_related)
|
||||
{
|
||||
FlatpakTransaction *t = g_new0 (FlatpakTransaction, 1);
|
||||
|
||||
t->dir = g_object_ref (dir);
|
||||
t->refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
t->no_pull = no_pull;
|
||||
t->no_deploy = no_deploy;
|
||||
t->add_deps = add_deps;
|
||||
t->add_related = add_related;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
flatpak_transaction_free (FlatpakTransaction *self)
|
||||
{
|
||||
g_hash_table_unref (self->refs);
|
||||
g_list_free_full (self->ops, (GDestroyNotify)flatpak_transaction_operation_free);
|
||||
g_object_unref (self->dir);
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_transaction_contains_ref (FlatpakTransaction *self,
|
||||
const char *ref)
|
||||
{
|
||||
FlatpakTransactionOp *op;
|
||||
|
||||
op = g_hash_table_lookup (self->refs, ref);
|
||||
|
||||
return op != NULL;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
subpaths_to_string (const char **subpaths)
|
||||
{
|
||||
GString *s = NULL;
|
||||
int i;
|
||||
|
||||
if (subpaths == NULL)
|
||||
return g_strdup ("[$old]");
|
||||
|
||||
if (*subpaths == 0)
|
||||
return g_strdup ("[*]");
|
||||
|
||||
s = g_string_new ("[");
|
||||
for (i = 0; subpaths[i] != NULL; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, subpaths[i]);
|
||||
}
|
||||
g_string_append (s, "]");
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
FlatpakTransactionOp *
|
||||
flatpak_transaction_add_op (FlatpakTransaction *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
gboolean install,
|
||||
gboolean update)
|
||||
{
|
||||
FlatpakTransactionOp *op;
|
||||
g_autofree char *subpaths_str = NULL;
|
||||
const char *opname;
|
||||
|
||||
if (install)
|
||||
{
|
||||
if (update)
|
||||
opname = "install/update";
|
||||
else
|
||||
opname = "install";
|
||||
}
|
||||
else
|
||||
opname = "update";
|
||||
subpaths_str = subpaths_to_string (subpaths);
|
||||
g_debug ("Transaction: %s %s:%s%s",
|
||||
opname, remote, ref, subpaths_str);
|
||||
|
||||
op = g_hash_table_lookup (self->refs, ref);
|
||||
if (op != NULL)
|
||||
{
|
||||
/* Only override subpaths if already specified,
|
||||
we always want the un-subpathed to win if specified. */
|
||||
if (op->subpaths != NULL && op->subpaths[0] != NULL && subpaths != NULL)
|
||||
{
|
||||
g_strfreev (op->subpaths);
|
||||
op->subpaths = g_strdupv ((char **)subpaths);
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
op = flatpak_transaction_operation_new (remote, ref, subpaths, install, update);
|
||||
g_hash_table_insert (self->refs, g_strdup (ref), op);
|
||||
self->ops = g_list_prepend (self->ops, op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
static char *
|
||||
ask_for_remote (const char **remotes)
|
||||
{
|
||||
int n_remotes = g_strv_length ((char **)remotes);
|
||||
int chosen = 0;
|
||||
int i;
|
||||
|
||||
if (n_remotes == 1)
|
||||
{
|
||||
if (flatpak_yes_no_prompt (_("Found in remote %s, do you want to install it?"), remotes[0]))
|
||||
chosen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print (_("Found in several remotes:\n"));
|
||||
for (i = 0; remotes[i] != NULL; i++)
|
||||
{
|
||||
g_print ("%d) %s\n", i + 1, remotes[i]);
|
||||
}
|
||||
chosen = flatpak_number_prompt (0, n_remotes, _("Which do you want to install (0 to abort)?"));
|
||||
}
|
||||
|
||||
if (chosen == 0)
|
||||
return NULL;
|
||||
|
||||
return g_strdup (remotes[chosen-1]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_related (FlatpakTransaction *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) related = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
int i;
|
||||
|
||||
if (!self->add_related)
|
||||
return TRUE;
|
||||
|
||||
if (self->no_pull)
|
||||
related = flatpak_dir_find_local_related (self->dir, ref, remote, NULL, &local_error);
|
||||
else
|
||||
related = flatpak_dir_find_remote_related (self->dir, ref, remote, NULL, &local_error);
|
||||
if (related == NULL)
|
||||
{
|
||||
g_printerr (_("Warning: Problem looking for related refs: %s\n"), local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < related->len; i++)
|
||||
{
|
||||
FlatpakRelated *rel = g_ptr_array_index (related, i);
|
||||
FlatpakTransactionOp *op;
|
||||
|
||||
if (!rel->download)
|
||||
continue;
|
||||
|
||||
op = flatpak_transaction_add_op (self, remote, rel->ref,
|
||||
(const char **)rel->subpaths,
|
||||
TRUE, TRUE);
|
||||
op->non_fatal = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_deps (FlatpakTransaction *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *runtime_ref = NULL;
|
||||
g_autofree char *full_runtime_ref = NULL;
|
||||
g_autofree char *runtime_remote = NULL;
|
||||
const char *pref;
|
||||
|
||||
runtime_ref = transaction_fetch_runtime_ref (self->dir, remote, ref);
|
||||
if (runtime_ref == NULL)
|
||||
return TRUE;
|
||||
|
||||
pref = strchr (ref, '/') + 1;
|
||||
|
||||
full_runtime_ref = g_strconcat ("runtime/", runtime_ref, NULL);
|
||||
|
||||
if (!flatpak_transaction_contains_ref (self, full_runtime_ref))
|
||||
{
|
||||
if (!ref_is_installed (full_runtime_ref))
|
||||
{
|
||||
g_auto(GStrv) remotes = NULL;
|
||||
|
||||
g_print (_("Required runtime for %s (%s) is not installed, searching...\n"),
|
||||
pref, runtime_ref);
|
||||
|
||||
remotes = flatpak_dir_search_for_dependency (self->dir, full_runtime_ref, NULL, NULL);
|
||||
if (remotes == NULL || *remotes == NULL)
|
||||
{
|
||||
g_print (_("The required runtime %s was not found in a configured remote.\n"),
|
||||
runtime_ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
runtime_remote = ask_for_remote ((const char **)remotes);
|
||||
}
|
||||
|
||||
if (runtime_remote == NULL)
|
||||
return flatpak_fail (error,
|
||||
"The Application %s requires the runtime %s which is not installed",
|
||||
pref, runtime_ref);
|
||||
|
||||
flatpak_transaction_add_op (self, runtime_remote, full_runtime_ref, NULL, TRUE, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update if in same dir */
|
||||
if (dir_ref_is_installed (self->dir, full_runtime_ref, &runtime_remote))
|
||||
{
|
||||
flatpak_transaction_add_op (self, runtime_remote, full_runtime_ref, NULL, FALSE, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (runtime_remote != NULL &&
|
||||
!add_related (self, runtime_remote, full_runtime_ref, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
flatpak_transaction_add_ref (FlatpakTransaction *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
gboolean is_update,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *origin = NULL;
|
||||
const char *pref;
|
||||
|
||||
pref = strchr (ref, '/') + 1;
|
||||
|
||||
if (is_update)
|
||||
{
|
||||
if (!dir_ref_is_installed (self->dir, ref, &origin))
|
||||
{
|
||||
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_NOT_INSTALLED,
|
||||
_("%s not installed"), pref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (flatpak_dir_get_remote_disabled (self->dir, origin))
|
||||
{
|
||||
g_debug (_("Remote %s disabled, ignoring %s update"), origin, pref);
|
||||
return TRUE;
|
||||
}
|
||||
remote = origin;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (remote != NULL);
|
||||
if (dir_ref_is_installed (self->dir, ref, NULL))
|
||||
{
|
||||
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
|
||||
_("%s already installed"), pref);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->add_deps)
|
||||
add_deps (self, remote, ref, error);
|
||||
|
||||
flatpak_transaction_add_op (self, remote, ref, subpaths, !is_update, is_update);
|
||||
|
||||
if (!add_related (self, remote, ref, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_transaction_add_install (FlatpakTransaction *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
GError **error)
|
||||
{
|
||||
const char *all_paths[] = { NULL };
|
||||
|
||||
/* If we install with no special args pull all subpaths */
|
||||
if (subpaths == NULL)
|
||||
subpaths = all_paths;
|
||||
|
||||
return flatpak_transaction_add_ref (self, remote, ref, subpaths, FALSE, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_transaction_add_update (FlatpakTransaction *self,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
GError **error)
|
||||
{
|
||||
return flatpak_transaction_add_ref (self, NULL, ref, subpaths, TRUE, error);
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
flatpak_transaction_run (FlatpakTransaction *self,
|
||||
gboolean stop_on_first_error,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GList *l;
|
||||
gboolean succeeded = TRUE;
|
||||
|
||||
self->ops = g_list_reverse (self->ops);
|
||||
|
||||
for (l = self->ops; l != NULL; l = l->next)
|
||||
{
|
||||
FlatpakTransactionOp *op = l->data;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
gboolean res;
|
||||
g_autofree char *subpaths_str = subpaths_to_string ((const char **)op->subpaths);
|
||||
const char *pref;
|
||||
const char *opname;
|
||||
|
||||
if (op->install && op->update)
|
||||
{
|
||||
if (dir_ref_is_installed (self->dir, op->ref, NULL))
|
||||
op->install = FALSE;
|
||||
else
|
||||
op->update = FALSE;
|
||||
}
|
||||
|
||||
pref = strchr (op->ref, '/') + 1;
|
||||
|
||||
if (op->install)
|
||||
{
|
||||
opname = _("install");
|
||||
g_print (_("Installing: %s from %s\n"), pref, op->remote);
|
||||
res = TRUE;
|
||||
res = flatpak_dir_install (self->dir,
|
||||
self->no_pull,
|
||||
self->no_deploy,
|
||||
op->ref, op->remote,
|
||||
(const char **)op->subpaths,
|
||||
NULL,
|
||||
cancellable, &local_error);
|
||||
}
|
||||
else /* update */
|
||||
{
|
||||
opname = _("update");
|
||||
g_print (_("Updating: %s from %s\n"), pref, op->remote);
|
||||
res = flatpak_dir_update (self->dir,
|
||||
self->no_pull,
|
||||
self->no_deploy,
|
||||
op->ref, op->remote, op->commit,
|
||||
(const char **)op->subpaths,
|
||||
NULL,
|
||||
cancellable, &local_error);
|
||||
|
||||
if (res)
|
||||
{
|
||||
g_autoptr(GVariant) deploy_data = NULL;
|
||||
g_autofree char *commit = NULL;
|
||||
deploy_data = flatpak_dir_get_deploy_data (self->dir, op->ref, NULL, NULL);
|
||||
commit = g_strndup (flatpak_deploy_data_get_commit (deploy_data), 12);
|
||||
g_print (_("Now at %s.\n"), commit);
|
||||
}
|
||||
|
||||
/* Handle noop-updates */
|
||||
if (!res && g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED))
|
||||
{
|
||||
g_print (_("No updates.\n"));
|
||||
res = TRUE;
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
if (op->non_fatal)
|
||||
{
|
||||
g_printerr (_("Warning: Failed to %s %s: %s\n"),
|
||||
opname, pref, local_error->message);
|
||||
}
|
||||
else if (!stop_on_first_error)
|
||||
{
|
||||
g_printerr (_("Error: Failed to %s %s: %s\n"),
|
||||
opname, pref, local_error->message);
|
||||
if (succeeded)
|
||||
{
|
||||
succeeded = FALSE;
|
||||
flatpak_fail (error, _("One or more operations failed"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, local_error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright © 2016 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:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __FLATPAK_TRANSACTION_H__
|
||||
#define __FLATPAK_TRANSACTION_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include "flatpak-dir.h"
|
||||
|
||||
typedef struct FlatpakTransaction FlatpakTransaction;
|
||||
|
||||
FlatpakTransaction *flatpak_transaction_new (FlatpakDir *dir,
|
||||
gboolean no_pull,
|
||||
gboolean no_deploy,
|
||||
gboolean add_deps,
|
||||
gboolean add_related);
|
||||
void flatpak_transaction_free (FlatpakTransaction *self);
|
||||
gboolean flatpak_transaction_run (FlatpakTransaction *self,
|
||||
gboolean stop_on_first_errror,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean flatpak_transaction_add_install (FlatpakTransaction *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
GError **error);
|
||||
gboolean flatpak_transaction_add_update (FlatpakTransaction *self,
|
||||
const char *ref,
|
||||
const char **subpaths,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakTransaction, flatpak_transaction_free)
|
||||
|
||||
#endif /* __FLATPAK_TRANSACTION_H__ */
|
||||
@@ -4227,6 +4227,29 @@ flatpak_dir_remote_fetch_summary (FlatpakDir *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_dir_remote_has_ref (FlatpakDir *self,
|
||||
const char *remote,
|
||||
const char *ref)
|
||||
{
|
||||
g_autoptr(GBytes) summary_bytes = NULL;
|
||||
g_autoptr(GVariant) summary = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
if (!flatpak_dir_remote_fetch_summary (self, remote,
|
||||
&summary_bytes,
|
||||
NULL, &local_error))
|
||||
{
|
||||
g_debug ("Can't get summary for remote %s: %s\n", remote, local_error->message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT,
|
||||
summary_bytes, FALSE));
|
||||
|
||||
return flatpak_summary_lookup_ref (summary, ref, NULL);
|
||||
}
|
||||
|
||||
/* This duplicates ostree_repo_list_refs so it can use flatpak_dir_remote_fetch_summary
|
||||
and get caching */
|
||||
static gboolean
|
||||
@@ -4978,6 +5001,66 @@ flatpak_dir_list_remotes (FlatpakDir *self,
|
||||
return res;
|
||||
}
|
||||
|
||||
char **
|
||||
flatpak_dir_list_enumerated_remotes (FlatpakDir *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) res = g_ptr_array_new_with_free_func (g_free);
|
||||
g_auto(GStrv) remotes = NULL;
|
||||
int i;
|
||||
|
||||
remotes = flatpak_dir_list_remotes (self, cancellable, error);
|
||||
if (remotes == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; remotes != NULL && remotes[i] != NULL; i++)
|
||||
{
|
||||
const char *remote = remotes[i];
|
||||
|
||||
if (flatpak_dir_get_remote_disabled (self, remote))
|
||||
continue;
|
||||
|
||||
if (flatpak_dir_get_remote_noenumerate (self, remote))
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (res, g_strdup (remote));
|
||||
}
|
||||
|
||||
g_ptr_array_add (res, NULL);
|
||||
return (char **)g_ptr_array_free (g_steal_pointer (&res), FALSE);
|
||||
}
|
||||
|
||||
char **
|
||||
flatpak_dir_search_for_dependency (FlatpakDir *self,
|
||||
const char *runtime_ref,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) found = g_ptr_array_new_with_free_func (g_free);
|
||||
g_auto(GStrv) remotes = NULL;
|
||||
int i;
|
||||
|
||||
remotes = flatpak_dir_list_enumerated_remotes (self, cancellable, error);
|
||||
if (remotes == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; remotes != NULL && remotes[i] != NULL; i++)
|
||||
{
|
||||
const char *remote = remotes[i];
|
||||
|
||||
if (flatpak_dir_get_remote_nodeps (self, remote))
|
||||
continue;
|
||||
|
||||
if (flatpak_dir_remote_has_ref (self, remote, runtime_ref))
|
||||
g_ptr_array_add (found, g_strdup (remote));
|
||||
}
|
||||
|
||||
g_ptr_array_add (found, NULL);
|
||||
|
||||
return (char **)g_ptr_array_free (g_steal_pointer (&found), FALSE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_dir_remove_remote (FlatpakDir *self,
|
||||
gboolean force_remove,
|
||||
|
||||
@@ -153,6 +153,13 @@ GFile * flatpak_dir_get_if_deployed (FlatpakDir *self,
|
||||
const char *ref,
|
||||
const char *checksum,
|
||||
GCancellable *cancellable);
|
||||
gboolean flatpak_dir_remote_has_ref (FlatpakDir *self,
|
||||
const char *remote,
|
||||
const char *ref);
|
||||
char ** flatpak_dir_search_for_dependency (FlatpakDir *self,
|
||||
const char *runtime_ref,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
char * flatpak_dir_find_remote_ref (FlatpakDir *self,
|
||||
const char *remote,
|
||||
const char *name,
|
||||
@@ -395,6 +402,9 @@ gboolean flatpak_dir_create_remote_for_ref_file (FlatpakDir *self,
|
||||
char **flatpak_dir_list_remotes (FlatpakDir *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
char **flatpak_dir_list_enumerated_remotes (FlatpakDir *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean flatpak_dir_modify_remote (FlatpakDir *self,
|
||||
const char *remote_name,
|
||||
GKeyFile *config,
|
||||
|
||||
@@ -3823,6 +3823,75 @@ flatpak_allocate_tmpdir (int tmpdir_dfd,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_yes_no_prompt (const char *prompt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list var_args;
|
||||
gchar *s;
|
||||
|
||||
va_start (var_args, prompt);
|
||||
s = g_strdup_vprintf (prompt, var_args);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_print ("%s %s: ", s, "[y/n]");
|
||||
if (fgets (buf, sizeof (buf), stdin) == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_strstrip (buf);
|
||||
if (g_ascii_strcasecmp (buf, "y") == 0 ||
|
||||
g_ascii_strcasecmp (buf, "yes") == 0)
|
||||
return TRUE;
|
||||
|
||||
if (g_ascii_strcasecmp (buf, "n") == 0 ||
|
||||
g_ascii_strcasecmp (buf, "no") == 0)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_number (const char *s)
|
||||
{
|
||||
while (*s != 0)
|
||||
{
|
||||
if (!g_ascii_isdigit (*s))
|
||||
return FALSE;
|
||||
s++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
long
|
||||
flatpak_number_prompt (int min, int max, const char *prompt, ...)
|
||||
{
|
||||
char buf[512];
|
||||
va_list var_args;
|
||||
gchar *s;
|
||||
|
||||
va_start (var_args, prompt);
|
||||
s = g_strdup_vprintf (prompt, var_args);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_print ("%s [%d-%d]: ", s, min, max);
|
||||
if (fgets (buf, sizeof (buf), stdin) == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_strstrip (buf);
|
||||
|
||||
if (is_number (buf))
|
||||
{
|
||||
long res = strtol (buf, NULL, 10);
|
||||
|
||||
if (res >= min && res <= max)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Uncomment to get debug traces in /tmp/flatpak-completion-debug.txt (nice
|
||||
* to not have it interfere with stdout/stderr)
|
||||
*/
|
||||
|
||||
@@ -467,6 +467,9 @@ gboolean flatpak_allocate_tmpdir (int tmpdir_dfd,
|
||||
GError **error);
|
||||
|
||||
|
||||
gboolean flatpak_yes_no_prompt (const char *prompt, ...);
|
||||
long flatpak_number_prompt (int min, int max, const char *prompt, ...);
|
||||
|
||||
typedef struct {
|
||||
char *shell_cur;
|
||||
char *cur;
|
||||
|
||||
@@ -157,6 +157,14 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-deps</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Don't update or install runtime dependencies when installing.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--app</option></term>
|
||||
|
||||
|
||||
Reference in new issue
Block a user