github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-tools-src/grumpy_tools/grumprun.py (about) 1 #!/usr/bin/env python 2 3 # Copyright 2016 Google Inc. All Rights Reserved. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 """grumprun compiles and runs a snippet of Python using Grumpy. 18 19 Usage: $ grumprun -m <module> # Run the named module. 20 $ echo 'print "hola!"' | grumprun # Execute Python code from stdin. 21 """ 22 23 import argparse 24 import os 25 import random 26 import shutil 27 import string 28 import subprocess 29 import sys 30 import tempfile 31 import logging 32 from StringIO import StringIO 33 34 from .compiler import imputil 35 from .pep_support.pep3147pycache import make_transpiled_module_folders 36 from . import grumpc 37 38 logger = logging.getLogger(__name__) 39 40 TRACEBACK_DEPENDENCIES = [ 41 '__go__/grumpy', 42 '__go__/io/ioutil', 43 '__go__/os', 44 '__go__/path/filepath', 45 '__go__/reflect', 46 '__go__/runtime', 47 '__go__/sync', 48 '__go__/syscall', 49 '__go__/time', 50 '__go__/unicode', 51 '_syscall', 52 'linecache', 53 'os', 54 'os/path', 55 'stat', 56 'sys', 57 'traceback', 58 'types', 59 ] 60 61 module_tmpl = string.Template("""\ 62 package main 63 import ( 64 \t"os" 65 \t"grumpy" 66 \tmod "$package" 67 $imports 68 ) 69 func main() { 70 \tgrumpy.ImportModule(grumpy.NewRootFrame(), "traceback") 71 \tos.Exit(grumpy.RunMain(mod.Code)) 72 } 73 """) 74 75 76 def main(stream=None, modname=None, pep3147=False, clean_tempfolder=True, go_action='run'): 77 assert pep3147, 'It is no longer optional' 78 assert (stream is None and modname) or (stream.name and not modname) 79 80 gopath = os.environ['GOPATH'] 81 82 # CPython does not cache the __main__. Should I? 83 try: 84 script = None 85 if modname and not stream: # TODO: move all this `if modname` to the CLI handling? 86 # Find the script associated with the given module. 87 for d in gopath.split(os.pathsep): 88 script = imputil.find_script( 89 os.path.join(d, 'src', '__python__'), modname) 90 if script: 91 break 92 if not script: 93 for d in sys.path: 94 script = imputil.find_script(d, modname, main=True) 95 if script: 96 break 97 if not script: 98 script = imputil.find_script(os.getcwd(), modname, main=True) 99 if not script: 100 raise RuntimeError("can't find module '%s'", modname) 101 102 stream = StringIO(open(script).read()) 103 if script.endswith('__main__.py'): 104 stream.name = script 105 else: 106 stream.name = '__main__.py' 107 108 script = os.path.abspath(stream.name) 109 modname = '__main__' 110 111 pep3147_folders = make_transpiled_module_folders(script, modname) 112 workdir = pep3147_folders['transpiled_base_folder'] 113 114 # Generate a dummy python script on the 'cache_folder' 115 script_name = os.path.join(pep3147_folders['cache_folder'], os.path.basename(script)) 116 with open(script_name, 'wb') as script_file: 117 stream.seek(0) 118 script_file.write(stream.read()) 119 120 py_dir = os.path.join(workdir, 'src', '__python__') 121 122 mod_dir = pep3147_folders['transpiled_module_folder'] 123 124 ## TODO: Manage the STDIN and `-c` scripts situation 125 # script = os.path.join(py_dir, 'module.py') 126 # with open(script, 'w') as f: 127 # f.write(stream.read()) 128 ## 129 130 gopath_folder = pep3147_folders['gopath_folder'] 131 os.environ['GOPATH'] = os.pathsep.join([gopath_folder, gopath]) #, workdir]) 132 133 # Compile the dummy script to Go using grumpc. 134 with open(os.path.join(mod_dir, 'module.go'), 'w+') as dummy_file: 135 result = grumpc.main(stream, modname=modname, pep3147=True, recursive=True, return_deps=True) 136 transpiled, deps = result['gocode'], result['deps'] 137 dummy_file.write(transpiled) 138 139 # Make sure traceback is available in all Python binaries. 140 names = sorted(set(['traceback'] + TRACEBACK_DEPENDENCIES).union(deps)) 141 142 go_main = os.path.join(workdir, 'main.go') 143 package = grumpc._package_name(modname) 144 imports = ''.join('\t_ "' + grumpc._package_name(name) + '"\n' for name in names) 145 with open(go_main, 'w') as f: 146 f.write(module_tmpl.substitute(package=package, imports=imports)) 147 logger.info('`go run` GOPATH=%s', os.environ['GOPATH']) 148 if go_action == 'run': 149 subprocess_cmd = 'go run ' + go_main 150 elif go_action == 'build': 151 subprocess_cmd = 'go build ' + go_main 152 elif go_action == 'debug': 153 subprocess_cmd = 'dlv debug --listen=:2345 --log ' + go_main 154 else: 155 raise NotImplementedError('Go action "%s" not implemented' % go_action) 156 logger.debug('Starting subprocess: `%s`', subprocess_cmd) 157 return subprocess.Popen(subprocess_cmd, shell=True).wait() 158 finally: 159 if 'pep3147_folders' in locals(): 160 if clean_tempfolder: 161 shutil.rmtree(pep3147_folders['cache_folder'], ignore_errors=True) 162 else: 163 logger.warning('not cleaning the temporary pycache folder: %s', pep3147_folders['cache_folder'])