7

I use a drawing program called Inkscape, which has both a GUI and a command line interface. When used on the command line, it has a large number of options that can only be controlled through a user-specific config file, which is hardcoded to be:

$HOME/.config/inkscape/preferences.xml

This config file always contains the options that were most recently used in the GUI, which may be the wrong ones when I'm scripting.

To work around this, I have my script save a copy of the config file, replace it with a standard config file, run the program, and then copy the saved config file back.

This works OK but is not really clean. For example, it won't work properly if two instances of the script are being run concurrently.

On Unix, is there a cleaner way to carry out this task of faking out a program so it takes its config file from someplace that I want, rather than from the pathname hardcoded in the program? Maybe something involving links, or something like BSD jails?

4 Answers 4

8
+100

Inkscape has a feature for this as of 0.47:

$ INKSCAPE_PORTABLE_PROFILE_DIR=/some/other/path inkscape --args

Put your script's custom preferences.xml file in /some/other/path. It should be a dedicated directory, because Inkscape will populate it with all the other files it normally puts in ~/.config/Inkscape when you run it like this.

4
  • So you can run multiple versions simply by giving the a different variable prior to running, right? Good sluething BTW!
    – slm
    Commented Nov 2, 2013 at 4:04
  • 1
    @slm: Yes. Here, the environment variable is being used more like a command line option, as it affects just the single instance being run. And I found it by reading the source. :) Commented Nov 2, 2013 at 4:14
  • related: bugs.launchpad.net/inkscape/+bug/1247448
    – user39248
    Commented Nov 2, 2013 at 18:22
  • @BenCrowell - thanks, I left a comment mentioning that the existence of that hidden env. variable in the official docs would've saved you and us a whole bunch of time.
    – slm
    Commented Nov 9, 2013 at 22:18
6

Because Inkscape is FOSS software, we can just add an option to the program which will let you pass the name of another config file, like so:

=== modified file 'src/inkscape.cpp'
--- src/inkscape.cpp    2013-09-28 19:20:27 +0000
+++ src/inkscape.cpp    2013-11-02 04:07:45 +0000
@@ -1443,6 +1443,12 @@
             prefdir = g_strdup(val);
         }

+        // Also accept an override via the command line
+        extern gchar* sp_preferences;
+        if (sp_preferences) {
+            prefdir = sp_preferences;
+        }
+
 #ifdef HAS_SHGetSpecialFolderLocation
         // prefer c:\Documents and Settings\UserName\Application Data\ to
         // c:\Documents and Settings\userName\;

=== modified file 'src/main.cpp'
--- src/main.cpp    2013-09-24 18:31:44 +0000
+++ src/main.cpp    2013-11-02 04:05:30 +0000
@@ -179,6 +179,7 @@
     SP_ARG_VERB_LIST,
     SP_ARG_VERB,
     SP_ARG_SELECT,
+    SP_ARG_PREFERENCES,
     SP_ARG_LAST
 };

@@ -228,6 +229,7 @@
 static gboolean sp_query_all = FALSE;
 static gchar *sp_query_id = NULL;
 static gboolean sp_shell = FALSE;
+gchar *sp_preferences = NULL;
 static gboolean sp_vacuum_defs = FALSE;
 #ifdef WITH_DBUS
 static gboolean sp_dbus_listen = FALSE;
@@ -520,6 +522,11 @@
      N_("Start Inkscape in interactive shell mode."),
      NULL},

+    {"preferences", 0,
+     POPT_ARG_STRING, &sp_preferences, SP_ARG_PREFERENCES,
+     N_("Specify a different preferences.xml file."),
+     NULL},
+
     POPT_AUTOHELP POPT_TABLEEND
 };

I wouldn't expect the Inkscape developers to accept this patch, for two reasons. First, they've got an alternative feature with the same effect already. But second, I wouldn't expect them to like the way I made sp_preferences program-global instead of module-global. That sort of code is fine for a personal feature that you do not intend to be part of the mainline software, however.

The above patch may look fairly ugly to a non-programmer or one not familiar with C++ and patch files, but trust me, this is about as simple as changes to software get. It's only 10 lines of new code.

(If you do your own count and come up with 13 new lines, three of those are blank or have only a curly brace, so you don't include those in the SLOC count.)

3
  • Using an alternative config file should be a command line option, but inkscape does not seem to have this. Strange. Commented Oct 22, 2015 at 15:33
  • @FaheemMitha: The Inkskape developers' choice to implement this as an environment variable is effectively the same thing. It's not wrong, just a different style choice. Still, if you prefer the command line option to the environment variable, you've got my patch now, which you can take as-is or build upon. Commented Oct 22, 2015 at 15:44
  • I think both choices are possible and can co-exist. Commented Oct 22, 2015 at 15:51
1

You could use symbolic links. Put the config file you use with your GUI somewhere, lets call it GUI_CONFIG, and the one with scripts to SCRIPT_CONFIG. At the beginning of your script put the line:

ln -sf SCRIPT_CONFIG $HOME/.config/inkscape/preferences.xml

and at the end:

ln -sf GUI_CONFIG $HOME/.config/inkscape/preferences.xml

When the script executes it will make preferences.xml a symbolic link that points to the config it needs. When it finishes, it points it back at the one the GUI uses. Running multiple scripts concurrently won't destroy your config, as it does when copying temp files, though the first script completing will break the config file for still running scripts. It maybe best to put the calls to ln around the individual calls to Inkscape, rather than the scripts as a whole, to try to prevent these race conditions.

Another option would be to run Inkscape as a different user from scripts, so you can set it up with a different config file. However, you'll then have to deal with permissions, possibly by copying files back and forth to /tmp.

3
  • 1
    This is scarcely better than copying files, and does nothing to actually solve the problem, which is that the current hard-coded path in Inkscape allows multiple programs to interfere with each other. Commented Nov 2, 2013 at 3:18
  • 1
    If you don't want to edit the ln option out of your answer, you should at least post the "other user" option as a separate answer. I could upvote that on its own, but not when tied to the ln answer. Commented Nov 2, 2013 at 3:19
  • 1
    The calls to ln are idempotent, so he doesn't have to worry about destroying his config files or leaving it in an undesired state after all processes have finished. It narrows the window for race conditions, and makes them less severe. Commented Nov 2, 2013 at 3:45
1

Looking through the documentation for the preferences subsystem in Inkscape it isn't possbile.

Your options:

  1. do what your doing
  2. play games via linking the file
  3. user a different user ID
  4. modify the source (see @WarrenYoung's answer for this!)
12
  • I don't see how you come to your first conclusion. That page tells me the program already has a way to pass a different path on Windows vs Linux. All you have to do is provide a third data source for the path, which gets it from the command line. If OP isn't a C programmer, find one. They're plentiful. :) Commented Nov 2, 2013 at 3:22
  • @WarrenYoung - well it's currently not a possibility as it stands on Linux, at least according to the docs. I didn't mean to imply the functionality wasn't buried in Inkscape and a modification to the source wouldn't be easy or possible, just that there were no switches currently avail.
    – slm
    Commented Nov 2, 2013 at 3:33
  • @WarrenYoung - are you volunteering to mods this for him?
    – slm
    Commented Nov 2, 2013 at 3:33
  • Would this even be a discussion if this were a config file in /etc instead of a C program? What's the essential difference? Is it just the fact that one edit is more difficult to make? If so, why does that affect whether my answer is an answer? Commented Nov 2, 2013 at 3:39
  • 1
    @WarrenYoung your answer certainly is a valid answer, but so would answering that OP should write a kernel module to allow bind mounts on a per-process basis so he can trick Inkspace into reading its config file from a different directory. Of course, if you code this feature into Inkscape for him you've gone well beyond the call fo duty :) Commented Nov 2, 2013 at 3:43

You must log in to answer this question.