#!/usr/bin/env python3 import argparse import os import re def main(): p = argparse.ArgumentParser() p.add_argument("name", help="The name of the new benchmark to be created") args = p.parse_args() # adds benchmark to `CMakeLists.txt` update_cmakelists(args.name) # create benchmark Swift file create_benchmark_file(args.name) # imports the benchmark module in `main.swift` add_import_benchmark(args.name) # registers the benchmark with the driver in `main.swift` add_register_benchmark(args.name) def update_cmakelists(name): """Adds a new entry to the `CMakeLists.txt` file with the given benchmark name. """ relative_path = create_relative_path("../CMakeLists.txt") file_contents = [] with open(relative_path, "r") as f: file_contents = f.readlines() file_new_contents = insert_line_alphabetically( name, " single-source/" + name + "\n", file_contents, r" single-source\/([a-zA-Z]+)", ) with open(relative_path, "w") as f: for line in file_new_contents: f.write(line) def create_benchmark_file(name): """Creates a new Swift file with the given name based on the template and places it in the `single-source` directory. """ template_path = create_relative_path("Template.swift") benchmark_template = "" with open(template_path, "r") as f: benchmark_template = "".join(f.readlines()) # fill in template with benchmark name. formatted_template = benchmark_template.format(name=name) relative_path = create_relative_path("../single-source/") source_file_path = os.path.join(relative_path, name + ".swift") with open(source_file_path, "w") as f: f.write(formatted_template) def add_import_benchmark(name): """Adds an `import` statement to the `main.swift` file for the new benchmark. """ relative_path = create_relative_path("../utils/main.swift") # read current contents into an array file_contents = [] with open(relative_path, "r") as f: file_contents = f.readlines() # the test dependencies are placed before all benchmarks, so we have to # insert the benchmark in the right alphabetical order after we have seen # all test dependencies. read_test_dependencies = False previous_benchmark_name = None file_new_contents = [] for line in file_contents: # check if this line is a definition of a benchmark and get its name match = re.search(r"import ([a-zA-Z]+)", line) if match and match.group(1): benchmark_name = match.group(1) # find where to insert the new benchmark in the right alphabetical # order. if ( name < benchmark_name and previous_benchmark_name is None or name < benchmark_name and name > previous_benchmark_name ): if read_test_dependencies: file_new_contents.append("import " + name + "\n" + line) else: # all test dependencies are first specified, so from now # on we can look where to insert the new benchmark. read_test_dependencies = True file_new_contents.append(line) else: file_new_contents.append(line) previous_benchmark_name = benchmark_name else: file_new_contents.append(line) with open(relative_path, "w") as f: for line in file_new_contents: f.write(line) def add_register_benchmark(name): """Adds an `import` statement to the `main.swift` file for the new benchmark. """ relative_path = create_relative_path("../utils/main.swift") file_contents = [] with open(relative_path, "r") as f: file_contents = f.readlines() file_new_contents = insert_line_alphabetically( name, "registerBenchmark(" + name + ")\n", file_contents, r"registerBenchmark\(([a-zA-Z]+)\)", ) with open(relative_path, "w") as f: for line in file_new_contents: f.write(line) def insert_line_alphabetically(name, new_line, lines, regex): """Iterates through the given lines and executes the regex on each line to find where the new benchmark should be inserted with the given `new_line`. """ # the name of the previous seen benchmark in order to insert the new # one at the correct position previous_benchmark_name = None # the new contents of the file updated_lines = [] for line in lines: # apply regex and get name of benchmark on this line match = re.search(regex, line) if match and match.group(1): benchmark_name = match.group(1) # check if we're at the line where we have to insert the new # benchmark in the correct alphabetical order if ( name < benchmark_name and previous_benchmark_name is None or name < benchmark_name and name > previous_benchmark_name ): updated_lines.append(new_line + line) else: updated_lines.append(line) previous_benchmark_name = benchmark_name else: updated_lines.append(line) return updated_lines def create_relative_path(file_path): return os.path.join(os.path.dirname(__file__), file_path) if __name__ == "__main__": main()