def test_config(): config_file = Config(os.path.abspath(os.getcwd()), ".styleguide") assert config_file.is_modifiable_file("." + os.sep + "wpiformat" + os.sep + "javaguidelink.png") assert config_file.is_generated_file("." + os.sep + "wpiformat" + os.sep + "wpiformat" + os.sep + "cpplint.py") assert not config_file.is_generated_file("." + os.sep + "wpiformat" + os.sep + "diff_cpplint.py") assert not config_file.is_generated_file("." + os.sep + "wpiformat" + os.sep + "update_cpplint.py") assert not config_file.is_modifiable_file("." + os.sep + "wpiformat" + os.sep + "license.txt")
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)