108 lines
4.2 KiB
Python
108 lines
4.2 KiB
Python
# Copyright (C) 2015 Elf M. Sternberg
|
|
# Author: Elf M. Sternberg
|
|
|
|
from functools import reduce
|
|
from collections import namedtuple
|
|
import getopt
|
|
|
|
try: # noqa: F401
|
|
from typing import Dict, List, Text, Any, Optional, Union, Callable, Tuple # noqa: F401
|
|
except: # noqa: F401
|
|
pass # noqa: F401
|
|
|
|
|
|
Option = namedtuple('Option', ['short', 'long', 'takes', 'help', 'conflicts']) # type: str, str, str, str, List[str]
|
|
Arguments = namedtuple('Arguments', ['arguments', 'filenames', 'excluded']) # type: Dict[str, str], List[str], List[str]
|
|
|
|
# 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 cleanup_options(options, commandline):
|
|
# type: (List[Option], List[str]) -> Arguments
|
|
"""Takes a table of options and the commandline, and returns a
|
|
dictionary of those options that appear on the commandline
|
|
along with any extra arguments.
|
|
|
|
:param List(Tuple (string, string, boolean, string, List(string))) options,
|
|
The table of options: One-letter option, long option, takes arguments,
|
|
Help text, list of (long) options superseded by this one.
|
|
|
|
: param List(strings) commandline
|
|
The arguments as received by the start-up process
|
|
|
|
: returns List(strings), List(strings), List(strings)
|
|
The longopt dictionary of arguments and associated values (if any)
|
|
The list of filenames left after argument processing
|
|
The longopt list of arguments that were excluded by argument precedence
|
|
"""
|
|
|
|
def make_option_streamliner(options):
|
|
# type: (List[Option]) -> Callable[[Dict[str, str], Option], Dict[str, str]]
|
|
|
|
"""Takes a list of option tuples, and returns a function that takes
|
|
the output of getopt and reduces it to the longopt key and
|
|
associated values as a dictionary.
|
|
"""
|
|
|
|
fullset = {} # type: Dict[str, str]
|
|
for option in options:
|
|
if option.long:
|
|
fullset['--' + option.long] = option.long
|
|
if option.short:
|
|
fullset['-' + option.short] = option.long
|
|
|
|
def streamliner(acc, it):
|
|
# type: (Dict[str, str], Option) -> Dict[str, str]
|
|
acc[fullset[it[0]]] = it[1]
|
|
return acc
|
|
|
|
return streamliner
|
|
|
|
def remove_conflicted_options(options, request):
|
|
# type: (List[Option], Dict[str, str]) -> Tuple[List[str], List[str]]
|
|
"""Takes our list of option tuples, and a cleaned copy of what was
|
|
requested from getopt, and returns a copy of the request
|
|
without any options that are marked as superseded, along with
|
|
the list of superseded options
|
|
"""
|
|
def get_excluded_keys(memo, option):
|
|
return memo + option.conflicts
|
|
|
|
keys = request.keys()
|
|
marked = [option for option in options if option.long in keys]
|
|
exclude = reduce(get_excluded_keys, marked, [])
|
|
excluded = [key for key in keys if key in exclude]
|
|
cleaned = {key: request[key] for key in keys
|
|
if key not in excluded}
|
|
return (cleaned, excluded)
|
|
|
|
def shortoptstogo(i):
|
|
return i.short + ((i.takes and ':') or '')
|
|
|
|
def longoptstogo(i):
|
|
return i.long + ((i.takes and '=') or '')
|
|
|
|
optstringsshort = ''.join([shortoptstogo(opt) for opt in options if opt.short])
|
|
optstringslong = [longoptstogo(opt) for opt in options]
|
|
(chosen_options, filenames) = getopt.getopt(commandline[1:],
|
|
optstringsshort,
|
|
optstringslong)
|
|
|
|
# Turns what getopt returns into something more human-readable
|
|
streamline_options = make_option_streamliner(options)
|
|
|
|
# Remove any options that are superseded by others.
|
|
(ret, excluded) = remove_conflicted_options(
|
|
options, reduce(streamline_options, chosen_options, {}))
|
|
|
|
return Arguments(ret, filenames, excluded)
|