|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +import argparse |
| 4 | +import os |
| 5 | +import re |
| 6 | + |
| 7 | + |
| 8 | +def main(): |
| 9 | + p = argparse.ArgumentParser() |
| 10 | + p.add_argument('name', help='The name of the new benchmark to be created') |
| 11 | + args = p.parse_args() |
| 12 | + |
| 13 | + # adds benchmark to `CMakeLists.txt` |
| 14 | + update_cmakelists(args.name) |
| 15 | + # create benchmark Swift file |
| 16 | + create_benchmark_file(args.name) |
| 17 | + # imports the benchmark module in `main.swift` |
| 18 | + add_import_benchmark(args.name) |
| 19 | + # registers the benchmark with the driver in `main.swift` |
| 20 | + add_register_benchmark(args.name) |
| 21 | + |
| 22 | + |
| 23 | +def update_cmakelists(name): |
| 24 | + """Adds a new entry to the `CMakeLists.txt` file with the given |
| 25 | + benchmark name. |
| 26 | + """ |
| 27 | + relative_path = create_relative_path('../CMakeLists.txt') |
| 28 | + |
| 29 | + file_contents = [] |
| 30 | + with open(relative_path, 'r') as f: |
| 31 | + file_contents = f.readlines() |
| 32 | + |
| 33 | + file_new_contents = insert_line_alphabetically( |
| 34 | + name, |
| 35 | + ' single-source/' + name + '\n', |
| 36 | + file_contents, |
| 37 | + r" single-source\/([a-zA-Z]+)" |
| 38 | + ) |
| 39 | + with open(relative_path, 'w') as f: |
| 40 | + for line in file_new_contents: |
| 41 | + f.write(line) |
| 42 | + |
| 43 | + |
| 44 | +def create_benchmark_file(name): |
| 45 | + """Creates a new Swift file with the given name based on the template |
| 46 | + and places it in the `single-source` directory. |
| 47 | + """ |
| 48 | + |
| 49 | + template_path = create_relative_path('Template.swift') |
| 50 | + benchmark_template = '' |
| 51 | + with open(template_path, 'r') as f: |
| 52 | + benchmark_template = ''.join(f.readlines()) |
| 53 | + |
| 54 | + # fill in template with benchmark name. |
| 55 | + formatted_template = benchmark_template.format(name=name) |
| 56 | + |
| 57 | + relative_path = create_relative_path('../single-source/') |
| 58 | + source_file_path = os.path.join(relative_path, name + '.swift') |
| 59 | + with open(source_file_path, 'w') as f: |
| 60 | + f.write(formatted_template) |
| 61 | + |
| 62 | + |
| 63 | +def add_import_benchmark(name): |
| 64 | + """Adds an `import` statement to the `main.swift` file for the new |
| 65 | + benchmark. |
| 66 | + """ |
| 67 | + relative_path = create_relative_path('../utils/main.swift') |
| 68 | + |
| 69 | + # read current contents into an array |
| 70 | + file_contents = [] |
| 71 | + with open(relative_path, 'r') as f: |
| 72 | + file_contents = f.readlines() |
| 73 | + |
| 74 | + # the test dependencies are placed before all benchmarks, so we have to |
| 75 | + # insert the benchmark in the right alphabetical order after we have seen |
| 76 | + # all test dependencies. |
| 77 | + read_test_dependencies = False |
| 78 | + previous_benchmark_name = None |
| 79 | + file_new_contents = [] |
| 80 | + for line in file_contents: |
| 81 | + # check if this line is a definition of a benchmark and get its name |
| 82 | + match = re.search(r"import ([a-zA-Z]+)", line) |
| 83 | + if match and match.group(1): |
| 84 | + benchmark_name = match.group(1) |
| 85 | + # find where to insert the new benchmark in the right alphabetical |
| 86 | + # order. |
| 87 | + if (name < benchmark_name and previous_benchmark_name is None or |
| 88 | + name < benchmark_name and name > previous_benchmark_name): |
| 89 | + if read_test_dependencies: |
| 90 | + file_new_contents.append('import ' + name + '\n' + line) |
| 91 | + else: |
| 92 | + # all test dependencies are first specified, so from now |
| 93 | + # on we can look where to insert the new benchmark. |
| 94 | + read_test_dependencies = True |
| 95 | + file_new_contents.append(line) |
| 96 | + else: |
| 97 | + file_new_contents.append(line) |
| 98 | + previous_benchmark_name = benchmark_name |
| 99 | + else: |
| 100 | + file_new_contents.append(line) |
| 101 | + with open(relative_path, 'w') as f: |
| 102 | + for line in file_new_contents: |
| 103 | + f.write(line) |
| 104 | + |
| 105 | + |
| 106 | +def add_register_benchmark(name): |
| 107 | + """Adds an `import` statement to the `main.swift` file for the new |
| 108 | + benchmark. |
| 109 | + """ |
| 110 | + relative_path = create_relative_path('../utils/main.swift') |
| 111 | + |
| 112 | + file_contents = [] |
| 113 | + with open(relative_path, 'r') as f: |
| 114 | + file_contents = f.readlines() |
| 115 | + |
| 116 | + file_new_contents = insert_line_alphabetically( |
| 117 | + name, |
| 118 | + 'registerBenchmark(' + name + ')\n', |
| 119 | + file_contents, |
| 120 | + r"registerBenchmark\(([a-zA-Z]+)\)" |
| 121 | + ) |
| 122 | + with open(relative_path, 'w') as f: |
| 123 | + for line in file_new_contents: |
| 124 | + f.write(line) |
| 125 | + |
| 126 | + |
| 127 | +def insert_line_alphabetically(name, new_line, lines, regex): |
| 128 | + """Iterates through the given lines and executes the regex on each line to |
| 129 | + find where the new benchmark should be inserted with the given `new_line`. |
| 130 | + """ |
| 131 | + # the name of the previous seen benchmark in order to insert the new |
| 132 | + # one at the correct position |
| 133 | + previous_benchmark_name = None |
| 134 | + # the new contents of the file |
| 135 | + updated_lines = [] |
| 136 | + for line in lines: |
| 137 | + # apply regex and get name of benchmark on this line |
| 138 | + match = re.search(regex, line) |
| 139 | + if match and match.group(1): |
| 140 | + benchmark_name = match.group(1) |
| 141 | + # check if we're at the line where we have to insert the new |
| 142 | + # benchmark in the correct alphabetical order |
| 143 | + if (name < benchmark_name and previous_benchmark_name is None or |
| 144 | + name < benchmark_name and name > previous_benchmark_name): |
| 145 | + updated_lines.append(new_line + line) |
| 146 | + else: |
| 147 | + updated_lines.append(line) |
| 148 | + previous_benchmark_name = benchmark_name |
| 149 | + else: |
| 150 | + updated_lines.append(line) |
| 151 | + return updated_lines |
| 152 | + |
| 153 | + |
| 154 | +def create_relative_path(file_path): |
| 155 | + return os.path.join(os.path.dirname(__file__), file_path) |
| 156 | + |
| 157 | + |
| 158 | +if __name__ == "__main__": |
| 159 | + main() |
0 commit comments