mirror of
https://github.com/flatpak/flatpak.git
synced 2026-05-06 23:18:40 -04:00
Add pin command to keep unused runtimes
As discussed here [1], we want a way to mark runtimes to be kept even when they are unused by any apps and we are removing such runtimes. Currently this is a command that can be run manually; a subsequent commit will pin runtimes automatically if they are installed independently of any app. A unit test is included. [1] https://github.com/flatpak/flatpak/issues/2639#issuecomment-662311756
This commit is contained in:
committed by
Alexander Larsson
parent
f24b1fdc1a
commit
d2d5397cc1
@@ -81,6 +81,7 @@ flatpak_SOURCES = \
|
||||
app/flatpak-builtins-update.c \
|
||||
app/flatpak-builtins-uninstall.c \
|
||||
app/flatpak-builtins-mask.c \
|
||||
app/flatpak-builtins-pin.c \
|
||||
app/flatpak-builtins-list.c \
|
||||
app/flatpak-builtins-info.c \
|
||||
app/flatpak-builtins-config.c \
|
||||
|
||||
@@ -138,7 +138,9 @@ flatpak_builtin_mask (int argc, char **argv, GCancellable *cancellable, GError *
|
||||
{
|
||||
g_autofree char *regexp;
|
||||
|
||||
regexp = flatpak_filter_glob_to_regexp (pattern, error);
|
||||
regexp = flatpak_filter_glob_to_regexp (pattern,
|
||||
FALSE, /* match apps or runtimes */
|
||||
error);
|
||||
if (regexp == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
||||
185
app/flatpak-builtins-pin.c
Normal file
185
app/flatpak-builtins-pin.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright © 2020 Endless OS Foundation LLC
|
||||
*
|
||||
* 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:
|
||||
* Matthew Leeds <matthew.leeds@endlessm.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include "flatpak-builtins.h"
|
||||
#include "flatpak-builtins-utils.h"
|
||||
#include "flatpak-cli-transaction.h"
|
||||
#include "flatpak-quiet-transaction.h"
|
||||
#include "flatpak-utils-private.h"
|
||||
#include "flatpak-error.h"
|
||||
|
||||
/* Note: the code here is copied from flatpak-builtins-mask.c */
|
||||
|
||||
static gboolean opt_remove;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "remove", 0, 0, G_OPTION_ARG_NONE, &opt_remove, N_("Remove matching pins"), NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static GPtrArray *
|
||||
get_old_patterns (FlatpakDir *dir)
|
||||
{
|
||||
g_autoptr(GPtrArray) patterns = NULL;
|
||||
g_autofree char *pinned = NULL;
|
||||
int i;
|
||||
|
||||
patterns = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
pinned = flatpak_dir_get_config (dir, "pinned", NULL);
|
||||
if (pinned)
|
||||
{
|
||||
g_auto(GStrv) oldv = g_strsplit (pinned, ";", -1);
|
||||
|
||||
for (i = 0; oldv[i] != NULL; i++)
|
||||
{
|
||||
const char *old = oldv[i];
|
||||
|
||||
if (*old != 0 && !flatpak_g_ptr_array_contains_string (patterns, old))
|
||||
g_ptr_array_add (patterns, g_strdup (old));
|
||||
}
|
||||
}
|
||||
|
||||
return g_steal_pointer (&patterns);
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
flatpak_builtin_pin (int argc, char **argv, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(GPtrArray) dirs = NULL;
|
||||
FlatpakDir *dir;
|
||||
g_autofree char *merged_patterns = NULL;
|
||||
g_autoptr(GPtrArray) patterns = NULL;
|
||||
int i;
|
||||
|
||||
context = g_option_context_new (_("[PATTERN…] - disable automatic removal of runtimes matching patterns"));
|
||||
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
||||
|
||||
if (!flatpak_option_context_parse (context, options, &argc, &argv,
|
||||
FLATPAK_BUILTIN_FLAG_ONE_DIR,
|
||||
&dirs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
dir = g_ptr_array_index (dirs, 0);
|
||||
|
||||
patterns = get_old_patterns (dir);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
if (patterns->len == 0)
|
||||
{
|
||||
g_print (_("No pinned patterns\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print (_("Pinned patterns:\n"));
|
||||
|
||||
for (i = 0; i < patterns->len; i++)
|
||||
{
|
||||
const char *old = g_ptr_array_index (patterns, i);
|
||||
g_print (" %s\n", old);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
const char *pattern = argv[i];
|
||||
|
||||
if (opt_remove)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < patterns->len; j++)
|
||||
{
|
||||
if (strcmp (g_ptr_array_index (patterns, j), pattern) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == patterns->len)
|
||||
return flatpak_fail (error, _("No current pin matching %s"), pattern);
|
||||
else
|
||||
g_ptr_array_remove_index (patterns, j);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *regexp;
|
||||
|
||||
regexp = flatpak_filter_glob_to_regexp (pattern,
|
||||
TRUE, /* only match runtimes */
|
||||
error);
|
||||
if (regexp == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!flatpak_g_ptr_array_contains_string (patterns, pattern))
|
||||
g_ptr_array_add (patterns, g_strdup (pattern));
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_sort (patterns, flatpak_strcmp0_ptr);
|
||||
|
||||
g_ptr_array_add (patterns, NULL);
|
||||
merged_patterns = g_strjoinv (";", (char **)patterns->pdata);
|
||||
|
||||
if (!flatpak_dir_set_config (dir, "pinned", merged_patterns, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_complete_pin (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)
|
||||
{
|
||||
case 0:
|
||||
case 1: /* PATTERN */
|
||||
flatpak_complete_options (completion, global_entries);
|
||||
flatpak_complete_options (completion, options);
|
||||
flatpak_complete_options (completion, user_entries);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -86,6 +86,7 @@ BUILTINPROTO (remote_info)
|
||||
BUILTINPROTO (remote_list)
|
||||
BUILTINPROTO (install)
|
||||
BUILTINPROTO (mask)
|
||||
BUILTINPROTO (pin)
|
||||
BUILTINPROTO (update)
|
||||
BUILTINPROTO (make_current_app)
|
||||
BUILTINPROTO (uninstall)
|
||||
|
||||
@@ -80,6 +80,7 @@ static FlatpakCommand commands[] = {
|
||||
/* Alias remove to uninstall to help users of yum/dnf/apt */
|
||||
{ "remove", NULL, flatpak_builtin_uninstall, flatpak_complete_uninstall, TRUE },
|
||||
{ "mask", N_("Mask out updates and automatic installation"), flatpak_builtin_mask, flatpak_complete_mask },
|
||||
{ "pin", N_("Pin a runtime to prevent automatic removal"), flatpak_builtin_pin, flatpak_complete_pin },
|
||||
{ "list", N_("List installed apps and/or runtimes"), flatpak_builtin_list, flatpak_complete_list },
|
||||
{ "info", N_("Show info for installed app or runtime"), flatpak_builtin_info, flatpak_complete_info },
|
||||
{ "history", N_("Show history"), flatpak_builtin_history, flatpak_complete_history },
|
||||
|
||||
@@ -474,6 +474,8 @@ char ** flatpak_dir_search_for_dependency (FlatpakDir *self,
|
||||
GError **error);
|
||||
gboolean flatpak_dir_ref_is_masked (FlatpakDir *self,
|
||||
const char *ref);
|
||||
gboolean flatpak_dir_ref_is_pinned (FlatpakDir *self,
|
||||
const char *ref);
|
||||
char * flatpak_dir_find_remote_ref (FlatpakDir *self,
|
||||
const char *remote,
|
||||
const char **opt_sideload_repos,
|
||||
|
||||
@@ -214,6 +214,7 @@ struct FlatpakDir
|
||||
|
||||
/* Config cache, protected by config_cache lock */
|
||||
GRegex *masked;
|
||||
GRegex *pinned;
|
||||
|
||||
SoupSession *soup_session;
|
||||
};
|
||||
@@ -2260,6 +2261,7 @@ flatpak_dir_finalize (GObject *object)
|
||||
g_clear_pointer (&self->summary_cache, g_hash_table_unref);
|
||||
g_clear_pointer (&self->remote_filters, g_hash_table_unref);
|
||||
g_clear_pointer (&self->masked, g_regex_unref);
|
||||
g_clear_pointer (&self->pinned, g_regex_unref);
|
||||
|
||||
G_OBJECT_CLASS (flatpak_dir_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -3436,6 +3438,7 @@ flatpak_dir_recreate_repo (FlatpakDir *self,
|
||||
G_LOCK (config_cache);
|
||||
|
||||
g_clear_pointer (&self->masked, g_regex_unref);
|
||||
g_clear_pointer (&self->pinned, g_regex_unref);
|
||||
|
||||
G_UNLOCK (config_cache);
|
||||
|
||||
@@ -3841,6 +3844,7 @@ _flatpak_dir_reload_config (FlatpakDir *self,
|
||||
G_LOCK (config_cache);
|
||||
|
||||
g_clear_pointer (&self->masked, g_regex_unref);
|
||||
g_clear_pointer (&self->pinned, g_regex_unref);
|
||||
|
||||
G_UNLOCK (config_cache);
|
||||
return TRUE;
|
||||
@@ -13603,7 +13607,7 @@ flatpak_dir_get_mask_regexp (FlatpakDir *self)
|
||||
{
|
||||
g_autofree char *regexp = NULL;
|
||||
|
||||
regexp = flatpak_filter_glob_to_regexp (pattern, NULL);
|
||||
regexp = flatpak_filter_glob_to_regexp (pattern, FALSE, NULL);
|
||||
if (regexp)
|
||||
{
|
||||
if (i != 0)
|
||||
@@ -13635,6 +13639,66 @@ flatpak_dir_ref_is_masked (FlatpakDir *self,
|
||||
return !flatpak_filters_allow_ref (NULL, masked, ref);
|
||||
}
|
||||
|
||||
static GRegex *
|
||||
flatpak_dir_get_pin_regexp (FlatpakDir *self)
|
||||
{
|
||||
GRegex *res = NULL;
|
||||
|
||||
G_LOCK (config_cache);
|
||||
|
||||
if (self->pinned == NULL)
|
||||
{
|
||||
g_autofree char *pinned = NULL;
|
||||
|
||||
pinned = flatpak_dir_get_config (self, "pinned", NULL);
|
||||
if (pinned)
|
||||
{
|
||||
g_auto(GStrv) patterns = g_strsplit (pinned, ";", -1);
|
||||
g_autoptr(GString) deny_regexp = g_string_new ("^(");
|
||||
int i;
|
||||
|
||||
for (i = 0; patterns[i] != NULL; i++)
|
||||
{
|
||||
const char *pattern = patterns[i];
|
||||
|
||||
if (*pattern != 0)
|
||||
{
|
||||
g_autofree char *regexp = NULL;
|
||||
|
||||
regexp = flatpak_filter_glob_to_regexp (pattern,
|
||||
TRUE, /* only match runtimes */
|
||||
NULL);
|
||||
if (regexp)
|
||||
{
|
||||
if (i != 0)
|
||||
g_string_append (deny_regexp, "|");
|
||||
g_string_append (deny_regexp, regexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_string_append (deny_regexp, ")$");
|
||||
self->pinned = g_regex_new (deny_regexp->str, G_REGEX_DOLLAR_ENDONLY|G_REGEX_RAW|G_REGEX_OPTIMIZE, G_REGEX_MATCH_ANCHORED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (self->pinned)
|
||||
res = g_regex_ref (self->pinned);
|
||||
|
||||
G_UNLOCK (config_cache);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_dir_ref_is_pinned (FlatpakDir *self,
|
||||
const char *ref)
|
||||
{
|
||||
g_autoptr(GRegex) pinned = flatpak_dir_get_pin_regexp (self);
|
||||
|
||||
return !flatpak_filters_allow_ref (NULL, pinned, ref);
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
flatpak_dir_find_remote_related_for_metadata (FlatpakDir *self,
|
||||
FlatpakRemoteState *state,
|
||||
|
||||
@@ -2926,6 +2926,7 @@ find_used_refs (FlatpakDir *dir,
|
||||
*
|
||||
* A reference is used if it is either an application, or an sdk,
|
||||
* or the runtime of a used ref, or an extension of a used ref.
|
||||
* Pinned runtimes are also considered used; see flatpak-pin(1).
|
||||
*
|
||||
* Returns: (transfer container) (element-type FlatpakInstalledRef): a GPtrArray of
|
||||
* #FlatpakInstalledRef instances
|
||||
@@ -3030,6 +3031,12 @@ flatpak_installation_list_unused_refs (FlatpakInstallation *self,
|
||||
if (arch != NULL && strcmp (parts[2], arch) != 0)
|
||||
continue;
|
||||
|
||||
if (flatpak_dir_ref_is_pinned (dir, ref))
|
||||
{
|
||||
g_debug ("Ref %s is pinned, considering as used", ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!g_hash_table_contains (used_refs, ref))
|
||||
{
|
||||
if (g_hash_table_add (refs_hash, (gpointer) ref))
|
||||
|
||||
@@ -194,7 +194,7 @@ gboolean flatpak_id_has_subref_suffix (const char *id);
|
||||
char **flatpak_decompose_ref (const char *ref,
|
||||
GError **error);
|
||||
|
||||
char * flatpak_filter_glob_to_regexp (const char *glob, GError **error);
|
||||
char * flatpak_filter_glob_to_regexp (const char *glob, gboolean runtime_only, GError **error);
|
||||
gboolean flatpak_parse_filters (const char *data,
|
||||
GRegex **allow_refs_out,
|
||||
GRegex **deny_refs_out,
|
||||
|
||||
@@ -1131,7 +1131,9 @@ line_get_word (char **line)
|
||||
}
|
||||
|
||||
char *
|
||||
flatpak_filter_glob_to_regexp (const char *glob, GError **error)
|
||||
flatpak_filter_glob_to_regexp (const char *glob,
|
||||
gboolean runtime_only,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GString) regexp = g_string_new ("");
|
||||
int parts = 1;
|
||||
@@ -1139,8 +1141,16 @@ flatpak_filter_glob_to_regexp (const char *glob, GError **error)
|
||||
|
||||
if (g_str_has_prefix (glob, "app/"))
|
||||
{
|
||||
glob += strlen ("app/");
|
||||
g_string_append (regexp, "app/");
|
||||
if (runtime_only)
|
||||
{
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Glob can't match apps"));
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
glob += strlen ("app/");
|
||||
g_string_append (regexp, "app/");
|
||||
}
|
||||
}
|
||||
else if (g_str_has_prefix (glob, "runtime/"))
|
||||
{
|
||||
@@ -1148,7 +1158,12 @@ flatpak_filter_glob_to_regexp (const char *glob, GError **error)
|
||||
g_string_append (regexp, "runtime/");
|
||||
}
|
||||
else
|
||||
g_string_append (regexp, "(app|runtime)/");
|
||||
{
|
||||
if (runtime_only)
|
||||
g_string_append (regexp, "runtime/");
|
||||
else
|
||||
g_string_append (regexp, "(app|runtime)/");
|
||||
}
|
||||
|
||||
/* We really need an id part, the rest is optional */
|
||||
if (*glob == 0)
|
||||
@@ -1253,7 +1268,7 @@ flatpak_parse_filters (const char *data,
|
||||
if (next != NULL)
|
||||
return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("Trailing text on line %d"), i + 1);
|
||||
|
||||
ref_regexp = flatpak_filter_glob_to_regexp (glob, error);
|
||||
ref_regexp = flatpak_filter_glob_to_regexp (glob, FALSE, error);
|
||||
if (ref_regexp == NULL)
|
||||
return glnx_prefix_error (error, _("on line %d"), i + 1);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ man1 = \
|
||||
flatpak-update.1 \
|
||||
flatpak-uninstall.1 \
|
||||
flatpak-mask.1 \
|
||||
flatpak-pin.1 \
|
||||
flatpak-list.1 \
|
||||
flatpak-info.1 \
|
||||
flatpak-make-current.1 \
|
||||
|
||||
151
doc/flatpak-pin.xml
Normal file
151
doc/flatpak-pin.xml
Normal file
@@ -0,0 +1,151 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<refentry id="flatpak-pin">
|
||||
|
||||
<refentryinfo>
|
||||
<title>flatpak pin</title>
|
||||
<productname>flatpak</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Matthew</firstname>
|
||||
<surname>Leeds</surname>
|
||||
<email>matthew.leeds@endlessm.com</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>flatpak pin</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>flatpak-pin</refname>
|
||||
<refpurpose>Pin runtimes to prevent automatic removal</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>flatpak pin</command>
|
||||
<arg choice="opt" rep="repeat">OPTION</arg>
|
||||
<arg choice="plain" rep="repeat">PATTERN</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
Flatpak maintains a list of patterns that define which refs are pinned.
|
||||
A pinned ref will never be automatically uninstalled (as are unused
|
||||
runtimes periodically). This can be useful if for example you are using
|
||||
a runtime for development purposes.
|
||||
</para>
|
||||
<para>
|
||||
The patterns are just a partial ref, with the * character matching anything
|
||||
within that part of the ref. Only runtimes can be pinned, not apps. Here
|
||||
are some example patterns:
|
||||
<programlisting>
|
||||
org.some.Runtime
|
||||
org.some.Runtime//unstable
|
||||
runtime/org.domain.*
|
||||
org.some.Runtime/arm
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
To list the current set of pins, run this command without any patterns.
|
||||
</para>
|
||||
</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>--remove</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Instead of adding the patterns, remove matching patterns.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--user</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Pin refs in a per-user installation.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--system</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Pin refs in the default system-wide installation.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--installation=NAME</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Pin refs 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>-v</option></term>
|
||||
<term><option>--verbose</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Print debug information during command processing.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
<command>$ flatpak pin</command>
|
||||
</para>
|
||||
<para>
|
||||
<command>$ flatpak pin org.freedesktop.Platform//19.08</command>
|
||||
</para>
|
||||
<para>
|
||||
<command>$ flatpak pin --remove org.freedesktop.Platform//19.08</command>
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>flatpak-uninstall</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@@ -215,6 +215,13 @@
|
||||
Mask out updates and automatic installation
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><citerefentry><refentrytitle>flatpak-pin</refentrytitle><manvolnum>1</manvolnum></citerefentry></term>
|
||||
|
||||
<listitem><para>
|
||||
Pin runtimes to prevent automatic removal.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><citerefentry><refentrytitle>flatpak-list</refentrytitle><manvolnum>1</manvolnum></citerefentry></term>
|
||||
|
||||
|
||||
@@ -1108,7 +1108,8 @@ handle_configure (FlatpakSystemHelper *object,
|
||||
|
||||
if ((strcmp (arg_key, "languages") != 0) &&
|
||||
(strcmp (arg_key, "extra-languages") != 0) &&
|
||||
(strcmp (arg_key, "masked") != 0))
|
||||
(strcmp (arg_key, "masked") != 0) &&
|
||||
(strcmp (arg_key, "pinned") != 0))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Unsupported key: %s", arg_key);
|
||||
|
||||
@@ -24,7 +24,7 @@ set -euo pipefail
|
||||
skip_without_bwrap
|
||||
skip_revokefs_without_fuse
|
||||
|
||||
echo "1..37"
|
||||
echo "1..38"
|
||||
|
||||
#Regular repo
|
||||
setup_repo
|
||||
@@ -587,6 +587,30 @@ assert_not_file_has_content list-log "org\.test\.Platform"
|
||||
|
||||
ok "uninstall --unused"
|
||||
|
||||
${FLATPAK} ${U} install -y test-repo org.test.Platform
|
||||
|
||||
${FLATPAK} ${U} list -a --columns=application > list-log
|
||||
assert_file_has_content list-log "org\.test\.Platform"
|
||||
|
||||
# Check that the runtime won't be removed if it's pinned
|
||||
${FLATPAK} ${U} pin org.test.Platform
|
||||
${FLATPAK} ${U} pin > pins
|
||||
assert_file_has_content pins "org\.test\.Platform"
|
||||
rm pins
|
||||
|
||||
${FLATPAK} ${U} uninstall -y --unused
|
||||
|
||||
${FLATPAK} ${U} list -a --columns=application > list-log
|
||||
assert_file_has_content list-log "org\.test\.Platform"
|
||||
|
||||
# Remove the pin and try again
|
||||
${FLATPAK} ${U} pin --remove "org.test.Platform"
|
||||
${FLATPAK} ${U} uninstall -y --unused
|
||||
${FLATPAK} ${U} list -a --columns=application > list-log
|
||||
assert_not_file_has_content list-log "org\.test\.Platform"
|
||||
|
||||
ok "uninstall --unused ignores pinned runtimes"
|
||||
|
||||
# Test that remote-ls works in all of the following cases:
|
||||
# * system remote, and --system is used
|
||||
# * system remote, and --system is omitted
|
||||
|
||||
Reference in New Issue
Block a user