| #!/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() |