Chromium Code Reviews| Index: infra/tools/new_tool/new_tool.py |
| diff --git a/infra/tools/new_tool/new_tool.py b/infra/tools/new_tool/new_tool.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1b29fca5366ca07afecfd7dc21f7890d086d155f |
| --- /dev/null |
| +++ b/infra/tools/new_tool/new_tool.py |
| @@ -0,0 +1,195 @@ |
| +# Copyright 2015 The Chromium Authors. All rights reserved. |
|
Ryan Tseng
2015/06/09 23:03:05
I think i'd prefer a filename.template file with a
|
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +import argparse |
| +import datetime |
| +import os |
| +import sys |
| +import textwrap |
| + |
| +# infra subdirectory containing tools. |
| +TOOL_DIR = os.path.dirname(os.path.dirname(__file__)) |
| + |
| + |
| +COPYRIGHT_NOTICE = """\ |
| +# Copyright %s The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| +""" % datetime.datetime.now().strftime('%Y') |
| + |
| + |
| +def add_argparse_options(parser): |
| + parser.add_argument( |
| + 'name', metavar='name', type=str, nargs=1, |
| + help='The name of the new tool.') |
| + |
| + parser.add_argument('--base-dir', default=TOOL_DIR, |
| + help='Directory where to create the tool. Default: ' |
| + '%(default)s') |
| + |
| + |
| +def generate_init_file(dirpath): |
| + """Generate a __init__.py file in the specified directory.""" |
| + |
| + init_file_path = os.path.join(dirpath, '__init__.py') |
| + if os.path.isfile(init_file_path): |
| + print 'Skipping existing file %s' % init_file_path |
| + return |
| + |
| + with open(init_file_path, 'w') as f: |
| + f.write(COPYRIGHT_NOTICE) |
| + |
| + |
| +def generate_main_file(dirpath, toolname): |
| + """Generate a __main__.py file in the specified directory.""" |
| + main_file_path = os.path.join(dirpath, '__main__.py') |
| + if os.path.isfile(main_file_path): |
| + print 'Skipping existing file %s' % main_file_path |
| + return |
| + |
| + MAIN_CONTENT = textwrap.dedent(""" |
| + \"\"\"<General description of {Toolname} here.> |
| + |
| + [TBD] Example invocation: |
| + ./run.py infra.tools.{toolname} <arguments> |
| + \"\"\" |
| + |
| + # This file is untested, keep as little code as possible in there. |
| + |
| + import argparse |
| + import logging |
| + import sys |
| + |
| + from infra.tools.{toolname} import {toolname} |
| + import infra_libs.logs |
| + |
| + |
| + # https://storage.googleapis.com/chromium-infra-docs/infra/html/logging.html |
| + LOGGER = logging.getLogger(__name__) |
| + |
| + |
| + def main(argv): |
| + parser = argparse.ArgumentParser( |
| + prog="{toolname}", |
| + description=sys.modules['__main__'].__doc__) |
| + {toolname}.add_argparse_options(parser) |
| + infra_libs.logs.add_argparse_options(parser) |
| + _args = parser.parse_args(argv) |
| + |
| + infra_libs.logs.process_argparse_options(parser) |
| + |
| + # Do more processing here |
| + LOGGER.info('{Toolname} starting.') |
| + |
| + |
| + if __name__ == '__main__': |
| + sys.exit(main(sys.argv[1:])) |
| + """).format(toolname=toolname, Toolname=toolname.capitalize()) |
| + |
| + with open(main_file_path, 'w') as f: |
| + f.write(COPYRIGHT_NOTICE) |
| + f.write(MAIN_CONTENT) |
| + |
| + |
| +def generate_tool_file(dirpath, toolname): |
| + """Generate a <toolname>.py file in the specified directory""" |
| + |
| + file_path = os.path.join(dirpath, '%s.py' % toolname) |
| + if os.path.isfile(file_path): |
| + print 'Skipping existing file %s' % file_path |
| + return |
| + |
| + MODULE_CONTENT = textwrap.dedent(""" |
| + \"\"\"Testable functions for {Toolname}.\"\"\" |
| + |
| + import logging |
| + |
| + |
| + # https://storage.googleapis.com/chromium-infra-docs/infra/html/logging.html |
| + LOGGER = logging.getLogger(__name__) |
| + |
| + |
| + def add_argparse_options(parser): |
| + \"\"\"Define command-line arguments.\"\"\" |
| + parser.add_argument('--my-argument', '-m', help='') |
| + """).format(Toolname=toolname.capitalize()) |
| + |
| + with open(file_path, 'w') as f: |
| + f.write(COPYRIGHT_NOTICE) |
| + f.write(MODULE_CONTENT) |
| + |
| + |
| +def generate_test_file(dirpath, toolname, tested_file): |
| + """Generate a test file in the proper place. |
| + |
| + Example: |
| + generate_test_file('foo', 'bar') creates foo/test/bar_test.py |
| + """ |
| + file_path = os.path.join(dirpath, 'test', '%s_test.py' % tested_file) |
| + if os.path.isfile(file_path): |
| + print 'Skipping existing file %s' % file_path |
| + return |
| + |
| + test_dir = os.path.join(dirpath, 'test') |
| + if not os.path.exists(test_dir): |
| + os.mkdir(os.path.join(test_dir)) |
| + |
| + MODULE_CONTENT = textwrap.dedent(""" |
| + \"\"\"Tests for ../{tested_file}.py\"\"\" |
| + |
| + import argparse |
| + import unittest |
| + |
| + from infra.tools.{toolname} import {tested_file} |
| + |
| + class MyTest(unittest.TestCase): |
| + def test_arguments(self): |
| + parser = argparse.ArgumentParser() |
| + {tested_file}.add_argparse_options(parser) |
| + args = parser.parse_args(['--my-argument', 'value']) |
| + self.assertEqual(args.my_argument, 'value') |
| + |
| + ## expect_tests style: the test method returns a value (expectation) |
| + ## that is stored when run in 'train' mode, and compared to in 'test' mode. |
| + ## If the stored and returned values do not match, the test fails. |
| + ## |
| + ## def test_my_first_test_with_expectation(self): |
| + ## # Use hash() here to make sure the test fails in any case. |
| + ## return hash(MyTest) |
|
Sergey Berezin
2015/06/10 00:32:37
nit: this looks confusing to me. Why would I want
|
| + """).format(toolname=toolname, tested_file=tested_file) |
| + |
| + with open(file_path, 'w') as f: |
| + f.write(COPYRIGHT_NOTICE) |
| + f.write(MODULE_CONTENT) |
| + |
| + |
| +def generate_tool_files(name, base_dir): |
| + """Generate a stub tool from template files. |
| + |
| + Args: |
| + name (str): name of the tool. This is also the name of the directory |
| + generated. |
| + base_dir (str): path to the directory where to create the files. |
| + |
| + Return: |
| + tool_path (str or None): directory created or None is nothing has been done. |
| + """ |
| + |
| + if not os.path.isdir(base_dir): |
| + print 'Destination directory does not exist' |
| + return 1 |
| + |
| + tool_dir = os.path.join(base_dir, name) |
| + if os.path.exists(tool_dir): |
| + print 'Tool seems to already exists: %s\nAborting.' % tool_dir |
| + return 1 |
| + |
| + print 'Generating %s...' % tool_dir |
| + os.mkdir(tool_dir) |
| + generate_init_file(tool_dir) |
| + generate_main_file(tool_dir, name) |
| + generate_tool_file(tool_dir, name) |
| + generate_test_file(tool_dir, name, name) |
| + generate_init_file(os.path.join(tool_dir, 'test')) |
| + print 'Done.' |