OLD | NEW |
(Empty) | |
| 1 # -*- python -*- |
| 2 # |
| 3 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S
Cons Foundation |
| 4 # |
| 5 # Permission is hereby granted, free of charge, to any person obtaining |
| 6 # a copy of this software and associated documentation files (the |
| 7 # "Software"), to deal in the Software without restriction, including |
| 8 # without limitation the rights to use, copy, modify, merge, publish, |
| 9 # distribute, sublicense, and/or sell copies of the Software, and to |
| 10 # permit persons to whom the Software is furnished to do so, subject to |
| 11 # the following conditions: |
| 12 # |
| 13 # The above copyright notice and this permission notice shall be included |
| 14 # in all copies or substantial portions of the Software. |
| 15 # |
| 16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 23 # |
| 24 |
| 25 __doc__ = """ |
| 26 Textfile/Substfile builder for SCons. |
| 27 |
| 28 Create file 'target' which typically is a textfile. The 'source' |
| 29 may be any combination of strings, Nodes, or lists of same. A |
| 30 'linesep' will be put between any part written and defaults to |
| 31 os.linesep. |
| 32 |
| 33 The only difference between the Textfile builder and the Substfile |
| 34 builder is that strings are converted to Value() nodes for the |
| 35 former and File() nodes for the latter. To insert files in the |
| 36 former or strings in the latter, wrap them in a File() or Value(), |
| 37 respectively. |
| 38 |
| 39 The values of SUBST_DICT first have any construction variables |
| 40 expanded (its keys are not expanded). If a value of SUBST_DICT is |
| 41 a python callable function, it is called and the result is expanded |
| 42 as the value. Values are substituted in a "random" order; if any |
| 43 substitution could be further expanded by another subsitition, it |
| 44 is unpredictible whether the expansion will occur. |
| 45 """ |
| 46 |
| 47 __revision__ = "src/engine/SCons/Tool/textfile.py 5134 2010/08/16 23:02:40 bdeeg
an" |
| 48 |
| 49 import SCons |
| 50 |
| 51 import os |
| 52 import re |
| 53 |
| 54 from SCons.Node import Node |
| 55 from SCons.Node.Python import Value |
| 56 from SCons.Util import is_String, is_Sequence, is_Dict |
| 57 |
| 58 def _do_subst(node, subs): |
| 59 """ |
| 60 Fetch the node contents and replace all instances of the keys with |
| 61 their values. For example, if subs is |
| 62 {'%VERSION%': '1.2345', '%BASE%': 'MyProg', '%prefix%': '/bin'}, |
| 63 then all instances of %VERSION% in the file will be replaced with |
| 64 1.2345 and so forth. |
| 65 """ |
| 66 contents = node.get_text_contents() |
| 67 if not subs: return contents |
| 68 for (k,v) in subs: |
| 69 contents = re.sub(k, v, contents) |
| 70 return contents |
| 71 |
| 72 def _action(target, source, env): |
| 73 # prepare the line separator |
| 74 linesep = env['LINESEPARATOR'] |
| 75 if linesep is None: |
| 76 linesep = os.linesep |
| 77 elif is_String(linesep): |
| 78 pass |
| 79 elif isinstance(linesep, Value): |
| 80 linesep = linesep.get_text_contents() |
| 81 else: |
| 82 raise SCons.Errors.UserError( |
| 83 'unexpected type/class for LINESEPARATOR: %s' |
| 84 % repr(linesep), None) |
| 85 |
| 86 # create a dictionary to use for the substitutions |
| 87 if 'SUBST_DICT' not in env: |
| 88 subs = None # no substitutions |
| 89 else: |
| 90 d = env['SUBST_DICT'] |
| 91 if is_Dict(d): |
| 92 d = list(d.items()) |
| 93 elif is_Sequence(d): |
| 94 pass |
| 95 else: |
| 96 raise SCons.Errors.UserError('SUBST_DICT must be dict or sequence') |
| 97 subs = [] |
| 98 for (k,v) in d: |
| 99 if callable(v): |
| 100 v = v() |
| 101 if is_String(v): |
| 102 v = env.subst(v) |
| 103 else: |
| 104 v = str(v) |
| 105 subs.append((k,v)) |
| 106 |
| 107 # write the file |
| 108 try: |
| 109 fd = open(target[0].get_path(), "wb") |
| 110 except (OSError,IOError), e: |
| 111 raise SCons.Errors.UserError("Can't write target file %s" % target[0]) |
| 112 # separate lines by 'linesep' only if linesep is not empty |
| 113 lsep = None |
| 114 for s in source: |
| 115 if lsep: fd.write(lsep) |
| 116 fd.write(_do_subst(s, subs)) |
| 117 lsep = linesep |
| 118 fd.close() |
| 119 |
| 120 def _strfunc(target, source, env): |
| 121 return "Creating '%s'" % target[0] |
| 122 |
| 123 def _convert_list_R(newlist, sources): |
| 124 for elem in sources: |
| 125 if is_Sequence(elem): |
| 126 _convert_list_R(newlist, elem) |
| 127 elif isinstance(elem, Node): |
| 128 newlist.append(elem) |
| 129 else: |
| 130 newlist.append(Value(elem)) |
| 131 def _convert_list(target, source, env): |
| 132 if len(target) != 1: |
| 133 raise SCons.Errors.UserError("Only one target file allowed") |
| 134 newlist = [] |
| 135 _convert_list_R(newlist, source) |
| 136 return target, newlist |
| 137 |
| 138 _common_varlist = ['SUBST_DICT', 'LINESEPARATOR'] |
| 139 |
| 140 _text_varlist = _common_varlist + ['TEXTFILEPREFIX', 'TEXTFILESUFFIX'] |
| 141 _text_builder = SCons.Builder.Builder( |
| 142 action = SCons.Action.Action(_action, _strfunc, varlist = _text_varlist), |
| 143 source_factory = Value, |
| 144 emitter = _convert_list, |
| 145 prefix = '$TEXTFILEPREFIX', |
| 146 suffix = '$TEXTFILESUFFIX', |
| 147 ) |
| 148 |
| 149 _subst_varlist = _common_varlist + ['SUBSTFILEPREFIX', 'TEXTFILESUFFIX'] |
| 150 _subst_builder = SCons.Builder.Builder( |
| 151 action = SCons.Action.Action(_action, _strfunc, varlist = _subst_varlist), |
| 152 source_factory = SCons.Node.FS.File, |
| 153 emitter = _convert_list, |
| 154 prefix = '$SUBSTFILEPREFIX', |
| 155 suffix = '$SUBSTFILESUFFIX', |
| 156 src_suffix = ['.in'], |
| 157 ) |
| 158 |
| 159 def generate(env): |
| 160 env['LINESEPARATOR'] = os.linesep |
| 161 env['BUILDERS']['Textfile'] = _text_builder |
| 162 env['TEXTFILEPREFIX'] = '' |
| 163 env['TEXTFILESUFFIX'] = '.txt' |
| 164 env['BUILDERS']['Substfile'] = _subst_builder |
| 165 env['SUBSTFILEPREFIX'] = '' |
| 166 env['SUBSTFILESUFFIX'] = '' |
| 167 |
| 168 def exists(env): |
| 169 return 1 |
| 170 |
| 171 # Local Variables: |
| 172 # tab-width:4 |
| 173 # indent-tabs-mode:nil |
| 174 # End: |
| 175 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |