| #!/usr/bin/env python | |
| # Overview | |
| # -------- | |
| # This is a centralized script for running VTR. | |
| # | |
| # It wraps various other scripts for running VTR and parses the results | |
| # into sub-commands. | |
| # This provides a straight forward interface based on sub-commands | |
| # (like 'git commit'). | |
| # | |
| # Run as 'vtr help' for usage. | |
| # Adding Sub-commands | |
| # ---------------------- | |
| # Each sub-command is a stand-alone python script which is loaded by | |
| # this script at run-time. | |
| # | |
| # To add a new sub-command simply create a file named: | |
| # | |
| # vtr-{command}.py | |
| # | |
| # located under: | |
| # | |
| # $VTR_ROOT/vtr_flow/scripts | |
| # | |
| # where {command} is the command name. | |
| # | |
| # For example the 'flow' command is implemented in the file: | |
| # | |
| # $VTR_ROOT/vtr_flow/scripts/vtr-flow.py | |
| # | |
| # Each command script is expected to implement the following two methods: | |
| # | |
| # def vtr_command_argparser(prog=None): | |
| # #Setup the argument parser | |
| # #... | |
| # return argparser | |
| # and | |
| # | |
| # def vtr_command_main(arg_list, prog=None): | |
| # args = vtr_command_argparser(prog).parse_args(arg_list) | |
| # | |
| # #Do something useful, based on args | |
| # #... | |
| # | |
| # vtr_command_argparser() takes the program name as it's first argument and returns | |
| # the argparse.ArgumentParser used by the command (this is used to implement the 'help' | |
| # subcommand). | |
| # | |
| # vtr_command_main() takes the list of command line arguments and the program name | |
| # and executes the command | |
| import argparse | |
| import sys | |
| import os | |
| import textwrap | |
| import importlib | |
| from fnmatch import fnmatch | |
| from collections import OrderedDict | |
| def determine_vtr_root(): | |
| """ | |
| Returns the root of the VTR source tree as determined by: | |
| 1. The VTR_ROOT environment variable, if set otherwise | |
| 2. The location of this script file | |
| """ | |
| if 'VTR_ROOT' in os.environ: | |
| return os.environ['VTR_ROOT'] | |
| else: | |
| #Infer from the directory containing this script file | |
| return os.path.dirname(os.path.abspath(__file__)) | |
| def import_vtr_commands(vtr_root): | |
| """ | |
| Loads the vtr-*.py scripts from $VTR_ROOT/vtr_flow/scripts as modules | |
| Returns a dictionary mapping from the command name to it's module | |
| """ | |
| unordered_commands = {} | |
| vtr_command_dir = os.path.join(vtr_root, "vtr_flow", "scripts") | |
| sys.path.insert(0, vtr_command_dir) | |
| for file in os.listdir(vtr_command_dir): | |
| if fnmatch(file, "vtr-*.py"): | |
| command_base, ext = os.path.splitext(file) | |
| command_name = command_base.split('-', 1)[1] | |
| unordered_commands[command_name] = importlib.import_module(command_base) | |
| #Re-build the command dictionary in preferred order, this ensures | |
| #the preferred (i.e. common) commands appear first in the help | |
| commands = OrderedDict() | |
| for command_name in ["flow", "task"]: | |
| if command_name in unordered_commands: | |
| commands[command_name] = unordered_commands[command_name] | |
| del unordered_commands[command_name] | |
| for command_name, module in unordered_commands.iteritems(): | |
| commands[command_name] = module | |
| return commands | |
| VTR_ROOT = determine_vtr_root() | |
| sys.path.insert(0, os.path.join(VTR_ROOT, 'vtr_flow', 'scripts', 'python_libs')) #For verilogtorouting module | |
| from verilogtorouting.util import RawDefaultHelpFormatter | |
| VTR_COMMANDS = import_vtr_commands(VTR_ROOT) | |
| def argument_parser(vtr_commands): | |
| main_description = textwrap.dedent( | |
| """ | |
| Script for running the Verilog-to-Routing design flow, | |
| conducting experiments and collecting results. | |
| """ | |
| ) | |
| main_epilog = textwrap.dedent( | |
| """ | |
| Examples | |
| -------- | |
| Get help with the 'flow' subcommand: | |
| %(prog)s help flow | |
| Run the standard design flow for a single architecture and circuit | |
| %(prog)s flow arch.xml circuit.v | |
| Run a VTR task named 'my_task' | |
| %(prog)s task my_task | |
| """ | |
| ) | |
| parser = argparse.ArgumentParser(description=main_description, | |
| epilog=main_epilog, | |
| formatter_class=RawDefaultHelpFormatter | |
| ) | |
| subparsers = parser.add_subparsers(title='VTR subcommands', | |
| #help="VTR subcommands", | |
| dest="command") | |
| help_description = textwrap.dedent( | |
| """ | |
| Get help with subcommands | |
| """ | |
| ) | |
| help_epilog = textwrap.dedent( | |
| """ | |
| Examples | |
| -------- | |
| Get help with the 'flow' subcommand: | |
| %(prog)s flow | |
| Get help with the 'task' subcommand: | |
| %(prog)s task | |
| """ | |
| ) | |
| help_parser = subparsers.add_parser('help', | |
| description=help_description, | |
| help=help_description, | |
| epilog=help_epilog, | |
| formatter_class=RawDefaultHelpFormatter) | |
| help_parser.add_argument("sub_command", | |
| nargs="?", | |
| help="Sub-command to get help with") | |
| for command, module in vtr_commands.iteritems(): | |
| if not hasattr(module, "vtr_command_argparser"): | |
| raise AttributeError("VTR command '{}' is missing required function '{}'".format(command, "vtr_command_argparser")) | |
| else: | |
| description = module.vtr_command_argparser().description | |
| subparsers.add_parser(command, | |
| add_help=False, #Show full usage if -h supplied | |
| help=module.vtr_command_argparser().description) | |
| return parser, help_parser | |
| def main(): | |
| parser, help_parser = argument_parser(VTR_COMMANDS) | |
| #Parse the subcommand. Any unkown arguments are passed to the subcommand. | |
| args, unkown_args = parser.parse_known_args() | |
| #The effective program being executed (used to make help messages consistent) | |
| prog = "{} {}".format(os.path.basename(sys.argv[0]), args.command) | |
| if args.command == "help": | |
| if not args.sub_command: | |
| #This script's help | |
| parser.print_help() | |
| elif args.sub_command == "help": | |
| help_parser.print_help() | |
| elif args.sub_command in VTR_COMMANDS: | |
| #Show the sub-command in the help output | |
| help_prog = "{} {}".format(os.path.basename(sys.argv[0]), args.sub_command) | |
| if not hasattr(VTR_COMMANDS[args.sub_command], "vtr_command_argparser"): | |
| raise AttributeError("VTR command '{}' is missing required function '{}'".format(args.sub_command, "vtr_command_argparser")) | |
| else: | |
| cmd_parser = VTR_COMMANDS[args.sub_command].vtr_command_argparser(help_prog) | |
| cmd_parser.print_help() | |
| else: | |
| print "Unrecognized help subcommand {}".format(args.sub_command) | |
| parser.print_help() | |
| sys.exit(1) | |
| elif args.command in VTR_COMMANDS: | |
| #Run the appropraite command | |
| if not hasattr(VTR_COMMANDS[args.command], "vtr_command_main"): | |
| raise AttributeError("VTR command '{}' is missing required function '{}'".format(args.command, vtr_command_main)) | |
| else: | |
| VTR_COMMANDS[args.command].vtr_command_main(unkown_args, prog=prog) | |
| else: | |
| print "Unrecognized subcommand {}".format(args.help_for_command) | |
| parser.print_help() | |
| sys.exit(1) | |
| sys.exit(0) | |
| if __name__ == "__main__": | |
| main() |