#!/usr/bin/env python import os import sys import subprocess from fnmatch import fnmatch from optparse import OptionParser, BadOptionError, AmbiguousOptionError APPLICATION = 'jshint' DEFAULT_ARGS = [] REPORT_DIRECTORY = '../../build/log' class PassThroughOptionParser(OptionParser): """ An unknown option pass-through implementation of OptionParser. When unknown arguments are encountered, bundle with largs and try again, until rargs is depleted. sys.exit(status) will still be called if a known argument is passed incorrectly (e.g. missing arguments or bad argument types, etc.) Borrowed from: http://stackoverflow.com/a/9307174 """ def _process_args(self, largs, rargs, values): while rargs: try: OptionParser._process_args(self, largs, rargs, values) except (BadOptionError, AmbiguousOptionError), error: largs.append(error.opt_str) def execute_command(command, return_output=False, shell=False): prog = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE if return_output else None) return prog.wait() if not return_output else \ prog.communicate()[0] def get_report_directory(): path = os.path.abspath(REPORT_DIRECTORY) try: os.makedirs(REPORT_DIRECTORY) except OSError: pass return path def get_script_directory(): return os.path.dirname(os.path.abspath(sys.argv[0])) def parse_commandline(): parser = PassThroughOptionParser(usage='%prog [options] [additional arguments' ' for {0}]'.format(APPLICATION)) parser.add_option('-b', '--build', action='store_true', help='Enable reporting.') parser.add_option('-v', '--verbose', action='store_true', help='Be more verbose.') parser.add_option('-i', '--include', metavar='PATTERN', action='append', help='Include only specific files/test cases.' ' (Can be supplied multiple times.)') parser.add_option('-e', '--exclude', metavar='PATTERN', action='append', help='Exclude specific files/test cases. ' '(Can be supplied multiple times.)') return parser.parse_args() def main(): options, arguments = parse_commandline() # Environment preparation and verification os.chdir(get_script_directory()) application_path = execute_command('which {0}'.format(APPLICATION), True, True).strip() if not application_path: print 'ERROR: {0} not found!'.format(APPLICATION) return 2 # Commandline preparation command_options = [] if options.build: command_options.extend(['--reporter', 'jslint']) else: command_options.append('--verbose') if options.verbose: command_options.append('--show-non-errors') path_args = [arguments.remove(a) or a for a in arguments[:len(arguments)] if os.path.isfile(a) or os.path.isdir(a)] if not path_args: path_args = ['../../application', '../../bin', '../../library/Icinga'] if options.include: path_args = [os.path.join(r, f) for a in path_args for r, _, fs in os.walk(a) for f in fs if any(fnmatch(os.path.join(r, f), p) for p in options.include)] if options.exclude: walk = lambda p: os.walk(p) if os.path.isdir(p) else \ [(os.path.dirname(p), None, [os.path.basename(p)])] path_args = [os.path.join(r, f) for a in path_args for r, _, fs in walk(a) for f in fs if not any(fnmatch(os.path.join(r, f), p) for p in options.exclude)] # Application invocation.. if options.build: result_data = execute_command([application_path] + DEFAULT_ARGS + command_options + arguments + path_args, True) result_path = os.path.join(get_report_directory(), 'jshint_results.xml') with open(result_path, 'w') as result_file: result_file.write(result_data) else: execute_command([application_path] + DEFAULT_ARGS + command_options + arguments + path_args) return 0 if __name__ == '__main__': sys.exit(main())