extensions-tool: Implement create command
This implements more functionality of the existing tool and, as 'reload' is an unreliable feature that doesn't work more often than not, the last bit that we will replicate. The command follows the original for the most part, with the most important difference being the installed template, which doesn't provide any sample functionality and uses modern JS syntax. https://gitlab.gnome.org/GNOME/gnome-shell/issues/1234
This commit is contained in:
parent
c8c93b2a70
commit
0b1e29e5e3
256
src/extensions-tool/command-create.c
Normal file
256
src/extensions-tool/command-create.c
Normal file
@ -0,0 +1,256 @@
|
||||
/* 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
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
|
||||
#include "commands.h"
|
||||
#include "common.h"
|
||||
|
||||
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;
|
||||
|
||||
split_version = g_strsplit (g_variant_get_string (variant, NULL), ".", 3);
|
||||
if (g_ascii_strtoll (split_version[1], NULL, 10) % 2 == 0)
|
||||
g_clear_pointer (&split_version[2], g_free);
|
||||
|
||||
return g_strjoinv (".", split_version);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_metadata (GFile *target_dir,
|
||||
const char *uuid,
|
||||
const char *name,
|
||||
const char *description,
|
||||
GError **error)
|
||||
{
|
||||
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;
|
||||
|
||||
json = g_string_new ("{\n");
|
||||
|
||||
g_string_append_printf (json, " \"name\": \"%s\",\n", name);
|
||||
g_string_append_printf (json, " \"description\": \"%s\",\n", description);
|
||||
g_string_append_printf (json, " \"uuid\": \"%s\",\n", uuid);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
#define TEMPLATE_PATH "/org/gnome/extensions-tool/template"
|
||||
static gboolean
|
||||
copy_extension_template (GFile *target_dir, GError **error)
|
||||
{
|
||||
g_auto (GStrv) templates;
|
||||
char **s;
|
||||
|
||||
templates = g_resources_enumerate_children (TEMPLATE_PATH, 0, NULL);
|
||||
for (s = templates; *s; s++)
|
||||
{
|
||||
g_autoptr (GFile) target = NULL;
|
||||
g_autoptr (GFile) source = NULL;
|
||||
g_autofree char *uri = NULL;
|
||||
|
||||
uri = g_strdup_printf ("resource://%s/%s", TEMPLATE_PATH, *s);
|
||||
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");
|
||||
handler = g_file_query_default_handler (main_source, NULL, error);
|
||||
if (handler == NULL)
|
||||
return FALSE;
|
||||
|
||||
l.data = main_source;
|
||||
l.next = l.prev = NULL;
|
||||
|
||||
return g_app_info_launch (handler, &l, NULL, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_extension (const char *uuid, const char *name, const char *description)
|
||||
{
|
||||
g_autoptr (GFile) dir = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!copy_extension_template (dir, &error))
|
||||
{
|
||||
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
|
||||
prompt_metadata (char **uuid, char **name, char **description)
|
||||
{
|
||||
g_autoptr (GInputStream) stdin = NULL;
|
||||
g_autoptr (GDataInputStream) istream = NULL;
|
||||
|
||||
stdin = g_unix_input_stream_new (0, FALSE);
|
||||
istream = g_data_input_stream_new (stdin);
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
char *line;
|
||||
|
||||
g_print (
|
||||
_("Name should be a very short (ideally descriptive) string.\n"
|
||||
"Examples are: %s"),
|
||||
"“Click To Focus”, “Adblock”, “Shell Window Shrinker”\n");
|
||||
g_print ("%s: ", _("Name"));
|
||||
|
||||
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
||||
*name = g_strdelimit (line, "\n", '\0');
|
||||
}
|
||||
|
||||
if (description != NULL)
|
||||
{
|
||||
char *line;
|
||||
|
||||
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");
|
||||
g_print ("%s: ", _("Description"));
|
||||
|
||||
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
||||
*description = g_strdelimit (line, "\n", '\0');
|
||||
}
|
||||
|
||||
if (uuid != NULL)
|
||||
{
|
||||
char *line;
|
||||
|
||||
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"));
|
||||
g_print ("UUID: ");
|
||||
|
||||
line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
|
||||
*uuid = g_strdelimit (line, "\n", '\0');
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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"));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
prompt_metadata (&uuid, &name, &description);
|
||||
|
||||
return create_extension (uuid, name, description) ? 0 : 2;
|
||||
}
|
@ -26,5 +26,6 @@ G_BEGIN_DECLS
|
||||
|
||||
int handle_enable (int argc, char *argv[], gboolean do_help);
|
||||
int handle_disable (int argc, char *argv[], gboolean do_help);
|
||||
int handle_create (int argc, char *argv[], gboolean do_help);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -20,13 +20,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void show_help (GOptionContext *context,
|
||||
const char *message);
|
||||
|
||||
GDBusProxy *get_shell_proxy (GError **error);
|
||||
GSettings *get_shell_settings (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
7
src/extensions-tool/gnome-extensions-tool.gresource.xml
Normal file
7
src/extensions-tool/gnome-extensions-tool.gresource.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/extensions-tool">
|
||||
<file>template/extension.js</file>
|
||||
<file>template/stylesheet.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
@ -38,6 +38,19 @@ show_help (GOptionContext *context, const char *message)
|
||||
g_printerr ("%s", help);
|
||||
}
|
||||
|
||||
GDBusProxy *
|
||||
get_shell_proxy (GError **error)
|
||||
{
|
||||
return g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL,
|
||||
"org.gnome.Shell",
|
||||
"/org/gnome/Shell",
|
||||
"org.gnome.Shell.Extensions",
|
||||
NULL,
|
||||
error);
|
||||
}
|
||||
|
||||
GSettings *
|
||||
get_shell_settings (void)
|
||||
{
|
||||
@ -87,6 +100,7 @@ usage (void)
|
||||
g_printerr (" version %s\n", _("Print version"));
|
||||
g_printerr (" enable %s\n", _("Enable extension"));
|
||||
g_printerr (" disable %s\n", _("Disable extension"));
|
||||
g_printerr (" create %s\n", _("Create extension"));
|
||||
g_printerr ("\n");
|
||||
g_printerr (_("Use %s to get detailed help.\n"), "“gnome-extensions help COMMAND”");
|
||||
}
|
||||
@ -144,6 +158,8 @@ main (int argc, char *argv[])
|
||||
return handle_enable (argc, argv, do_help);
|
||||
else if (g_str_equal (command, "disable"))
|
||||
return handle_disable (argc, argv, do_help);
|
||||
else if (g_str_equal (command, "create"))
|
||||
return handle_create (argc, argv, do_help);
|
||||
else
|
||||
usage ();
|
||||
|
||||
|
@ -1,12 +1,19 @@
|
||||
sources = [
|
||||
'commands.h',
|
||||
'command-create.c',
|
||||
'command-disable.c',
|
||||
'command-enable.c',
|
||||
'common.h',
|
||||
'main.c'
|
||||
]
|
||||
|
||||
resources = gnome.compile_resources('resources',
|
||||
'gnome-extensions-tool.gresource.xml',
|
||||
source_dir: '.'
|
||||
)
|
||||
|
||||
executable('gnome-extensions',
|
||||
sources,
|
||||
dependencies: gio_dep,
|
||||
sources, resources,
|
||||
dependencies: [gio_dep, gio_unix_dep],
|
||||
install: true
|
||||
)
|
||||
|
@ -9,13 +9,19 @@ configure_file(
|
||||
)
|
||||
|
||||
sources = [
|
||||
'command-create.c',
|
||||
'command-disable.c',
|
||||
'command-enable.c',
|
||||
'main.c'
|
||||
]
|
||||
|
||||
resources = gnome.compile_resources('resources',
|
||||
'gnome-extensions-tool.gresource.xml',
|
||||
source_dir: '.'
|
||||
)
|
||||
|
||||
executable('gnome-extensions',
|
||||
sources,
|
||||
dependencies: gio_dep,
|
||||
sources, resources,
|
||||
dependencies: [gio_dep, gio_unix_dep],
|
||||
install: true
|
||||
)
|
||||
|
34
src/extensions-tool/template/extension.js
Normal file
34
src/extensions-tool/template/extension.js
Normal file
@ -0,0 +1,34 @@
|
||||
/* extension.js
|
||||
*
|
||||
* 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 2 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-2.0-or-later
|
||||
*/
|
||||
|
||||
/* exported init */
|
||||
|
||||
class Extension {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
enable() {
|
||||
}
|
||||
|
||||
disable() {
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
return new Extension();
|
||||
}
|
1
src/extensions-tool/template/stylesheet.css
Normal file
1
src/extensions-tool/template/stylesheet.css
Normal file
@ -0,0 +1 @@
|
||||
/* Add your custom extension styling here */
|
Loading…
Reference in New Issue
Block a user