install: Add --reinstall

If you're installing something and its already installed, we undeploy
the old install first before deploying the new. This makes it very
easy to switch an application from one remote to another, without
having to uninstall first, which is both painful and could cause
the download to be unnecessary large.

Closes: #1241
Approved by: alexlarsson
This commit is contained in:
Alexander Larsson 2017-12-11 16:49:40 +01:00 committed by Atomic Bot
parent 97683cfbe1
commit 3ade86b292
9 changed files with 116 additions and 32 deletions

View File

@ -51,6 +51,7 @@ static gboolean opt_app;
static gboolean opt_bundle;
static gboolean opt_from;
static gboolean opt_yes;
static gboolean opt_reinstall;
static GOptionEntry options[] = {
{ "arch", 0, 0, G_OPTION_ARG_STRING, &opt_arch, N_("Arch to install for"), N_("ARCH") },
@ -66,6 +67,7 @@ static GOptionEntry options[] = {
{ "gpg-file", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_gpg_file, N_("Check bundle signatures with GPG key from FILE (- for stdin)"), N_("FILE") },
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, N_("Only install this subpath"), N_("PATH") },
{ "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 },
{ NULL }
};
@ -286,7 +288,7 @@ install_bundle (FlatpakDir *dir,
return FALSE;
transaction = flatpak_transaction_new (dir, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, opt_reinstall);
if (!flatpak_transaction_add_install_bundle (transaction, file, gpg_data, error))
return FALSE;
@ -440,7 +442,7 @@ install_from (FlatpakDir *dir,
g_print (_("Installing: %s\n"), slash + 1);
transaction = flatpak_transaction_new (clone, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, opt_reinstall);
if (!flatpak_transaction_add_install (transaction, remote, ref, (const char **)opt_subpaths, error))
return FALSE;
@ -510,7 +512,7 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
kinds = flatpak_kinds_from_bools (opt_app, opt_runtime);
transaction = flatpak_transaction_new (dir, opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, opt_reinstall);
for (i = 0; i < n_prefs; i++)
{

View File

@ -187,7 +187,7 @@ flatpak_builtin_update (int argc,
{
FlatpakTransaction *transaction = flatpak_transaction_new (g_ptr_array_index (dirs, k),
opt_yes, opt_no_pull, opt_no_deploy,
opt_no_static_deltas, !opt_no_deps, !opt_no_related);
opt_no_static_deltas, !opt_no_deps, !opt_no_related, FALSE);
g_ptr_array_add (transactions, transaction);
}

View File

@ -60,6 +60,7 @@ struct FlatpakTransaction {
gboolean no_static_deltas;
gboolean add_deps;
gboolean add_related;
gboolean reinstall;
};
@ -170,7 +171,8 @@ flatpak_transaction_new (FlatpakDir *dir,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean add_deps,
gboolean add_related)
gboolean add_related,
gboolean reinstall)
{
FlatpakTransaction *t = g_new0 (FlatpakTransaction, 1);
@ -183,6 +185,7 @@ flatpak_transaction_new (FlatpakDir *dir,
t->no_static_deltas = no_static_deltas;
t->add_deps = add_deps;
t->add_related = add_related;
t->reinstall = reinstall;
return t;
}
@ -482,10 +485,20 @@ flatpak_transaction_add_ref (FlatpakTransaction *self,
else if (kind == FLATPAK_TRANSACTION_OP_KIND_INSTALL)
{
g_assert (remote != NULL);
if (dir_ref_is_installed (self->dir, ref, NULL, NULL))
if (!self->reinstall &&
dir_ref_is_installed (self->dir, ref, &origin, NULL))
{
g_printerr (_("%s already installed, skipping\n"), pref);
return TRUE;
if (strcmp (remote, origin) == 0)
{
g_printerr (_("%s already installed, skipping\n"), pref);
return TRUE;
}
else
{
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
_("%s is already installed from other remote (%s)"), pref, origin);
return FALSE;
}
}
}
@ -665,7 +678,7 @@ flatpak_transaction_run (FlatpakTransaction *self,
{
FlatpakTransactionOp *op = l->data;
g_autoptr(GError) local_error = NULL;
gboolean res;
gboolean res = TRUE;
const char *pref;
const char *opname;
FlatpakTransactionOpKind kind;
@ -704,6 +717,7 @@ flatpak_transaction_run (FlatpakTransaction *self,
self->no_pull,
self->no_deploy,
self->no_static_deltas,
self->reinstall,
op->ref, op->remote,
(const char **)op->subpaths,
progress,

View File

@ -34,7 +34,8 @@ FlatpakTransaction *flatpak_transaction_new (FlatpakDir *dir,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean add_deps,
gboolean add_related);
gboolean add_related,
gboolean reinstall);
void flatpak_transaction_free (FlatpakTransaction *self);
gboolean flatpak_transaction_update_metadata (FlatpakTransaction *self,
gboolean all_remotes,

View File

@ -5598,11 +5598,24 @@ flatpak_dir_deploy (FlatpakDir *self,
return TRUE;
}
/* -origin remotes are deleted when the last ref refering to it is undeployed */
static void
maybe_prune_remote (FlatpakDir *self,
const char *remote)
{
if (remote != NULL &&
g_str_has_suffix (remote, "-origin") &&
flatpak_dir_get_remote_noenumerate (self, remote) &&
!flatpak_dir_remote_has_deploys (self, remote))
ostree_repo_remote_delete (self->repo, remote, NULL, NULL);
}
gboolean
flatpak_dir_deploy_install (FlatpakDir *self,
const char *ref,
const char *origin,
const char **subpaths,
gboolean reinstall,
GCancellable *cancellable,
GError **error)
{
@ -5613,6 +5626,7 @@ flatpak_dir_deploy_install (FlatpakDir *self,
gboolean ret = FALSE;
g_autoptr(GError) local_error = NULL;
g_auto(GStrv) ref_parts = g_strsplit (ref, "/", -1);
g_autofree char *remove_ref_from_remote = NULL;
if (!flatpak_dir_lock (self, &lock,
cancellable, error))
@ -5621,9 +5635,33 @@ flatpak_dir_deploy_install (FlatpakDir *self,
old_deploy_dir = flatpak_dir_get_if_deployed (self, ref, NULL, cancellable);
if (old_deploy_dir != NULL)
{
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
_("%s branch %s already installed"), ref_parts[1], ref_parts[3]);
goto out;
if (reinstall)
{
g_autofree char *old_active = flatpak_dir_read_active (self, ref, cancellable);
g_autoptr(GVariant) old_deploy = NULL;
const char *old_origin;
old_deploy = flatpak_load_deploy_data (old_deploy_dir, cancellable, error);
if (old_deploy == NULL)
goto out;
/* If the old install was from a different remote, remove the ref */
old_origin = flatpak_deploy_data_get_origin (old_deploy);
if (strcmp (old_origin, origin) != 0)
remove_ref_from_remote = g_strdup (old_origin);
g_debug ("Removing old deployment for reinstall");
if (!flatpak_dir_undeploy (self, ref, old_active,
TRUE, FALSE,
cancellable, error))
goto out;
}
else
{
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
_("%s branch %s already installed"), ref_parts[1], ref_parts[3]);
goto out;
}
}
deploy_base = flatpak_dir_get_deploy_dir (self, ref);
@ -5652,6 +5690,15 @@ flatpak_dir_deploy_install (FlatpakDir *self,
goto out;
}
/* Remove old ref if the reinstalled was from a different remote */
if (remove_ref_from_remote != NULL)
{
if (!flatpak_dir_remove_ref (self, remove_ref_from_remote, ref, cancellable, error))
goto out;
maybe_prune_remote (self, remove_ref_from_remote);
}
/* Release lock before doing possibly slow prune */
glnx_release_lock_file (&lock);
@ -5898,6 +5945,7 @@ flatpak_dir_install (FlatpakDir *self,
gboolean no_pull,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean reinstall,
const char *ref,
const char *remote_name,
const char **opt_subpaths,
@ -6060,6 +6108,9 @@ flatpak_dir_install (FlatpakDir *self,
if (no_deploy)
helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY;
if (reinstall)
helper_flags |= FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL;
g_debug ("Calling system helper: Deploy");
if (!flatpak_system_helper_call_deploy_sync (system_helper,
child_repo_path ? child_repo_path : "",
@ -6089,7 +6140,7 @@ flatpak_dir_install (FlatpakDir *self,
if (!no_deploy)
{
if (!flatpak_dir_deploy_install (self, ref, remote_name, opt_subpaths,
cancellable, error))
reinstall, cancellable, error))
return FALSE;
}
@ -6312,7 +6363,7 @@ flatpak_dir_install_bundle (FlatpakDir *self,
}
else
{
if (!flatpak_dir_deploy_install (self, ref, remote, NULL, cancellable, error))
if (!flatpak_dir_deploy_install (self, ref, remote, NULL, FALSE, cancellable, error))
return FALSE;
}
@ -6800,11 +6851,7 @@ flatpak_dir_uninstall (FlatpakDir *self,
glnx_release_lock_file (&lock);
if (repository != NULL &&
g_str_has_suffix (repository, "-origin") &&
flatpak_dir_get_remote_noenumerate (self, repository) &&
!flatpak_dir_remote_has_deploys (self, repository))
ostree_repo_remote_delete (self->repo, repository, NULL, NULL);
maybe_prune_remote (self, repository);
if (!keep_ref)
flatpak_dir_prune (self, cancellable, NULL);

View File

@ -88,9 +88,10 @@ typedef enum {
FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE = 1 << 0,
FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY = 1 << 1,
FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL = 1 << 2,
FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL = 1 << 3,
} FlatpakHelperDeployFlags;
#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE|FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY|FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL)
#define FLATPAK_HELPER_DEPLOY_FLAGS_ALL (FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE|FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY|FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL|FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL)
typedef enum {
FLATPAK_HELPER_UNINSTALL_FLAGS_NONE = 0,
@ -436,12 +437,14 @@ gboolean flatpak_dir_deploy_install (FlatpakDir *self,
const char *ref,
const char *origin,
const char **subpaths,
gboolean reinstall,
GCancellable *cancellable,
GError **error);
gboolean flatpak_dir_install (FlatpakDir *self,
gboolean no_pull,
gboolean no_deploy,
gboolean no_static_deltas,
gboolean reinstall,
const char *ref,
const char *remote_name,
const char **subpaths,

View File

@ -1434,6 +1434,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,
ref, remote_name, (const char **)subpaths,
ostree_progress, cancellable, error))
goto out;

View File

@ -159,6 +159,7 @@ handle_deploy (FlatpakSystemHelper *object,
gboolean is_oci;
gboolean no_deploy;
gboolean local_pull;
gboolean reinstall;
g_autoptr(GMainContext) main_context = NULL;
g_autofree char *url = NULL;
@ -187,6 +188,7 @@ handle_deploy (FlatpakSystemHelper *object,
is_update = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_UPDATE) != 0;
no_deploy = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_NO_DEPLOY) != 0;
local_pull = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_LOCAL_PULL) != 0;
reinstall = (arg_flags & FLATPAK_HELPER_DEPLOY_FLAGS_REINSTALL) != 0;
deploy_dir = flatpak_dir_get_if_deployed (system, arg_ref, NULL, NULL);
@ -195,18 +197,23 @@ handle_deploy (FlatpakSystemHelper *object,
g_autofree char *real_origin = NULL;
if (!is_update)
{
/* Can't install already installed app */
g_dbus_method_invocation_return_error (invocation, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
"%s is already installed", arg_ref);
return TRUE;
if (!reinstall)
{
/* Can't install already installed app */
g_dbus_method_invocation_return_error (invocation, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
"%s is already installed", arg_ref);
return TRUE;
}
}
real_origin = flatpak_dir_get_origin (system, arg_ref, NULL, NULL);
if (g_strcmp0 (real_origin, arg_origin) != 0)
else
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
"Wrong origin %s for update", arg_origin);
return TRUE;
real_origin = flatpak_dir_get_origin (system, arg_ref, NULL, NULL);
if (g_strcmp0 (real_origin, arg_origin) != 0)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
"Wrong origin %s for update", arg_origin);
return TRUE;
}
}
}
else if (!deploy_dir && is_update)
@ -389,6 +396,7 @@ handle_deploy (FlatpakSystemHelper *object,
{
if (!flatpak_dir_deploy_install (system, arg_ref, arg_origin,
(const char **) arg_subpaths,
reinstall,
NULL, &error))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,

View File

@ -28,7 +28,7 @@ if [ x${USE_COLLECTIONS_IN_CLIENT-} == xyes ] || [ x${USE_COLLECTIONS_IN_SERVER-
skip_without_p2p
fi
echo "1..10"
echo "1..12"
#Regular repo
setup_repo
@ -76,6 +76,14 @@ fi
install_repo test-gpg2
echo "ok with alternative gpg key"
if ${FLATPAK} ${U} install test-repo org.test.Platform 2> install-error-log; then
assert_not_reached "Should not be able to install again from different remote without reinstall"
fi
echo "ok failed to install again from different remote"
${FLATPAK} ${U} install --reinstall test-repo org.test.Platform
echo "ok re-install"
${FLATPAK} ${U} uninstall org.test.Platform org.test.Hello
if ${FLATPAK} ${U} install test-missing-gpg-repo org.test.Platform 2> install-error-log; then