]> git.sur5r.net Git - i3/i3/commitdiff
Allow to validate the config file without X.
authoraszlig <aszlig@redmoonstudios.org>
Sat, 2 Aug 2014 05:01:15 +0000 (07:01 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Mon, 25 Aug 2014 17:34:26 +0000 (19:34 +0200)
We're going to call parse_configuration() very early if -C is given on
the command line. Instead of the previous "only_check_config", which has
been a global variable, we now simply pass use_nagbar as false if we're
just validating.

This causes the whole parsing to run without X and of course without
starting nagbar and displaying the errors to standard out/error instead.

The return code of parse_configuration() is now a boolean which
represents whether an error occured during parsing and the programs exit
code is returned accordingly.

Although the config parser still has a lot of side-effects, we now can
parse without the need to have an XCB connection. A nicer implementation
would be to just set the new font and load it just after we're done
parsing, but to ensure we don't break functionality we just load a dummy
FONT_TYPE_NONE if XCB isn't available. The main reason for going this
route is that it's a bit difficult to test fonts in a distribution
agnostic way without bundling fonts with i3 (or Xdummy to be more
exact).

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
include/config.h
include/config_parser.h
libi3/font.c
src/config.c
src/config_parser.c
src/main.c
testcases/t/235-check-config-no-x.t [new file with mode: 0644]

index b0f22417ab038715812c1c537ab43576909e7a02..dea26d96344548a5573ebdb6de2813b4a1ccc32e 100644 (file)
@@ -326,6 +326,20 @@ struct Barconfig {
     TAILQ_ENTRY(Barconfig) configs;
 };
 
+/**
+ * Finds the configuration file to use (either the one specified by
+ * override_configpath), the user’s one or the system default) and calls
+ * parse_file().
+ *
+ * If you specify override_configpath, only this path is used to look for a
+ * configuration file.
+ *
+ * If use_nagbar is false, don't try to start i3-nagbar but log the errors to
+ * stdout/stderr instead.
+ *
+ */
+bool parse_configuration(const char *override_configpath, bool use_nagbar);
+
 /**
  * Reads the configuration from ~/.i3/config or /etc/i3/config if not found.
  *
index e18e5cf2a892180436c870b0261ab7035ec8026f..9fc3bf2ffb5ea63e2b3e22bef34a69f9472dd9d5 100644 (file)
@@ -33,7 +33,10 @@ struct ConfigResultIR *parse_config(const char *input, struct context *context);
 
 /**
  * Parses the given file by first replacing the variables, then calling
- * parse_config and possibly launching i3-nagbar.
+ * parse_config and launching i3-nagbar if use_nagbar is true.
+ *
+ * The return value is a boolean indicating whether there were errors during
+ * parsing.
  *
  */
-void parse_file(const char *f);
+bool parse_file(const char *f, bool use_nagbar);
index fc868e60bb95eb0e413ac93079df41c4051cec90..7670335fa805fb62f0869fae3b181c000d8a287d 100644 (file)
@@ -167,6 +167,12 @@ i3Font load_font(const char *pattern, const bool fallback) {
     i3Font font;
     font.type = FONT_TYPE_NONE;
 
+    /* No XCB connction, return early because we're just validating the
+     * configuration file. */
+    if (conn == NULL) {
+        return font;
+    }
+
 #if PANGO_SUPPORT
     /* Try to load a pango font if specified */
     if (strlen(pattern) > strlen("pango:") && !strncmp(pattern, "pango:", strlen("pango:"))) {
index ec084bb19d8282844edba1cdd8cbdb9fc803a7cb..5089ef2202b89a5eac0f48c1d00e78d770cf7d5b 100644 (file)
@@ -112,12 +112,19 @@ static char *get_config_path(const char *override_configpath) {
  * parse_file().
  *
  */
-static void parse_configuration(const char *override_configpath) {
+bool parse_configuration(const char *override_configpath, bool use_nagbar) {
     char *path = get_config_path(override_configpath);
     LOG("Parsing configfile %s\n", path);
     FREE(current_configpath);
     current_configpath = path;
-    parse_file(path);
+
+    /* initialize default bindings if we're just validating the config file */
+    if (!use_nagbar && bindings == NULL) {
+        bindings = scalloc(sizeof(struct bindings_head));
+        TAILQ_INIT(bindings);
+    }
+
+    return parse_file(path, use_nagbar);
 }
 
 /*
@@ -260,7 +267,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
     if (config.workspace_urgency_timer == 0)
         config.workspace_urgency_timer = 0.5;
 
-    parse_configuration(override_configpath);
+    parse_configuration(override_configpath, true);
 
     if (reload) {
         translate_keysyms();
index ee02c3935354bf664189ed363d9098b7a810bff1..24cebcece9707755087d83928a49030629ecea63 100644 (file)
@@ -840,7 +840,7 @@ static char *migrate_config(char *input, off_t size) {
  * parse_config and possibly launching i3-nagbar.
  *
  */
-void parse_file(const char *f) {
+bool parse_file(const char *f, bool use_nagbar) {
     SLIST_HEAD(variables_head, Variable) variables = SLIST_HEAD_INITIALIZER(&variables);
     int fd, ret, read_bytes = 0;
     struct stat stbuf;
@@ -1000,7 +1000,7 @@ void parse_file(const char *f) {
 
     check_for_duplicate_bindings(context);
 
-    if (context->has_errors || context->has_warnings) {
+    if (use_nagbar && (context->has_errors || context->has_warnings)) {
         ELOG("FYI: You are using i3 version " I3_VERSION "\n");
         if (version == 3)
             ELOG("Please convert your configfile first, then fix any remaining errors (see above).\n");
@@ -1030,6 +1030,8 @@ void parse_file(const char *f) {
         free(pageraction);
     }
 
+    bool has_errors = context->has_errors;
+
     FREE(context->line_copy);
     free(context);
     free(new);
@@ -1042,6 +1044,8 @@ void parse_file(const char *f) {
         SLIST_REMOVE_HEAD(&variables, variables);
         FREE(current);
     }
+
+    return !has_errors;
 }
 
 #endif
index 9c086235ca4b64907d8e2238329a3fe2fd52cb23..b696e031a2dfc60c34cc8c4eda5b4af17575d26f 100644 (file)
@@ -88,11 +88,6 @@ struct ws_assignments_head ws_assignments = TAILQ_HEAD_INITIALIZER(ws_assignment
 /* We hope that those are supported and set them to true */
 bool xcursor_supported = true;
 
-/* This will be set to true when -C is used so that functions can behave
- * slightly differently. We don’t want i3-nagbar to be started when validating
- * the config, for example. */
-bool only_check_config = false;
-
 /*
  * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb.
  * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop
@@ -201,6 +196,7 @@ int main(int argc, char *argv[]) {
     bool force_xinerama = false;
     char *fake_outputs = NULL;
     bool disable_signalhandler = false;
+    bool only_check_config = false;
     static struct option long_options[] = {
         {"no-autostart", no_argument, 0, 'a'},
         {"config", required_argument, 0, 'c'},
@@ -366,10 +362,14 @@ int main(int argc, char *argv[]) {
         }
     }
 
+    if (only_check_config) {
+        exit(parse_configuration(override_configpath, false) ? 0 : 1);
+    }
+
     /* If the user passes more arguments, we act like i3-msg would: Just send
      * the arguments as an IPC message to i3. This allows for nice semantic
      * commands such as 'i3 border none'. */
-    if (!only_check_config && optind < argc) {
+    if (optind < argc) {
         /* We enable verbose mode so that the user knows what’s going on.
          * This should make it easier to find mistakes when the user passes
          * arguments by mistake. */
@@ -492,10 +492,6 @@ int main(int argc, char *argv[]) {
     xcb_query_pointer_cookie_t pointercookie = xcb_query_pointer(conn, root);
 
     load_configuration(conn, override_configpath, false);
-    if (only_check_config) {
-        LOG("Done checking configuration file. Exiting.\n");
-        exit(0);
-    }
 
     if (config.ipc_socket_path == NULL) {
         /* Fall back to a file name in /tmp/ based on the PID */
diff --git a/testcases/t/235-check-config-no-x.t b/testcases/t/235-check-config-no-x.t
new file mode 100644 (file)
index 0000000..614d6b3
--- /dev/null
@@ -0,0 +1,60 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://build.i3wm.org/docs/ipc.html
+#   (or docs/ipc)
+#
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
+#   (unless you are already familiar with Perl)
+#
+# Check whether the -C option works without a display and doesn't
+# accidentally start the nagbar.
+#
+use i3test i3_autostart => 0;
+use File::Temp qw(tempfile);
+
+sub check_config {
+    my ($config) = @_;
+    my ($fh, $tmpfile) = tempfile(UNLINK => 1);
+    print $fh $config;
+    my $output = qx(DISPLAY= ../i3 -C -c $tmpfile 2>&1);
+    my $retval = $?;
+    $fh->flush;
+    close($fh);
+    return ($retval >> 8, $output);
+}
+
+################################################################################
+# 1: test with a bogus configuration file
+################################################################################
+
+my $cfg = <<EOT;
+# i3 config file (v4)
+i_am_an_unknown_config option
+EOT
+
+my ($ret, $out) = check_config($cfg);
+is($ret, 1, "exit code == 1");
+like($out, qr/ERROR: *CONFIG: *[Ee]xpected.*tokens/, 'bogus config file');
+
+################################################################################
+# 2: test with a valid configuration file
+################################################################################
+
+my $cfg = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+EOT
+
+my ($ret, $out) = check_config($cfg);
+is($ret, 0, "exit code == 0");
+is($out, "", 'valid config file');
+
+done_testing;