0001# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
0002# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
0003import re
0004import os
0005import sys
0006import shlex
0007import pkg_resources
0008import command
0009
0010class ExeCommand(command.Command):
0011
0012    parser = command.Command.standard_parser(verbose=False)
0013    summary = "Run #! executable files"
0014    description = """\
0015Use this at the top of files like:
0016
0017  #!/usr/bin/env /path/to/paster exe subcommand <command options>
0018
0019The rest of the file will be used as a config file for the given
0020command, if it wants a config file.
0021
0022You can also include an [exe] section in the file, which looks
0023like:
0024
0025  [exe]
0026  command = serve
0027  log_file = /path/to/log
0028  add = /path/to/other/config.ini
0029
0030Which translates to:
0031
0032  paster serve --log-file=/path/to/log /path/to/other/config.ini
0033"""
0034
0035    hidden = True
0036
0037    _exe_section_re = re.compile(r'^\s*\[\s*exe\s*\]\s*$')
0038    _section_re = re.compile(r'^\s*\[')
0039
0040    def run(self, argv):
0041        if argv and argv[0] in ('-h', '--help'):
0042            print self.description
0043            return
0044
0045        if os.environ.get('REQUEST_METHOD'):
0046            # We're probably in a CGI environment
0047            sys.stdout = sys.stderr
0048            os.environ['PASTE_DEFAULT_QUIET'] = 'true'
0049            # Maybe import cgitb or something?
0050
0051        if '_' not in os.environ:
0052            print "Warning: this command is intended to be run with a #! like:"
0053            print "  #!/usr/bin/env paster exe"
0054            print "It only works with /usr/bin/env, and only as a #! line."
0055            # Should I actually shlex.split the args?
0056            filename = argv[-1]
0057            args = argv[:-1]
0058            extra_args = []
0059        else:
0060            filename = os.environ['_']
0061            extra_args = argv[:]
0062            args = []
0063            while extra_args:
0064                if extra_args[0] == filename:
0065                    extra_args.pop(0)
0066                    break
0067                args.append(extra_args.pop(0))
0068        vars = {'here': os.path.dirname(filename),
0069                '__file__': filename}
0070        f = open(filename)
0071        lines = f.readlines()
0072        f.close()
0073        options = {}
0074        lineno = 1
0075        while lines:
0076            if self._exe_section_re.search(lines[0]):
0077                lines.pop(0)
0078                break
0079            lines.pop(0)
0080            lineno += 1
0081        pre_options = []
0082        options = args
0083        for line in lines:
0084            lineno += 1
0085            line = line.strip()
0086            if not line or line.startswith('#'):
0087                continue
0088            if self._section_re.search(line):
0089                break
0090            if '=' not in line:
0091                raise command.BadCommand('Missing = in %s at %s: %r'
0092                                         % (filename, lineno, line))
0093            name, value = line.split('=', 1)
0094            name = name.strip()
0095            value = value.strip()
0096            if name == 'require':
0097                pkg_resources.require(value)
0098            elif name == 'command' or name == 'add':
0099                options.extend(shlex.split(value))
0100            elif name == 'plugin':
0101                options[:0] = ['--plugin', value]
0102            else:
0103                value = value % vars
0104                options.append('--%s=%s' % (name.replace('_', '-'), value))
0105        os.environ['PASTE_CONFIG_FILE'] = filename
0106        options.extend(extra_args)
0107        command.run(options)