Previous: , Up: Docker Entrypoint   [Contents][Index]


7.2 Using xenv

Another way to expand environment variables in the configuration file is to use xenv. xenv is a specialized preprocessor that expands environment variables in its input. It is also able to conditionally include parts of text depending on whether the environment variable is defined. The program is described in https://www.gnu.org.ua/software/xenv/.

To use xenv as preprocessor, start pies as follows:

pies --foreground --stderr --preprocessor="xenv -s"

The -s option instructs xenv to emit synchronization lines, that inform pies about actual location of configuration statements in case when the expansion adds or removes portions of text spanning several lines.

You can also combine the functionality of m4 and xenv by running

pies --foreground --stderr --preprocessor="xenv -s -m"

In this case xenv will automatically feed its output to the standard input of m4, started for this purpose.

By default, xenv uses the shell syntax to expand the variables. For example, in the following configuration file fragment, ‘$WORKDIR’ will expand to the actual value of the WORKDIR environment variable:

component {
  chdir "$WORKDIR";
  ...
}  

There are two ways to conditionally include portions of text. The first one is to use the ‘${X:+W}’ construct. For example:

component {
  ${WORKDIR:+chdir "$WORKDIR";}
  ...
}  

Another way is to use the xenv$$ifset’ (or ‘$$ifdef’) statement:

component {
$$ifset WORKDIR
  chdir "$WORKDIR";
$$endif  
  ...
}  

The difference between ‘$$ifset X’ and ‘$$ifdef X’ is the same as between ‘${X:+W}’ and ‘${X+W}’, i.e. ‘$$ifset’ tests whether the variable is set and not-null, and ‘$$ifdef’ tests only whether it is set, no matter its value.

xenv extends the shell syntax by providing a ternary operator. The construct ‘${X|A|B}’ expands to ‘A’ if the variable X is set and to ‘B’ otherwise (as usual, placing the colon before first ‘|’ checks if the variable is set and not null). This allows for writing compact conditionals:

component syslogd {
   mode respawn;
   command "/sbin/syslogd -n ${LOGHOST:|-R $LOGHOST|-O /proc/1/fd/1}";
}

In this example syslogd is instructed to relay messages to the IP address specified by the LOGHOST variable and to send messages to the container stdout otherwise.

Using shell indirection operator ‘$’ can be confusing in parts of pies configuration file that deal with environment variables by themselves. The common point of confusion is using env and command statements when shell or expandenv flag is set. For example:

component X {
   env {
      set "HOME=/var/lib/nobody";
   }
   flags shell;
   command "marb -C $HOME";
}

Here, the intent is to pass ‘/var/lib/nobody’ as the command line argument to marb. However, if pies was started with xenv as preprocessor, the reference ‘$HOME’ will be expanded by xenv at the early stage to whatever value the HOME variable had at pies startup. Consequently, when it comes to launching the ‘X’ component, the intended expansion won’t take place.

There are three options to handle such cases:

  1. Escape the ‘$

    Use backslash to suppress expansion by xenv:

    component X {
       env {
          set "HOME=/var/lib/nobody";
       }
       flags shell;
       command "marb -C \$HOME";
    }
    
  2. Use the verbatim operator

    This allows to reproduce the desired part of text verbatim. There are two verbatim operators: inline operator ‘$[...]’ and block operator ‘$$verbatim ... $$end’. Examples:

    component X {
       env {
          set "HOME=/var/lib/nobody";
       }
       flags shell;
       $[command "marb -C $HOME";]
    }
    

    or

    component X {
       env {
          set "HOME=/var/lib/nobody";
       }
       flags shell;
    $$verbatim   
       command "marb -C $HOME";
    $$end   
    }
    
  3. Change the indirection operator

    The indirection operator ‘$’ can be changed either globally, by using the -S option, or locally by using the ‘$$sigil’ statement. E.g.:

    $$sigil @
    # From this point on, $ looses its special meaning in xenv.
    
    component X {
       env {
          set "HOME=/var/lib/nobody";
       }
       flags shell;
       command "marb -C $HOME @FILE";
    }
    

    In the command line of this example, @FILE will be expanded by xenv when processing the configuration file, and $HOME will be expanded by shell (to the value ‘/var/lib/nobody’, set by the env statement) when pies will start the command.


Previous: , Up: Docker Entrypoint   [Contents][Index]