def make_include_guard(self, config_file, name): """Returns properly formatted include guard based on repository root and file name. Keyword arguments: config_file -- Config object name -- file name string """ repo_root_name_override = config_file.group("repoRootNameOverride") repo_root = Task.get_repo_root() guard_root = os.path.relpath(name, repo_root) if not repo_root_name_override: guard_path = os.path.basename(repo_root) + os.sep else: guard_path = repo_root_name_override[0] + os.sep include_roots = config_file.group("includeGuardRoots") if include_roots: prefix = "" for include_root in include_roots: if guard_root.startswith( include_root) and len(include_root) > len(prefix): prefix = include_root guard_path += guard_root[len(prefix):] return (regex.sub("[^a-zA-Z0-9]", "_", guard_path).upper() + "_").lstrip("_") # No include guard roots matched, so append full name guard_path += guard_root return regex.sub("[^a-zA-Z0-9]", "_", guard_path).upper() + "_"
def make_include_guard(self, config_file, name): """Returns properly formatted include guard based on repository root and file name. Keyword arguments: config_file -- Config object name -- file name string """ repo_root = Task.get_repo_root() name = os.path.relpath(name, repo_root) guard_path = os.path.basename(repo_root) + "/" include_roots = config_file.group("includeGuardRoots") if include_roots: for include_root in include_roots: if name.startswith(include_root): guard_path += name[len(include_root):] return re.sub("[^a-zA-Z0-9]", "_", guard_path).upper() + "_" # No include guard roots matched, so append full name guard_path += name return re.sub("[^a-zA-Z0-9]", "_", guard_path).upper() + "_"
def main(): # Parse command-line arguments parser = argparse.ArgumentParser( description= "Runs all formatting tasks on the code base. This should be invoked from a directory within the project." ) parser.add_argument( "-v", dest="verbose1", action="store_true", help="verbosity level 1 (prints names of processed files)") parser.add_argument( "-vv", dest="verbose2", action="store_true", help= "verbosity level 2 (prints names of processed files and tasks run on them)" ) parser.add_argument( "-j", dest="jobs", type=int, default=mp.cpu_count(), help="number of jobs to run (default is number of cores)") parser.add_argument( "-y", dest="year", type=int, default=date.today().year, help= "year to use when updating license headers (default is current year)") parser.add_argument( "-clang", dest="clang_version", type=str, default="", help= "version suffix for clang-format (invokes \"clang-format-CLANG_VERSION\" or \"clang-format\" if no suffix provided)" ) parser.add_argument( "-f", dest="file", type=str, default="", nargs="+", help= "file or directory names (can be path relative to python invocation directory or absolute path)" ) args = parser.parse_args() # All discovered files are relative to Git repo root directory, so find the # root. root_path = Task.get_repo_root() if root_path == "": print("Error: not invoked within a Git repository", file=sys.stderr) sys.exit(1) # If no files explicitly specified if not args.file: # Delete temporary files from previous incomplete run files = [ os.path.join(dp, f) for dp, dn, fn in os.walk(root_path) for f in fn if f.endswith(".tmp") ] for f in files: os.remove(f) # Recursively create list of files in given directory files = [ os.path.join(dp, f) for dp, dn, fn in os.walk(root_path) for f in fn ] if not files: print("Error: no files found to format", file=sys.stderr) sys.exit(1) else: files = [] for name in args.file: # If a directory was specified, recursively expand it if os.path.isdir(name): files.extend([ os.path.join(dp, f) for dp, dn, fn in os.walk(name) for f in fn ]) else: files.append(name) # Convert relative paths of files to absolute paths files = [os.path.abspath(name) for name in files] # Don't run tasks on Git metadata files = [name for name in files if os.sep + ".git" + os.sep not in name] # Don't check for changes in or run tasks on ignored files files = filter_ignored_files(files) # Create list of all changed files changed_file_list = [] output_list = subprocess.run( ["git", "diff", "--name-only", "master"], stdout=subprocess.PIPE).stdout.split() for line in output_list: changed_file_list.append(root_path + os.sep + line.strip().decode("ascii")) # Don't run tasks on modifiable or generated files work = [] for name in files: config_file = Config(os.path.dirname(name), ".styleguide") if config_file.is_modifiable_file(name): continue if config_file.is_generated_file(name): # Emit warning if a generated file was editted if name in changed_file_list: print("Warning: generated file '" + name + "' modified") continue work.append(name) files = work # If there are no files left, do nothing if len(files) == 0: sys.exit(0) # Prepare file batches for batch tasks chunksize = math.ceil(len(files) / args.jobs) file_batches = [ files[i:i + chunksize] for i in range(0, len(files), chunksize) ] # IncludeOrder is run after Stdlib so any C std headers changed to C++ or # vice versa are sorted properly. ClangFormat is run after the other tasks # so it can clean up their formatting. task_pipeline = [ BraceComment(), CIdentList(), IncludeGuard(), LicenseUpdate(str(args.year)), JavaClass(), Newline(), Stdlib(), IncludeOrder(), UsingDeclaration(), UsingNamespaceStd(), Whitespace() ] run_pipeline(task_pipeline, args, files) task_pipeline = [ClangFormat(args.clang_version)] run_batch(task_pipeline, args, file_batches) # These tasks fix clang-format formatting task_pipeline = [Jni()] run_pipeline(task_pipeline, args, files) # Lint is run last since previous tasks can affect its output. task_pipeline = [PyFormat(), Lint()] run_batch(task_pipeline, args, file_batches)
def test_includeguard(): test = TaskTest(IncludeGuard()) repo_root = os.path.basename(Task.get_repo_root()).upper() # Fix incorrect include guard test.add_input("./Test.h", "#ifndef WRONG_H" + os.linesep + \ "#define WRONG_C" + os.linesep + \ os.linesep + \ "#endif" + os.linesep) test.add_output( "#ifndef " + repo_root + "_TEST_H_" + os.linesep + \ "#define " + repo_root + "_TEST_H_" + os.linesep + \ os.linesep + \ "#endif // " + repo_root + "_TEST_H_" + os.linesep, True, True) # Ensure nested preprocessor statements are handled properly for incorrect # include guard test.add_input("./Test.h", "#ifndef WRONG_H" + os.linesep + \ "#define WRONG_C" + os.linesep + \ os.linesep + \ "#if SOMETHING" + os.linesep + \ "// do something" + os.linesep + \ "#endif" + os.linesep + \ "#endif" + os.linesep) test.add_output( "#ifndef " + repo_root + "_TEST_H_" + os.linesep + \ "#define " + repo_root + "_TEST_H_" + os.linesep + \ os.linesep + \ "#if SOMETHING" + os.linesep + \ "// do something" + os.linesep + \ "#endif" + os.linesep + \ "#endif // " + repo_root + "_TEST_H_" + os.linesep, True, True) # Don't touch correct include guard test.add_input("./Test.h", "#ifndef " + repo_root + "_TEST_H_" + os.linesep + \ "#define " + repo_root + "_TEST_H_" + os.linesep + \ os.linesep + \ "#endif // " + repo_root + "_TEST_H_" + os.linesep) test.add_latest_input_as_output(True) # Fail on missing include guard test.add_input("./Test.h", "// Empty file" + os.linesep) test.add_latest_input_as_output(False) # Verify pragma once counts as include guard test.add_input("./Test.h", "#pragma once" + os.linesep) test.add_latest_input_as_output(True) # Ensure include guard roots are processed correctly test.add_input("./Test.h", "#ifndef " + repo_root + "_WPIFORMAT_TEST_H_" + os.linesep + \ "#define " + repo_root + "_WPIFORMAT_TEST_H_" + os.linesep + \ os.linesep + \ "#endif // " + repo_root + "_WPIFORMAT_TEST_H_" + os.linesep) test.add_output( "#ifndef " + repo_root + "_TEST_H_" + os.linesep + \ "#define " + repo_root + "_TEST_H_" + os.linesep + \ os.linesep + \ "#endif // " + repo_root + "_TEST_H_" + os.linesep, True, True) # Ensure leading underscores are removed (this occurs if the user doesn't # include a trailing "/" in the include guard root) test.add_input("./Test/Test.h", "#ifndef " + repo_root + "_WPIFORMAT_TEST_TEST_H_" + os.linesep + \ "#define " + repo_root + "_WPIFORMAT_TEST_TEST_H_" + os.linesep + \ os.linesep + \ "#endif // " + repo_root + "_WPIFORMAT_TEST_TEST_H_" + os.linesep) test.add_output( "#ifndef " + repo_root + "_TEST_H_" + os.linesep + \ "#define " + repo_root + "_TEST_H_" + os.linesep + \ os.linesep + \ "#endif // " + repo_root + "_TEST_H_" + os.linesep, True, True) test.run(OutputType.FILE)