mirror of
https://github.com/flatpak/flatpak.git
synced 2026-02-01 11:31:21 -05:00
This is a fsck-like command that tries to automatically repair your flatpak installations. It works by running an fsck on all the refs in the local repo, and removing all refs that has an unexpectedly missing (or deleted) object. Then it runs a prune, which will remove all the object that were referenced by these removed refs (that were not references by anything else), so that any non-detected invalid objects are also removed. Then it looks at all the deployed refs, and if they lack a ref in the local repo, we `install --reinstall $origin $ref` them. Closes: #1739 Approved by: alexlarsson
624 lines
21 KiB
C
624 lines
21 KiB
C
/*
|
|
* 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 <locale.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
|
|
#include <glib/gi18n.h>
|
|
#include <gio/gio.h>
|
|
#include "libglnx/libglnx.h"
|
|
|
|
#include "flatpak-builtins.h"
|
|
#include "flatpak-utils-private.h"
|
|
|
|
static int opt_verbose;
|
|
static gboolean opt_ostree_verbose;
|
|
static gboolean opt_version;
|
|
static gboolean opt_default_arch;
|
|
static gboolean opt_supported_arches;
|
|
static gboolean opt_gl_drivers;
|
|
static gboolean opt_user;
|
|
static gboolean opt_system;
|
|
static char **opt_installations;
|
|
|
|
static gboolean is_in_complete;
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
const char *description;
|
|
gboolean (*fn)(int argc,
|
|
char **argv,
|
|
GCancellable *cancellable,
|
|
GError **error);
|
|
gboolean (*complete)(FlatpakCompletion *completion);
|
|
gboolean deprecated;
|
|
} FlatpakCommand;
|
|
|
|
static FlatpakCommand commands[] = {
|
|
/* translators: please keep the leading space */
|
|
{ N_(" Manage installed apps and runtimes") },
|
|
{ "install", N_("Install an application or runtime"), flatpak_builtin_install, flatpak_complete_install },
|
|
{ "update", N_("Update an installed application or runtime"), flatpak_builtin_update, flatpak_complete_update },
|
|
{ "uninstall", N_("Uninstall an installed application or runtime"), flatpak_builtin_uninstall, flatpak_complete_uninstall },
|
|
/* Alias remove to uninstall to help users of yum/dnf/apt */
|
|
{ "remove", NULL, flatpak_builtin_uninstall, flatpak_complete_uninstall, TRUE },
|
|
{ "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 },
|
|
{ "config", N_("Configure flatpak"), flatpak_builtin_config, flatpak_complete_config },
|
|
{ "repair", N_("Repair flatpak installation"), flatpak_builtin_repair, flatpak_complete_repair },
|
|
|
|
/* translators: please keep the leading newline and space */
|
|
{ N_("\n Finding applications and runtimes") },
|
|
{ "search", N_("Search for remote apps/runtimes"), flatpak_builtin_search, flatpak_complete_search },
|
|
|
|
/* translators: please keep the leading newline and space */
|
|
{ N_("\n Running applications") },
|
|
{ "run", N_("Run an application"), flatpak_builtin_run, flatpak_complete_run },
|
|
{ "override", N_("Override permissions for an application"), flatpak_builtin_override, flatpak_complete_override },
|
|
{ "make-current", N_("Specify default version to run"), flatpak_builtin_make_current_app, flatpak_complete_make_current_app },
|
|
{ "enter", N_("Enter the namespace of a running application"), flatpak_builtin_enter, flatpak_complete_enter },
|
|
|
|
/* translators: please keep the leading newline and space */
|
|
{ N_("\n Manage file access") },
|
|
{ "document-export", N_("Grant an application access to a specific file"), flatpak_builtin_document_export, flatpak_complete_document_export },
|
|
{ "document-unexport", N_("Revoke access to a specific file"), flatpak_builtin_document_unexport, flatpak_complete_document_unexport },
|
|
{ "document-info", N_("Show information about a specific file"), flatpak_builtin_document_info, flatpak_complete_document_info },
|
|
{ "document-list", N_("List exported files"), flatpak_builtin_document_list, flatpak_complete_document_list },
|
|
|
|
/* translators: please keep the leading newline and space */
|
|
{ N_("\n Manage remote repositories") },
|
|
{ "remotes", N_("List all configured remotes"), flatpak_builtin_list_remotes, flatpak_complete_list_remotes },
|
|
{ "remote-add", N_("Add a new remote repository (by URL)"), flatpak_builtin_add_remote, flatpak_complete_add_remote },
|
|
{ "remote-modify", N_("Modify properties of a configured remote"), flatpak_builtin_modify_remote, flatpak_complete_modify_remote },
|
|
{ "remote-delete", N_("Delete a configured remote"), flatpak_builtin_delete_remote, flatpak_complete_delete_remote },
|
|
{ "remote-list", NULL, flatpak_builtin_list_remotes, flatpak_complete_list_remotes, TRUE },
|
|
{ "remote-ls", N_("List contents of a configured remote"), flatpak_builtin_ls_remote, flatpak_complete_ls_remote },
|
|
{ "remote-info", N_("Show information about a remote app or runtime"), flatpak_builtin_info_remote, flatpak_complete_info_remote },
|
|
|
|
/* translators: please keep the leading newline and space */
|
|
{ N_("\n Build applications") },
|
|
{ "build-init", N_("Initialize a directory for building"), flatpak_builtin_build_init, flatpak_complete_build_init },
|
|
{ "build", N_("Run a build command inside the build dir"), flatpak_builtin_build, flatpak_complete_build },
|
|
{ "build-finish", N_("Finish a build dir for export"), flatpak_builtin_build_finish, flatpak_complete_build_finish },
|
|
{ "build-export", N_("Export a build dir to a repository"), flatpak_builtin_build_export, flatpak_complete_build_export },
|
|
{ "build-bundle", N_("Create a bundle file from a ref in a local repository"), flatpak_builtin_build_bundle, flatpak_complete_build_bundle },
|
|
{ "build-import-bundle", N_("Import a bundle file"), flatpak_builtin_build_import, flatpak_complete_build_import },
|
|
{ "build-sign", N_("Sign an application or runtime"), flatpak_builtin_build_sign, flatpak_complete_build_sign },
|
|
{ "build-update-repo", N_("Update the summary file in a repository"), flatpak_builtin_build_update_repo, flatpak_complete_build_update_repo },
|
|
{ "build-commit-from", N_("Create new commit based on existing ref"), flatpak_builtin_build_commit_from, flatpak_complete_build_commit_from },
|
|
{ "repo", N_("Print information about a repo"), flatpak_builtin_repo, flatpak_complete_repo },
|
|
|
|
{ NULL }
|
|
};
|
|
|
|
static gboolean
|
|
opt_verbose_cb (const gchar *option_name,
|
|
const gchar *value,
|
|
gpointer data,
|
|
GError **error)
|
|
{
|
|
opt_verbose++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
GOptionEntry global_entries[] = {
|
|
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, &opt_verbose_cb, N_("Print debug information during command processing, -vv for more detail"), NULL },
|
|
{ "ostree-verbose", 0, 0, G_OPTION_ARG_NONE, &opt_ostree_verbose, N_("Print OSTree debug information during command processing"), NULL },
|
|
{ "help", '?', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, N_("Show help options"), NULL, NULL },
|
|
{ NULL }
|
|
};
|
|
|
|
static GOptionEntry empty_entries[] = {
|
|
{ "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, N_("Print version information and exit"), NULL },
|
|
{ "default-arch", 0, 0, G_OPTION_ARG_NONE, &opt_default_arch, N_("Print default arch and exit"), NULL },
|
|
{ "supported-arches", 0, 0, G_OPTION_ARG_NONE, &opt_supported_arches, N_("Print supported arches and exit"), NULL },
|
|
{ "gl-drivers", 0, 0, G_OPTION_ARG_NONE, &opt_gl_drivers, N_("Print active gl drivers and exit"), NULL },
|
|
{ NULL }
|
|
};
|
|
|
|
GOptionEntry user_entries[] = {
|
|
{ "user", 0, 0, G_OPTION_ARG_NONE, &opt_user, N_("Work on user installations"), NULL },
|
|
{ "system", 0, 0, G_OPTION_ARG_NONE, &opt_system, N_("Work on system-wide installations (default)"), NULL },
|
|
{ "installation", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_installations, N_("Work on specific system-wide installation(s)"), N_("NAME") },
|
|
{ NULL }
|
|
};
|
|
|
|
static void
|
|
message_handler (const gchar *log_domain,
|
|
GLogLevelFlags log_level,
|
|
const gchar *message,
|
|
gpointer user_data)
|
|
{
|
|
/* Make this look like normal console output */
|
|
if (log_level & G_LOG_LEVEL_DEBUG)
|
|
g_printerr ("F: %s\n", message);
|
|
else
|
|
g_printerr ("%s: %s\n", g_get_prgname (), message);
|
|
}
|
|
|
|
static GOptionContext *
|
|
flatpak_option_context_new_with_commands (FlatpakCommand *commands)
|
|
{
|
|
GOptionContext *context;
|
|
GString *summary;
|
|
|
|
context = g_option_context_new (_("COMMAND"));
|
|
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
|
|
|
|
summary = g_string_new (_("Builtin Commands:"));
|
|
|
|
while (commands->name != NULL)
|
|
{
|
|
if (!commands->deprecated)
|
|
{
|
|
if (commands->fn != NULL)
|
|
{
|
|
g_string_append_printf (summary, "\n %s", commands->name);
|
|
if (commands->description)
|
|
g_string_append_printf (summary, "%*s%s", (int) (20 - strlen (commands->name)), "", _(commands->description));
|
|
}
|
|
else
|
|
{
|
|
g_string_append_printf (summary, "\n%s", _(commands->name));
|
|
}
|
|
}
|
|
commands++;
|
|
}
|
|
|
|
g_option_context_set_summary (context, summary->str);
|
|
|
|
g_string_free (summary, TRUE);
|
|
|
|
return context;
|
|
}
|
|
|
|
static int
|
|
flatpak_usage (FlatpakCommand *commands,
|
|
gboolean is_error)
|
|
{
|
|
GOptionContext *context;
|
|
g_autofree char *help = NULL;
|
|
|
|
context = flatpak_option_context_new_with_commands (commands);
|
|
|
|
g_option_context_add_main_entries (context, global_entries, NULL);
|
|
|
|
help = g_option_context_get_help (context, FALSE, NULL);
|
|
|
|
if (is_error)
|
|
g_printerr ("%s", help);
|
|
else
|
|
g_print ("%s", help);
|
|
|
|
g_option_context_free (context);
|
|
|
|
return is_error ? 1 : 0;
|
|
}
|
|
|
|
gboolean
|
|
flatpak_option_context_parse (GOptionContext *context,
|
|
const GOptionEntry *main_entries,
|
|
int *argc,
|
|
char ***argv,
|
|
FlatpakBuiltinFlags flags,
|
|
GPtrArray **out_dirs,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GPtrArray) dirs = NULL;
|
|
|
|
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_DIR) &&
|
|
!(flags & FLATPAK_BUILTIN_FLAG_ONE_DIR) &&
|
|
!(flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS) &&
|
|
!(flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS))
|
|
g_assert_not_reached ();
|
|
|
|
if (flags & FLATPAK_BUILTIN_FLAG_NO_DIR &&
|
|
(flags & FLATPAK_BUILTIN_FLAG_ONE_DIR ||
|
|
flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS ||
|
|
flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS))
|
|
g_assert_not_reached ();
|
|
|
|
if (flags & FLATPAK_BUILTIN_FLAG_ONE_DIR &&
|
|
(flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS ||
|
|
flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS))
|
|
g_assert_not_reached ();
|
|
|
|
if (flags & FLATPAK_BUILTIN_FLAG_STANDARD_DIRS &&
|
|
flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS)
|
|
g_assert_not_reached ();
|
|
|
|
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_DIR))
|
|
g_option_context_add_main_entries (context, user_entries, NULL);
|
|
|
|
if (main_entries != NULL)
|
|
g_option_context_add_main_entries (context, main_entries, NULL);
|
|
|
|
g_option_context_add_main_entries (context, global_entries, NULL);
|
|
|
|
if (!g_option_context_parse (context, argc, argv, error))
|
|
return FALSE;
|
|
|
|
/* We never want verbose output in the complete case, that breaks completion */
|
|
if (!is_in_complete)
|
|
{
|
|
if (opt_verbose > 0)
|
|
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, message_handler, NULL);
|
|
if (opt_verbose > 1)
|
|
g_log_set_handler (G_LOG_DOMAIN "2", G_LOG_LEVEL_DEBUG, message_handler, NULL);
|
|
|
|
if (opt_ostree_verbose)
|
|
g_log_set_handler ("OSTree", G_LOG_LEVEL_DEBUG, message_handler, NULL);
|
|
}
|
|
|
|
if (opt_version)
|
|
{
|
|
g_print ("%s\n", PACKAGE_STRING);
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
|
|
if (opt_default_arch)
|
|
{
|
|
g_print ("%s\n", flatpak_get_arch ());
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
|
|
if (opt_supported_arches)
|
|
{
|
|
const char **arches = flatpak_get_arches ();
|
|
int i;
|
|
for (i = 0; arches[i] != NULL; i++)
|
|
g_print ("%s\n", arches[i]);
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
|
|
if (opt_gl_drivers)
|
|
{
|
|
const char **drivers = flatpak_get_gl_drivers ();
|
|
int i;
|
|
for (i = 0; drivers[i] != NULL; i++)
|
|
g_print ("%s\n", drivers[i]);
|
|
exit (EXIT_SUCCESS);
|
|
}
|
|
|
|
if (!(flags & FLATPAK_BUILTIN_FLAG_NO_DIR))
|
|
{
|
|
dirs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
|
int i;
|
|
|
|
if (!(flags & FLATPAK_BUILTIN_FLAG_ONE_DIR))
|
|
{
|
|
/*
|
|
* FLATPAK_BUILTIN_FLAG_STANDARD_DIRS or FLATPAK_BUILTIN_FLAG_ALL_DIRS
|
|
* must be set.
|
|
*/
|
|
if (opt_user || (!opt_system && opt_installations == NULL))
|
|
g_ptr_array_add (dirs, flatpak_dir_get_user ());
|
|
|
|
if (opt_system || (!opt_user && opt_installations == NULL))
|
|
g_ptr_array_add (dirs, flatpak_dir_get_system_default ());
|
|
|
|
if (opt_installations != NULL)
|
|
{
|
|
for (i = 0; opt_installations[i] != NULL; i++)
|
|
{
|
|
FlatpakDir *installation_dir = NULL;
|
|
|
|
/* Already included the default system installation */
|
|
if (opt_system && g_strcmp0 (opt_installations[i], "default") == 0)
|
|
continue;
|
|
|
|
installation_dir = flatpak_dir_get_system_by_id (opt_installations[i], cancellable, error);
|
|
if (installation_dir == NULL)
|
|
return FALSE;
|
|
|
|
g_ptr_array_add (dirs, installation_dir);
|
|
}
|
|
}
|
|
|
|
if (flags & FLATPAK_BUILTIN_FLAG_ALL_DIRS &&
|
|
opt_installations == NULL && !opt_user && !opt_system)
|
|
{
|
|
g_autoptr(GPtrArray) system_dirs = NULL;
|
|
|
|
g_ptr_array_set_size (dirs, 0);
|
|
g_ptr_array_add (dirs, flatpak_dir_get_user ());
|
|
|
|
system_dirs = flatpak_dir_get_system_list (cancellable, error);
|
|
if (system_dirs == NULL)
|
|
return FALSE;
|
|
|
|
for (i = 0; i < system_dirs->len; i++)
|
|
{
|
|
FlatpakDir *dir = g_ptr_array_index (system_dirs, i);
|
|
g_ptr_array_add (dirs, g_object_ref (dir));
|
|
}
|
|
}
|
|
}
|
|
else /* FLATPAK_BUILTIN_FLAG_ONE_DIR */
|
|
{
|
|
FlatpakDir *dir;
|
|
|
|
if (opt_system || (!opt_user && opt_installations == NULL))
|
|
dir = flatpak_dir_get_system_default ();
|
|
else if (opt_user)
|
|
dir = flatpak_dir_get_user ();
|
|
else if (opt_installations != NULL)
|
|
{
|
|
if (g_strv_length (opt_installations) > 1)
|
|
return usage_error (context, _("The --installation option was used multiple times "
|
|
"for a command that works on one installation"), error);
|
|
dir = flatpak_dir_get_system_by_id (opt_installations[0], cancellable, error);
|
|
if (dir == NULL)
|
|
return FALSE;
|
|
}
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
g_ptr_array_add (dirs, dir);
|
|
}
|
|
|
|
for (i = 0; i < dirs->len; i++)
|
|
{
|
|
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
|
|
|
if (flags & FLATPAK_BUILTIN_FLAG_OPTIONAL_REPO)
|
|
{
|
|
if (!flatpak_dir_maybe_ensure_repo (dir, cancellable, error))
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!flatpak_dir_ensure_repo (dir, cancellable, error))
|
|
return FALSE;
|
|
}
|
|
|
|
flatpak_log_dir_access (dir);
|
|
}
|
|
}
|
|
|
|
if (out_dirs)
|
|
*out_dirs = g_steal_pointer (&dirs);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
usage_error (GOptionContext *context, const char *message, GError **error)
|
|
{
|
|
g_autofree gchar *help = g_option_context_get_help (context, TRUE, NULL);
|
|
|
|
g_printerr ("%s", help);
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message);
|
|
return FALSE;
|
|
}
|
|
|
|
static FlatpakCommand *
|
|
extract_command (int *argc,
|
|
char **argv,
|
|
const char **command_name_out)
|
|
{
|
|
FlatpakCommand *command;
|
|
const char *command_name = NULL;
|
|
int in, out;
|
|
|
|
/*
|
|
* Parse the global options. We rearrange the options as
|
|
* necessary, in order to pass relevant options through
|
|
* to the commands, but also have them take effect globally.
|
|
*/
|
|
for (in = 1, out = 1; in < *argc; in++, out++)
|
|
{
|
|
/* The non-option is the command, take it out of the arguments */
|
|
if (argv[in][0] != '-')
|
|
{
|
|
if (command_name == NULL)
|
|
{
|
|
command_name = argv[in];
|
|
out--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
argv[out] = argv[in];
|
|
}
|
|
|
|
*argc = out;
|
|
argv[out] = NULL;
|
|
|
|
command = commands;
|
|
while (command->name)
|
|
{
|
|
if (command->fn != NULL &&
|
|
g_strcmp0 (command_name, command->name) == 0)
|
|
break;
|
|
command++;
|
|
}
|
|
|
|
*command_name_out = command_name;
|
|
|
|
return command;
|
|
}
|
|
|
|
|
|
static int
|
|
flatpak_run (int argc,
|
|
char **argv,
|
|
GError **res_error)
|
|
{
|
|
FlatpakCommand *command;
|
|
GError *error = NULL;
|
|
GCancellable *cancellable = NULL;
|
|
g_autofree char *prgname = NULL;
|
|
gboolean success = FALSE;
|
|
const char *command_name = NULL;
|
|
|
|
command = extract_command (&argc, argv, &command_name);
|
|
|
|
if (!command->fn)
|
|
{
|
|
GOptionContext *context;
|
|
g_autofree char *help = NULL;
|
|
|
|
context = flatpak_option_context_new_with_commands (commands);
|
|
|
|
if (command_name != NULL)
|
|
{
|
|
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
_("Unknown command '%s'"), command_name);
|
|
}
|
|
else
|
|
{
|
|
/* This will not return for some options (e.g. --version). */
|
|
if (flatpak_option_context_parse (context, empty_entries, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, &error))
|
|
{
|
|
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
_("No command specified"));
|
|
}
|
|
}
|
|
|
|
help = g_option_context_get_help (context, FALSE, NULL);
|
|
g_printerr ("%s", help);
|
|
|
|
g_option_context_free (context);
|
|
|
|
goto out;
|
|
}
|
|
|
|
prgname = g_strdup_printf ("%s %s", g_get_prgname (), command_name);
|
|
g_set_prgname (prgname);
|
|
|
|
if (!command->fn (argc, argv, cancellable, &error))
|
|
goto out;
|
|
|
|
success = TRUE;
|
|
out:
|
|
g_assert (success || error);
|
|
|
|
if (error)
|
|
{
|
|
g_propagate_error (res_error, error);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
complete (int argc,
|
|
char **argv)
|
|
{
|
|
FlatpakCommand *command;
|
|
FlatpakCompletion *completion;
|
|
const char *command_name = NULL;
|
|
|
|
is_in_complete = TRUE;
|
|
|
|
completion = flatpak_completion_new (argv[2], argv[3], argv[4]);
|
|
if (completion == NULL)
|
|
return 1;
|
|
|
|
command = extract_command (&completion->argc, completion->argv, &command_name);
|
|
flatpak_completion_debug ("command=%p '%s'", command->fn, command->name);
|
|
|
|
if (!command->fn)
|
|
{
|
|
FlatpakCommand *c = commands;
|
|
while (c->name)
|
|
{
|
|
if (c->fn != NULL)
|
|
flatpak_complete_word (completion, "%s ", c->name);
|
|
c++;
|
|
}
|
|
|
|
flatpak_complete_options (completion, global_entries);
|
|
flatpak_complete_options (completion, empty_entries);
|
|
flatpak_complete_options (completion, user_entries);
|
|
}
|
|
else if (command->complete)
|
|
{
|
|
if (!command->complete (completion))
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
flatpak_complete_options (completion, global_entries);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char **argv)
|
|
{
|
|
GError *error = NULL;
|
|
g_autofree const char *old_env = NULL;
|
|
int ret;
|
|
|
|
setlocale (LC_ALL, "");
|
|
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
|
textdomain (GETTEXT_PACKAGE);
|
|
|
|
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_WARNING, message_handler, NULL);
|
|
|
|
g_set_prgname (argv[0]);
|
|
|
|
/* avoid gvfs (http://bugzilla.gnome.org/show_bug.cgi?id=526454) */
|
|
old_env = g_strdup (g_getenv ("GIO_USE_VFS"));
|
|
g_setenv ("GIO_USE_VFS", "local", TRUE);
|
|
g_vfs_get_default ();
|
|
if (old_env)
|
|
g_setenv ("GIO_USE_VFS", old_env, TRUE);
|
|
else
|
|
g_unsetenv ("GIO_USE_VFS");
|
|
|
|
if (argc >= 4 && strcmp (argv[1], "complete") == 0)
|
|
return complete (argc, argv);
|
|
|
|
flatpak_migrate_from_xdg_app ();
|
|
|
|
ret = flatpak_run (argc, argv, &error);
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
|
flatpak_usage (commands, TRUE);
|
|
|
|
if (error != NULL)
|
|
{
|
|
const char *prefix = "";
|
|
const char *suffix = "";
|
|
if (flatpak_fancy_output ())
|
|
{
|
|
prefix = FLATPAK_ANSI_RED FLATPAK_ANSI_BOLD_ON;
|
|
suffix = FLATPAK_ANSI_BOLD_OFF FLATPAK_ANSI_COLOR_RESET;
|
|
}
|
|
g_printerr ("%s%s %s%s\n", prefix, _("error:"), suffix, error->message);
|
|
g_error_free (error);
|
|
}
|
|
|
|
return ret;
|
|
}
|