12eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenbergerimport re 22eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenbergerfrom SCons.Script import * # the usual scons stuff you get in a SConscript 32eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenbergerimport collections 42eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 52eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenbergerdef generate(env): 62eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """ 72eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger Add builders and construction variables for the 82eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger SubstInFile tool. 92eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 102eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger Adds SubstInFile builder, which substitutes the keys->values of SUBST_DICT 112eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger from the source to the target. 122eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger The values of SUBST_DICT first have any construction variables expanded 132eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger (its keys are not expanded). 142eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger If a value of SUBST_DICT is a python callable function, it is called and 152eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger the result is expanded as the value. 162eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger If there's more than one source and more than one target, each target gets 172eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger substituted from the corresponding source. 182eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """ 192eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger def do_subst_in_file(targetfile, sourcefile, dict): 202eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """Replace all instances of the keys of dict with their values. 212eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, 222eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger then all instances of %VERSION% in the file will be replaced with 1.2345 etc. 232eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """ 242eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger try: 252eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger f = open(sourcefile, 'rb') 262eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger contents = f.read() 272eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger f.close() 282eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger except: 292eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger raise SCons.Errors.UserError("Can't read source file %s"%sourcefile) 302eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger for (k,v) in list(dict.items()): 312eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger contents = re.sub(k, v, contents) 322eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger try: 332eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger f = open(targetfile, 'wb') 342eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger f.write(contents) 352eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger f.close() 362eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger except: 372eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger raise SCons.Errors.UserError("Can't write target file %s"%targetfile) 382eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger return 0 # success 392eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 402eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger def subst_in_file(target, source, env): 412eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger if 'SUBST_DICT' not in env: 422eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger raise SCons.Errors.UserError("SubstInFile requires SUBST_DICT to be set.") 432eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger d = dict(env['SUBST_DICT']) # copy it 442eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger for (k,v) in list(d.items()): 452eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger if isinstance(v, collections.Callable): 462eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger d[k] = env.subst(v()).replace('\\','\\\\') 472eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger elif SCons.Util.is_String(v): 482eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger d[k] = env.subst(v).replace('\\','\\\\') 492eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger else: 502eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger raise SCons.Errors.UserError("SubstInFile: key %s: %s must be a string or callable"%(k, repr(v))) 512eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger for (t,s) in zip(target, source): 522eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger return do_subst_in_file(str(t), str(s), d) 532eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 542eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger def subst_in_file_string(target, source, env): 552eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """This is what gets printed on the console.""" 562eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) 572eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger for (t,s) in zip(target, source)]) 582eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 592eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger def subst_emitter(target, source, env): 602eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """Add dependency from substituted SUBST_DICT to target. 612eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger Returns original target, source tuple unchanged. 622eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """ 632eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger d = env['SUBST_DICT'].copy() # copy it 642eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger for (k,v) in list(d.items()): 652eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger if isinstance(v, collections.Callable): 662eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger d[k] = env.subst(v()) 672eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger elif SCons.Util.is_String(v): 682eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger d[k]=env.subst(v) 692eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger Depends(target, SCons.Node.Python.Value(d)) 702eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger return target, source 712eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 722eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger## env.Append(TOOLS = 'substinfile') # this should be automaticaly done by Scons ?!? 732eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger subst_action = SCons.Action.Action( subst_in_file, subst_in_file_string ) 742eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger env['BUILDERS']['SubstInFile'] = Builder(action=subst_action, emitter=subst_emitter) 752eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger 762eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenbergerdef exists(env): 772eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """ 782eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger Make sure tool exists. 792eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger """ 802eb3b4d7ea1a3cbb0f8775de3b6d92c0a6152f9fDerek Sollenberger return True 81