Please note:The SCons wiki is in read-only mode due to ongoing spam/DoS issues. Also, new account creation is currently disabled. We are looking into alternative wiki hosts.

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)