Please note:The SCons wiki is now restored from the attack in March 2013. All old passwords have been invalidated. Please reset your password if you have an account. If you note missing pages, please report them to webmaster@scons.org. Also, new account creation is currently disabled due to an ongoing spam flood (2013/08/27).

This is a substitution builder much like the original SubstInFile builder. This builder directly uses the environment as the substitution dictionary and emits only the keys a given target uses as dependencies of that target. The values in the environment to be substituted should either be strings or functions that return to a string. An environment substitution will occur on the result first before it is replaced in the file.

Example Usage:

   1 env = Environment()
   2 TOOL_SUBST(env)
   3 
   4 def f():
   5     return "Test"
   6 
   7 env['NAME'] = 'John Doe'
   8 env['VERSION'] = '2.10.0'
   9 env['FULLNAME'] = '$NAME $VERSION'
  10 env['FUNCTION'] = f
  11 
  12 env.SubstInFile('output', 'input')

Sample input file:

Name: @NAME@
Version: @VERSION@
Fullname: @FULLNAME@
Function: @FUNCTION@
Email: johndoe@@nowhere.com

Ouput of that file:

Name: John Doe
Version: 2.10.0
Fullname: John Doe 2.10.0
Function: Test
Email: johndoe@nowhere.com

The builder code:

   1 # File:         subst.py
   2 # Author:       Brian A. Vanderburg II
   3 # Purpose:      SCons substitution in file mechanism
   4 # Copyright:    This file is placed in the public domain.
   5 # Notice:       Portions of this file are based on the original
   6 #               SubstInFile builder.
   7 ########################################################################
   8 
   9 
  10 # Requirements
  11 ########################################################################
  12 import re
  13 
  14 from SCons.Script import *
  15 import SCons.Errors
  16 
  17 
  18 # This will replace any occurance of @keyname@ with the value of the
  19 # key from the environment dictionary.  @@ will produce a single @
  20 ########################################################################
  21 
  22 _searchre = re.compile('@(.*?)@')
  23 
  24 def subst_file(target, source, data):
  25     # Sub function
  26     def subfn(mo, data=data):
  27         key = mo.group(1)
  28         if key == '':
  29             return '@'
  30         return data[key]
  31 
  32     # Read file
  33     f = open(source, 'rU')
  34     try:
  35         contents = f.read()
  36     finally:
  37         f.close()
  38 
  39     # Substitute
  40     contents = _searchre.sub(subfn, contents)
  41 
  42     # Write file
  43     f = open(target, 'wt')
  44     try:
  45         f.write(contents)
  46     finally:
  47         f.close()
  48 
  49 def subst_keys(source):
  50     keys = []
  51 
  52     # Sub function
  53     def subfn(mo):
  54         key = mo.group(1)
  55         if key != '':
  56             keys.append(key)
  57         return ''
  58 
  59     # Read file
  60     f = open(source, 'rU')
  61     try:
  62         contents = f.read()
  63     finally:
  64         f.close()
  65 
  66     # Determine keys
  67     _searchre.sub(subfn, contents)
  68 
  69     return keys
  70 
  71 def subst_in_file(target, source, env):
  72     # What keys do the sources use
  73     keys = []
  74     
  75     for s in source:
  76         skeys = subst_keys(str(s))
  77         for k in skeys:
  78             if not k in keys:
  79                 keys.append(k)
  80 
  81     # Get these keys from the environment
  82     d = dict()
  83     for k in keys:
  84         try:
  85             v = env[k]
  86         except:
  87             raise SCons.Errors.UserError('SubstInFile key not found in environment: ' + k)
  88 
  89         if callable(v):
  90             d[k] = env.subst(v())
  91         elif SCons.Util.is_String(v):
  92             d[k] = env.subst(v)
  93         else:
  94             raise SCons.Errors.UserError('SubstInFile key must be a string or callable: ' + k)
  95 
  96     # Substitute in the files
  97     for (t, s) in zip(target, source):
  98         subst_file(str(t), str(s), d)
  99 
 100     return 0
 101 
 102 
 103 def subst_string(target, source, env):
 104     items = ['Substituting vars from %s to %s' % (str(s), str(t))
 105              for (t, s) in zip(target, source)]
 106 
 107     return '\n'.join(items)
 108 
 109 def subst_emitter(target, source, env):
 110     for (t, s) in zip(target, source):
 111         # Get keys used
 112         keys = subst_keys(str(s))
 113 
 114         d = dict()
 115         for k in keys:
 116             try:
 117                 v = env[k]
 118             except:
 119                 raise SCons.Errors.UserError('SubstInFile key not found in environment: ' + k)
 120 
 121             if callable(v):
 122                 d[k] = env.subst(v())
 123             elif SCons.Util.is_String(v):
 124                 d[k] = env.subst(v)
 125 
 126         # Only the current target depends on this dictionary
 127         Depends(t, SCons.Node.Python.Value(d))
 128 
 129     return target, source
 130 
 131 # Create builders
 132 def TOOL_SUBST(env):
 133     subst_in_file_action = SCons.Action.Action(subst_in_file, subst_string)
 134     env['BUILDERS']['SubstInFile'] = Builder(action=subst_in_file_action,
 135                                              emitter=subst_emitter)

SubstInFileBuilder2 (last edited 2009-08-07 13:46:51 by BrianVanderburgII)