gnome-shell/subprojects/extensions-tool/src/command-install.c
Florian Müllner f5a170ce46 extensions-tool: Add common option to silence errors
Error reporting is useful when used interactively, but often undesirable
when used in scripts. Account for that with a common --quiet option,
which is more convenient than redirection stderr to /dev/null.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/2391
2020-04-05 13:42:50 +02:00

214 lines
5.6 KiB
C

/* command-install.c
*
* Copyright 2018 Florian Müllner <fmuellner@gnome.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gnome-autoar/gnome-autoar.h>
#include <json-glib/json-glib.h>
#include "commands.h"
#include "common.h"
#include "config.h"
static JsonObject *
load_metadata (GFile *dir,
GError **error)
{
g_autoptr (JsonParser) parser = NULL;
g_autoptr (GInputStream) stream = NULL;
g_autoptr (GFile) file = NULL;
file = g_file_get_child (dir, "metadata.json");
stream = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (stream == NULL)
return NULL;
parser = json_parser_new_immutable ();
if (!json_parser_load_from_stream (parser, stream, NULL, error))
return NULL;
return json_node_dup_object (json_parser_get_root (parser));
}
static void
on_error (AutoarExtractor *extractor,
GError *error,
gpointer data)
{
*((GError **)data) = g_error_copy (error);
}
static GFile *
on_decide_destination (AutoarExtractor *extractor,
GFile *dest,
GList *files,
gpointer data)
{
g_autofree char *dest_path = NULL;
GFile *new_dest;
int copy = 1;
dest_path = g_file_get_path (dest);
new_dest = g_object_ref (dest);
while (g_file_query_exists (new_dest, NULL))
{
g_autofree char *new_path = g_strdup_printf ("%s (%d)", dest_path, copy);
g_object_unref (new_dest);
new_dest = g_file_new_for_path (new_path);
copy++;
}
*((GFile **)data) = g_object_ref (new_dest);
return new_dest;
}
static int
install_extension (const char *bundle,
gboolean force)
{
g_autoptr (AutoarExtractor) extractor = NULL;
g_autoptr (JsonObject) metadata = NULL;
g_autoptr (GFile) cachedir = NULL;
g_autoptr (GFile) tmpdir = NULL;
g_autoptr (GFile) src = NULL;
g_autoptr (GFile) dst = NULL;
g_autoptr (GFile) dstdir = NULL;
g_autoptr (GError) error = NULL;
g_autofree char *cwd = NULL;
const char *uuid;
cwd = g_get_current_dir ();
src = g_file_new_for_commandline_arg_and_cwd (bundle, cwd);
cachedir = g_file_new_for_path (g_get_user_cache_dir ());
extractor = autoar_extractor_new (src, cachedir);
g_signal_connect (extractor, "error", G_CALLBACK (on_error), &error);
g_signal_connect (extractor, "decide-destination", G_CALLBACK (on_decide_destination), &tmpdir);
autoar_extractor_start (extractor, NULL);
if (error != NULL)
goto err;
metadata = load_metadata (tmpdir, &error);
if (metadata == NULL)
goto err;
dstdir = g_file_new_build_filename (g_get_user_data_dir (),
"gnome-shell", "extensions", NULL);
if (!g_file_make_directory_with_parents (dstdir, NULL, &error))
{
if (error->code == G_IO_ERROR_EXISTS)
g_clear_error (&error);
else
goto err;
}
uuid = json_object_get_string_member (metadata, "uuid");
dst = g_file_get_child (dstdir, uuid);
if (g_file_query_exists (dst, NULL))
{
if (!force)
{
g_set_error (&error, G_IO_ERROR, G_IO_ERROR_EXISTS,
"%s exists and --force was not specified", uuid);
goto err;
}
else if (!file_delete_recursively (dst, &error))
{
goto err;
}
}
if (!g_file_move (tmpdir, dst, G_FILE_COPY_NONE, NULL, NULL, NULL, &error))
goto err;
return 0;
err:
if (error != NULL)
g_printerr ("%s\n", error->message);
if (tmpdir != NULL)
file_delete_recursively (tmpdir, NULL);
return 2;
}
int
handle_install (int argc, char *argv[], gboolean do_help)
{
g_autoptr (GOptionContext) context = NULL;
g_autoptr (GError) error = NULL;
g_auto (GStrv) filenames = NULL;
gboolean force = FALSE;
GOptionEntry entries[] = {
{ .long_name = "force", .short_name = 'f',
.arg = G_OPTION_ARG_NONE, .arg_data = &force,
.description = _("Overwrite an existing extension") },
{ .long_name = G_OPTION_REMAINING,
.arg_description =_("EXTENSION_BUNDLE"),
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = &filenames },
{ NULL }
};
g_set_prgname ("gnome-extensions install");
context = g_option_context_new (NULL);
g_option_context_set_help_enabled (context, FALSE);
g_option_context_set_summary (context, _("Install an extension bundle"));
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
g_option_context_add_group (context, get_option_group());
if (do_help)
{
show_help (context, NULL);
return 0;
}
if (!g_option_context_parse (context, &argc, &argv, &error))
{
show_help (context, error->message);
return 1;
}
if (filenames == NULL)
{
show_help (context, _("No extension bundle specified"));
return 1;
}
if (g_strv_length (filenames) > 1)
{
show_help (context, _("More than one extension bundle specified"));
return 1;
}
return install_extension (*filenames, force);
}