blob: 1a9793394be5935017be9af7ca8cc8c9e7aa20e4 [file]
#!/usr/bin/env python3
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import pathlib
import sys
_THIS_DIR = pathlib.Path(__file__).resolve().parent
_SRC_ROOT = next(p for p in _THIS_DIR.parents
if (p / 'build' / '3pp_common').is_dir())
sys.path.insert(1, str(_SRC_ROOT / 'build' / '3pp_common'))
import common
import fetch_github_release
import graalvm
_PROJECT = 'google/google-java-format'
_ARTIFACT_REGEX = r'-all-deps\.jar$'
_RAW_BASE_URL = (
'https://raw.githubusercontent.com/google/google-java-format/'
'{version}/core/src/main/java/com/google/googlejavaformat/java')
_SAMPLE_JAVA = """\
package org.chromium.sample;
import java.util.List;
import org.chromium.build.annotations.Nullable;
/** Sample javadoc comment. */
public class Sample {
public @Nullable String format(int x, List<String> items) {
return switch (x) {
case 1 -> items.isEmpty() ? null : items.get(0);
default -> "default";
};
}
}
"""
def _apply_replace(path, target, replacement):
text = path.read_text(encoding='utf-8')
if target not in text:
raise RuntimeError(f'Failed to find {target!r} in {path}')
path.write_text(text.replace(target, replacement, 1), encoding='utf-8')
def _build_overrides_jar(version, jar_path):
"""Fetches upstream sources, applies patches, and updates jar_path."""
graal_home = graalvm.ensure_graalvm()
javac_bin = os.path.join(graal_home, 'bin', 'javac')
jar_bin = os.path.join(graal_home, 'bin', 'jar')
src_dir = pathlib.Path('overrides_src')
src_dir.mkdir(exist_ok=True)
import_java = src_dir / 'ImportOrderer.java'
common.download_file(
f'{_RAW_BASE_URL.format(version=version)}/ImportOrderer.java',
str(import_java),
)
_apply_replace(
import_java,
'.thenComparing(Import::isThirdParty, trueFirst())',
'.thenComparing(Import::isThirdParty, trueFirst())\n'
' .thenComparing(Import::isChromium, trueFirst())',
)
_apply_replace(
import_java,
'if (prev.isAndroid() && !curr.isAndroid()) {\n'
' return true;\n'
' }',
'if (prev.isAndroid() && !curr.isAndroid()) {\n'
' return true;\n'
' }\n'
' if (prev.isChromium() != curr.isChromium()) {\n'
' return true;\n'
' }',
)
_apply_replace(
import_java,
'return !(isAndroid() || isJava());',
'return !(isAndroid() || isJava() || isChromium());\n'
' }\n\n'
' /** True if this is a Chromium import per AOSP style. */\n'
' boolean isChromium() {\n'
' return java.util.stream.Stream.of(\n'
' "org.chromium.", "com.google.android.apps.chrome")\n'
' .anyMatch(imported::startsWith);',
)
visitor_java = src_dir / 'JavaInputAstVisitor.java'
common.download_file(
f'{_RAW_BASE_URL.format(version=version)}/JavaInputAstVisitor.java',
str(visitor_java),
)
_apply_replace(
visitor_java,
'"org.jspecify.annotations.NonNull",',
'"org.chromium.build.annotations.Nullable",\n'
' "org.jspecify.annotations.NonNull",',
)
classes_dir = pathlib.Path('overrides_classes')
classes_dir.mkdir(exist_ok=True)
common.run_cmd([
javac_bin,
'-d',
str(classes_dir),
'--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED',
'--add-exports=jdk.compiler/com.sun.tools.javac.code=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.util=ALL-UNNAMED',
'--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED',
'--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',
'--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED',
# Setting JVM version doesn't matter for graalvm binary, but does
# matter when google-java-format.jar is used (e.g. on non-Linux hosts).
'-source',
'21',
'-target',
'21',
'-cp',
jar_path,
str(import_java),
str(visitor_java),
])
common.run_cmd([
jar_bin,
'--update',
'--file',
jar_path,
'-C',
str(classes_dir),
'.',
])
def do_latest():
return fetch_github_release.latest_release(_PROJECT,
artifact_regex=_ARTIFACT_REGEX)
def do_install(args):
jar_path = os.path.join(args.output_prefix, 'google-java-format.jar')
fetch_github_release.download_artifact(
_PROJECT,
args.version,
jar_path,
artifact_regex=_ARTIFACT_REGEX,
)
_build_overrides_jar(args.version, jar_path)
sample_java = os.path.abspath('Sample.java')
pathlib.Path(sample_java).write_text(_SAMPLE_JAVA, encoding='utf-8')
graalvm.build_native_image(
jar_path,
os.path.join(args.output_prefix, 'google-java-format'),
tracing_args_list=[['--aosp', sample_java]],
# Formatting JDK sources is used as a representative workload for
# profile-guided optimizations.
pgo_args_list=[['--aosp', '--dry-run'] +
graalvm.extract_jdk_sources(os.path.abspath('pgo_src'))
],
)
def main():
common.main(
do_latest=do_latest,
do_install=do_install,
version_strings_func=graalvm.version_strings,
)
if __name__ == '__main__':
main()