2018-08-26 21:24:10 -04:00
|
|
|
|
/* command-create.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
|
|
|
|
|
*/
|
|
|
|
|
|
2019-11-07 09:16:34 -05:00
|
|
|
|
#define _GNU_SOURCE /* for strcasestr */
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
|
#include <gio/gio.h>
|
2019-11-07 09:36:35 -05:00
|
|
|
|
#include <gio/gdesktopappinfo.h>
|
2018-08-26 21:24:10 -04:00
|
|
|
|
#include <gio/gunixinputstream.h>
|
|
|
|
|
|
|
|
|
|
#include "commands.h"
|
|
|
|
|
#include "common.h"
|
2018-08-26 22:30:53 -04:00
|
|
|
|
#include "config.h"
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
2019-11-06 04:06:11 -05:00
|
|
|
|
#define TEMPLATES_PATH "/org/gnome/extensions-tool/templates"
|
2019-11-07 09:36:35 -05:00
|
|
|
|
#define TEMPLATE_KEY "Path"
|
|
|
|
|
#define SORT_DATA "desktop-id"
|
2019-11-06 04:06:11 -05:00
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
static char *
|
|
|
|
|
get_shell_version (GError **error)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GDBusProxy) proxy = NULL;
|
|
|
|
|
g_autoptr (GVariant) variant = NULL;
|
|
|
|
|
g_auto (GStrv) split_version = NULL;
|
|
|
|
|
|
|
|
|
|
proxy = get_shell_proxy (error);
|
|
|
|
|
if (proxy == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
variant = g_dbus_proxy_get_cached_property (proxy, "ShellVersion");
|
|
|
|
|
if (variant == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2021-02-25 18:54:50 -05:00
|
|
|
|
split_version = g_strsplit (g_variant_get_string (variant, NULL), ".", 2);
|
|
|
|
|
return g_steal_pointer(&split_version[0]);
|
2018-08-26 21:24:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 09:36:35 -05:00
|
|
|
|
static GDesktopAppInfo *
|
|
|
|
|
load_app_info_from_resource (const char *uri)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GFile) file = NULL;
|
|
|
|
|
g_autofree char *contents = NULL;
|
|
|
|
|
g_autoptr (GKeyFile) keyfile = NULL;
|
|
|
|
|
|
|
|
|
|
file = g_file_new_for_uri (uri);
|
|
|
|
|
if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, NULL))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
keyfile = g_key_file_new ();
|
|
|
|
|
if (!g_key_file_load_from_data (keyfile, contents, -1, G_KEY_FILE_NONE, NULL))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return g_desktop_app_info_new_from_keyfile (keyfile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
sort_func (gconstpointer a, gconstpointer b)
|
|
|
|
|
{
|
|
|
|
|
GObject *info1 = *((GObject **) a);
|
|
|
|
|
GObject *info2 = *((GObject **) b);
|
|
|
|
|
const char *desktop1 = g_object_get_data (info1, SORT_DATA);
|
|
|
|
|
const char *desktop2 = g_object_get_data (info2, SORT_DATA);
|
|
|
|
|
|
|
|
|
|
return g_strcmp0 (desktop1, desktop2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GPtrArray *
|
|
|
|
|
get_templates (void)
|
|
|
|
|
{
|
|
|
|
|
g_auto (GStrv) children = NULL;
|
|
|
|
|
GPtrArray *templates = g_ptr_array_new_with_free_func (g_object_unref);
|
|
|
|
|
char **s;
|
|
|
|
|
|
|
|
|
|
children = g_resources_enumerate_children (TEMPLATES_PATH, 0, NULL);
|
|
|
|
|
|
|
|
|
|
for (s = children; *s; s++)
|
|
|
|
|
{
|
|
|
|
|
g_autofree char *uri = NULL;
|
|
|
|
|
GDesktopAppInfo *info;
|
|
|
|
|
|
|
|
|
|
if (!g_str_has_suffix (*s, ".desktop"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
uri = g_strdup_printf ("resource://" TEMPLATES_PATH "/%s", *s);
|
|
|
|
|
info = load_app_info_from_resource (uri);
|
|
|
|
|
if (!info)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
g_object_set_data_full (G_OBJECT (info), SORT_DATA, g_strdup (*s), g_free);
|
|
|
|
|
g_ptr_array_add (templates, info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ptr_array_sort (templates, sort_func);
|
|
|
|
|
|
|
|
|
|
return templates;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-24 01:40:07 -04:00
|
|
|
|
static char *
|
|
|
|
|
escape_json_string (const char *string)
|
|
|
|
|
{
|
|
|
|
|
GString *escaped = g_string_new (string);
|
|
|
|
|
|
|
|
|
|
for (gsize i = 0; i < escaped->len; ++i)
|
|
|
|
|
{
|
|
|
|
|
if (escaped->str[i] == '"' || escaped->str[i] == '\\')
|
|
|
|
|
{
|
|
|
|
|
g_string_insert_c (escaped, i, '\\');
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_string_free (escaped, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
static gboolean
|
|
|
|
|
create_metadata (GFile *target_dir,
|
|
|
|
|
const char *uuid,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *description,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
2020-05-24 01:40:07 -04:00
|
|
|
|
g_autofree char *uuid_escaped = NULL;
|
|
|
|
|
g_autofree char *name_escaped = NULL;
|
|
|
|
|
g_autofree char *desc_escaped = NULL;
|
2018-08-26 21:24:10 -04:00
|
|
|
|
g_autoptr (GFile) target = NULL;
|
|
|
|
|
g_autoptr (GString) json = NULL;
|
|
|
|
|
g_autofree char *version = NULL;
|
|
|
|
|
|
|
|
|
|
version = get_shell_version (error);
|
|
|
|
|
if (version == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2020-05-24 01:40:07 -04:00
|
|
|
|
uuid_escaped = escape_json_string (uuid);
|
|
|
|
|
name_escaped = escape_json_string (name);
|
|
|
|
|
desc_escaped = escape_json_string (description);
|
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
json = g_string_new ("{\n");
|
|
|
|
|
|
2020-05-24 01:40:07 -04:00
|
|
|
|
g_string_append_printf (json, " \"name\": \"%s\",\n", name_escaped);
|
|
|
|
|
g_string_append_printf (json, " \"description\": \"%s\",\n", desc_escaped);
|
|
|
|
|
g_string_append_printf (json, " \"uuid\": \"%s\",\n", uuid_escaped);
|
2018-08-26 21:24:10 -04:00
|
|
|
|
g_string_append_printf (json, " \"shell-version\": [\n");
|
|
|
|
|
g_string_append_printf (json, " \"%s\"\n", version);
|
|
|
|
|
g_string_append_printf (json, " ]\n}\n");
|
|
|
|
|
|
|
|
|
|
target = g_file_get_child (target_dir, "metadata.json");
|
|
|
|
|
return g_file_replace_contents (target,
|
|
|
|
|
json->str,
|
|
|
|
|
json->len,
|
|
|
|
|
NULL,
|
|
|
|
|
FALSE,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2019-11-06 04:06:11 -05:00
|
|
|
|
copy_extension_template (const char *template, GFile *target_dir, GError **error)
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
2020-03-02 12:16:25 -05:00
|
|
|
|
g_auto (GStrv) templates = NULL;
|
2019-11-06 04:06:11 -05:00
|
|
|
|
g_autofree char *path = NULL;
|
2018-08-26 21:24:10 -04:00
|
|
|
|
char **s;
|
|
|
|
|
|
2019-11-06 04:06:11 -05:00
|
|
|
|
path = g_strdup_printf (TEMPLATES_PATH "/%s", template);
|
|
|
|
|
templates = g_resources_enumerate_children (path, 0, NULL);
|
|
|
|
|
|
|
|
|
|
if (templates == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
|
|
|
|
"No template %s", template);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
for (s = templates; *s; s++)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GFile) target = NULL;
|
|
|
|
|
g_autoptr (GFile) source = NULL;
|
|
|
|
|
g_autofree char *uri = NULL;
|
|
|
|
|
|
2019-11-06 04:06:11 -05:00
|
|
|
|
uri = g_strdup_printf ("resource://%s/%s", path, *s);
|
2018-08-26 21:24:10 -04:00
|
|
|
|
source = g_file_new_for_uri (uri);
|
|
|
|
|
target = g_file_get_child (target_dir, *s);
|
|
|
|
|
|
|
|
|
|
if (!g_file_copy (source, target, G_FILE_COPY_TARGET_DEFAULT_PERMS, NULL, NULL, NULL, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
launch_extension_source (GFile *dir, GError **error)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GFile) main_source = NULL;
|
|
|
|
|
g_autoptr (GAppInfo) handler = NULL;
|
|
|
|
|
GList l;
|
|
|
|
|
|
|
|
|
|
main_source = g_file_get_child (dir, "extension.js");
|
2019-12-19 14:00:51 -05:00
|
|
|
|
handler = g_file_query_default_handler (main_source, NULL, NULL);
|
2018-08-26 21:24:10 -04:00
|
|
|
|
if (handler == NULL)
|
2019-12-19 14:00:51 -05:00
|
|
|
|
{
|
|
|
|
|
/* Translators: a file path to an extension directory */
|
|
|
|
|
g_print (_("The new extension was successfully created in %s.\n"),
|
|
|
|
|
g_file_peek_path (dir));
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
|
|
|
|
l.data = main_source;
|
|
|
|
|
l.next = l.prev = NULL;
|
|
|
|
|
|
|
|
|
|
return g_app_info_launch (handler, &l, NULL, error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2019-11-07 06:46:47 -05:00
|
|
|
|
create_extension (const char *uuid, const char *name, const char *description, const char *template)
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
|
|
|
|
g_autoptr (GFile) dir = NULL;
|
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
2019-11-07 06:46:47 -05:00
|
|
|
|
if (template == NULL)
|
|
|
|
|
template = "plain";
|
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
dir = g_file_new_build_filename (g_get_user_data_dir (),
|
|
|
|
|
"gnome-shell",
|
|
|
|
|
"extensions",
|
|
|
|
|
uuid,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (!g_file_make_directory_with_parents (dir, NULL, &error))
|
|
|
|
|
{
|
|
|
|
|
g_printerr ("%s\n", error->message);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!create_metadata (dir, uuid, name, description, &error))
|
|
|
|
|
{
|
|
|
|
|
g_printerr ("%s\n", error->message);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 06:46:47 -05:00
|
|
|
|
if (!copy_extension_template (template, dir, &error))
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
|
|
|
|
g_printerr ("%s\n", error->message);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!launch_extension_source (dir, &error))
|
|
|
|
|
{
|
|
|
|
|
g_printerr ("%s\n", error->message);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-11-07 09:16:34 -05:00
|
|
|
|
prompt_metadata (char **uuid, char **name, char **description, char **template)
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
|
|
|
|
g_autoptr (GInputStream) stdin = NULL;
|
|
|
|
|
g_autoptr (GDataInputStream) istream = NULL;
|
|
|
|
|
|
2018-08-26 22:30:53 -04:00
|
|
|
|
if ((uuid == NULL || *uuid != NULL) &&
|
|
|
|
|
(name == NULL || *name != NULL) &&
|
2019-11-07 09:16:34 -05:00
|
|
|
|
(description == NULL || *description != NULL) &&
|
|
|
|
|
(template == NULL || *template != NULL))
|
2018-08-26 22:30:53 -04:00
|
|
|
|
return;
|
|
|
|
|
|
2018-08-26 21:24:10 -04:00
|
|
|
|
stdin = g_unix_input_stream_new (0, FALSE);
|
|
|
|
|
istream = g_data_input_stream_new (stdin);
|
|
|
|
|
|
2018-08-26 22:30:53 -04:00
|
|
|
|
if (name != NULL && *name == NULL)
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
2020-04-06 19:49:30 -04:00
|
|
|
|
char *line = NULL;
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
|
|
|
|
g_print (
|
|
|
|
|
_("Name should be a very short (ideally descriptive) string.\n"
|
|
|
|
|
"Examples are: %s"),
|
|
|
|
|
"“Click To Focus”, “Adblock”, “Shell Window Shrinker”\n");
|
|
|
|
|
|
2020-04-06 19:49:30 -04:00
|
|
|
|
while (line == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_print ("%s: ", _("Name"));
|
|
|
|
|
|
|
|
|
|
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
|
|
|
|
}
|
2018-08-26 21:24:10 -04:00
|
|
|
|
*name = g_strdelimit (line, "\n", '\0');
|
2019-11-09 21:00:37 -05:00
|
|
|
|
|
|
|
|
|
g_print ("\n");
|
2018-08-26 21:24:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 22:30:53 -04:00
|
|
|
|
if (description != NULL && *description == NULL)
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
2020-04-06 19:49:30 -04:00
|
|
|
|
char *line = NULL;
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
|
|
|
|
g_print (
|
|
|
|
|
_("Description is a single-sentence explanation of what your extension does.\n"
|
|
|
|
|
"Examples are: %s"),
|
|
|
|
|
"“Make windows visible on click”, “Block advertisement popups”, “Animate windows shrinking on minimize”\n");
|
|
|
|
|
|
2020-04-06 19:49:30 -04:00
|
|
|
|
while (line == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_print ("%s: ", _("Description"));
|
|
|
|
|
|
|
|
|
|
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
|
|
|
|
}
|
2018-08-26 21:24:10 -04:00
|
|
|
|
*description = g_strdelimit (line, "\n", '\0');
|
2019-11-09 21:00:37 -05:00
|
|
|
|
|
|
|
|
|
g_print ("\n");
|
2018-08-26 21:24:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 22:30:53 -04:00
|
|
|
|
if (uuid != NULL && *uuid == NULL)
|
2018-08-26 21:24:10 -04:00
|
|
|
|
{
|
2020-04-06 19:49:30 -04:00
|
|
|
|
char *line = NULL;
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
|
|
|
|
g_print (
|
|
|
|
|
_("UUID is a globally-unique identifier for your extension.\n"
|
|
|
|
|
"This should be in the format of an email address (clicktofocus@janedoe.example.com)\n"));
|
|
|
|
|
|
2020-04-06 19:49:30 -04:00
|
|
|
|
while (line == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_print ("UUID: ");
|
|
|
|
|
|
|
|
|
|
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
|
|
|
|
}
|
2018-08-26 21:24:10 -04:00
|
|
|
|
*uuid = g_strdelimit (line, "\n", '\0');
|
2019-11-09 21:00:37 -05:00
|
|
|
|
|
|
|
|
|
g_print ("\n");
|
2018-08-26 21:24:10 -04:00
|
|
|
|
}
|
2019-11-07 09:16:34 -05:00
|
|
|
|
|
|
|
|
|
if (template != NULL && *template == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GPtrArray) templates = get_templates ();
|
|
|
|
|
|
|
|
|
|
if (templates->len == 1)
|
|
|
|
|
{
|
|
|
|
|
GDesktopAppInfo *info = g_ptr_array_index (templates, 0);
|
|
|
|
|
*template = g_desktop_app_info_get_string (info, TEMPLATE_KEY);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
g_print (_("Choose one of the available templates:\n"));
|
|
|
|
|
for (i = 0; i < templates->len; i++)
|
|
|
|
|
{
|
|
|
|
|
GAppInfo *info = g_ptr_array_index (templates, i);
|
|
|
|
|
g_print ("%d) %-10s – %s\n",
|
|
|
|
|
i + 1,
|
|
|
|
|
g_app_info_get_name (info),
|
|
|
|
|
g_app_info_get_description (info));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (*template == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_autofree char *line = NULL;
|
|
|
|
|
|
|
|
|
|
g_print ("%s [1-%d]: ", _("Template"), templates->len);
|
|
|
|
|
|
|
|
|
|
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
if (line == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (g_ascii_isdigit (*line))
|
|
|
|
|
{
|
|
|
|
|
long i = strtol (line, NULL, 10);
|
|
|
|
|
|
|
|
|
|
if (i > 0 && i <= templates->len)
|
|
|
|
|
{
|
|
|
|
|
GDesktopAppInfo *info;
|
|
|
|
|
|
|
|
|
|
info = g_ptr_array_index (templates, i - 1);
|
|
|
|
|
*template =
|
|
|
|
|
g_desktop_app_info_get_string (info, TEMPLATE_KEY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < templates->len; i++)
|
|
|
|
|
{
|
|
|
|
|
GDesktopAppInfo *info = g_ptr_array_index (templates, i);
|
|
|
|
|
g_autofree char *cur_template = NULL;
|
|
|
|
|
|
|
|
|
|
cur_template =
|
|
|
|
|
g_desktop_app_info_get_string (info, TEMPLATE_KEY);
|
|
|
|
|
|
|
|
|
|
if (strcasestr (cur_template, line) != NULL)
|
|
|
|
|
*template = g_steal_pointer (&cur_template);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_print ("\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-26 21:24:10 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
handle_create (int argc, char *argv[], gboolean do_help)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GOptionContext) context = NULL;
|
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
g_autofree char *name = NULL;
|
|
|
|
|
g_autofree char *description = NULL;
|
|
|
|
|
g_autofree char *uuid = NULL;
|
2019-11-07 06:46:47 -05:00
|
|
|
|
g_autofree char *template = NULL;
|
2018-08-26 22:30:53 -04:00
|
|
|
|
gboolean interactive = FALSE;
|
2019-11-07 09:36:35 -05:00
|
|
|
|
gboolean list_templates = FALSE;
|
2018-08-26 22:30:53 -04:00
|
|
|
|
GOptionEntry entries[] = {
|
|
|
|
|
{ .long_name = "uuid",
|
|
|
|
|
.arg = G_OPTION_ARG_STRING, .arg_data = &uuid,
|
|
|
|
|
.arg_description = "UUID",
|
|
|
|
|
.description = _("The unique identifier of the new extension") },
|
|
|
|
|
{ .long_name = "name",
|
|
|
|
|
.arg = G_OPTION_ARG_STRING, .arg_data = &name,
|
|
|
|
|
.arg_description = _("NAME"),
|
|
|
|
|
.description = _("The user-visible name of the new extension") },
|
|
|
|
|
{ .long_name = "description",
|
|
|
|
|
.arg_description = _("DESCRIPTION"),
|
|
|
|
|
.arg = G_OPTION_ARG_STRING, .arg_data = &description,
|
|
|
|
|
.description = _("A short description of what the extension does") },
|
2019-11-07 06:46:47 -05:00
|
|
|
|
{ .long_name = "template",
|
|
|
|
|
.arg = G_OPTION_ARG_STRING, .arg_data = &template,
|
|
|
|
|
.arg_description = _("TEMPLATE"),
|
|
|
|
|
.description = _("The template to use for the new extension") },
|
2019-11-07 09:36:35 -05:00
|
|
|
|
{ .long_name = "list-templates",
|
|
|
|
|
.arg = G_OPTION_ARG_NONE, .arg_data = &list_templates,
|
|
|
|
|
.flags = G_OPTION_FLAG_HIDDEN },
|
2018-08-26 22:30:53 -04:00
|
|
|
|
{ .long_name = "interactive", .short_name = 'i',
|
|
|
|
|
.arg = G_OPTION_ARG_NONE, .arg_data = &interactive,
|
|
|
|
|
.description = _("Enter extension information interactively") },
|
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
|
|
|
|
g_set_prgname ("gnome-extensions create");
|
|
|
|
|
|
|
|
|
|
context = g_option_context_new (NULL);
|
|
|
|
|
g_option_context_set_help_enabled (context, FALSE);
|
|
|
|
|
g_option_context_set_summary (context, _("Create a new extension"));
|
2018-08-26 22:30:53 -04:00
|
|
|
|
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
|
2020-03-14 07:58:04 -04:00
|
|
|
|
g_option_context_add_group (context, get_option_group ());
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
|
|
|
|
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 (argc > 1)
|
|
|
|
|
{
|
|
|
|
|
show_help (context, _("Unknown arguments"));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 09:36:35 -05:00
|
|
|
|
if (list_templates)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GPtrArray) templates = get_templates ();
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < templates->len; i++)
|
|
|
|
|
{
|
|
|
|
|
GDesktopAppInfo *info = g_ptr_array_index (templates, i);
|
|
|
|
|
g_autofree char *template = NULL;
|
|
|
|
|
|
|
|
|
|
template = g_desktop_app_info_get_string (info, TEMPLATE_KEY);
|
|
|
|
|
g_print ("%s\n", template);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 22:30:53 -04:00
|
|
|
|
if (interactive)
|
2019-11-07 09:16:34 -05:00
|
|
|
|
prompt_metadata (&uuid, &name, &description, &template);
|
2018-08-26 22:30:53 -04:00
|
|
|
|
|
|
|
|
|
if (uuid == NULL || name == NULL || description == NULL)
|
|
|
|
|
{
|
|
|
|
|
show_help (context, _("UUID, name and description are required"));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2018-08-26 21:24:10 -04:00
|
|
|
|
|
2019-11-07 06:46:47 -05:00
|
|
|
|
return create_extension (uuid, name, description, template) ? 0 : 2;
|
2018-08-26 21:24:10 -04:00
|
|
|
|
}
|