From 78f5f2204d3b25ce0bac948eb7c0ed8d35808262 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 5 Aug 2012 14:29:19 +0200 Subject: [PATCH] ipc: implement GET_VERSION to find out the i3 version MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This is useful for third-party scripts which require certain features and want to error out cleanly when they are run with an old i3 version. Additionally, i3 --version might be different from what’s actually running (an old version of the binary), so i3-msg -t get_version will be the best way to figure out the i3 version you are actually running from this commit on. --- common.mk | 9 ++++++++ docs/ipc | 34 +++++++++++++++++++++++++++++ i3-msg/main.c | 6 +++-- include/i3/ipc.h | 8 ++++++- man/i3-msg.man | 7 ++++-- src/ipc.c | 41 ++++++++++++++++++++++++++++++++++- testcases/t/193-ipc-version.t | 23 ++++++++++++++++++++ 7 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 testcases/t/193-ipc-version.t diff --git a/common.mk b/common.mk index f202166d..21e10257 100644 --- a/common.mk +++ b/common.mk @@ -23,6 +23,12 @@ else VERSION := ${I3_VERSION} endif +MAJOR_VERSION := $(shell echo ${VERSION} | cut -d '.' -f 1) +MINOR_VERSION := $(shell echo ${VERSION} | cut -d '.' -f 2) +PATCH_VERSION := $(shell echo ${VERSION} | cut -d '.' -f 3) +ifeq (${PATCH_VERSION},) +PATCH_VERSION := 0 +endif ## Generic flags @@ -46,6 +52,9 @@ I3_CFLAGS += -Wunused-value I3_CFLAGS += -Iinclude I3_CPPFLAGS = -DI3_VERSION=\"${I3_VERSION}\" +I3_CPPFLAGS += -DMAJOR_VERSION=${MAJOR_VERSION} +I3_CPPFLAGS += -DMINOR_VERSION=${MINOR_VERSION} +I3_CPPFLAGS += -DPATCH_VERSION=${PATCH_VERSION} I3_CPPFLAGS += -DSYSCONFDIR=\"${SYSCONFDIR}\" diff --git a/docs/ipc b/docs/ipc index 525e9968..508e789c 100644 --- a/docs/ipc +++ b/docs/ipc @@ -70,6 +70,9 @@ GET_BAR_CONFIG (6):: Gets the configuration (as JSON map) of the workspace bar with the given ID. If no ID is provided, an array with all configured bar IDs is returned instead. +GET_VERSION (7):: + Gets the version of i3. The reply will be a JSON-encoded dictionary + with the major, minor, patch and human-readable version. So, a typical message could look like this: -------------------------------------------------- @@ -125,6 +128,8 @@ MARKS (5):: Reply to the GET_MARKS message. BAR_CONFIG (6):: Reply to the GET_BAR_CONFIG message. +VERSION (7):: + Reply to the GET_VERSION message. === COMMAND reply @@ -534,6 +539,35 @@ urgent_workspace_text/urgent_workspace_bar:: } -------------- +=== Version reply + +The reply consists of a single JSON dictionary with the following keys: + +major (integer):: + The major version of i3, such as +4+. +minor (integer):: + The minor version of i3, such as +2+. Changes in the IPC interface (new + features) will only occur with new minor (or major) releases. However, + bugfixes might be introduced in patch releases, too. +patch (integer):: + The patch version of i3, such as +1+ (when the complete version is + +4.2.1+). +human_readable (string):: + A human-readable version of i3 containing the precise git version, + build date and branch name. When you need to display the i3 version to + your users, use the human-readable version whenever possible (since + this is what +i3 --version+ displays, too). + +*Example:* +------------------- +{ + "human_readable" : "4.2-169-gf80b877 (2012-08-05, branch \"next\")", + "minor" : 2, + "patch" : 0, + "major" : 4 +} +------------------- + == Events [[events]] diff --git a/i3-msg/main.c b/i3-msg/main.c index ccf6e10f..a04e6690 100644 --- a/i3-msg/main.c +++ b/i3-msg/main.c @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) * * i3-msg/main.c: Utility which sends messages to a running i3-instance using * IPC via UNIX domain sockets. @@ -73,9 +73,11 @@ int main(int argc, char *argv[]) { message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS; else if (strcasecmp(optarg, "get_bar_config") == 0) message_type = I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG; + else if (strcasecmp(optarg, "get_version") == 0) + message_type = I3_IPC_MESSAGE_TYPE_GET_VERSION; else { printf("Unknown message type\n"); - printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config\n"); + printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_version\n"); exit(EXIT_FAILURE); } } else if (o == 'q') { diff --git a/include/i3/ipc.h b/include/i3/ipc.h index bfadf4cf..0906b7f9 100644 --- a/include/i3/ipc.h +++ b/include/i3/ipc.h @@ -2,7 +2,7 @@ * vim:ts=4:sw=4:expandtab * * i3 - an improved dynamic tiling window manager - * © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE) + * © 2009-2012 Michael Stapelberg and contributors (see also: LICENSE) * * This public header defines the different constants and message types to use * for the IPC interface to i3 (see docs/ipc for more information). @@ -40,6 +40,9 @@ /** Request the configuration for a specific 'bar' */ #define I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG 6 +/** Request the i3 version */ +#define I3_IPC_MESSAGE_TYPE_GET_VERSION 7 + /* * Messages from i3 to clients * @@ -66,6 +69,9 @@ /** Bar config reply type */ #define I3_IPC_REPLY_TYPE_BAR_CONFIG 6 +/** i3 version reply type */ +#define I3_IPC_REPLY_TYPE_VERSION 7 + /* * Events from i3 to clients. Events have the first bit set high. * diff --git a/man/i3-msg.man b/man/i3-msg.man index 891c6c28..6b548d36 100644 --- a/man/i3-msg.man +++ b/man/i3-msg.man @@ -1,7 +1,7 @@ i3-msg(1) ========= -Michael Stapelberg -v4.2, January 2012 +Michael Stapelberg +v4.2, August 2012 == NAME @@ -38,6 +38,9 @@ get_bar_config:: Gets the configuration (as JSON map) of the workspace bar with the given ID. If no ID is provided, an array with all configured bar IDs is returned instead. +get_version:: +Gets the version of i3. The reply will be a JSON-encoded dictionary with the +major, minor, patch and human-readable version. == DESCRIPTION diff --git a/src/ipc.c b/src/ipc.c index 1d19fc6c..77b8dbb3 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -536,6 +536,44 @@ IPC_HANDLER(get_marks) { y(free); } +/* + * Returns the version of i3 + * + */ +IPC_HANDLER(get_version) { +#if YAJL_MAJOR >= 2 + yajl_gen gen = yajl_gen_alloc(NULL); +#else + yajl_gen gen = yajl_gen_alloc(NULL, NULL); +#endif + y(map_open); + + ystr("major"); + y(integer, MAJOR_VERSION); + + ystr("minor"); + y(integer, MINOR_VERSION); + + ystr("patch"); + y(integer, PATCH_VERSION); + + ystr("human_readable"); + ystr(I3_VERSION); + + y(map_close); + + const unsigned char *payload; +#if YAJL_MAJOR >= 2 + size_t length; +#else + unsigned int length; +#endif + y(get_buf, &payload, &length); + + ipc_send_message(fd, length, I3_IPC_REPLY_TYPE_VERSION, payload); + y(free); +} + /* * Formats the reply message for a GET_BAR_CONFIG request and sends it to the * client. @@ -792,7 +830,7 @@ IPC_HANDLER(subscribe) { /* The index of each callback function corresponds to the numeric * value of the message type (see include/i3/ipc.h) */ -handler_t handlers[7] = { +handler_t handlers[8] = { handle_command, handle_get_workspaces, handle_subscribe, @@ -800,6 +838,7 @@ handler_t handlers[7] = { handle_tree, handle_get_marks, handle_get_bar_config, + handle_get_version, }; /* diff --git a/testcases/t/193-ipc-version.t b/testcases/t/193-ipc-version.t new file mode 100644 index 00000000..172dd8f0 --- /dev/null +++ b/testcases/t/193-ipc-version.t @@ -0,0 +1,23 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# Verifies that we can get the version number of i3 via IPC. +use i3test; + +my $i3 = i3(get_socket_path()); +$i3->connect->recv; +# We explicitly send the version message because AnyEvent::I3’s 'version' sugar +# method has a fallback which tries to parse the version number from i3 +# --version for older versions, and we want to avoid using that. +my $version = $i3->message(7, "")->recv; + +# We need to change this when the major version changes (but we need to touch a +# lot of changes then anyways). +is($version->{major}, 4, 'major version is 4'); + +cmp_ok($version->{minor}, '>', 0, 'minor version > 0'); + +is(int($version->{minor}), $version->{minor}, 'minor version is an integer'); +is(int($version->{patch}), $version->{patch}, 'patch version is an integer'); +like($version->{human_readable}, qr/branch/, 'human readable version contains branch name'); + +done_testing; -- 2.39.2