custom.py revision 97e2c5ac0bba7298c9a32703fe3d19de1f7b815a
197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca"""custom 297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé FonsecaCustom builders and methods. 497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca""" 697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# 897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# All Rights Reserved. 1097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# 1197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# Permission is hereby granted, free of charge, to any person obtaining a 1297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# copy of this software and associated documentation files (the 1397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# "Software"), to deal in the Software without restriction, including 1497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# without limitation the rights to use, copy, modify, merge, publish, 1597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# distribute, sub license, and/or sell copies of the Software, and to 1697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# permit persons to whom the Software is furnished to do so, subject to 1797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# the following conditions: 1897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# 1997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# The above copyright notice and this permission notice (including the 2097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# next paragraph) shall be included in all copies or substantial portions 2197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# of the Software. 2297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# 2397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 2497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 2797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 3097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# 3197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 3297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 3397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport os 3497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport os.path 3597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport re 3697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 3797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport SCons.Action 3897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport SCons.Builder 3997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport SCons.Scanner 4097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 4197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport fixes 4297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 4397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 4497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef quietCommandLines(env): 4597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # Quiet command lines 4697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # See also http://www.scons.org/wiki/HidingCommandLinesInOutput 4797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['ASCOMSTR'] = " Assembling $SOURCE ..." 4897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['ASPPCOMSTR'] = " Assembling $SOURCE ..." 4997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['CCCOMSTR'] = " Compiling $SOURCE ..." 5097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['SHCCCOMSTR'] = " Compiling $SOURCE ..." 5197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['CXXCOMSTR'] = " Compiling $SOURCE ..." 5297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['SHCXXCOMSTR'] = " Compiling $SOURCE ..." 5397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['ARCOMSTR'] = " Archiving $TARGET ..." 5497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['RANLIBCOMSTR'] = " Indexing $TARGET ..." 5597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['LINKCOMSTR'] = " Linking $TARGET ..." 5697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['SHLINKCOMSTR'] = " Linking $TARGET ..." 5797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['LDMODULECOMSTR'] = " Linking $TARGET ..." 5897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['SWIGCOMSTR'] = " Generating $TARGET ..." 5997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 6097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 6197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef createConvenienceLibBuilder(env): 6297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca """This is a utility function that creates the ConvenienceLibrary 6397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca Builder in an Environment if it is not there already. 6497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 6597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca If it is already there, we return the existing one. 6697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 6797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca Based on the stock StaticLibrary and SharedLibrary builders. 6897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca """ 6997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 7097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca try: 7197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca convenience_lib = env['BUILDERS']['ConvenienceLibrary'] 7297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca except KeyError: 7397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] 7497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca if env.Detect('ranlib'): 7597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") 7697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca action_list.append(ranlib_action) 7797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 7897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca convenience_lib = SCons.Builder.Builder(action = action_list, 7997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca emitter = '$LIBEMITTER', 8097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca prefix = '$LIBPREFIX', 8197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca suffix = '$LIBSUFFIX', 8297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca src_suffix = '$SHOBJSUFFIX', 8397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca src_builder = 'SharedObject') 8497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env['BUILDERS']['ConvenienceLibrary'] = convenience_lib 8597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 8697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca return convenience_lib 8797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 8897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 8997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# TODO: handle import statements with multiple modules 9097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca# TODO: handle from import statements 9197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecaimport_re = re.compile(r'^import\s+(\S+)$', re.M) 9297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 9397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef python_scan(node, env, path): 9497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # http://www.scons.org/doc/0.98.5/HTML/scons-user/c2781.html#AEN2789 9597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca contents = node.get_contents() 9697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca source_dir = node.get_dir() 9797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca imports = import_re.findall(contents) 9897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca results = [] 9997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca for imp in imports: 10097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca for dir in path: 10197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca file = os.path.join(str(dir), imp.replace('.', os.sep) + '.py') 10297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca if os.path.exists(file): 10397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca results.append(env.File(file)) 10497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca break 10597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca file = os.path.join(str(dir), imp.replace('.', os.sep), '__init__.py') 10697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca if os.path.exists(file): 10797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca results.append(env.File(file)) 10897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca break 10997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca return results 11097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 11197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecapython_scanner = SCons.Scanner.Scanner(function = python_scan, skeys = ['.py']) 11297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 11397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 11497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef code_generate(env, script, target, source, command): 11597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca """Method to simplify code generation via python scripts. 11697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 11797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca http://www.scons.org/wiki/UsingCodeGenerators 11897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca http://www.scons.org/doc/0.98.5/HTML/scons-user/c2768.html 11997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca """ 12097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 12197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # We're generating code using Python scripts, so we have to be 12297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # careful with our scons elements. This entry represents 12397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # the generator file *in the source directory*. 12497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca script_src = env.File(script).srcnode() 12597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 12697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # This command creates generated code *in the build directory*. 12797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca command = command.replace('$SCRIPT', script_src.path) 12897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca code = env.Command(target, source, command) 12997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 13097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # Explicitly mark that the generated code depends on the generator, 13197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # and on implicitly imported python modules 13297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca path = (script_src.get_dir(),) 13397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca deps = [script_src] 13497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca deps += script_src.get_implicit_deps(env, python_scanner, path) 13597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.Depends(code, deps) 13697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 13797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # Running the Python script causes .pyc files to be generated in the 13897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # source directory. When we clean up, they should go too. So add side 13997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # effects for .pyc files 14097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca for dep in deps: 14197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca pyc = env.File(str(dep) + 'c') 14297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.SideEffect(pyc, code) 14397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 14497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca return code 14597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 14697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 14797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef createCodeGenerateMethod(env): 14897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.Append(SCANNERS = python_scanner) 14997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.AddMethod(code_generate, 'CodeGenerate') 15097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 15197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 15297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef symlink(target, source, env): 15397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca target = str(target[0]) 15497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca source = str(source[0]) 15597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca if os.path.islink(target) or os.path.exists(target): 15697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca os.remove(target) 15797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca os.symlink(os.path.basename(source), target) 15897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 15997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef install_program(env, source): 16097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca source = str(source[0]) 16197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca target_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build'], 'bin') 16297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca target_name = str(source) 16397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.InstallAs(os.path.join(target_dir, target_name), source) 16497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 16597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef install_shared_library(env, source, version = ()): 16697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca source = str(source[0]) 16797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca version = tuple(map(str, version)) 16897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca target_dir = os.path.join(env.Dir('#.').srcnode().abspath, env['build'], 'lib') 16997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca target_name = '.'.join((str(source),) + version) 17097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca last = env.InstallAs(os.path.join(target_dir, target_name), source) 17197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca while len(version): 17297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca version = version[:-1] 17397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca target_name = '.'.join((str(source),) + version) 17497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca action = SCons.Action.Action(symlink, "$TARGET -> $SOURCE") 17597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca last = env.Command(os.path.join(target_dir, target_name), last, action) 17697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 17797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef createInstallMethods(env): 17897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.AddMethod(install_program, 'InstallProgram') 17997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca env.AddMethod(install_shared_library, 'InstallSharedLibrary') 18097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 18197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 18297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef generate(env): 18397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca """Common environment generation code""" 18497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 18597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca if env.get('quiet', True): 18697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca quietCommandLines(env) 18797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 18897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # Custom builders and methods 18997e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca createConvenienceLibBuilder(env) 19097e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca createCodeGenerateMethod(env) 19197e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca createInstallMethods(env) 19297e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 19397e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca # for debugging 19497e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca #print env.Dump() 19597e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 19697e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca 19797e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonsecadef exists(env): 19897e2c5ac0bba7298c9a32703fe3d19de1f7b815aJosé Fonseca return 1 199