github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/tools/grumprun (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  
    32  from grumpy.compiler import imputil
    33  
    34  
    35  parser = argparse.ArgumentParser()
    36  parser.add_argument('-m', '--modname', help='Run the named module')
    37  
    38  module_tmpl = string.Template("""\
    39  package main
    40  import (
    41  \t"os"
    42  \t"grumpy"
    43  \tmod "$package"
    44  $imports
    45  )
    46  func main() {
    47  \tgrumpy.ImportModule(grumpy.NewRootFrame(), "traceback")
    48  \tos.Exit(grumpy.RunMain(mod.Code))
    49  }
    50  """)
    51  
    52  
    53  def main(args):
    54    gopath = os.getenv('GOPATH', None)
    55    if not gopath:
    56      print >> sys.stderr, 'GOPATH not set'
    57      return 1
    58  
    59    modname = args.modname
    60    workdir = tempfile.mkdtemp()
    61    try:
    62      if modname:
    63        # Find the script associated with the given module.
    64        for d in gopath.split(os.pathsep):
    65          script = imputil.find_script(
    66              os.path.join(d, 'src', '__python__'), modname)
    67          if script:
    68            break
    69        else:
    70          print >> sys.stderr, "can't find module", modname
    71          return 1
    72      else:
    73        # Generate a dummy python script on the GOPATH.
    74        modname = ''.join(random.choice(string.ascii_letters) for _ in range(16))
    75        py_dir = os.path.join(workdir, 'src', '__python__')
    76        mod_dir = os.path.join(py_dir, modname)
    77        os.makedirs(mod_dir)
    78        script = os.path.join(py_dir, 'module.py')
    79        with open(script, 'w') as f:
    80          f.write(sys.stdin.read())
    81        gopath = gopath + os.pathsep + workdir
    82        os.putenv('GOPATH', gopath)
    83        # Compile the dummy script to Go using grumpc.
    84        fd = os.open(os.path.join(mod_dir, 'module.go'), os.O_WRONLY | os.O_CREAT)
    85        try:
    86          p = subprocess.Popen('grumpc ' + script, stdout=fd, shell=True)
    87          if p.wait():
    88            return 1
    89        finally:
    90          os.close(fd)
    91  
    92      names = imputil.calculate_transitive_deps(modname, script, gopath)
    93      # Make sure traceback is available in all Python binaries.
    94      names.add('traceback')
    95      go_main = os.path.join(workdir, 'main.go')
    96      package = _package_name(modname)
    97      imports = ''.join('\t_ "' + _package_name(name) + '"\n' for name in names)
    98      with open(go_main, 'w') as f:
    99        f.write(module_tmpl.substitute(package=package, imports=imports))
   100      return subprocess.Popen('go run ' + go_main, shell=True).wait()
   101    finally:
   102      shutil.rmtree(workdir)
   103  
   104  
   105  def _package_name(modname):
   106    if modname.startswith('__go__/'):
   107      return '__python__/' + modname
   108    return '__python__/' + modname.replace('.', '/')
   109  
   110  
   111  if __name__ == '__main__':
   112    sys.exit(main(parser.parse_args()))