def pretty_format_kotlin( argv: typing.Optional[typing.List[str]] = None) -> int: parser = argparse.ArgumentParser() parser.add_argument( "--autofix", action="store_true", dest="autofix", help="Automatically fixes encountered not-pretty-formatted files", ) parser.add_argument( "--ktlint-version", dest="ktlint_version", default=_get_default_version("ktlint"), help="KTLint version to use (default %(default)s)", ) parser.add_argument("filenames", nargs="*", help="Filenames to fix") args = parser.parse_args(argv) # KTLint does not yet support Java 16+, before that version. # Let's make sure that we report a nice error message instead of a complex # Java Stacktrace # the tool can only be executed on Java up to version 15. # Context: https://github.com/JLLeitschuh/ktlint-gradle/issues/461 assert_max_jdk_version(Version("16.0"), inclusive=False) # pragma: no cover ktlint_jar = _download_kotlin_formatter_jar(args.ktlint_version, ) # ktlint does not return exit-code!=0 if we're formatting them. # To workaround this limitation we do run ktlint in check mode only, # which provides the expected exit status and we run it again in format # mode if autofix flag is enabled check_status, check_output = run_command("java", "-jar", ktlint_jar, "--verbose", "--relative", "--", *_fix_paths(args.filenames)) not_pretty_formatted_files: typing.Set[str] = set() if check_status != 0: not_pretty_formatted_files.update( line.split(":", 1)[0] for line in check_output.splitlines()) if args.autofix: print("Running ktlint format on {}".format( not_pretty_formatted_files)) run_command("java", "-jar", ktlint_jar, "--verbose", "--relative", "--format", "--", *_fix_paths(not_pretty_formatted_files)) status = 0 if not_pretty_formatted_files: status = 1 print( "{}: {}".format( "The following files have been fixed by ktlint" if args.autofix else "The following files are not properly formatted", ", ".join(sorted(not_pretty_formatted_files)), ), ) return status
def pretty_format_rust(argv=None): # type: (typing.Optional[typing.List[typing.Text]]) -> int parser = argparse.ArgumentParser() parser.add_argument( "--autofix", action="store_true", dest="autofix", help="Automatically fixes encountered not-pretty-formatted files", ) parser.add_argument("filenames", nargs="*", help="Filenames to fix") args = parser.parse_args(argv) rust_toolchain_version = getenv("RUST_TOOLCHAIN", "stable") # Check status_code, output = run_command("cargo", "+{}".format(rust_toolchain_version), "fmt", "--", "--check", *args.filenames) not_well_formatted_files = sorted(line.split()[2] for line in output.splitlines() if line.startswith("Diff in ")) if not_well_formatted_files: print( "{}: {}".format( "The following files have been fixed by cargo format" if args.autofix else "The following files are not properly formatted", ", ".join(not_well_formatted_files), ), ) if args.autofix: run_command("cargo", "+{}".format(rust_toolchain_version), "fmt", "--", *not_well_formatted_files) elif status_code != 0: print("Detected not valid rust source files among {}".format("\n".join(sorted(args.filenames)))) return 1 if status_code != 0 or not_well_formatted_files else 0
def pretty_format_kotlin(argv=None): # type: (typing.Optional[typing.List[typing.Text]]) -> int parser = argparse.ArgumentParser() parser.add_argument( "--autofix", action="store_true", dest="autofix", help="Automatically fixes encountered not-pretty-formatted files", ) parser.add_argument( "--ktlint-version", dest="ktlint_version", default=_get_default_version("ktlint"), help="KTLint version to use (default %(default)s)", ) parser.add_argument("filenames", nargs="*", help="Filenames to fix") args = parser.parse_args(argv) ktlint_jar = __download_kotlin_formatter_jar(args.ktlint_version, ) # ktlint does not return exit-code!=0 if we're formatting them. # To workaround this limitation we do run ktlint in check mode only, # which provides the expected exit status and we run it again in format # mode if autofix flag is enabled check_status, check_output = run_command("java", "-jar", ktlint_jar, "--verbose", "--relative", "--", *args.filenames) not_pretty_formatted_files = set() # type: typing.Set[typing.Text] if check_status != 0: not_pretty_formatted_files.update( line.split(":", 1)[0] for line in check_output.splitlines()) if args.autofix: print("Running ktlint format on {}".format( not_pretty_formatted_files)) run_command("java", "-jar", ktlint_jar, "--verbose", "--relative", "--format", "--", *not_pretty_formatted_files) status = 0 if not_pretty_formatted_files: status = 1 print( "{}: {}".format( "The following files have been fixed by ktlint" if args.autofix else "The following files are not properly formatted", ", ".join(sorted(not_pretty_formatted_files)), ), ) return status
def pretty_format_java(argv=None): parser = argparse.ArgumentParser() parser.add_argument( '--autofix', action='store_true', dest='autofix', help='Automatically fixes encountered not-pretty-formatted files', ) parser.add_argument('filenames', nargs='*', help='Filenames to fix') args = parser.parse_args(argv) google_java_formatter_jar = download_google_java_formatter_jar() status, output = run_command( 'java -jar {} --set-exit-if-changed --aosp {} {}'.format( google_java_formatter_jar, '--replace' if args.autofix else '--dry-run', ' '.join(set(args.filenames)), ), ) if output: print( '{}: {}'.format( 'The following files have been fixed by google-java-formatter' if args.autofix else 'The following files are not properly formatted', # noqa ', '.join(output.splitlines()), ), ) return 0 if status == 0 else 1
def pretty_format_golang(argv=None): parser = argparse.ArgumentParser() parser.add_argument( '--autofix', action='store_true', dest='autofix', help='Automatically fixes encountered not-pretty-formatted files', ) parser.add_argument('filenames', nargs='*', help='Filenames to fix') args = parser.parse_args(argv) status, output = run_command( 'gofmt{} -l {}'.format( ' -w' if args.autofix else '', ' '.join(set(args.filenames)), ), ) if status != 0: # pragma: no cover print(output) return 1 status = 0 if output: status = 1 print( '{}: {}'.format( 'The following files have been fixed by gofmt' if args.autofix else 'The following files are not properly formatted', ', '.join(output.splitlines()), ), ) return status
def _is_command_success( *command_args: str, output_should_match: typing.Optional[typing.Callable[[str], bool]] = None, ) -> bool: exit_status, output = run_command(*command_args) return exit_status == 0 and (output_should_match is None or output_should_match(output))
def test_pretty_format_kotlin_autofix(tmpdir, undecorate_method): srcfile = tmpdir.join('to_be_fixed.kt') shutil.copyfile( 'invalid.kt', srcfile.strpath, ) with change_dir_context(tmpdir.strpath): # KTLint does not provide information if files have been formatted # so the only way is to check if there are non stashed files in the repo run_command('git init && git add {}'.format(srcfile.strpath)) assert undecorate_method(['--autofix', srcfile.strpath]) == 1 # Stage the file in the repository run_command('git add {}'.format(srcfile.strpath)) # file was formatted (shouldn't trigger linter again) assert undecorate_method([srcfile.strpath]) == 0
def pretty_format_rust(argv=None): parser = argparse.ArgumentParser() parser.add_argument( '--autofix', action='store_true', dest='autofix', help='Automatically fixes encountered not-pretty-formatted files', ) parser.add_argument('filenames', nargs='*', help='Filenames to fix') args = parser.parse_args(argv) rust_toolchain_version = getenv('RUST_TOOLCHAIN', 'stable') # Check status_code, output = run_command( 'cargo +{} fmt -- --check {}'.format( rust_toolchain_version, ' '.join(set(args.filenames)), ), ) not_well_formatted_files = sorted( line.split()[2] for line in output.splitlines() if line.startswith('Diff in ') ) if not_well_formatted_files: print( '{}: {}'.format( 'The following files have been fixed by cargo format' if args.autofix else 'The following files are not properly formatted', ', '.join(not_well_formatted_files), ), ) if args.autofix: run_command( 'cargo +{} fmt -- {}'.format( rust_toolchain_version, ' '.join(not_well_formatted_files), ), ) return 1 if status_code != 0 or not_well_formatted_files else 0
def get_jdk_version() -> Version: """ Extract the version of the JDK accessible by the tool. :raises UnableToVerifyJDKVersion: if it was not possible to gather the JDK version This includes the case of `java` binary is not found in the path. """ _, output = run_command("java", "-XshowSettings:properties", "-version") try: java_property_line = next( line for line in output.splitlines() if re.match(r"^\s+java.version\s+=\s+[^s]+$", line)) return Version(java_property_line.split()[-1]) except Exception as e: raise UnableToVerifyJDKVersion() from e
def pretty_format_java(argv: typing.Optional[typing.List[str]] = None) -> int: parser = argparse.ArgumentParser() parser.add_argument( "--autofix", action="store_true", dest="autofix", help="Automatically fixes encountered not-pretty-formatted files", ) parser.add_argument( "--google-java-formatter-version", dest="google_java_formatter_version", default=_get_default_version("google_java_formatter"), help="Google Java Formatter version to use (default %(default)s)", ) parser.add_argument( "--aosp", action="store_true", dest="aosp", help="Formats Java code into AOSP format", ) parser.add_argument("filenames", nargs="*", help="Filenames to fix") args = parser.parse_args(argv) google_java_formatter_jar = __download_google_java_formatter_jar( args.google_java_formatter_version, ) cmd_args = [ "java", "-jar", google_java_formatter_jar, "--set-exit-if-changed" ] if args.aosp: # pragma: no cover cmd_args.append("--aosp") if args.autofix: cmd_args.append("--replace") else: cmd_args.append("--dry-run") status, output = run_command(*(cmd_args + args.filenames)) if output: print( "{}: {}".format( "The following files have been fixed by google-java-formatter" if args.autofix else "The following files are not properly formatted", # noqa ", ".join(output.splitlines()), ), ) return 0 if status == 0 else 1
def pretty_format_golang(argv=None): # type: (typing.Optional[typing.List[typing.Text]]) -> int parser = argparse.ArgumentParser() parser.add_argument( "--autofix", action="store_true", dest="autofix", help="Automatically fixes encountered not-pretty-formatted files", ) parser.add_argument("filenames", nargs="*", help="Filenames to fix") args = parser.parse_args(argv) cmd_args = ["gofmt", "-l"] if args.autofix: cmd_args.append("-w") status, output = run_command(*(cmd_args + args.filenames)) if status != 0: # pragma: no cover print(output) return 1 status = 0 if output: status = 1 print( "{}: {}".format( "The following files have been fixed by gofmt" if args.autofix else "The following files are not properly formatted", ", ".join(output.splitlines()), ), ) if sys.platform == "win32": # pragma: no cover eol_attribute = _get_eol_attribute() if eol_attribute and eol_attribute != "lf": print( "Hint: gofmt uses LF (aka `\\n`) as new line, but on Windows the default new line is CRLF (aka `\\r\\n`). " "You might want to ensure that go files are forced to use LF via `.gitattributes`. " "Example: https://github.com/macisamuele/language-formatters-pre-commit-hooks/commit/53f27fda02ead5b1b9b6a9bbd9c36bb66d229887", # noqa: E501 file=sys.stderr, ) return status
def pretty_format_kotlin(argv=None): parser = argparse.ArgumentParser() parser.add_argument( '--autofix', action='store_true', dest='autofix', help='Automatically fixes encountered not-pretty-formatted files', ) parser.add_argument('filenames', nargs='*', help='Filenames to fix') args = parser.parse_args(argv) ktlint_jar = download_kotlin_formatter_jar() modified_files_pre_kotlin_formatting = get_modified_files_in_repo() status, output = run_command( 'java -jar {} --verbose {} {}'.format( ktlint_jar, '--format' if args.autofix else '--', ' '.join(set(args.filenames)), ), ) if output: print(output) return 1 # Check all the file modified by the execution of the previous commands modified_files_post_kotlin_formatting = get_modified_files_in_repo() if modified_files_pre_kotlin_formatting != modified_files_post_kotlin_formatting: print( '{}: {}'.format( 'The following files have been fixed by ktlint' if args.autofix else 'The following files are not properly formatted', # noqa ', '.join(sorted( modified_files_post_kotlin_formatting.difference(modified_files_pre_kotlin_formatting), )), ), ) return 1 return 0
def _get_eol_attribute() -> typing.Optional[str]: """ Retrieve eol attribute defined for golang files The method will return None in case of any error interacting with git """ status_code, output = run_command("git", "check-attr", "-z", "eol", "--", "filename.go") if status_code != 0: return None try: # Expected output: "filename.go\0eol\0lf\0" _, _, eol, _ = output.split("\0") return eol except: # noqa: E722 (allow usage of bare 'except') print( "`git check-attr` output is not consistent to `<filename>\0<key>\0<value>\0` format: {output}".format( output=output, ), file=sys.stderr, ) return None
def test_run_command(command, expected_status, expected_output): assert run_command(*command) == (expected_status, expected_output)
def _assert_command_succeed(command, assertion_error_message): status, _ = run_command(command) assert status == 0, assertion_error_message
def pretty_format_java(argv: typing.Optional[typing.List[str]] = None) -> int: parser = argparse.ArgumentParser() parser.add_argument( "--autofix", action="store_true", dest="autofix", help="Automatically fixes encountered not-pretty-formatted files", ) parser.add_argument( "--google-java-formatter-version", dest="google_java_formatter_version", default=_get_default_version("google_java_formatter"), help="Google Java Formatter version to use (default %(default)s)", ) parser.add_argument( "--aosp", action="store_true", dest="aosp", help="Formats Java code into AOSP format", ) parser.add_argument("filenames", nargs="*", help="Filenames to fix") args = parser.parse_args(argv) # Google Java Formatter 1.10+ does support Java 16+, before that version # the tool can only be executed on Java up to version 15. # Context: https://github.com/google/google-java-format/releases/tag/v1.10.0 if Version(args.google_java_formatter_version) <= Version("1.9"): assert_max_jdk_version(Version("16.0"), inclusive=False) # pragma: no cover google_java_formatter_jar = _download_google_java_formatter_jar( args.google_java_formatter_version, ) cmd_args = [ "java", # export JDK internal classes for Java 16+ "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", "-jar", google_java_formatter_jar, "--set-exit-if-changed", ] if args.aosp: # pragma: no cover cmd_args.append("--aosp") if args.autofix: cmd_args.append("--replace") else: cmd_args.append("--dry-run") status, output = run_command(*(cmd_args + args.filenames)) if output: print( "{}: {}".format( "The following files have been fixed by google-java-formatter" if args.autofix else "The following files are not properly formatted", # noqa ", ".join(output.splitlines()), ), ) return 0 if status == 0 else 1
def _is_command_success(*command_args: str) -> bool: exit_status, _ = run_command(*command_args) return exit_status == 0
def _is_command_success(*command_args): # type: (typing.Text) -> bool exit_status, _ = run_command(*command_args) return exit_status == 0