mirror of
https://github.com/flatpak/flatpak.git
synced 2026-01-26 14:13:26 +00:00
app: Add a new alias command
This command lets you create aliases for running apps so that you can pass "flatpak run" a short string you specify rather than the full app ID, as discussed here: https://github.com/flatpak/flatpak/pull/4848
This commit is contained in:
parent
bf37034663
commit
2c704ef21d
@ -110,6 +110,7 @@ flatpak_SOURCES = \
|
||||
app/flatpak-builtins-create-usb.c \
|
||||
app/flatpak-builtins-kill.c \
|
||||
app/flatpak-builtins-history.c \
|
||||
app/flatpak-builtins-alias.c \
|
||||
app/flatpak-complete.c \
|
||||
app/flatpak-complete.h \
|
||||
app/flatpak-cli-transaction.c \
|
||||
|
||||
233
app/flatpak-builtins-alias.c
Normal file
233
app/flatpak-builtins-alias.c
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright © 2022 Matthew Leeds
|
||||
*
|
||||
* 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 <mwleeds@protonmail.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "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"
|
||||
#include "flatpak-table-printer.h"
|
||||
|
||||
static gboolean opt_remove;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "remove", 0, 0, G_OPTION_ARG_NONE, &opt_remove, N_("Remove the specified alias"), NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
gboolean
|
||||
flatpak_builtin_alias (int argc, char **argv, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(GPtrArray) dirs = NULL;
|
||||
int i;
|
||||
|
||||
context = g_option_context_new (_("ALIAS [APP] - Add an alias for running the app APP"));
|
||||
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;
|
||||
|
||||
/* Move the user dir to the front so it "wins" in case an app is in more than
|
||||
* one installation */
|
||||
if (dirs->len > 1)
|
||||
{
|
||||
/* Walk through the array backwards so we can safely remove */
|
||||
for (i = dirs->len; i > 0; i--)
|
||||
{
|
||||
FlatpakDir *dir = g_ptr_array_index (dirs, i - 1);
|
||||
if (flatpak_dir_is_user (dir))
|
||||
{
|
||||
g_ptr_array_insert (dirs, 0, g_object_ref (dir));
|
||||
g_ptr_array_remove_index (dirs, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
g_autoptr(FlatpakTablePrinter) printer = NULL;
|
||||
|
||||
printer = flatpak_table_printer_new ();
|
||||
flatpak_table_printer_set_column_title (printer, 0, _("Alias"));
|
||||
flatpak_table_printer_set_column_title (printer, 1, _("App"));
|
||||
flatpak_table_printer_set_column_title (printer, 2, _("Installation"));
|
||||
|
||||
for (i = 0; i < dirs->len; i++)
|
||||
{
|
||||
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
||||
g_autoptr(GHashTable) aliases = NULL; /* alias → app-id */
|
||||
|
||||
aliases = flatpak_dir_get_aliases (dir);
|
||||
|
||||
GLNX_HASH_TABLE_FOREACH_KV (aliases, const char *, alias, const char *, app_id)
|
||||
{
|
||||
flatpak_table_printer_add_column (printer, alias);
|
||||
flatpak_table_printer_add_column (printer, app_id);
|
||||
flatpak_table_printer_add_column (printer, flatpak_dir_get_name_cached (dir));
|
||||
flatpak_table_printer_finish_row (printer);
|
||||
}
|
||||
}
|
||||
|
||||
if (flatpak_table_printer_get_current_row (printer) > 0)
|
||||
flatpak_table_printer_print (printer);
|
||||
else if (flatpak_fancy_output ())
|
||||
g_print (_("No aliases\n"));
|
||||
}
|
||||
else if (opt_remove && argc == 2)
|
||||
{
|
||||
const char *alias = argv[1];
|
||||
g_autoptr(GError) saved_error = NULL;
|
||||
|
||||
for (i = 0; i < dirs->len; i++)
|
||||
{
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
||||
|
||||
if (flatpak_dir_remove_alias (dir, alias, &local_error))
|
||||
return TRUE;
|
||||
else
|
||||
{
|
||||
if (g_error_matches (local_error, FLATPAK_ERROR, FLATPAK_ERROR_ALIAS_NOT_FOUND))
|
||||
{
|
||||
if (saved_error == NULL)
|
||||
g_propagate_error (&saved_error, g_steal_pointer (&local_error));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_propagate_error (error, g_steal_pointer (&saved_error));
|
||||
return FALSE;
|
||||
}
|
||||
else if (!opt_remove && argc == 3)
|
||||
{
|
||||
const char *alias = argv[1];
|
||||
const char *app = argv[2];
|
||||
FlatpakDir *dir_to_use = NULL;
|
||||
g_autoptr(FlatpakDecomposed) current = NULL;
|
||||
|
||||
/* Check if the named app is deployed */
|
||||
for (i = 0; i < dirs->len; i++)
|
||||
{
|
||||
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
||||
g_autoptr(GFile) deploy = NULL;
|
||||
|
||||
g_clear_pointer (¤t, flatpak_decomposed_unref);
|
||||
current = flatpak_dir_current_ref (dir, app, cancellable);
|
||||
if (current)
|
||||
deploy = flatpak_dir_get_if_deployed (dir, current, NULL, cancellable);
|
||||
|
||||
if (deploy != NULL)
|
||||
{
|
||||
dir_to_use = dir;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dir_to_use == NULL)
|
||||
return flatpak_fail_error (error, FLATPAK_ERROR_NOT_INSTALLED,
|
||||
_("App %s not installed"), app);
|
||||
|
||||
if (!flatpak_dir_make_alias (dir_to_use, current, alias, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return usage_error (context, _("Wrong number of arguments"), error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_complete_alias (FlatpakCompletion *completion)
|
||||
{
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
g_autoptr(GPtrArray) dirs = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
int i;
|
||||
|
||||
context = g_option_context_new ("");
|
||||
if (!flatpak_option_context_parse (context, options, &completion->argc, &completion->argv,
|
||||
FLATPAK_BUILTIN_FLAG_ALL_DIRS | FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO,
|
||||
&dirs, NULL, NULL))
|
||||
return FALSE;
|
||||
|
||||
switch (completion->argc)
|
||||
{
|
||||
case 0:
|
||||
case 1: /* ALIAS */
|
||||
flatpak_complete_options (completion, global_entries);
|
||||
flatpak_complete_options (completion, options);
|
||||
flatpak_complete_options (completion, user_entries);
|
||||
|
||||
if (opt_remove)
|
||||
{
|
||||
for (i = 0; i < dirs->len; i++)
|
||||
{
|
||||
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
||||
g_autoptr(GHashTable) aliases = NULL; /* alias → app-id */
|
||||
|
||||
aliases = flatpak_dir_get_aliases (dir);
|
||||
GLNX_HASH_TABLE_FOREACH (aliases, const char *, alias)
|
||||
flatpak_complete_word (completion, "%s", alias);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: /* APP */
|
||||
if (!opt_remove)
|
||||
{
|
||||
for (i = 0; i < dirs->len; i++)
|
||||
{
|
||||
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
||||
g_autoptr(GPtrArray) refs = NULL;
|
||||
refs = flatpak_dir_find_installed_refs (dir, NULL, NULL, NULL,
|
||||
FLATPAK_KINDS_APP,
|
||||
FIND_MATCHING_REFS_FLAGS_NONE,
|
||||
&error);
|
||||
if (refs == NULL)
|
||||
flatpak_completion_debug ("find installed refs error: %s", error->message);
|
||||
|
||||
flatpak_complete_ref_id (completion, refs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -124,6 +124,7 @@ BUILTINPROTO (repair)
|
||||
BUILTINPROTO (create_usb)
|
||||
BUILTINPROTO (kill)
|
||||
BUILTINPROTO (history)
|
||||
BUILTINPROTO (alias)
|
||||
|
||||
#undef BUILTINPROTO
|
||||
|
||||
|
||||
@ -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 },
|
||||
{ "alias", N_("Manage short aliases for running applications"), flatpak_builtin_alias, flatpak_complete_alias },
|
||||
|
||||
/* translators: please keep the leading newline and space */
|
||||
{ N_("\n Find applications and runtimes") },
|
||||
|
||||
@ -257,6 +257,15 @@ typedef enum {
|
||||
#define FLATPAK_HELPER_CONFIGURE_FLAGS_ALL (FLATPAK_HELPER_CONFIGURE_FLAGS_UNSET | \
|
||||
FLATPAK_HELPER_CONFIGURE_FLAGS_NO_INTERACTION)
|
||||
|
||||
typedef enum {
|
||||
FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_NONE = 0,
|
||||
FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_NO_INTERACTION = 1 << 0,
|
||||
FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_REMOVE = 1 << 0,
|
||||
} FlatpakHelperConfigureAliasesFlags;
|
||||
|
||||
#define FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_ALL (FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_NO_INTERACTION | \
|
||||
FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_REMOVE)
|
||||
|
||||
typedef enum {
|
||||
FLATPAK_HELPER_UPDATE_REMOTE_FLAGS_NONE = 0,
|
||||
FLATPAK_HELPER_UPDATE_REMOTE_FLAGS_NO_INTERACTION = 1 << 0,
|
||||
@ -495,6 +504,7 @@ GFile * flatpak_dir_get_exports_dir (Fla
|
||||
GFile * flatpak_dir_get_removed_dir (FlatpakDir *self);
|
||||
GFile * flatpak_dir_get_sideload_repos_dir (FlatpakDir *self);
|
||||
GFile * flatpak_dir_get_runtime_sideload_repos_dir (FlatpakDir *self);
|
||||
GFile * flatpak_dir_get_aliases_dir (FlatpakDir *self);
|
||||
GFile * flatpak_dir_get_if_deployed (FlatpakDir *self,
|
||||
FlatpakDecomposed *ref,
|
||||
const char *checksum,
|
||||
@ -596,6 +606,14 @@ gboolean flatpak_dir_config_remove_pattern (Fla
|
||||
const char *key,
|
||||
const char *pattern,
|
||||
GError **error);
|
||||
GHashTable * flatpak_dir_get_aliases (FlatpakDir *self);
|
||||
gboolean flatpak_dir_make_alias (FlatpakDir *self,
|
||||
FlatpakDecomposed *current_ref,
|
||||
const char *alias,
|
||||
GError **error);
|
||||
gboolean flatpak_dir_remove_alias (FlatpakDir *self,
|
||||
const char *alias,
|
||||
GError **error);
|
||||
gboolean flatpak_dir_mark_changed (FlatpakDir *self,
|
||||
GError **error);
|
||||
gboolean flatpak_dir_remove_appstream (FlatpakDir *self,
|
||||
|
||||
@ -79,6 +79,7 @@
|
||||
#define SYSCONF_REMOTES_FILE_EXT ".flatpakrepo"
|
||||
|
||||
#define SIDELOAD_REPOS_DIR_NAME "sideload-repos"
|
||||
#define ALIASES_DIR_NAME "aliases"
|
||||
|
||||
#ifdef USE_SYSTEM_HELPER
|
||||
/* This uses a weird Auto prefix to avoid conflicts with later added polkit types.
|
||||
@ -2356,6 +2357,30 @@ flatpak_dir_system_helper_call_configure (FlatpakDir *self,
|
||||
return ret != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
flatpak_dir_system_helper_call_configure_aliases (FlatpakDir *self,
|
||||
guint arg_flags,
|
||||
const gchar *arg_ref,
|
||||
const gchar *arg_alias,
|
||||
const gchar *arg_installation,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (flatpak_dir_get_no_interaction (self))
|
||||
arg_flags |= FLATPAK_HELPER_CONFIGURE_FLAGS_NO_INTERACTION;
|
||||
|
||||
g_autoptr(GVariant) ret =
|
||||
flatpak_dir_system_helper_call (self, "ConfigureAliases",
|
||||
g_variant_new ("(usss)",
|
||||
arg_flags,
|
||||
arg_ref,
|
||||
arg_alias,
|
||||
arg_installation),
|
||||
G_VARIANT_TYPE ("()"), NULL,
|
||||
cancellable, error);
|
||||
return ret != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
flatpak_dir_system_helper_call_update_remote (FlatpakDir *self,
|
||||
guint arg_flags,
|
||||
@ -3086,6 +3111,12 @@ flatpak_dir_get_runtime_sideload_repos_dir (FlatpakDir *self)
|
||||
return g_file_get_child (base, SIDELOAD_REPOS_DIR_NAME);
|
||||
}
|
||||
|
||||
GFile *
|
||||
flatpak_dir_get_aliases_dir (FlatpakDir *self)
|
||||
{
|
||||
return g_file_get_child (self->basedir, ALIASES_DIR_NAME);
|
||||
}
|
||||
|
||||
OstreeRepo *
|
||||
flatpak_dir_get_repo (FlatpakDir *self)
|
||||
{
|
||||
@ -4445,6 +4476,194 @@ flatpak_dir_config_remove_pattern (FlatpakDir *self,
|
||||
return flatpak_dir_set_config (self, key, merged_patterns, error);
|
||||
}
|
||||
|
||||
GHashTable *
|
||||
flatpak_dir_get_aliases (FlatpakDir *self)
|
||||
{
|
||||
g_autoptr(GHashTable) aliases = NULL; /* alias → app-id */
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFile) parent = NULL;
|
||||
|
||||
aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
|
||||
if (!flatpak_dir_maybe_ensure_repo (self, NULL, NULL))
|
||||
return g_steal_pointer (&aliases);
|
||||
|
||||
parent = flatpak_dir_get_aliases_dir (self);
|
||||
dir_enum = g_file_enumerate_children (parent,
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, NULL);
|
||||
if (dir_enum == NULL)
|
||||
return g_steal_pointer (&aliases);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
GFileInfo *info;
|
||||
GFile *path;
|
||||
g_autofree char *path_basename = NULL;
|
||||
const char *target;
|
||||
g_autoptr(GFile) target_file = NULL;
|
||||
g_autofree char *target_basename = NULL;
|
||||
|
||||
if (!g_file_enumerator_iterate (dir_enum, &info, &path, NULL, NULL) ||
|
||||
info == NULL)
|
||||
break;
|
||||
|
||||
/* We expect symlinks to files in $FLATPAK_DIR/exports/bin/ */
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_SYMBOLIC_LINK)
|
||||
continue;
|
||||
|
||||
path_basename = g_file_get_basename (path);
|
||||
if (path_basename == NULL)
|
||||
continue;
|
||||
|
||||
target = g_file_info_get_symlink_target (info);
|
||||
if (target == NULL)
|
||||
continue;
|
||||
|
||||
target_file = g_file_new_for_path (target);
|
||||
target_basename = g_file_get_basename (target_file);
|
||||
if (target_basename == NULL || !flatpak_is_valid_name (target_basename, -1, NULL))
|
||||
continue;
|
||||
|
||||
g_hash_table_insert (aliases,
|
||||
g_steal_pointer (&path_basename),
|
||||
g_steal_pointer (&target_basename));
|
||||
}
|
||||
|
||||
return g_steal_pointer (&aliases);
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_dir_remove_alias (FlatpakDir *self,
|
||||
const char *alias,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFile) exports = NULL;
|
||||
g_autoptr(GFile) bindir = NULL;
|
||||
g_autoptr(GFile) runner = NULL;
|
||||
g_autoptr(GFile) aliases = NULL;
|
||||
g_autoptr(GFile) alias_file = NULL;
|
||||
g_autofree char *runner_relpath = NULL;
|
||||
g_autofree char *symlink_target = NULL;
|
||||
g_autofree char *app_id = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
if (!flatpak_is_valid_alias (alias, error))
|
||||
return FALSE;
|
||||
|
||||
if (flatpak_dir_use_system_helper (self, NULL))
|
||||
{
|
||||
FlatpakHelperConfigureAliasesFlags flags = FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_REMOVE;
|
||||
const char *installation = flatpak_dir_get_id (self);
|
||||
|
||||
if (!flatpak_dir_system_helper_call_configure_aliases (self,
|
||||
flags,
|
||||
"", alias,
|
||||
installation ? installation : "",
|
||||
NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
aliases = flatpak_dir_get_aliases_dir (self);
|
||||
alias_file = g_file_get_child (aliases, alias);
|
||||
|
||||
/* The caller is responsible for handling FLATPAK_ERROR_ALIAS_NOT_FOUND as needed */
|
||||
if (!g_file_delete (alias_file, NULL, &local_error))
|
||||
{
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_ALIAS_NOT_FOUND,
|
||||
_("Error removing alias '%s': it does not exist"),
|
||||
alias);
|
||||
else
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_dir_make_alias (FlatpakDir *self,
|
||||
FlatpakDecomposed *current_ref,
|
||||
const char *alias,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFile) exports = NULL;
|
||||
g_autoptr(GFile) bindir = NULL;
|
||||
g_autoptr(GFile) runner = NULL;
|
||||
g_autoptr(GFile) aliases = NULL;
|
||||
g_autoptr(GFile) alias_file = NULL;
|
||||
g_autofree char *runner_relpath = NULL;
|
||||
g_autofree char *symlink_target = NULL;
|
||||
g_autofree char *app_id = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
/* If the alias is valid and the app is installed, we create a symlink to the
|
||||
* wrapper script created by flatpak_dir_deploy(). This will be used by the
|
||||
* flatpak run command.
|
||||
*/
|
||||
|
||||
if (!flatpak_is_valid_alias (alias, error))
|
||||
return FALSE;
|
||||
|
||||
if (flatpak_dir_use_system_helper (self, NULL))
|
||||
{
|
||||
FlatpakHelperConfigureAliasesFlags flags = 0;
|
||||
const char *installation = flatpak_dir_get_id (self);
|
||||
const char *current_ref_str;
|
||||
|
||||
current_ref_str = flatpak_decomposed_get_ref (current_ref);
|
||||
if (!flatpak_dir_system_helper_call_configure_aliases (self,
|
||||
flags,
|
||||
current_ref_str, alias,
|
||||
installation ? installation : "",
|
||||
NULL, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
app_id = flatpak_decomposed_dup_id (current_ref);
|
||||
exports = flatpak_dir_get_exports_dir (self);
|
||||
bindir = g_file_get_child (exports, "bin");
|
||||
runner = g_file_get_child (bindir, app_id);
|
||||
|
||||
if (!g_file_query_exists (runner, NULL))
|
||||
return flatpak_fail_error (error, FLATPAK_ERROR_NOT_INSTALLED,
|
||||
_("No wrapper script found for %s"), app_id);
|
||||
|
||||
aliases = flatpak_dir_get_aliases_dir (self);
|
||||
alias_file = g_file_get_child (aliases, alias);
|
||||
|
||||
if (g_mkdir_with_parents (flatpak_file_get_path_cached (aliases), 0755) != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
runner_relpath = g_file_get_relative_path (self->basedir, runner);
|
||||
symlink_target = g_build_filename ("..", runner_relpath, NULL);
|
||||
if (!g_file_make_symbolic_link (alias_file, symlink_target, NULL, &local_error))
|
||||
{
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_ALIAS_ALREADY_EXISTS,
|
||||
_("Error making alias '%s': %s"),
|
||||
alias, local_error->message);
|
||||
else
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
flatpak_dir_mark_changed (FlatpakDir *self,
|
||||
GError **error)
|
||||
|
||||
@ -52,7 +52,7 @@ G_BEGIN_DECLS
|
||||
* @FLATPAK_ERROR_EXPORT_FAILED: Exporting data failed. (Since: 1.0.3)
|
||||
* @FLATPAK_ERROR_REMOTE_USED: Remote can't be uninstalled. (Since: 1.0.3)
|
||||
* @FLATPAK_ERROR_RUNTIME_USED: Runtime can't be uninstalled. (Since: 1.0.3)
|
||||
* @FLATPAK_ERROR_INVALID_NAME: Application, runtime or remote name is invalid. (Since: 1.0.3)
|
||||
* @FLATPAK_ERROR_INVALID_NAME: Application, runtime, remote, or alias name is invalid. (Since: 1.0.3)
|
||||
* @FLATPAK_ERROR_OUT_OF_SPACE: More disk space needed. (Since: 1.2.0)
|
||||
* @FLATPAK_ERROR_WRONG_USER: An operation is being attempted by the wrong user (such as
|
||||
* root operating on a user installation). (Since: 1.2.0)
|
||||
@ -66,6 +66,8 @@ G_BEGIN_DECLS
|
||||
* @FLATPAK_ERROR_NOT_AUTHORIZED: An operation tried to access a ref, or information about it that it
|
||||
* was not authorized. For example, when succesfully authenticating with a
|
||||
* server but the user doesn't have permissions for a private ref. (Since: 1.7.3)
|
||||
* @FLATPAK_ERROR_ALIAS_NOT_FOUND: The specified alias was not found. (Since: 1.13.4)
|
||||
* @FLATPAK_ERROR_ALIAS_ALREADY_EXISTS: The specified alias was already exists. (Since: 1.13.4)
|
||||
*
|
||||
* Error codes for library functions.
|
||||
*/
|
||||
@ -95,6 +97,8 @@ typedef enum {
|
||||
FLATPAK_ERROR_PERMISSION_DENIED,
|
||||
FLATPAK_ERROR_AUTHENTICATION_FAILED,
|
||||
FLATPAK_ERROR_NOT_AUTHORIZED,
|
||||
FLATPAK_ERROR_ALIAS_NOT_FOUND,
|
||||
FLATPAK_ERROR_ALIAS_ALREADY_EXISTS,
|
||||
} FlatpakError;
|
||||
|
||||
/**
|
||||
|
||||
@ -169,5 +169,7 @@ char * flatpak_build_app_ref (const char *app,
|
||||
const char *branch,
|
||||
const char *arch);
|
||||
|
||||
gboolean flatpak_is_valid_alias (const char *string,
|
||||
GError **error);
|
||||
|
||||
#endif /* __FLATPAK_REF_UTILS_H__ */
|
||||
|
||||
@ -1687,3 +1687,66 @@ flatpak_build_app_ref (const char *app,
|
||||
return g_build_filename ("app", app, arch, branch, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* flatpak_is_valid_alias:
|
||||
* @string: The string to check
|
||||
* @error: Return location for an error
|
||||
*
|
||||
* Checks if @string is a valid alias for use with the "flatpak alias" and
|
||||
* "flatpak run" commands.
|
||||
*
|
||||
* Per flatpak-alias(1), valid characters are "[A-Z][a-z][0-9]_-" and "-" is
|
||||
* not valid as the first character (to avoid confusion with CLI options).
|
||||
*
|
||||
* Aliases must not exceed 255 characters in length.
|
||||
*
|
||||
* Returns: %TRUE if valid, %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
flatpak_is_valid_alias (const char *string,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *s;
|
||||
gssize len;
|
||||
|
||||
g_return_val_if_fail (string != NULL, FALSE);
|
||||
|
||||
len = strlen (string);
|
||||
if (G_UNLIKELY (len == 0))
|
||||
{
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_INVALID_NAME,
|
||||
_("Alias can't be empty"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (len > 255))
|
||||
{
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_INVALID_NAME,
|
||||
_("Alias can't be longer than 255 characters"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s = string;
|
||||
if (G_UNLIKELY (!is_valid_name_character (*s, FALSE)))
|
||||
{
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_INVALID_NAME,
|
||||
_("Alias can't start with %c"), *s);
|
||||
return FALSE;
|
||||
}
|
||||
s += 1;
|
||||
while (*s != '\0')
|
||||
{
|
||||
/* Disallowing '.' means that aliases are never valid app IDs which seems
|
||||
* desirable
|
||||
*/
|
||||
if (G_UNLIKELY (!is_valid_name_character (*s, TRUE)))
|
||||
{
|
||||
flatpak_fail_error (error, FLATPAK_ERROR_INVALID_NAME,
|
||||
_("Alias can't contain %c"), *s);
|
||||
return FALSE;
|
||||
}
|
||||
s += 1;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -81,6 +81,8 @@ static const GDBusErrorEntry flatpak_error_entries[] = {
|
||||
{FLATPAK_ERROR_PERMISSION_DENIED, "org.freedesktop.Flatpak.Error.PermissionDenied"}, /* Since: 1.5.1 */
|
||||
{FLATPAK_ERROR_AUTHENTICATION_FAILED, "org.freedesktop.Flatpak.Error.AuthenticationFailed"}, /* Since: 1.7.3 */
|
||||
{FLATPAK_ERROR_NOT_AUTHORIZED, "org.freedesktop.Flatpak.Error.NotAuthorized"}, /* Since: 1.7.3 */
|
||||
{FLATPAK_ERROR_ALIAS_NOT_FOUND, "org.freedesktop.Flatpak.Error.AliasNotFound"}, /* Since: 1.13.4 */
|
||||
{FLATPAK_ERROR_ALIAS_ALREADY_EXISTS, "org.freedesktop.Flatpak.Error.AliasAlreadyExists"}, /* Since: 1.13.4 */
|
||||
};
|
||||
|
||||
typedef struct archive FlatpakAutoArchiveRead;
|
||||
|
||||
@ -269,6 +269,13 @@
|
||||
<arg type='s' name='installation' direction='in'/>
|
||||
</method>
|
||||
|
||||
<method name="ConfigureAliases">
|
||||
<arg type='u' name='flags' direction='in'/>
|
||||
<arg type='s' name='ref' direction='in'/>
|
||||
<arg type='s' name='alias' direction='in'/>
|
||||
<arg type='s' name='installation' direction='in'/>
|
||||
</method>
|
||||
|
||||
<method name="UpdateRemote">
|
||||
<arg type='u' name='flags' direction='in'/>
|
||||
<arg type='s' name='remote' direction='in'/>
|
||||
|
||||
@ -63,6 +63,7 @@ man1 = \
|
||||
flatpak-kill.1 \
|
||||
flatpak-history.1 \
|
||||
flatpak-spawn.1 \
|
||||
flatpak-alias.1 \
|
||||
$(NULL)
|
||||
|
||||
man5 = \
|
||||
|
||||
176
doc/flatpak-alias.xml
Normal file
176
doc/flatpak-alias.xml
Normal file
@ -0,0 +1,176 @@
|
||||
<?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-alias">
|
||||
|
||||
<refentryinfo>
|
||||
<title>flatpak alias</title>
|
||||
<productname>flatpak</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Matthew</firstname>
|
||||
<surname>Leeds</surname>
|
||||
<email>mwleeds@protonmail.com</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>flatpak alias</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>flatpak-alias</refname>
|
||||
<refpurpose>Manage short aliases for running applications</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>flatpak alias</command>
|
||||
<arg choice="opt" rep="repeat">OPTION</arg>
|
||||
<arg choice="plain">ALIAS</arg>
|
||||
<arg choice="plain">APP</arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>flatpak alias</command>
|
||||
<arg choice="opt" rep="repeat">OPTION</arg>
|
||||
<arg choice="opt">--remove</arg>
|
||||
<arg choice="plain">ALIAS</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
Normally to run a Flatpak app from the command line you specify the full
|
||||
App ID (and optionally the arch and branch) to the
|
||||
<command>flatpak run</command> command. This can be tedious, so the
|
||||
<command>alias</command> command allows you to set up aliases that can
|
||||
be passed to <command>flatpak run</command> instead. Once set up, no
|
||||
additional confirmation prompts are needed each time the alias is used.
|
||||
</para>
|
||||
<para>
|
||||
The <arg choice="plain">APP</arg> argument is the application ID of an
|
||||
installed application. Only the current branch will be used; see
|
||||
<citerefentry><refentrytitle>flatpak-make-current</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
As with the <command>flatpak run</command> command, if an app is installed
|
||||
both system-wide and per-user, the per-user one will be used unless
|
||||
otherwise specified with <option>--system</option> or <option>--installation</option>.
|
||||
</para>
|
||||
<para>
|
||||
The <arg choice="plain">ALIAS</arg> argument is a string which can only
|
||||
contain the ASCII characters "[A-Z][a-z][0-9]_-" and cannot start with a "-".
|
||||
</para>
|
||||
<para>
|
||||
To list the current set of aliases, run this command without any arguments.
|
||||
</para>
|
||||
<para>
|
||||
Aliases are created as files in an <filename>aliases</filename>
|
||||
subdirectory of the relevant installation directory. However, it is not
|
||||
recommended to add this directory to your <envar>PATH</envar> since
|
||||
Flatpaks cannot handle file arguments like OS packages. For example, a
|
||||
command such as <command>media-player ~/some-file.ogg</command> would not
|
||||
work if the relevant Flatpak doesn't have home directory access. To
|
||||
provide access to particular files specified on the command line, use the
|
||||
<option>--file-forwarding</option> option documented in
|
||||
<citerefentry><refentrytitle>flatpak-run</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
|
||||
</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 specified alias, remove it. In this case
|
||||
there's no need to specify the <arg choice="plain">APP</arg>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--user</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Operate on the per-user installation.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--system</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Operate on the default system-wide installation.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--installation=NAME</option></term>
|
||||
|
||||
<listitem><para>
|
||||
Operate on the 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 alias</command>
|
||||
</para>
|
||||
<para>
|
||||
<command>$ flatpak alias app-bin org.example.App</command>
|
||||
</para>
|
||||
<para>
|
||||
<command>$ flatpak alias --system org.example.App app-bin</command>
|
||||
</para>
|
||||
<para>
|
||||
<command>$ flatpak alias --remove app-bin</command>
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See also</title>
|
||||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>flatpak</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>flatpak-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@ -287,6 +287,13 @@
|
||||
Copy apps and/or runtimes onto removable media.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><citerefentry><refentrytitle>flatpak-alias</refentrytitle><manvolnum>1</manvolnum></citerefentry></term>
|
||||
|
||||
<listitem><para>
|
||||
Manage short aliases for running applications.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# List of source files containing translatable strings.
|
||||
# Please keep this file sorted alphabetically.
|
||||
app/flatpak-builtins-alias.c
|
||||
app/flatpak-builtins-build-bundle.c
|
||||
app/flatpak-builtins-build.c
|
||||
app/flatpak-builtins-build-commit-from.c
|
||||
|
||||
@ -1177,6 +1177,95 @@ handle_configure (FlatpakSystemHelper *object,
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
/* Note: While this currently only supports creating aliases for apps, the
|
||||
* argument being a full ref rather than an app ID means we can change it to
|
||||
* support runtimes in the future if needed.
|
||||
*/
|
||||
static gboolean
|
||||
handle_configure_aliases (FlatpakSystemHelper *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
guint arg_flags,
|
||||
const gchar *arg_ref,
|
||||
const gchar *arg_alias,
|
||||
const gchar *arg_installation)
|
||||
{
|
||||
g_autoptr(FlatpakDir) system = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(FlatpakDecomposed) ref = NULL;
|
||||
g_autoptr(GFile) deploy = NULL;
|
||||
gboolean remove_alias = (arg_flags & FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_REMOVE) != 0;
|
||||
|
||||
g_debug ("ConfigureAliases %u %s %s %s", arg_flags, arg_ref, arg_alias, arg_installation);
|
||||
|
||||
system = dir_get_system (arg_installation, get_sender_pid (invocation), (arg_flags & FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_NO_INTERACTION) != 0, &error);
|
||||
if (system == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if ((arg_flags & ~FLATPAK_HELPER_CONFIGURE_ALIASES_FLAGS_ALL) != 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Unsupported flags enabled: 0x%x", (arg_flags & ~FLATPAK_HELPER_CONFIGURE_FLAGS_ALL));
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (!remove_alias)
|
||||
{
|
||||
ref = flatpak_decomposed_new_from_ref (arg_ref, &error);
|
||||
if (ref == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (!flatpak_decomposed_is_app (ref))
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid ref %s: must be an app", arg_ref);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
deploy = flatpak_dir_get_if_deployed (system, ref, NULL, NULL);
|
||||
if (deploy == NULL)
|
||||
{
|
||||
flatpak_invocation_return_error (invocation, error, "App %s not installed", arg_ref);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flatpak_dir_ensure_repo (system, NULL, &error))
|
||||
{
|
||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
if (!remove_alias)
|
||||
{
|
||||
if (!flatpak_dir_make_alias (system, ref, arg_alias, &error))
|
||||
{
|
||||
flatpak_invocation_return_error (invocation, error, "Error making alias");
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Here we consider it an error if the alias does not exist */
|
||||
if (!flatpak_dir_remove_alias (system, arg_alias, &error))
|
||||
{
|
||||
flatpak_invocation_return_error (invocation, error, "Error removing alias");
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
flatpak_system_helper_complete_configure_aliases (object, invocation);
|
||||
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_update_remote (FlatpakSystemHelper *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
@ -2121,6 +2210,15 @@ flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface,
|
||||
|
||||
polkit_details_insert (details, "key", key);
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "ConfigureAliases") == 0)
|
||||
{
|
||||
guint32 flags;
|
||||
|
||||
g_variant_get_child (parameters, 0, "u", &flags);
|
||||
|
||||
action = "org.freedesktop.Flatpak.configure-aliases";
|
||||
no_interaction = (flags & FLATPAK_HELPER_CONFIGURE_FLAGS_NO_INTERACTION) != 0;
|
||||
}
|
||||
else if (g_strcmp0 (method_name, "UpdateRemote") == 0)
|
||||
{
|
||||
const char *remote;
|
||||
@ -2223,6 +2321,7 @@ on_bus_acquired (GDBusConnection *connection,
|
||||
g_signal_connect (helper, "handle-install-bundle", G_CALLBACK (handle_install_bundle), NULL);
|
||||
g_signal_connect (helper, "handle-configure-remote", G_CALLBACK (handle_configure_remote), NULL);
|
||||
g_signal_connect (helper, "handle-configure", G_CALLBACK (handle_configure), NULL);
|
||||
g_signal_connect (helper, "handle-configure-aliases", G_CALLBACK (handle_configure_aliases), NULL);
|
||||
g_signal_connect (helper, "handle-update-remote", G_CALLBACK (handle_update_remote), NULL);
|
||||
g_signal_connect (helper, "handle-remove-local-ref", G_CALLBACK (handle_remove_local_ref), NULL);
|
||||
g_signal_connect (helper, "handle-prune-local-repo", G_CALLBACK (handle_prune_local_repo), NULL);
|
||||
|
||||
@ -199,6 +199,21 @@
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.Flatpak.configure-aliases">
|
||||
<!-- SECURITY:
|
||||
- Normal users need admin authentication to configure aliases in the
|
||||
system-wide Flatpak installation.
|
||||
-->
|
||||
<description>Configure</description>
|
||||
<message>Authentication is required to configure software installation</message>
|
||||
<icon_name>package-x-generic</icon_name>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.Flatpak.appstream-update">
|
||||
<!-- SECURITY:
|
||||
- Normal users do not require admin authentication to update
|
||||
|
||||
@ -28,6 +28,8 @@ TEST_MATRIX= \
|
||||
tests/test-summaries@system.wrap \
|
||||
tests/test-subset@user.wrap \
|
||||
tests/test-subset@system.wrap \
|
||||
tests/test-alias@user.wrap \
|
||||
tests/test-alias@system.wrap \
|
||||
$(NULL)
|
||||
TEST_MATRIX_DIST= \
|
||||
tests/test-basic.sh \
|
||||
@ -58,4 +60,5 @@ TEST_MATRIX_EXTRA_DIST= \
|
||||
tests/test-update-portal.sh \
|
||||
tests/test-summaries.sh \
|
||||
tests/test-subset.sh \
|
||||
tests/test-alias.sh \
|
||||
$(NULL)
|
||||
|
||||
77
tests/test-alias.sh
Executable file
77
tests/test-alias.sh
Executable file
@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2022 Matthew Leeds <mwleeds@protonmail.com>
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
. $(dirname $0)/libtest.sh
|
||||
|
||||
echo "1..3"
|
||||
|
||||
setup_repo
|
||||
${FLATPAK} ${U} install -y test-repo org.test.Hello >&2
|
||||
|
||||
# List aliases (none)
|
||||
${FLATPAK} ${U} alias > aliases
|
||||
assert_file_empty aliases
|
||||
|
||||
# Make an alias
|
||||
${FLATPAK} ${U} alias hello org.test.Hello
|
||||
${FLATPAK} ${U} alias > aliases
|
||||
if [ x${USE_SYSTEMDIR-} == xyes ]; then
|
||||
assert_file_has_content aliases "hello org\.test\.Hello system"
|
||||
else
|
||||
assert_file_has_content aliases "hello org\.test\.Hello user"
|
||||
fi
|
||||
|
||||
# Shouldn't be able to make an alias that already exists
|
||||
if ${FLATPAK} ${U} alias hello org.test.Hello &> alias-error-log; then
|
||||
assert_not_reached "Should not be able to create an alias that already exists"
|
||||
fi
|
||||
assert_file_has_content alias-error-log "error: Error making alias 'hello': Error making symbolic link .*: File exists"
|
||||
|
||||
# Shouldn't be able to make an alias that for an app that's not installed
|
||||
if ${FLATPAK} ${U} alias hello org.test.Bonjour &> alias-error-log; then
|
||||
assert_not_reached "Should not be able to create an alias for an uninstalled app"
|
||||
fi
|
||||
assert_file_has_content alias-error-log "error: App org.test.Bonjour not installed"
|
||||
|
||||
# Remove an alias
|
||||
${FLATPAK} ${U} alias --remove hello
|
||||
${FLATPAK} ${U} alias > aliases
|
||||
assert_file_empty aliases
|
||||
|
||||
ok "alias command works"
|
||||
|
||||
if ${FLATPAK} ${U} alias .hello org.test.Hello &> alias-error-log; then
|
||||
assert_not_reached "Should not be able to create an alias starting with a period"
|
||||
fi
|
||||
assert_file_has_content alias-error-log "error: Alias can't start with \."
|
||||
|
||||
if ${FLATPAK} ${U} alias org.test.Goodbye org.test.Hello &> alias-error-log; then
|
||||
assert_not_reached "Should not be able to create an alias which contains a period"
|
||||
fi
|
||||
assert_file_has_content alias-error-log "error: Alias can't contain \."
|
||||
|
||||
if ${FLATPAK} ${U} alias 🦋 org.test.Hello &> alias-error-log; then
|
||||
assert_not_reached "Should not be able to create an alias which is a butterfly"
|
||||
fi
|
||||
# In flatpak_is_valid_alias() we look at the string byte by byte so multi-byte
|
||||
# characters don't get printed properly in the error message.
|
||||
assert_file_has_content alias-error-log "error: Alias can't start with "
|
||||
|
||||
ok "alias command rejects invalid alias characters"
|
||||
|
||||
if ${FLATPAK} ${U} alias --remove notarealalias &> alias-error-log; then
|
||||
assert_not_reached "Should not be able to remove an alias that doesn't exist"
|
||||
fi
|
||||
assert_file_has_content alias-error-log "error: Error removing alias 'notarealalias': it does not exist"
|
||||
|
||||
# clean up
|
||||
rm aliases alias-error-log
|
||||
${FLATPAK} ${U} uninstall -y org.test.Platform org.test.Hello >&2
|
||||
${FLATPAK} ${U} remote-delete test-repo >&2
|
||||
|
||||
ok "alias --remove command rejects non-existent alias"
|
||||
@ -71,7 +71,7 @@ for cmd in install update uninstall list info config repair create-usb \
|
||||
remote-modify remote-delete remote-ls remote-info build-init \
|
||||
build build-finish build-export build-bundle build-import-bundle \
|
||||
build-sign build-update-repo build-commit-from repo kill history \
|
||||
mask;
|
||||
mask alias;
|
||||
do
|
||||
${FLATPAK} $cmd --help > help_out
|
||||
head -2 help_out > help_out2
|
||||
|
||||
@ -34,6 +34,7 @@ install_repo
|
||||
|
||||
${FLATPAK} complete "flatpak a" 9 "a" | sort > complete_out
|
||||
(diff -u complete_out - || exit 1) <<EOF
|
||||
alias
|
||||
EOF
|
||||
|
||||
ok "complete a commands"
|
||||
@ -167,7 +168,7 @@ ok "complete NO_DIR commands"
|
||||
for cmd in history info list run update mask \
|
||||
config install make-current override remote-add repair \
|
||||
create-usb remote-delete remote-info remote-list remote-ls \
|
||||
remote-modify search uninstall update; do
|
||||
remote-modify search uninstall update alias; do
|
||||
len=$(awk '{ print length($0) }' <<< "flatpak $cmd --")
|
||||
${FLATPAK} complete "flatpak $cmd --" $len "--" > complete_out
|
||||
assert_file_has_content complete_out "^--system "
|
||||
|
||||
@ -34,6 +34,7 @@ TEST_MATRIX_SOURCE=(
|
||||
'tests/test-prune.sh' \
|
||||
'tests/test-seccomp.sh' \
|
||||
'tests/test-repair.sh' \
|
||||
'tests/test-alias.sh{user+system}' \
|
||||
)
|
||||
|
||||
"${tests_srcdir}/expand-test-matrix.sh" --automake "${TEST_MATRIX_SOURCE[*]}" > "${tests_srcdir}/Makefile-test-matrix.am.inc"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user