mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 14:43:55 +08:00
Update littlecheck
This allows: - Running scripts via shebang (not important here) - Progress output (so we can ditch more of our run script) - Context (only after, for now) - this is important if there is a test failure
This commit is contained in:
parent
d910bada82
commit
25810b70f2
|
@ -27,6 +27,10 @@ class Config(object):
|
|||
self.verbose = False
|
||||
# Whether output gets ANSI colorization.
|
||||
self.colorize = False
|
||||
# Whether to show which file was tested.
|
||||
self.progress = False
|
||||
# How many after lines to print
|
||||
self.after = 5
|
||||
|
||||
def colors(self):
|
||||
""" Return a dictionary mapping color names to ANSI escapes """
|
||||
|
@ -112,13 +116,16 @@ class RunCmd(object):
|
|||
|
||||
|
||||
class TestFailure(object):
|
||||
def __init__(self, line, check, testrun):
|
||||
def __init__(self, line, check, testrun, after = None):
|
||||
self.line = line
|
||||
self.check = check
|
||||
self.testrun = testrun
|
||||
self.error_annotation_line = None
|
||||
# The output that comes *after* the failure.
|
||||
self.after = after
|
||||
|
||||
def message(self):
|
||||
afterlines = self.testrun.config.after
|
||||
fields = self.testrun.config.colors()
|
||||
fields["name"] = self.testrun.name
|
||||
fields["subbed_command"] = self.testrun.subbed_command
|
||||
|
@ -139,7 +146,8 @@ class TestFailure(object):
|
|||
"check_type": self.check.type,
|
||||
}
|
||||
)
|
||||
fmtstrs = ["{RED}Failure{RESET} in {name}:", ""]
|
||||
filemsg = "" if self.testrun.config.progress else " in {name}"
|
||||
fmtstrs = ["{RED}Failure{RESET}" + filemsg + ":", ""]
|
||||
if self.line and self.check:
|
||||
fmtstrs += [
|
||||
" The {check_type} on line {input_lineno} wants:",
|
||||
|
@ -171,6 +179,12 @@ class TestFailure(object):
|
|||
" additional output on stderr:{error_annotation_lineno}:",
|
||||
" {BOLD}{error_annotation}{RESET}",
|
||||
]
|
||||
if self.after:
|
||||
fields["additional_output"] = " ".join(self.after[:afterlines])
|
||||
fmtstrs += [
|
||||
" additional output:",
|
||||
" {BOLD}{additional_output}{RESET}",
|
||||
]
|
||||
fmtstrs += [" when running command:", " {subbed_command}"]
|
||||
return "\n".join(fmtstrs).format(**fields)
|
||||
|
||||
|
@ -194,7 +208,9 @@ def perform_substitution(input_str, subs):
|
|||
for key, replacement in subs_ordered:
|
||||
if text.startswith(key):
|
||||
return replacement + text[len(key) :]
|
||||
raise CheckerError("Unknown substitution: " + m.group(0))
|
||||
# No substitution found, so we default to running it as-is,
|
||||
# which will end up running it via $PATH.
|
||||
return text
|
||||
|
||||
return re.sub(r"%(%|[a-zA-Z0-9_-]+)", subber, input_str)
|
||||
|
||||
|
@ -224,7 +240,9 @@ class TestRun(object):
|
|||
lineq.pop()
|
||||
else:
|
||||
# Failed to match.
|
||||
return TestFailure(line, check, self)
|
||||
lineq.pop()
|
||||
# Add context, ignoring empty lines.
|
||||
return TestFailure(line, check, self, after = [line.text for line in lineq[::-1] if not line.is_empty_space()])
|
||||
# Drain empties.
|
||||
while lineq and lineq[-1].is_empty_space():
|
||||
lineq.pop()
|
||||
|
@ -258,6 +276,13 @@ class TestRun(object):
|
|||
close_fds=True, # For Python 2.6 as shipped on RHEL 6
|
||||
)
|
||||
stdout, stderr = proc.communicate()
|
||||
# HACK: This is quite cheesy: POSIX specifies that sh should return 127 for a missing command.
|
||||
# Technically it's also possible to return it in other conditions.
|
||||
# Practically, that's *probably* not going to happen.
|
||||
status = proc.returncode
|
||||
if status == 127:
|
||||
raise CheckerError("Command could not be found: " + self.subbed_command)
|
||||
|
||||
outlines = [
|
||||
Line(text, idx + 1, "stdout")
|
||||
for idx, text in enumerate(split_by_newlines(stdout))
|
||||
|
@ -343,7 +368,12 @@ class Checker(object):
|
|||
# Find run commands.
|
||||
self.runcmds = [RunCmd.parse(sl) for sl in group1s(RUN_RE)]
|
||||
if not self.runcmds:
|
||||
raise CheckerError("No runlines ('# RUN') found")
|
||||
# If no RUN command has been given, fall back to the shebang.
|
||||
if lines[0].text.startswith("#!"):
|
||||
# Remove the "#!" at the beginning, and the newline at the end.
|
||||
self.runcmds = [RunCmd(lines[0].text[2:-1] + " %s", lines[0])]
|
||||
else:
|
||||
raise CheckerError("No runlines ('# RUN') found")
|
||||
|
||||
# Find check cmds.
|
||||
self.outchecks = [
|
||||
|
@ -406,7 +436,22 @@ def get_argparse():
|
|||
action="append",
|
||||
default=[],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--progress",
|
||||
action='store_true',
|
||||
dest='progress',
|
||||
help="Show the files to be checked",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument("file", nargs="+", help="File to check")
|
||||
parser.add_argument(
|
||||
"-A", "--after",
|
||||
type=int,
|
||||
help="How many non-empty lines of output after a failure to print (default: 5)",
|
||||
action="store",
|
||||
default=5,
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
|
@ -419,11 +464,19 @@ def main():
|
|||
success = True
|
||||
config = Config()
|
||||
config.colorize = sys.stdout.isatty()
|
||||
config.progress = args.progress
|
||||
fields = config.colors()
|
||||
config.after = args.after
|
||||
for path in args.file:
|
||||
fields["path"] = path
|
||||
if config.progress:
|
||||
print("Testing file {path} ... ".format(**fields), end='')
|
||||
subs = def_subs.copy()
|
||||
subs["s"] = path
|
||||
if not check_path(path, subs, config, TestFailure.print_message):
|
||||
success = False
|
||||
elif config.progress:
|
||||
print("{GREEN}ok{RESET}".format(**fields))
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user