The Python file is a hand-edited version of the Hy version. It has
the exact same functionality, but I recommend using the Hy version if you can, as it's the one I'm actively maintaining.
This commit is contained in:
parent
83fa9eed0c
commit
96573504bb
|
@ -0,0 +1,188 @@
|
|||
VERSION = '0.0.2'
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
CONFIG_PATH = os.path.join(os.environ.get('GIT_DIR', './.git'), 'pccs')
|
||||
GIT_MODIFIED_PATTERN = re.compile('^[MA]\\s+(?P<name>.*)$')
|
||||
CHECKS = [
|
||||
{
|
||||
'output': 'Running Jshint...',
|
||||
'command': 'jshint -c {config_path}/jshint.rc {filename}',
|
||||
'match_files': ['.*\\.js$'],
|
||||
'print_filename': False,
|
||||
'error_condition': 'error'
|
||||
},
|
||||
{
|
||||
'output': 'Running Coffeelint...',
|
||||
'command': 'coffeelint {filename}',
|
||||
'match_files': ['.*\\.coffee$'],
|
||||
'print_filename': False,
|
||||
'error_condition': 'error'
|
||||
},
|
||||
{
|
||||
'output': 'Running JSCS...',
|
||||
'command': 'jscs -c {config_path}/jscs.rc {filename}',
|
||||
'match_files': ['.*\\.js$'],
|
||||
'print_filename': False,
|
||||
'error_condition': 'error'
|
||||
},
|
||||
{
|
||||
'output': 'Running pep8...',
|
||||
'command': 'pep8 -r --ignore=E501,W293,W391 {filename}',
|
||||
'match_files': ['.*\\.py$'],
|
||||
'print_filename': False,
|
||||
'error_condition': 'error'
|
||||
},
|
||||
{
|
||||
'output': 'Running xmllint...',
|
||||
'command': 'xmllint {filename}',
|
||||
'match_files': ['.*\\.xml'],
|
||||
'print_filename': False,
|
||||
'error_condition': 'error'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def flatten(alist):
|
||||
if isinstance(alist, list):
|
||||
if len(alist) == 0:
|
||||
return []
|
||||
first, rest = alist[0], alist[1:]
|
||||
return flatten(first) + flatten(rest)
|
||||
return [alist]
|
||||
|
||||
|
||||
def get_git_response(cmd):
|
||||
fullcmd = (['git'] + cmd)
|
||||
process = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(out, err) = process.communicate()
|
||||
(out, err)
|
||||
return (out, err, process.returncode)
|
||||
|
||||
|
||||
def run_git_command(cmd):
|
||||
fullcmd = (['git'] + cmd)
|
||||
return subprocess.call(fullcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
|
||||
def get_shell_response(fullcmd):
|
||||
process = subprocess.Popen(fullcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||
(out, err) = process.communicate()
|
||||
(out, err)
|
||||
return (out, err, process.returncode)
|
||||
|
||||
|
||||
def derive_max_code(code_pairs):
|
||||
def find_max_code(m, i):
|
||||
if abs(i[0]) > abs(m):
|
||||
return i[0]
|
||||
return m
|
||||
return reduce(find_max_code, code_pairs, 0)
|
||||
|
||||
|
||||
def lmap(pred, iterable):
|
||||
return list(map(pred, iterable))
|
||||
|
||||
|
||||
def derive_message_bodies(code_pairs):
|
||||
def get_first(i):
|
||||
return i[1]
|
||||
return lmap(get_first, code_pairs)
|
||||
|
||||
|
||||
def encode_shell_messages(prefix, messages):
|
||||
def encode(line):
|
||||
return '{}{}'.format(prefix, line.decode('utf-8'))
|
||||
return lmap(encode, messages.splitlines())
|
||||
|
||||
|
||||
def run_external_checker(filename, check):
|
||||
cmd = check['command'].format(filename=filename, config_path=CONFIG_PATH)
|
||||
(out, err, returncode) = get_shell_response(cmd)
|
||||
if ((out and (check.get('error_condition', 'error') == 'output')) or err or (not (returncode == 0))):
|
||||
prefix = ('\t{}:'.format(filename) if check['print_filename'] else '\t')
|
||||
output = (encode_shell_messages(prefix, out) + (encode_shell_messages(prefix, err) if err else []))
|
||||
return [(returncode or 1), output]
|
||||
return [0, []]
|
||||
|
||||
|
||||
def matches_file(filename, match_files):
|
||||
def match_one(match_file):
|
||||
return re.compile(match_file).match(filename)
|
||||
return any(map(match_one, match_files))
|
||||
|
||||
|
||||
def check_scan_wanted(filename, check):
|
||||
if (('match_files' in check) and (not matches_file(filename, check['match_files']))):
|
||||
return False
|
||||
if (('ignore_files' in check) and matches_file(filename, check['ignore_files'])):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def check_files(filenames, check):
|
||||
def scan_wanted(filename):
|
||||
return check_scan_wanted(filename, check)
|
||||
filenames_to_check = filter(scan_wanted, filenames)
|
||||
|
||||
def external_check(filename):
|
||||
return run_external_checker(filename, check)
|
||||
|
||||
results_of_checks = lmap(external_check, filenames_to_check)
|
||||
messages = ([check['output']] + derive_message_bodies(results_of_checks))
|
||||
return [derive_max_code(results_of_checks), messages]
|
||||
|
||||
|
||||
def gather_all_filenames():
|
||||
def build_filenames(filenames):
|
||||
def make_path(f):
|
||||
return os.path.join(filenames[0], f)
|
||||
return map(make_path, filenames[2])
|
||||
return list(flatten([build_filenames(o) for o in os.walk('.')]))
|
||||
|
||||
|
||||
def gather_staged_filenames(against):
|
||||
(out, err, returncode) = get_git_response(['diff-index', '--name-status', against])
|
||||
(out, err, returncode)
|
||||
lines = out.splitlines()
|
||||
|
||||
def matcher(line):
|
||||
return GIT_MODIFIED_PATTERN.match(line.decode('utf-8'))
|
||||
|
||||
return [s for s in [match.group('name')
|
||||
for match in [matcher(l) for l in lines] if match]
|
||||
if not (s == '')]
|
||||
|
||||
|
||||
def run_checks_for(scan_all_files, against):
|
||||
run_git_command(['stash', '--keep-index'])
|
||||
filenames_to_scan = (gather_all_filenames() if scan_all_files else gather_staged_filenames(against))
|
||||
|
||||
def run_check(check):
|
||||
return check_files(filenames_to_scan, check)
|
||||
results_of_scan = lmap(run_check, CHECKS)
|
||||
exit_code = derive_max_code(results_of_scan)
|
||||
messages = flatten(derive_message_bodies(results_of_scan))
|
||||
for line in messages:
|
||||
print(line)
|
||||
run_git_command(['reset', '--hard'])
|
||||
run_git_command(['stash', 'pop', '--quiet', '--index'])
|
||||
return exit_code
|
||||
|
||||
|
||||
def get_head_tag():
|
||||
empty_repository_hash = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
|
||||
(out, err, returncode) = get_git_response(['rev-parse', '--verify HEAD'])
|
||||
(out, err, returncode)
|
||||
return (empty_repository_hash if err else 'HEAD')
|
||||
|
||||
|
||||
def main(*args):
|
||||
scan_all_files = ((len(args) > 1) and (args[2] == u'--all-files'))
|
||||
return int(run_checks_for(scan_all_files, get_head_tag()))
|
||||
|
||||
if (__name__ == u'__main__'):
|
||||
import sys
|
||||
sys.exit(main(*sys.argv))
|
Loading…
Reference in New Issue