summaryrefslogtreecommitdiffstats
path: root/third_party/python/cram/cram/_main.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/python/cram/cram/_main.py')
-rw-r--r--third_party/python/cram/cram/_main.py211
1 files changed, 211 insertions, 0 deletions
diff --git a/third_party/python/cram/cram/_main.py b/third_party/python/cram/cram/_main.py
new file mode 100644
index 0000000000..11d457bb16
--- /dev/null
+++ b/third_party/python/cram/cram/_main.py
@@ -0,0 +1,211 @@
+"""Main entry point"""
+
+import optparse
+import os
+import shlex
+import shutil
+import sys
+import tempfile
+
+try:
+ import configparser
+except ImportError: # pragma: nocover
+ import ConfigParser as configparser
+
+from cram._cli import runcli
+from cram._encoding import b, fsencode, stderrb, stdoutb
+from cram._run import runtests
+from cram._xunit import runxunit
+
+def _which(cmd):
+ """Return the path to cmd or None if not found"""
+ cmd = fsencode(cmd)
+ for p in os.environ['PATH'].split(os.pathsep):
+ path = os.path.join(fsencode(p), cmd)
+ if os.path.isfile(path) and os.access(path, os.X_OK):
+ return os.path.abspath(path)
+ return None
+
+def _expandpath(path):
+ """Expands ~ and environment variables in path"""
+ return os.path.expanduser(os.path.expandvars(path))
+
+class _OptionParser(optparse.OptionParser):
+ """Like optparse.OptionParser, but supports setting values through
+ CRAM= and .cramrc."""
+
+ def __init__(self, *args, **kwargs):
+ self._config_opts = {}
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+
+ def add_option(self, *args, **kwargs):
+ option = optparse.OptionParser.add_option(self, *args, **kwargs)
+ if option.dest and option.dest != 'version':
+ key = option.dest.replace('_', '-')
+ self._config_opts[key] = option.action == 'store_true'
+ return option
+
+ def parse_args(self, args=None, values=None):
+ config = configparser.RawConfigParser()
+ config.read(_expandpath(os.environ.get('CRAMRC', '.cramrc')))
+ defaults = {}
+ for key, isbool in self._config_opts.items():
+ try:
+ if isbool:
+ try:
+ value = config.getboolean('cram', key)
+ except ValueError:
+ value = config.get('cram', key)
+ self.error('--%s: invalid boolean value: %r'
+ % (key, value))
+ else:
+ value = config.get('cram', key)
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ pass
+ else:
+ defaults[key] = value
+ self.set_defaults(**defaults)
+
+ eargs = os.environ.get('CRAM', '').strip()
+ if eargs:
+ args = args or []
+ args += shlex.split(eargs)
+
+ try:
+ return optparse.OptionParser.parse_args(self, args, values)
+ except optparse.OptionValueError:
+ self.error(str(sys.exc_info()[1]))
+
+def _parseopts(args):
+ """Parse command line arguments"""
+ p = _OptionParser(usage='cram [OPTIONS] TESTS...', prog='cram')
+ p.add_option('-V', '--version', action='store_true',
+ help='show version information and exit')
+ p.add_option('-q', '--quiet', action='store_true',
+ help="don't print diffs")
+ p.add_option('-v', '--verbose', action='store_true',
+ help='show filenames and test status')
+ p.add_option('-i', '--interactive', action='store_true',
+ help='interactively merge changed test output')
+ p.add_option('-d', '--debug', action='store_true',
+ help='write script output directly to the terminal')
+ p.add_option('-y', '--yes', action='store_true',
+ help='answer yes to all questions')
+ p.add_option('-n', '--no', action='store_true',
+ help='answer no to all questions')
+ p.add_option('-E', '--preserve-env', action='store_true',
+ help="don't reset common environment variables")
+ p.add_option('--keep-tmpdir', action='store_true',
+ help='keep temporary directories')
+ p.add_option('--shell', action='store', default='/bin/sh', metavar='PATH',
+ help='shell to use for running tests (default: %default)')
+ p.add_option('--shell-opts', action='store', metavar='OPTS',
+ help='arguments to invoke shell with')
+ p.add_option('--indent', action='store', default=2, metavar='NUM',
+ type='int', help=('number of spaces to use for indentation '
+ '(default: %default)'))
+ p.add_option('--xunit-file', action='store', metavar='PATH',
+ help='path to write xUnit XML output')
+ opts, paths = p.parse_args(args)
+ paths = [fsencode(path) for path in paths]
+ return opts, paths, p.get_usage
+
+def main(args):
+ """Main entry point.
+
+ If you're thinking of using Cram in other Python code (e.g., unit tests),
+ consider using the test() or testfile() functions instead.
+
+ :param args: Script arguments (excluding script name)
+ :type args: str
+ :return: Exit code (non-zero on failure)
+ :rtype: int
+ """
+ opts, paths, getusage = _parseopts(args)
+ if opts.version:
+ sys.stdout.write("""Cram CLI testing framework (version 0.7)
+
+Copyright (C) 2010-2016 Brodie Rao <brodie@bitheap.org> and others
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+""")
+ return
+
+ conflicts = [('--yes', opts.yes, '--no', opts.no),
+ ('--quiet', opts.quiet, '--interactive', opts.interactive),
+ ('--debug', opts.debug, '--quiet', opts.quiet),
+ ('--debug', opts.debug, '--interactive', opts.interactive),
+ ('--debug', opts.debug, '--verbose', opts.verbose),
+ ('--debug', opts.debug, '--xunit-file', opts.xunit_file)]
+ for s1, o1, s2, o2 in conflicts:
+ if o1 and o2:
+ sys.stderr.write('options %s and %s are mutually exclusive\n'
+ % (s1, s2))
+ return 2
+
+ shellcmd = _which(opts.shell)
+ if not shellcmd:
+ stderrb.write(b('shell not found: ') + fsencode(opts.shell) + b('\n'))
+ return 2
+ shell = [shellcmd]
+ if opts.shell_opts:
+ shell += shlex.split(opts.shell_opts)
+
+ patchcmd = None
+ if opts.interactive:
+ patchcmd = _which('patch')
+ if not patchcmd:
+ sys.stderr.write('patch(1) required for -i\n')
+ return 2
+
+ if not paths:
+ sys.stdout.write(getusage())
+ return 2
+
+ badpaths = [path for path in paths if not os.path.exists(path)]
+ if badpaths:
+ stderrb.write(b('no such file: ') + badpaths[0] + b('\n'))
+ return 2
+
+ if opts.yes:
+ answer = 'y'
+ elif opts.no:
+ answer = 'n'
+ else:
+ answer = None
+
+ tmpdir = os.environ['CRAMTMP'] = tempfile.mkdtemp('', 'cramtests-')
+ tmpdirb = fsencode(tmpdir)
+ proctmp = os.path.join(tmpdir, 'tmp')
+ for s in ('TMPDIR', 'TEMP', 'TMP'):
+ os.environ[s] = proctmp
+
+ os.mkdir(proctmp)
+ try:
+ tests = runtests(paths, tmpdirb, shell, indent=opts.indent,
+ cleanenv=not opts.preserve_env, debug=opts.debug)
+ if not opts.debug:
+ tests = runcli(tests, quiet=opts.quiet, verbose=opts.verbose,
+ patchcmd=patchcmd, answer=answer)
+ if opts.xunit_file is not None:
+ tests = runxunit(tests, opts.xunit_file)
+
+ hastests = False
+ failed = False
+ for path, test in tests:
+ hastests = True
+ refout, postout, diff = test()
+ if diff:
+ failed = True
+
+ if not hastests:
+ sys.stderr.write('no tests found\n')
+ return 2
+
+ return int(failed)
+ finally:
+ if opts.keep_tmpdir:
+ stdoutb.write(b('# Kept temporary directory: ') + tmpdirb +
+ b('\n'))
+ else:
+ shutil.rmtree(tmpdir)