It's all coming together.
This commit is contained in:
parent
33c3d7a189
commit
9029eef623
|
@ -0,0 +1,65 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from .options import OPTIONS
|
||||||
|
from .option_handler import cleanup_options
|
||||||
|
from .reporters import print_report, print_help
|
||||||
|
from .git_lint import load_config, run_linters, git_base
|
||||||
|
from getopt import GetoptError
|
||||||
|
|
||||||
|
import gettext
|
||||||
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
def main(*args):
|
||||||
|
if git_base is None:
|
||||||
|
sys.exit(_('A git repository was not found.'))
|
||||||
|
|
||||||
|
(options, filenames, excluded_commands) = cleanup_options(OPTIONS, args)
|
||||||
|
|
||||||
|
if len(excluded_commands) > 0:
|
||||||
|
print(_('These command line options were ignored due to option precedence.'))
|
||||||
|
for exc in excluded_commands:
|
||||||
|
print("\t{}".format(exc))
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = load_config(options, git_base)
|
||||||
|
|
||||||
|
if 'help' in options:
|
||||||
|
print_help(OPTIONS, NAME)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if 'version' in options:
|
||||||
|
from .reporters get print_version
|
||||||
|
print_version(NAME, VERSION)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if 'linters' in options:
|
||||||
|
from .gitSlint import get_linter_status
|
||||||
|
working_linter_names, broken_linter_names = get_linter_status(config)
|
||||||
|
print_linters(working_linter_names, broken_linter_names))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
(results,
|
||||||
|
unlintable_filenames,
|
||||||
|
cant_lint_filenames,
|
||||||
|
broken_linter_names,
|
||||||
|
unfindable_filenames) = run_linters(options, config, filenames)
|
||||||
|
|
||||||
|
print_report(results,
|
||||||
|
unlintable_filenames,
|
||||||
|
cant_lint_filenames,
|
||||||
|
broken_linter_names,
|
||||||
|
unfindable_filenames,
|
||||||
|
options)
|
||||||
|
|
||||||
|
if not len(results):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return max([i[2] for i in results if len(i)])
|
||||||
|
|
||||||
|
except GetoptError as err:
|
||||||
|
print_help(OPTIONS)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
sys.exit(main(*sys.argv))
|
|
@ -21,13 +21,6 @@ VERSION = '0.0.4'
|
||||||
NAME = 'git-lint'
|
NAME = 'git-lint'
|
||||||
|
|
||||||
|
|
||||||
# ___ _ _ _
|
|
||||||
# / __|___ _ __ _ __ __ _ _ _ __| | | | (_)_ _ ___
|
|
||||||
# | (__/ _ \ ' \| ' \/ _` | ' \/ _` | | |__| | ' \/ -_)
|
|
||||||
# \___\___/_|_|_|_|_|_\__,_|_||_\__,_| |____|_|_||_\___|
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
# ___ __ _ ___ _
|
# ___ __ _ ___ _
|
||||||
# / __|___ _ _ / _(_)__ _ | _ \___ __ _ __| |___ _ _
|
# / __|___ _ _ / _(_)__ _ | _ \___ __ _ __| |___ _ _
|
||||||
# | (__/ _ \ ' \| _| / _` | | / -_) _` / _` / -_) '_|
|
# | (__/ _ \ ' \| _| / _` | | / -_) _` / _` / -_) '_|
|
||||||
|
@ -69,7 +62,7 @@ def find_config_file(options, base):
|
||||||
|
|
||||||
|
|
||||||
# (commandLineDictionary, repositoryLocation) -> (configurationDictionary | exit)
|
# (commandLineDictionary, repositoryLocation) -> (configurationDictionary | exit)
|
||||||
def get_config(options, base):
|
def load_config(options, base):
|
||||||
"""Loads the git-lint configuration file.
|
"""Loads the git-lint configuration file.
|
||||||
|
|
||||||
Returns the configuration file as a dictionary of dictionaries.
|
Returns the configuration file as a dictionary of dictionaries.
|
||||||
|
@ -161,21 +154,21 @@ def base_file_cleaner(files):
|
||||||
return [file.replace(git_base + '/', '', 1) for file in files]
|
return [file.replace(git_base + '/', '', 1) for file in files]
|
||||||
|
|
||||||
|
|
||||||
def make_match_filter_matcher(extensions):
|
class MatchFilter:
|
||||||
trimmed = [s.strip() for s in reduce(operator.add,
|
|
||||||
[ex.split(',') for ex in extensions], [])]
|
|
||||||
cleaned = [re.sub(r'^\.', '', s) for s in trimmed]
|
|
||||||
return re.compile(r'\.' + '|'.join(cleaned) + r'$')
|
|
||||||
|
|
||||||
|
def __init__(self, config):
|
||||||
|
self.matcher = self.make_match_filter_matcher([v.linter.get('match', '') for v in config])
|
||||||
|
|
||||||
def make_match_filter(config):
|
def __call__(self, path):
|
||||||
matcher = make_match_filter_matcher([v.linter.get('match', '') for v in config])
|
return self.matcher.search(path)
|
||||||
|
|
||||||
def match_filter(path):
|
@staticmethod
|
||||||
return matcher.search(path)
|
def make_match_filter_matcher(extensions):
|
||||||
|
trimmed = [s.strip() for s in reduce(operator.add,
|
||||||
return match_filter
|
[ex.split(',') for ex in extensions], [])]
|
||||||
|
cleaned = [re.sub(r'^\.', '', s) for s in trimmed]
|
||||||
|
return re.compile(r'\.' + '|'.join(cleaned) + r'$')
|
||||||
|
|
||||||
|
|
||||||
# ICK. Mutation, references, and hidden assignment.
|
# ICK. Mutation, references, and hidden assignment.
|
||||||
def group_by(iterable, field_id):
|
def group_by(iterable, field_id):
|
||||||
|
@ -247,7 +240,7 @@ def print_linters(config):
|
||||||
# \___\___|\__| |_|_/__/\__| \___/_| |_| |_|_\___/__/
|
# \___\___|\__| |_|_/__/\__| \___/_| |_| |_|_\___/__/
|
||||||
#
|
#
|
||||||
|
|
||||||
def get_filelist(cmdline, extras):
|
def get_filelist(options, extras):
|
||||||
""" Returns the list of files against which we'll run the linters. """
|
""" Returns the list of files against which we'll run the linters. """
|
||||||
|
|
||||||
def base_file_filter(files):
|
def base_file_filter(files):
|
||||||
|
@ -331,13 +324,13 @@ def get_filelist(cmdline, extras):
|
||||||
return ([os.path.relpath(f, cwd) for f in (extras_fullpathed - not_found)], not_found)
|
return ([os.path.relpath(f, cwd) for f in (extras_fullpathed - not_found)], not_found)
|
||||||
|
|
||||||
working_directory_trans = cwd_file_filter
|
working_directory_trans = cwd_file_filter
|
||||||
if 'base' in cmdline or 'every' in cmdline:
|
if 'base' in options or 'every' in options:
|
||||||
working_directory_trans = base_file_filter
|
working_directory_trans = base_file_filter
|
||||||
|
|
||||||
file_list_generator = working_list
|
file_list_generator = working_list
|
||||||
if 'all' in cmdline:
|
if 'all' in options:
|
||||||
file_list_generator = all_list
|
file_list_generator = all_list
|
||||||
if 'staging' in cmdline:
|
if 'staging' in options:
|
||||||
file_list_generator = staging_list
|
file_list_generator = staging_list
|
||||||
|
|
||||||
return (working_directory_trans(remove_submodules(file_list_generator())), [])
|
return (working_directory_trans(remove_submodules(file_list_generator())), [])
|
||||||
|
@ -349,16 +342,15 @@ def get_filelist(cmdline, extras):
|
||||||
# |___/\__\__,_\__, |_|_||_\__, | \_/\_/|_| \__,_| .__/ .__/\___|_|
|
# |___/\__\__,_\__, |_|_||_\__, | \_/\_/|_| \__,_| .__/ .__/\___|_|
|
||||||
# |___/ |___/ |_| |_|
|
# |___/ |___/ |_| |_|
|
||||||
|
|
||||||
def pick_stash_runner(cmdline):
|
|
||||||
"""Choose a runner.
|
|
||||||
|
|
||||||
This is the operation that will run the linters. It exists to
|
class Runner:
|
||||||
provide a way to stash the repository, then restore it when
|
def __init__(self, options):
|
||||||
complete. If possible, it attempts to restore the access and
|
self.runner = ('staging' in options and self.staging_wrapper) or self.workspace_wrapper
|
||||||
modification times of the file in order to comfort IDEs that are
|
|
||||||
constantly monitoring file times.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
def __call__(run_linters, filenames):
|
||||||
|
return self.runner(run_linters, filenames)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def staging_wrapper(run_linters, filenames):
|
def staging_wrapper(run_linters, filenames):
|
||||||
def time_gather(f):
|
def time_gather(f):
|
||||||
stats = os.stat(f)
|
stats = os.stat(f)
|
||||||
|
@ -375,11 +367,10 @@ def pick_stash_runner(cmdline):
|
||||||
os.utime(filename, timepair)
|
os.utime(filename, timepair)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def workspace_wrapper(run_linters, filenames):
|
def workspace_wrapper(run_linters, filenames):
|
||||||
return run_linters()
|
return run_linters()
|
||||||
|
|
||||||
return ('staging' in cmdline and staging_wrapper) or workspace_wrapper
|
|
||||||
|
|
||||||
|
|
||||||
# ___ _ _ _
|
# ___ _ _ _
|
||||||
# | _ \_ _ _ _ | (_)_ _| |_ _ __ __ _ ______
|
# | _ \_ _ _ _ | (_)_ _| |_ _ __ __ _ ______
|
||||||
|
@ -387,131 +378,87 @@ def pick_stash_runner(cmdline):
|
||||||
# |_|_\\_,_|_||_| |_|_|_||_\__| | .__/\__,_/__/__/
|
# |_|_\\_,_|_||_| |_|_|_||_\__| | .__/\__,_/__/__/
|
||||||
# |_|
|
# |_|
|
||||||
|
|
||||||
def run_external_linter(filename, linter, linter_name):
|
class Linter:
|
||||||
|
def __init__(linters, filenames):
|
||||||
"""Run one linter against one file.
|
self.linters = linters
|
||||||
|
self.filenames = filenames
|
||||||
If the result matches the error condition specified in the
|
|
||||||
configuration file, return the error code and messages, either
|
|
||||||
return nothing.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def encode_shell_messages(prefix, messages):
|
def encode_shell_messages(prefix, messages):
|
||||||
return ['{}{}'.format(prefix, line)
|
return ['{}{}'.format(prefix, line)
|
||||||
for line in messages.splitlines()]
|
for line in messages.splitlines()]
|
||||||
|
|
||||||
cmd = linter['command'] + ' "' + filename + '"'
|
@staticmethod
|
||||||
(out, err, returncode) = get_shell_response(cmd)
|
def run_external_linter(filename, linter, linter_name):
|
||||||
failed = ((out and (linter.get('condition', 'error') == 'output')) or err or (not (returncode == 0)))
|
"""Run one linter against one file.
|
||||||
trimmed_filename = filename.replace(git_base + '/', '', 1)
|
|
||||||
if not failed:
|
|
||||||
return (trimmed_filename, linter_name, 0, [])
|
|
||||||
|
|
||||||
prefix = (((linter.get('print', 'false').strip().lower() != 'true') and ' ')
|
If the result matches the error condition specified in the configuration file,
|
||||||
or ' {}: '.format(trimmed_filename))
|
return the error code and messages, either return nothing.
|
||||||
output = (encode_shell_messages(prefix, out) +
|
"""
|
||||||
((err and encode_shell_messages(prefix, err)) or []))
|
|
||||||
return (trimmed_filename, linter_name, (returncode or 1), output)
|
|
||||||
|
|
||||||
|
cmd = linter['command'] + ' "' + filename + '"'
|
||||||
def run_one_linter(linter, filenames):
|
(out, err, returncode) = get_shell_response(cmd)
|
||||||
""" Runs one linter against a set of files
|
failed = ((out and (linter.get('condition', 'error') == 'output')) or err or (not (returncode == 0)))
|
||||||
|
|
||||||
Creates a match filter for the linter, extract the files to be
|
|
||||||
linted, and runs the linter against each file, returning the
|
|
||||||
result as a list of successes and failures. Failures have a
|
|
||||||
return code and the output of the lint process.
|
|
||||||
"""
|
|
||||||
match_filter = make_match_filter([linter])
|
|
||||||
files = set([file for file in filenames if match_filter(file)])
|
|
||||||
return [run_external_linter(file, linter.linter, linter.name) for file in files]
|
|
||||||
|
|
||||||
|
|
||||||
def build_lint_runner(linters, filenames):
|
|
||||||
|
|
||||||
""" Returns a function to run a set of linters against a set of filenames
|
|
||||||
|
|
||||||
This returns a function because it's going to be wrapped in a
|
|
||||||
runner to better handle stashing and restoring a staged commit.
|
|
||||||
"""
|
|
||||||
def lint_runner():
|
|
||||||
return reduce(operator.add,
|
|
||||||
[run_one_linter(linter, filenames) for linter in linters], [])
|
|
||||||
return lint_runner
|
|
||||||
|
|
||||||
|
|
||||||
def dryrun(linters, filenames):
|
|
||||||
|
|
||||||
def dryrunonefile(filename, linter):
|
|
||||||
trimmed_filename = filename.replace(git_base + '/', '', 1)
|
trimmed_filename = filename.replace(git_base + '/', '', 1)
|
||||||
return (trimmed_filename, linter.name, 0, [' {}'.format(trimmed_filename)])
|
if not failed:
|
||||||
|
return (trimmed_filename, linter_name, 0, [])
|
||||||
def dryrunonce(linter, filenames):
|
|
||||||
match_filter = make_match_filter([linter])
|
prefix = (((linter.get('print', 'false').strip().lower() != 'true') and ' ')
|
||||||
files_to_check = [filename for filename in filenames if match_filter(filename)]
|
or ' {}: '.format(trimmed_filename))
|
||||||
return [dryrunonefile(filename, linter) for filename in files_to_check]
|
output = (encode_shell_messages(prefix, out) +
|
||||||
|
((err and encode_shell_messages(prefix, err)) or []))
|
||||||
return reduce(operator.add, [dryrunonce(linter, filenames) for linter in linters], [])
|
return (trimmed_filename, linter_name, (returncode or 1), output)
|
||||||
|
|
||||||
|
|
||||||
# __ __ _
|
@staticmethod
|
||||||
# | \/ |__ _(_)_ _
|
def run_one_linter(linter, filenames):
|
||||||
# | |\/| / _` | | ' \
|
""" Runs one linter against a set of files
|
||||||
# |_| |_\__,_|_|_||_|
|
|
||||||
#
|
Creates a match filter for the linter, extract the files to be
|
||||||
|
linted, and runs the linter against each file, returning the
|
||||||
def print_report(results, cmdline, unlintable_filenames, cant_lint_filenames,
|
result as a list of successes and failures. Failures have a
|
||||||
broken_linter_names, unfindable_filenames):
|
return code and the output of the lint process.
|
||||||
sort_position = 1
|
"""
|
||||||
grouping = 'Linter: {}'
|
match_filter = make_match_filter([linter])
|
||||||
if 'byfile' in cmdline:
|
files = set([filename for filename in filenames if match_filter(filename)])
|
||||||
sort_position = 0
|
return [self.run_external_linter(filename, linter.linter, linter.name) for filename in files]
|
||||||
grouping = 'Filename: {}'
|
|
||||||
grouped_results = group_by(results, sort_position)
|
|
||||||
for group in grouped_results:
|
|
||||||
print(grouping.format(group[0]))
|
|
||||||
for (filename, lintername, returncode, text) in group[1]:
|
|
||||||
print("\n".join(text))
|
|
||||||
print("")
|
|
||||||
if len(broken_linter_names):
|
|
||||||
print("These linters could not be run:", ",".join(broken_linter_names))
|
|
||||||
if len(cant_lint_filenames):
|
|
||||||
print("As a result, these files were not linted:")
|
|
||||||
print("\n".join([" {}".format(f) for f in cant_lint_filenames]))
|
|
||||||
if len(unlintable_filenames):
|
|
||||||
print("The following files had no recognizeable linters:")
|
|
||||||
print("\n".join([" {}".format(f) for f in unlintable_filenames]))
|
|
||||||
if len(unfindable_filenames):
|
|
||||||
print("The following files could not be found:")
|
|
||||||
print("\n".join([" {}".format(f) for f in unfindable_filenames]))
|
|
||||||
|
|
||||||
|
|
||||||
|
def __call__(self, linters, filenames):
|
||||||
|
""" Returns a function to run a set of linters against a set of filenames
|
||||||
|
|
||||||
|
This returns a function because it's going to be wrapped in a
|
||||||
|
runner to better handle stashing and restoring a staged commit.
|
||||||
|
"""
|
||||||
|
return reduce(operator.add,
|
||||||
|
[run_one_linter(linter, self.filenames) for linter in self.linters], [])
|
||||||
|
|
||||||
|
|
||||||
def print_help(options_list, name):
|
def dryrun(self):
|
||||||
print(_('Usage: {} [options] [filenames]').format(name))
|
|
||||||
for item in options_list:
|
def dryrunonefile(filename, linter):
|
||||||
print(' -{:<1} --{:<12} {}'.format(item[0], item[1], item[3]))
|
trimmed_filename = filename.replace(git_base + '/', '', 1)
|
||||||
return sys.exit()
|
return (trimmed_filename, linter.name, 0, [' {}'.format(trimmed_filename)])
|
||||||
|
|
||||||
|
def dryrunonce(linter, filenames):
|
||||||
|
match_filter = MatchFilter([linter])
|
||||||
|
files_to_check = [filename for filename in filenames if match_filter(filename)]
|
||||||
|
return [dryrunonefile(filename, linter) for filename in files_to_check]
|
||||||
|
|
||||||
|
return reduce(operator.add, [dryrunonce(linter, self.filenames) for linter in self.linters], [])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def print_version(name, version):
|
def run_linters(options, config, extras):
|
||||||
print('{} {} Copyright (c) 2009, 2016 Kennth M. "Elf" Sternberg'.format(name, version))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def run_gitlint(cmdline, config, extras):
|
|
||||||
|
|
||||||
def build_config_subset(keys):
|
def build_config_subset(keys):
|
||||||
""" Returns a subset of the configuration, with only those linters mentioned in keys """
|
""" Returns a subset of the configuration, with only those linters mentioned in keys """
|
||||||
return [item for item in config if item.name in keys]
|
return [item for item in config if item.name in keys]
|
||||||
|
|
||||||
""" Runs the requested linters """
|
""" Runs the requested linters """
|
||||||
all_filenames, unfindable_filenames = get_filelist(cmdline, extras)
|
all_filenames, unfindable_filenames = get_filelist(options, extras)
|
||||||
|
|
||||||
stash_runner = pick_stash_runner(cmdline)
|
is_lintable = MatchFilter(config)
|
||||||
|
|
||||||
is_lintable = make_match_filter(config)
|
|
||||||
|
|
||||||
lintable_filenames = set([filename for filename in all_filenames
|
lintable_filenames = set([filename for filename in all_filenames
|
||||||
if is_lintable(filename)])
|
if is_lintable(filename)])
|
||||||
|
@ -520,26 +467,23 @@ def run_gitlint(cmdline, config, extras):
|
||||||
|
|
||||||
working_linter_names, broken_linter_names = get_linter_status(config)
|
working_linter_names, broken_linter_names = get_linter_status(config)
|
||||||
|
|
||||||
cant_lint_filter = make_match_filter(build_config_subset(
|
cant_lint_filter = MatchFilter(build_config_subset(
|
||||||
broken_linter_names))
|
broken_linter_names))
|
||||||
|
|
||||||
cant_lint_filenames = [filename for filename in lintable_filenames
|
cant_lint_filenames = [filename for filename in lintable_filenames
|
||||||
if cant_lint_filter(filename)]
|
if cant_lint_filter(filename)]
|
||||||
|
|
||||||
if 'dryrun' in cmdline:
|
if 'dryrun' in options:
|
||||||
return print_report(
|
dryrun_results = dryrun(
|
||||||
dryrun(
|
build_config_subset(working_linter_names), sorted(lintable_filenames))
|
||||||
build_config_subset(working_linter_names), sorted(lintable_filenames)),
|
return (dryrun_results, unlintable_filenames, cant_lint_filenames,
|
||||||
cmdline, unlintable_filenames, cant_lint_filenames,
|
broken_linter_names, unfindable_filenames)
|
||||||
|
|
||||||
|
runner = Runner(options)
|
||||||
|
linter = Linter(build_config_subset(working_linter_names),
|
||||||
|
sorted(lintable_filenames))
|
||||||
|
results = runner(linter, lintable_filenames)
|
||||||
|
|
||||||
|
return (results, unlintable_filenames, cant_lint_filenames,
|
||||||
broken_linter_names, unfindable_filenames)
|
broken_linter_names, unfindable_filenames)
|
||||||
|
|
||||||
lint_runner = build_lint_runner(
|
|
||||||
build_config_subset(working_linter_names), sorted(lintable_filenames))
|
|
||||||
|
|
||||||
results = stash_runner(lint_runner, lintable_filenames)
|
|
||||||
|
|
||||||
print_report(results, cmdline, unlintable_filenames, cant_lint_filenames,
|
|
||||||
broken_linter_names, unfindable_filenames)
|
|
||||||
if not len(results):
|
|
||||||
return 0
|
|
||||||
return max([i[2] for i in results if len(i)])
|
|
||||||
|
|
|
@ -6,8 +6,17 @@
|
||||||
|
|
||||||
# This was a lot shorter and smarter in Hy...
|
# This was a lot shorter and smarter in Hy...
|
||||||
|
|
||||||
|
# A lot of what you see here is separated from git_lint itself, since this will not be
|
||||||
|
# relevant to the operation of pre-commit.
|
||||||
|
|
||||||
def make_rational_options(options, commandline):
|
# ___ _ _ _
|
||||||
|
# / __|___ _ __ _ __ __ _ _ _ __| | | | (_)_ _ ___
|
||||||
|
# | (__/ _ \ ' \| ' \/ _` | ' \/ _` | | |__| | ' \/ -_)
|
||||||
|
# \___\___/_|_|_|_|_|_\__,_|_||_\__,_| |____|_|_||_\___|
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_options(options, commandline):
|
||||||
"""Takes a table of options and the commandline, and returns a
|
"""Takes a table of options and the commandline, and returns a
|
||||||
dictionary of those options that appear on the commandline
|
dictionary of those options that appear on the commandline
|
||||||
along with any extra arguments.
|
along with any extra arguments.
|
||||||
|
@ -19,7 +28,7 @@ def make_rational_options(options, commandline):
|
||||||
The arguments as received by the start-up process
|
The arguments as received by the start-up process
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def make_options_rationalizer(options):
|
def make_option_streamliner(options):
|
||||||
|
|
||||||
"""Takes a list of option tuples, and returns a function that takes
|
"""Takes a list of option tuples, and returns a function that takes
|
||||||
the output of getopt and reduces it to the longopt key and
|
the output of getopt and reduces it to the longopt key and
|
||||||
|
@ -28,17 +37,16 @@ def make_rational_options(options, commandline):
|
||||||
|
|
||||||
fullset = {}
|
fullset = {}
|
||||||
for option in options:
|
for option in options:
|
||||||
if not option[1]:
|
if option[1]:
|
||||||
continue
|
fullset['--' + option[1]] = option[1]
|
||||||
if option[0]:
|
if option[0]:
|
||||||
fullset['-' + option[0]] = option[1]
|
fullset['-' + option[0]] = option[1]
|
||||||
fullset['--' + option[1]] = option[1]
|
|
||||||
|
|
||||||
def rationalizer(acc, it):
|
def streamliner(acc, it):
|
||||||
acc[fullset[it[0]]] = it[1]
|
acc[fullset[it[0]]] = it[1]
|
||||||
return acc
|
return acc
|
||||||
|
|
||||||
return rationalizer
|
return streamliner
|
||||||
|
|
||||||
def remove_conflicted_options(options, request):
|
def remove_conflicted_options(options, request):
|
||||||
"""Takes our list of option tuples, and a cleaned copy of what was
|
"""Takes our list of option tuples, and a cleaned copy of what was
|
||||||
|
@ -68,10 +76,10 @@ def make_rational_options(options, commandline):
|
||||||
optstringslong)
|
optstringslong)
|
||||||
|
|
||||||
# Turns what getopt returns into something more human-readable
|
# Turns what getopt returns into something more human-readable
|
||||||
rationalize_options = make_options_rationalizer(options)
|
streamline_options = make_option_streamliner(options)
|
||||||
|
|
||||||
# Remove any options that are superseded by others.
|
# Remove any options that are superseded by others.
|
||||||
(retoptions, excluded) = remove_conflicted_options(
|
(ret, excluded) = remove_conflicted_options(
|
||||||
optlist, reduce(rationalize_options, options, {}))
|
optlist, reduce(streamline_options, options, {}))
|
||||||
|
|
||||||
return (retoptions, filenames, excluded)
|
return (ret, filenames, excluded)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import gettext
|
||||||
|
_ = gettext.gettext
|
||||||
|
|
||||||
OPTIONS_LIST = [
|
OPTIONS = [
|
||||||
('o', 'only', True,
|
('o', 'only', True,
|
||||||
_('A comma-separated list of only those linters to run'), ['exclude']),
|
_('A comma-separated list of only those linters to run'), ['exclude']),
|
||||||
('x', 'exclude', True,
|
('x', 'exclude', True,
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import gettext
|
||||||
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
def print_report(results, unlintable_filenames, cant_lint_filenames,
|
||||||
|
broken_linter_names, unfindable_filenames, options = {'bylinter': True}):
|
||||||
|
sort_position = 1
|
||||||
|
grouping = _('Linter: {}')
|
||||||
|
if 'byfile' in options:
|
||||||
|
sort_position = 0
|
||||||
|
grouping = _('Filename: {}')
|
||||||
|
grouped_results = group_by(results, sort_position)
|
||||||
|
for group in grouped_results:
|
||||||
|
print(grouping.format(group[0]))
|
||||||
|
for (filename, lintername, returncode, text) in group[1]:
|
||||||
|
print('\n'.join(text))
|
||||||
|
print('')
|
||||||
|
if len(broken_linter_names):
|
||||||
|
print(_('These linters could not be run:'), ','.join(broken_linter_names))
|
||||||
|
if len(cant_lint_filenames):
|
||||||
|
print(_('As a result, these files were not linted:'))
|
||||||
|
print('\n'.join([' {}'.format(f) for f in cant_lint_filenames]))
|
||||||
|
if len(unlintable_filenames):
|
||||||
|
print(_('The following files had no recognizeable linters:'))
|
||||||
|
print('\n'.join([' {}'.format(f) for f in unlintable_filenames]))
|
||||||
|
if len(unfindable_filenames):
|
||||||
|
print(_('The following files could not be found:'))
|
||||||
|
print('\n'.join([' {}'.format(f) for f in unfindable_filenames]))
|
||||||
|
|
||||||
|
|
||||||
|
def print_help(options, name):
|
||||||
|
print(_('Usage: {} [options] [filenames]').format(name))
|
||||||
|
for item in options:
|
||||||
|
print(' -{:<1} --{:<12} {}'.format(item[0], item[1], item[3]))
|
||||||
|
return sys.exit()
|
||||||
|
|
||||||
|
|
||||||
|
def print_version(name, version):
|
||||||
|
print(_'{} {} Copyright (c) 2009, 2016 Kennth M. "Elf" Sternberg').format(name, version))
|
||||||
|
|
||||||
|
|
||||||
|
def print_linters(working_linter_names, broken_linter_names):
|
||||||
|
print(_('Currently supported linters:'))
|
||||||
|
for linter in config:
|
||||||
|
print('{:<14} {}'.format(linter.name,
|
||||||
|
((linter.name in broken_linter_names and
|
||||||
|
_('(WARNING: executable not found)') or
|
||||||
|
linter.linter.get('comment', '')))))
|
||||||
|
|
||||||
|
|
18
setup.py
18
setup.py
|
@ -23,13 +23,13 @@ test_requirements = [
|
||||||
]
|
]
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='git_lint',
|
name='git_linter',
|
||||||
version='0.0.2',
|
version='0.0.4',
|
||||||
description="A git command to lint everything in your workspace (or stage) that was changed since the last commit.",
|
description="A git command to lint everything in your workspace (or stage) that was changed since the last commit.",
|
||||||
long_description=readme + '\n\n' + history,
|
long_description=readme + '\n\n' + history,
|
||||||
author="Kenneth M. "Elf" Sternberg",
|
author='Kenneth M. "Elf" Sternberg',
|
||||||
author_email='elf.sternberg@gmail.com',
|
author_email='elf.sternberg@gmail.com',
|
||||||
url='https://github.com/elfsternberg/git_lint',
|
url='https://github.com/elfsternberg/git_linter',
|
||||||
packages=[
|
packages=[
|
||||||
'git_lint',
|
'git_lint',
|
||||||
],
|
],
|
||||||
|
@ -37,16 +37,20 @@ setup(
|
||||||
'git_lint'},
|
'git_lint'},
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
license="ISCL",
|
license="MIT",
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
keywords='git_lint',
|
keywords='git lint style syntaxt development',
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'git-lint = git_lint.__main__:main'
|
||||||
|
]
|
||||||
|
},
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 2 - Pre-Alpha',
|
'Development Status :: 2 - Pre-Alpha',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: ISC License (ISCL)',
|
'License :: OSI Approved :: ISC License (ISCL)',
|
||||||
'Natural Language :: English',
|
'Natural Language :: English',
|
||||||
"Programming Language :: Python :: 2",
|
"Programming Language :: Python :: 2",
|
||||||
'Programming Language :: Python :: 2.6',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.3',
|
'Programming Language :: Python :: 3.3',
|
||||||
|
|
Loading…
Reference in New Issue