2016-09-23 20:11:06 +00:00
from hy . core . language import filter , is_integer , map , reduce
import ConfigParser
import os
import subprocess
import operator
import re
import gettext
import sys
import getopt
sys . path . append ( u ' Users/ksternberg/build/git-lint/git_lint_src ' )
from git_lint_options import hyopt
from git_lint_config import get_config
_ = gettext . gettext
VERSION = u ' 0.0.2 '
def tap ( a ) :
print ( u ' TAP: ' , a )
return a
optlist = [ [ u ' o ' , u ' only ' , True , _ ( u ' A comma-separated list of only those linters to run ' ) , [ u ' exclude ' ] ] , [ u ' x ' , u ' exclude ' , True , _ ( u ' A comma-separated list of linters to skip ' ) , [ ] ] , [ u ' l ' , u ' linters ' , False , _ ( u ' Show the list of configured linters ' ) ] , [ u ' b ' , u ' base ' , False , _ ( u ' Check all changed files in the repository, not just those in the current directory. ' ) , [ ] ] , [ u ' a ' , u ' all ' , False , _ ( u ' Scan all files in the repository, not just those that have changed. ' ) ] , [ u ' e ' , u ' every ' , False , _ ( u ' Short for -b -a: scan everything ' ) ] , [ u ' w ' , u ' workspace ' , False , _ ( u ' Scan the workspace ' ) , [ u ' staging ' ] ] , [ u ' s ' , u ' staging ' , False , _ ( u ' Scan the staging area (useful for pre-commit). ' ) , [ ] ] , [ u ' g ' , u ' changes ' , False , _ ( u " Report lint failures only for diff ' d sections " ) , [ u ' complete ' ] ] , [ u ' p ' , u ' complete ' , False , _ ( u ' Report lint failures for all files ' ) , [ ] ] , [ u ' c ' , u ' config ' , True , _ ( u ' Path to config file ' ) , [ ] ] , [ u ' h ' , u ' help ' , False , _ ( u ' This help message ' ) , [ ] ] , [ u ' v ' , u ' version ' , False , _ ( u ' Version information ' ) , [ ] ] ]
def get_git_response_raw ( cmd ) :
def _hy_anon_fn_2 ( ) :
fullcmd = ( [ u ' git ' ] + cmd )
process = subprocess . Popen ( fullcmd , stdout = subprocess . PIPE , stderr = subprocess . PIPE )
( out , err ) = process . communicate ( )
( out , err )
return ( out , err , process . returncode )
return _hy_anon_fn_2 ( )
def get_git_response ( cmd ) :
def _hy_anon_fn_4 ( ) :
( out , error , returncode ) = get_git_response_raw ( cmd )
( out , error , returncode )
return out
return _hy_anon_fn_4 ( )
def split_git_response ( cmd ) :
def _hy_anon_fn_6 ( ) :
( out , error , returncode ) = get_git_response_raw ( cmd )
( out , error , returncode )
return out . splitlines ( )
return _hy_anon_fn_6 ( )
def run_git_command ( cmd ) :
def _hy_anon_fn_8 ( ) :
fullcmd = ( [ u ' git ' ] + cmd )
return subprocess . call ( fullcmd , stdout = subprocess . PIPE , stderr = subprocess . PIPE )
return _hy_anon_fn_8 ( )
def get_shell_response ( fullcmd ) :
def _hy_anon_fn_10 ( ) :
process = subprocess . Popen ( fullcmd , stdout = subprocess . PIPE , stderr = subprocess . PIPE , shell = True )
( out , err ) = process . communicate ( )
( out , err )
return ( out , err , process . returncode )
return _hy_anon_fn_10 ( )
def _hy_anon_fn_12 ( ) :
( out , error , returncode ) = get_git_response_raw ( [ u ' rev-parse ' , u ' --show-toplevel ' ] )
( out , error , returncode )
return ( None if ( not ( returncode == 0 L ) ) else out . rstrip ( ) )
git_base = _hy_anon_fn_12 ( )
def _hy_anon_fn_13 ( ) :
empty_repository_hash = u ' 4b825dc642cb6eb9a060e54bf8d69288fbee4904 '
( out , err , returncode ) = get_git_response_raw ( [ u ' rev-parse ' , u ' --verify HEAD ' ] )
( out , err , returncode )
return ( u ' HEAD ' if ( not err ) else empty_repository_hash )
git_head = _hy_anon_fn_13 ( )
def run_external_checker ( path , config ) :
def _hy_anon_fn_15 ( ) :
cmd = config [ u ' command ' ] . format ( ( command + u ' " {} " ' ) , path )
( out , err , returncode ) = get_shell_response ( cmd )
( out , err , returncode )
if ( ( out and ( check . get ( u ' error_condition ' , u ' error ' ) == u ' output ' ) ) or err or ( not ( returncode == 0 L ) ) ) :
def _hy_anon_fn_14 ( ) :
prefix = ( u ' \t {} : ' . format ( filename ) if check [ u ' print_filename ' ] else u ' \t ' )
output = ( encode_shell_messages ( prefix , out ) + ( encode_shell_messages ( prefix , err ) if err else [ ] ) )
return [ ( returncode or 1 L ) , output ]
_hy_anon_var_1 = _hy_anon_fn_14 ( )
else :
_hy_anon_var_1 = [ 0 L , [ ] ]
return _hy_anon_var_1
return _hy_anon_fn_15 ( )
def make_match_filter_matcher ( extensions ) :
def _hy_anon_fn_17 ( s ) :
return re . compile ( s , re . I )
def _hy_anon_fn_18 ( s ) :
return ( ( u ' \\ .( ' + s ) + u ' )$ ' )
def _hy_anon_fn_19 ( s ) :
return re . sub ( u ' ^ \\ . ' , u ' ' , s )
def _hy_anon_fn_20 ( s ) :
return ( not ( 0 L == len ( s ) ) )
def _hy_anon_fn_21 ( s ) :
return s . strip ( )
def _hy_anon_fn_22 ( s ) :
return s . split ( u ' , ' )
return _hy_anon_fn_17 ( _hy_anon_fn_18 ( u ' | ' . join ( map ( _hy_anon_fn_19 , filter ( _hy_anon_fn_20 , set ( map ( _hy_anon_fn_21 , reduce ( operator . add , map ( _hy_anon_fn_22 , extensions ) ) ) ) ) ) ) ) )
def make_match_filter ( config ) :
def _hy_anon_fn_26 ( ) :
def _hy_anon_fn_24 ( v ) :
return v . get ( u ' match ' , u ' ' )
matcher = make_match_filter_matcher ( map ( _hy_anon_fn_24 , config . itervalues ( ) ) )
def _hy_anon_fn_25 ( path ) :
return matcher . search ( path )
return _hy_anon_fn_25
return _hy_anon_fn_26 ( )
def executable_exists ( script , label ) :
if ( not len ( script ) ) :
_hy_anon_var_4 = sys . exit ( _ ( u ' Syntax error in command configuration for {} ' ) . format ( label ) )
else :
def _hy_anon_fn_31 ( ) :
scriptname = script . split ( u ' ' ) [ 0 L ]
paths = os . environ . get ( u ' PATH ' ) . split ( u ' : ' )
def isexecutable ( p ) :
return ( os . path . exists ( p ) and os . access ( p , os . X_OK ) )
if ( not len ( scriptname ) ) :
_hy_anon_var_3 = sys . exit ( _ ( u ' Syntax error in command configuration for {} ' ) . format ( label ) )
else :
if ( scriptname [ 0 L ] == u ' / ' ) :
_hy_anon_var_2 = ( scriptname if isexecutable ( scriptname ) else None )
else :
def _hy_anon_fn_30 ( ) :
def _hy_anon_fn_29 ( path ) :
return isexecutable ( os . path . join ( path , scriptname ) )
possibles = list ( filter ( _hy_anon_fn_29 , paths ) )
return ( possibles [ 0 L ] if len ( possibles ) else None )
_hy_anon_var_2 = _hy_anon_fn_30 ( )
_hy_anon_var_3 = _hy_anon_var_2
return _hy_anon_var_3
_hy_anon_var_4 = _hy_anon_fn_31 ( )
return _hy_anon_var_4
def get_working_linters ( config ) :
def _hy_anon_fn_34 ( ) :
def found ( key ) :
return executable_exists ( config . get ( key ) . get ( u ' command ' ) , key )
return set ( filter ( found , config . keys ( ) ) )
return _hy_anon_fn_34 ( )
def print_linters ( config ) :
print ( _ ( u ' Currently supported linters: ' ) )
def _hy_anon_fn_36 ( ) :
working = get_working_linters ( config )
broken = ( set ( config . keys ( ) ) - working )
for key in sorted ( working ) :
print ( u ' {:<14} {} ' . format ( key , config . get ( key ) . get ( u ' comment ' , u ' ' ) ) )
for key in sorted ( broken ) :
print ( u ' {:<14} {} ' . format ( key , _ ( u ' (WARNING: executable not found) ' ) ) )
return _hy_anon_fn_36 ( )
def base_file_filter ( files ) :
def _hy_anon_fn_38 ( f ) :
return os . path . join ( git_base , f )
return map ( _hy_anon_fn_38 , files )
def cwd_file_filter ( files ) :
def _hy_anon_fn_41 ( ) :
gitcwd = os . path . join ( os . path . relpath ( os . getcwd ( ) , git_base ) , u ' ' )
def _hy_anon_fn_40 ( f ) :
return f . startswith ( gitcwd )
return base_file_filter ( filter ( _hy_anon_fn_40 , files ) )
return _hy_anon_fn_41 ( )
def base_file_cleaner ( files ) :
def _hy_anon_fn_43 ( f ) :
return f . replace ( git_base , 1 L )
return map ( _hy_anon_fn_43 , files )
MERGE_CONFLICT_PAIRS = set ( [ u ' DD ' , u ' DU ' , u ' AU ' , u ' AA ' , u ' UD ' , u ' UA ' , u ' UU ' ] )
def check_for_conflicts ( files ) :
def _hy_anon_fn_46 ( ) :
def _hy_anon_fn_45 ( _hy_anon_var_5 ) :
( index , workspace , filename ) = _hy_anon_var_5
( index , workspace , filename )
return ( ( u ' ' + index ) + workspace )
status_pairs = map ( _hy_anon_fn_45 , files )
conflicts = ( set ( MERGE_CONFLICT_PAIRS ) & set ( status_pairs ) )
return ( sys . exit ( _ ( u ' Current repository contains merge conflicts. Linters will not be run. ' ) ) if len ( conflicts ) else files )
return _hy_anon_fn_46 ( )
def remove_submodules ( files ) :
def _hy_anon_fn_52 ( ) :
def split_out_paths ( s ) :
return s . split ( u ' ' ) [ 2 L ]
fixer_re = re . compile ( u ' ^( \\ . \\ . \\ /)+ ' )
def fixer_to_base ( s ) :
return fixer_re . sub ( u ' ' , s )
submodule_entries = split_git_response ( [ u ' submodule ' , u ' status ' ] )
def _hy_anon_fn_50 ( s ) :
return fixer_to_base ( split_out_paths ( s ) )
submodule_names = map ( _hy_anon_fn_50 , submodule_entries )
def _hy_anon_fn_51 ( s ) :
return ( not ( s in submodule_names ) )
return filter ( _hy_anon_fn_51 , files )
return _hy_anon_fn_52 ( )
def get_porcelain_status ( ) :
def _hy_anon_fn_57 ( ) :
cmd = [ u ' status ' , u ' -z ' , u ' --porcelain ' , u ' --untracked-files=all ' , u ' --ignore-submodules=all ' ]
def nonnull ( s ) :
return ( len ( s ) > 0 L )
stream = list ( filter ( nonnull , get_git_response ( cmd ) . split ( u ' \x00 ' ) ) )
def parse_stream ( acc , stream ) :
if ( 0 L == len ( stream ) ) :
_hy_anon_var_6 = acc
else :
def _hy_anon_fn_55 ( ) :
temp = stream . pop ( 0 L )
index = temp [ 0 L ]
workspace = temp [ 1 L ]
filename = temp [ 3 L : ]
( stream . pop ( 0 L ) if ( index == u ' R ' ) else None )
return parse_stream ( ( acc + [ ( index , workspace , filename ) ] ) , stream )
_hy_anon_var_6 = _hy_anon_fn_55 ( )
return _hy_anon_var_6
return check_for_conflicts ( parse_stream ( [ ] , stream ) )
return _hy_anon_fn_57 ( )
def staging_list ( ) :
def _hy_anon_fn_59 ( _hy_anon_var_7 ) :
( index , workspace , filename ) = _hy_anon_var_7
( index , workspace , filename )
return filename
def _hy_anon_fn_60 ( _hy_anon_var_8 ) :
( index , workspace , filename ) = _hy_anon_var_8
( index , workspace , filename )
return ( index in [ u ' A ' , u ' M ' ] )
return map ( _hy_anon_fn_59 , filter ( _hy_anon_fn_60 , get_porcelain_status ( ) ) )
def working_list ( ) :
def _hy_anon_fn_62 ( _hy_anon_var_9 ) :
( index , workspace , filename ) = _hy_anon_var_9
( index , workspace , filename )
return filename
def _hy_anon_fn_63 ( _hy_anon_var_10 ) :
( index , workspace , filename ) = _hy_anon_var_10
( index , workspace , filename )
return ( workspace in [ u ' A ' , u ' M ' , u ' ? ' ] )
return map ( _hy_anon_fn_62 , filter ( _hy_anon_fn_63 , get_porcelain_status ( ) ) )
def all_list ( ) :
def _hy_anon_fn_66 ( ) :
cmd = [ u ' ls-tree ' , u ' --name-only ' , u ' --full-tree ' , u ' -r ' , u ' -z ' , git_head ]
def _hy_anon_fn_65 ( s ) :
return ( len ( s ) > 0 L )
return filter ( _hy_anon_fn_65 , get_git_response ( cmd ) . split ( u ' \x00 ' ) )
return _hy_anon_fn_66 ( )
def get_filelist ( options ) :
def _hy_anon_fn_69 ( ) :
keys = options . keys ( )
working_directory_trans = ( base_file_filter if len ( ( set ( keys ) & set ( [ u ' base ' , u ' every ' ] ) ) ) else cwd_file_filter )
file_list_generator = ( staging_list if ( u ' staging ' in keys ) else ( all_list if ( u ' all ' in keys ) else ( working_list if True else None ) ) )
def _hy_anon_fn_68 ( ) :
return working_directory_trans ( remove_submodules ( file_list_generator ( ) ) )
return set ( _hy_anon_fn_68 ( ) )
return _hy_anon_fn_69 ( )
def staging_wrapper ( run_linters ) :
def _hy_anon_fn_74 ( ) :
def time_gather ( f ) :
def _hy_anon_fn_71 ( ) :
stats = os . stat ( f )
return ( f , ( stats . atime , stats . mtime ) )
return _hy_anon_fn_71 ( )
times = list ( map ( time_gather , files ) )
run_git_command ( [ u ' stash ' , u ' --keep-index ' ] )
def _hy_anon_fn_73 ( ) :
results = run_linters ( )
run_git_command ( [ u ' reset ' , u ' --hard ' ] )
run_git_command ( [ u ' stash ' , u ' pop ' , u ' --quiet ' , u ' --index ' ] )
for ( filename , timepair ) in times :
os . utime ( filename , timepair )
return results
return _hy_anon_fn_73 ( )
return _hy_anon_fn_74 ( )
def workspace_wrapper ( run_linters ) :
return run_linters ( )
def pick_runner ( options ) :
def _hy_anon_fn_77 ( ) :
keys = options . keys ( )
return ( staging_wrapper if ( u ' staging ' in keys ) else workspace_wrapper )
return _hy_anon_fn_77 ( )
def lmap ( pred , iter ) :
return list ( map ( pred , iter ) )
def encode_shell_messages ( prefix , messages ) :
def _hy_anon_fn_80 ( line ) :
return u ' {} {} ' . format ( prefix , line . decode ( u ' utf-8 ' ) )
return lmap ( _hy_anon_fn_80 , messages . splitlines ( ) )
def run_external_linter ( filename , linter ) :
def _hy_anon_fn_83 ( ) :
cmd = ( ( ( linter [ u ' command ' ] + u ' " ' ) + filename ) + u ' " ' )
( out , err , returncode ) = get_shell_response ( cmd )
( out , err , returncode )
if ( ( out and ( linter . get ( u ' condition ' , u ' error ' ) == u ' output ' ) ) or err or ( not ( returncode == 0 L ) ) ) :
def _hy_anon_fn_82 ( ) :
prefix = ( u ' \t {} : ' . format ( filename ) if linter [ u ' print ' ] else u ' \t ' )
output = ( encode_shell_messages ( prefix , out ) + ( encode_shell_messages ( prefix , err ) if err else [ ] ) )
return [ ( returncode or 1 L ) , output ]
_hy_anon_var_11 = _hy_anon_fn_82 ( )
else :
_hy_anon_var_11 = [ 0 L , [ ] ]
return _hy_anon_var_11
return _hy_anon_fn_83 ( )
def run_one_linter ( linter , filenames ) :
def _hy_anon_fn_86 ( ) :
match_filter = make_match_filter ( linter )
config = linter . values ( ) [ 0 L ]
files = set ( filter ( match_filter , filenames ) )
def _hy_anon_fn_85 ( f ) :
return run_external_linter ( f , config )
return list ( map ( _hy_anon_fn_85 , files ) )
return _hy_anon_fn_86 ( )
def build_lint_runner ( linters , filenames ) :
def _hy_anon_fn_90 ( ) :
def _hy_anon_fn_89 ( ) :
keys = sorted ( linters . keys ( ) )
def _hy_anon_fn_88 ( key ) :
return run_one_linter ( { key : linters [ key ] , } , filenames )
return map ( _hy_anon_fn_88 , keys )
return _hy_anon_fn_89 ( )
return _hy_anon_fn_90
def subset_config ( config , keys ) :
def _hy_anon_fn_92 ( ) :
ret = { }
for item in config . items ( ) :
if ( item [ 0 L ] in keys ) :
ret [ item [ 0 L ] ] = item [ 1 L ]
_hy_anon_var_12 = None
else :
_hy_anon_var_12 = None
return ret
return _hy_anon_fn_92 ( )
def run_gitlint ( options , config , extras ) :
def _hy_anon_fn_94 ( ) :
all_files = get_filelist ( options )
runner = pick_runner ( options )
match_filter = make_match_filter ( config )
lintable_files = set ( filter ( match_filter , all_files ) )
unlintables = ( set ( all_files ) - lintable_files )
working_linters = get_working_linters ( config )
broken_linters = ( set ( config ) - set ( working_linters ) )
cant_lint_filter = make_match_filter ( subset_config ( config , broken_linters ) )
cant_lintable = set ( filter ( cant_lint_filter , lintable_files ) )
lint_runner = build_lint_runner ( subset_config ( config , working_linters ) , lintable_files )
results = runner ( lint_runner )
print ( u ' No Linter Available: ' , list ( unlintables ) )
print ( u ' Linter Executable Not Found for: ' , list ( cant_lintable ) )
return print ( list ( results ) )
return _hy_anon_fn_94 ( )
def main ( * args ) :
def _hy_anon_fn_97 ( ) :
opts = hyopt ( optlist , args , u ' git lint ' , u ' Copyright (c) 2008, 2016 Kenneth M. " Elf " Sternberg <elf.sternberg@gmail.com> ' , u ' 0.0.4 ' )
if ( git_base == None ) :
_hy_anon_var_14 = sys . exit ( _ ( u ' Not currently in a git repository. ' ) )
else :
try :
def _hy_anon_fn_96 ( ) :
options = opts . get_options ( )
config = get_config ( options , git_base )
return ( opts . print_help ( ) if options . has_key ( u ' help ' ) else ( opts . print_version ( ) if options . has_key ( u ' version ' ) else ( print_linters ( config ) if options . has_key ( u ' linters ' ) else ( run_gitlint ( options , config , opts . filenames ) if True else None ) ) ) )
_hy_anon_var_13 = _hy_anon_fn_96 ( )
except getopt . GetoptError as err :
_hy_anon_var_13 = opts . print_help ( )
_hy_anon_var_14 = _hy_anon_var_13
return _hy_anon_var_14
return _hy_anon_fn_97 ( )
if ( __name__ == u ' __main__ ' ) :
import sys
: G_1235 = main ( * sys . argv )
_hy_anon_var_15 = ( sys . exit ( : G_1235 ) if is_integer ( : G_1235 ) else None )
else :
_hy_anon_var_15 = None