Skip to content

Instantly share code, notes, and snippets.

@cmin764
Last active August 29, 2015 14:06
Show Gist options
  • Select an option

  • Save cmin764/463fd28607d0079a46c5 to your computer and use it in GitHub Desktop.

Select an option

Save cmin764/463fd28607d0079a46c5 to your computer and use it in GitHub Desktop.
A proof of concept for the powershell checker based on wispy.
#! /usr/bin/env python3
# pylint: disable=missing-docstring, star-args, no-self-use
import re
import argparse
from wispy import grammar, builder, tree
def to_underscore(string):
new_string = []
for char in string:
if char.isupper():
char = char.lower()
new_string.append("_")
new_string.append(char)
return "".join(new_string).strip("_")
def flatten_tree(node):
for child in node.get_children():
if not isinstance(child, list):
child = [child]
for part in child:
yield part
if isinstance(part, tree.Node):
yield from flatten_tree(part)
class Checker(object):
MESSAGES = {
"improper-function-name": (
"the function {!r} isn't properly named",
"Functions names should consist of a verb-noun pair "
"in which the verb identifies the action that the "
"function performs and the noun identifies the "
"item on which the cmdlet performs its action."
)
}
def __init__(self, root):
func = lambda arg: isinstance(arg, tree.Node)
self.nodes = list(filter(func, flatten_tree(root)))
def emit(self, message, args=()):
text = Checker.MESSAGES[message][0]
text = text.format(*args)
print("{}: {}".format(message, text))
def generic_visit(self, node):
if node is None:
return
cls = node.__class__.__name__.replace("<", "").replace(">", "")
visit_name = 'visit_' + to_underscore(cls)
visit_method = getattr(self, visit_name, None)
if visit_method:
return visit_method(node)
def visit_function_statement(self, node):
function_name = node.name.value
pattern = r"[A-Z][A-Za-z]*-[A-Z][A-Za-z]*"
if not re.match(pattern, function_name):
self.emit("improper-function-name", args=(function_name,))
def check(self):
for node in self.nodes:
self.generic_visit(node)
def file_check(file_object):
# parse file and obtain the grammar
with file_object:
node = grammar.ScriptBlock.parser().parse_text(
file_object.read().strip(),
eof=True,
matchtype="complete"
)
# build AST tree
ast_tree = builder.build_tree(node)
# check it
checker = Checker(ast_tree)
checker.check()
def main():
parser = argparse.ArgumentParser(description="Check powershell scripts.")
group = parser.add_mutually_exclusive_group()
group.add_argument("-f", "--file", metavar="FILE",
type=argparse.FileType("r"),
help="path to file")
group.add_argument("-m", "--help-msg", metavar="MESSAGE",
help="show full description of the given message")
args = parser.parse_args()
if args.help_msg:
full = Checker.MESSAGES[args.help_msg]
print(full[1])
else:
if not hasattr(args, "file") or not args.file:
parser.error("no file specified")
file_check(args.file)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment