From 7c7e1a1c576fb32631d025d55d3ceee8d667ed40 Mon Sep 17 00:00:00 2001 From: Leonid Shalupov Date: Sun, 22 Aug 2021 23:25:48 +0300 Subject: [PATCH] jps-bootstrap initial commit this is a utility to run any main class from intellij project. it incrementally compiles Java/Kotlin/Groovy code and runs main class from specified module GitOrigin-RevId: 0a095bfe8d64fe9c0b031ae142612b56d69049c8 --- platform/jps-bootstrap/.gitignore | 3 + platform/jps-bootstrap/.idea/.gitignore | 8 + platform/jps-bootstrap/.idea/ant.xml | 6 + platform/jps-bootstrap/.idea/compiler.xml | 13 ++ platform/jps-bootstrap/.idea/encodings.xml | 9 + .../jps-bootstrap/.idea/jarRepositories.xml | 30 ++++ platform/jps-bootstrap/.idea/misc.xml | 14 ++ platform/jps-bootstrap/.idea/vcs.xml | 6 + .../jps-bootstrap/jps-bootstrap-classpath.xml | 128 ++++++++++++++ platform/jps-bootstrap/jps-bootstrap.sh | 106 +++++++++++ platform/jps-bootstrap/pom.xml | 71 ++++++++ .../src/main/java/JpsBootstrapMain.java | 167 ++++++++++++++++++ 12 files changed, 561 insertions(+) create mode 100644 platform/jps-bootstrap/.gitignore create mode 100644 platform/jps-bootstrap/.idea/.gitignore create mode 100644 platform/jps-bootstrap/.idea/ant.xml create mode 100644 platform/jps-bootstrap/.idea/compiler.xml create mode 100644 platform/jps-bootstrap/.idea/encodings.xml create mode 100644 platform/jps-bootstrap/.idea/jarRepositories.xml create mode 100644 platform/jps-bootstrap/.idea/misc.xml create mode 100644 platform/jps-bootstrap/.idea/vcs.xml create mode 100644 platform/jps-bootstrap/jps-bootstrap-classpath.xml create mode 100644 platform/jps-bootstrap/jps-bootstrap.sh create mode 100644 platform/jps-bootstrap/pom.xml create mode 100644 platform/jps-bootstrap/src/main/java/JpsBootstrapMain.java diff --git a/platform/jps-bootstrap/.gitignore b/platform/jps-bootstrap/.gitignore new file mode 100644 index 000000000000..7f8de99b273c --- /dev/null +++ b/platform/jps-bootstrap/.gitignore @@ -0,0 +1,3 @@ +/target +/classpath.pathlist +/out diff --git a/platform/jps-bootstrap/.idea/.gitignore b/platform/jps-bootstrap/.idea/.gitignore new file mode 100644 index 000000000000..13566b81b018 --- /dev/null +++ b/platform/jps-bootstrap/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/platform/jps-bootstrap/.idea/ant.xml b/platform/jps-bootstrap/.idea/ant.xml new file mode 100644 index 000000000000..50049ea2d346 --- /dev/null +++ b/platform/jps-bootstrap/.idea/ant.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/.idea/compiler.xml b/platform/jps-bootstrap/.idea/compiler.xml new file mode 100644 index 000000000000..42ae2bbbc47d --- /dev/null +++ b/platform/jps-bootstrap/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/.idea/encodings.xml b/platform/jps-bootstrap/.idea/encodings.xml new file mode 100644 index 000000000000..3daf701f72b0 --- /dev/null +++ b/platform/jps-bootstrap/.idea/encodings.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/.idea/jarRepositories.xml b/platform/jps-bootstrap/.idea/jarRepositories.xml new file mode 100644 index 000000000000..ccb6e98034ec --- /dev/null +++ b/platform/jps-bootstrap/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/.idea/misc.xml b/platform/jps-bootstrap/.idea/misc.xml new file mode 100644 index 000000000000..5f3e0f8d5e19 --- /dev/null +++ b/platform/jps-bootstrap/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/.idea/vcs.xml b/platform/jps-bootstrap/.idea/vcs.xml new file mode 100644 index 000000000000..c2365ab11f9b --- /dev/null +++ b/platform/jps-bootstrap/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/jps-bootstrap-classpath.xml b/platform/jps-bootstrap/jps-bootstrap-classpath.xml new file mode 100644 index 000000000000..a3743ba702f3 --- /dev/null +++ b/platform/jps-bootstrap/jps-bootstrap-classpath.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/jps-bootstrap.sh b/platform/jps-bootstrap/jps-bootstrap.sh new file mode 100644 index 000000000000..40603b1f530e --- /dev/null +++ b/platform/jps-bootstrap/jps-bootstrap.sh @@ -0,0 +1,106 @@ +#!/bin/sh +# Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +set -eu + +JPS_BOOTSTRAP_DIR="$(cd "$(dirname "$0")"; pwd)" +COMMUNITY_HOME="$(cd "$JPS_BOOTSTRAP_DIR/../.."; pwd)" +JPS_BOOTSTRAP_WORK_DIR=${JPS_BOOTSTRAP_WORK_DIR:-$COMMUNITY_HOME/out/jps-bootstrap} + +SCRIPT_VERSION=jps-bootstrap-cmd-v1 + +warn () { + echo "$@" +} + +die () { + echo 2>&1 + echo "$@" 2>&1 + echo 2>&1 + exit 1 +} + +darwin=false +case "$(uname)" in + Darwin* ) + darwin=true + ;; +esac + +if [ "$darwin" = "true" ]; then + case $(uname -m) in + x86_64) + JVM_URL=https://corretto.aws/downloads/resources/11.0.9.12.1/amazon-corretto-11.0.9.12.1-macosx-x64.tar.gz + JVM_TARGET_DIR="$JPS_BOOTSTRAP_WORK_DIR/jvm/amazon-corretto-11.0.9.12.1-macosx-x64-$SCRIPT_VERSION" + ;; + arm64) + JVM_URL=https://cdn.azul.com/zulu/bin/zulu11.45.27-ca-jdk11.0.10-macosx_aarch64.tar.gz + JVM_TARGET_DIR="$JPS_BOOTSTRAP_WORK_DIR/jvm/zulu-11.0.10-macosx-arm64-$SCRIPT_VERSION" + ;; + *) + die "Unknown architecture $(uname -m)" + ;; + esac +else + case $(uname -m) in + x86_64) + JVM_URL=https://corretto.aws/downloads/resources/11.0.9.12.1/amazon-corretto-11.0.9.12.1-linux-x64.tar.gz + JVM_TARGET_DIR="$JPS_BOOTSTRAP_WORK_DIR/jvm/amazon-corretto-11.0.9.12.1-linux-x64-$SCRIPT_VERSION" + ;; + aarch64) + JVM_URL=https://corretto.aws/downloads/resources/11.0.9.12.1/amazon-corretto-11.0.9.12.1-linux-aarch64.tar.gz + JVM_TARGET_DIR="$JPS_BOOTSTRAP_WORK_DIR/jvm/amazon-corretto-11.0.9.12.1-linux-aarch64-$SCRIPT_VERSION" + ;; + *) + die "Unknown architecture $(uname -m)" + ;; + esac +fi + +mkdir -p "$JPS_BOOTSTRAP_WORK_DIR/jvm" + +if [ -e "$JVM_TARGET_DIR/.flag" ] && [ -n "$(ls "$JVM_TARGET_DIR")" ] && [ "x$(cat "$JVM_TARGET_DIR/.flag")" = "x${JVM_URL}" ]; then + # Everything is up-to-date in $JVM_TARGET_DIR, do nothing + true +else + warn "Downloading $JVM_URL to $JVM_TEMP_FILE" + + JVM_TEMP_FILE=$(mktemp "$JPS_BOOTSTRAP_WORK_DIR/jvm.tar.gz.XXXXXXXXX") + trap 'echo "Removing $JVM_TEMP_FILE"; rm -f "$JVM_TEMP_FILE"; trap - EXIT' EXIT INT HUP + + if command -v curl >/dev/null 2>&1; then + if [ -t 1 ]; then CURL_PROGRESS="--progress-bar"; else CURL_PROGRESS="--silent --show-error"; fi + curl $CURL_PROGRESS --output "${JVM_TEMP_FILE}" "$JVM_URL" + elif command -v wget >/dev/null 2>&1; then + if [ -t 1 ]; then WGET_PROGRESS=""; else WGET_PROGRESS="-nv"; fi + wget $WGET_PROGRESS -O "${JVM_TEMP_FILE}" "$JVM_URL" + else + die "ERROR: Please install wget or curl" + fi + + warn "Extracting $JVM_TEMP_FILE to $JVM_TARGET_DIR" + rm -rf "$JVM_TARGET_DIR" + mkdir -p "$JVM_TARGET_DIR" + + tar -x -f "$JVM_TEMP_FILE" -C "$JVM_TARGET_DIR" + rm -f "$JVM_TEMP_FILE" + + echo "$JVM_URL" >"$JVM_TARGET_DIR/.flag" +fi + +JAVA_HOME= +for d in "$JVM_TARGET_DIR" "$JVM_TARGET_DIR"/* "$JVM_TARGET_DIR/Contents/Home" "$JVM_TARGET_DIR/"*/Contents/Home; do + if [ -e "$d/bin/java" ]; then + JAVA_HOME="$d" + fi +done + +if [ ! -e "$JAVA_HOME/bin/java" ]; then + die "Unable to find bin/java under $JVM_TARGET_DIR" +fi + +set -x + +"$JAVA_HOME/bin/java" -jar "$COMMUNITY_HOME/lib/ant/lib/ant-launcher.jar" -f "$JPS_BOOTSTRAP_DIR/jps-bootstrap-classpath.xml" + +exec "$JAVA_HOME/bin/java" -classpath "@$JPS_BOOTSTRAP_WORK_DIR/classpath.pathlist" JpsBootstrapMain "$@" diff --git a/platform/jps-bootstrap/pom.xml b/platform/jps-bootstrap/pom.xml new file mode 100644 index 000000000000..7f5eb7744dca --- /dev/null +++ b/platform/jps-bootstrap/pom.xml @@ -0,0 +1,71 @@ + + + + 4.0.0 + + org.jetbrains.jps-bootstrap + jps-bootstrap + 1.0.0 + + + 11 + 213.2547 + UTF-8 + + + + + com.jetbrains.intellij.platform + jps-model + ${bootstrap.intellij.version} + + + com.jetbrains.intellij.platform + jps-model-impl + ${bootstrap.intellij.version} + + + com.jetbrains.intellij.platform + jps-model-serialization + ${bootstrap.intellij.version} + + + com.jetbrains.intellij.tools + jps-build-standalone + ${bootstrap.intellij.version} + + + com.jetbrains.intellij.groovy + groovy-jps + ${bootstrap.intellij.version} + + + com.jetbrains.intellij.groovy + groovy-rt + ${bootstrap.intellij.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + + + + + + intellij-dependencies + https://cache-redirector.jetbrains.com/intellij-dependencies + + + kotlin-ide-plugin-dependencies + https://cache-redirector.jetbrains.com/maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-ide-plugin-dependencies + + + + \ No newline at end of file diff --git a/platform/jps-bootstrap/src/main/java/JpsBootstrapMain.java b/platform/jps-bootstrap/src/main/java/JpsBootstrapMain.java new file mode 100644 index 000000000000..00e51345f843 --- /dev/null +++ b/platform/jps-bootstrap/src/main/java/JpsBootstrapMain.java @@ -0,0 +1,167 @@ +// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.URLUtil; +import org.jetbrains.groovy.compiler.rt.GroovyRtConstants; +import org.jetbrains.jps.api.GlobalOptions; +import org.jetbrains.jps.build.Standalone; +import org.jetbrains.jps.incremental.groovy.JpsGroovycRunner; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator; +import org.jetbrains.jps.model.java.JpsJavaExtensionService; +import org.jetbrains.jps.model.library.JpsLibrary; +import org.jetbrains.jps.model.library.JpsOrderRootType; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.serialization.JpsModelSerializationDataService; +import org.jetbrains.jps.model.serialization.JpsPathVariablesConfiguration; +import org.jetbrains.jps.model.serialization.JpsProjectLoader; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +@SuppressWarnings({"UseOfSystemOutOrSystemErr", "SameParameterValue"}) +public class JpsBootstrapMain { + + private static final String PROJECT_HOME_ENV = "JPS_BOOTSTRAP_PROJECT_HOME"; + + @SuppressWarnings("ConfusingArgumentToVarargsMethod") + public static void main(String[] args) throws Throwable { + long startTime = System.currentTimeMillis(); + + String projectHomeString = System.getenv(PROJECT_HOME_ENV); + if (projectHomeString == null) { + System.err.println("Please set " + PROJECT_HOME_ENV + " environment variable"); + System.exit(1); + } + + Path projectHome = Path.of(projectHomeString); + Path buildDir = projectHome.resolve("out").resolve("jps-bootstrap"); + + JpsModel model = JpsElementFactory.getInstance().createModel(); + JpsPathVariablesConfiguration pathVariablesConfiguration = + JpsModelSerializationDataService.getOrCreatePathVariablesConfiguration(model.getGlobal()); + pathVariablesConfiguration.addPathVariable( + "MAVEN_REPOSITORY", + FileUtilRt.toSystemIndependentName(buildDir.resolve("m2").toAbsolutePath().toString())); + + System.setProperty("kotlin.incremental.compilation", "true"); + System.setProperty(GlobalOptions.COMPILE_PARALLEL_OPTION, "true"); + + Map pathVariables = JpsModelSerializationDataService.computeAllPathVariables(model.getGlobal()); + JpsProjectLoader.loadProject(model.getProject(), pathVariables, projectHome.toString()); + System.out.println( + "Loaded project " + projectHome + ": " + + model.getProject().getModules().size() + " modules, " + + model.getProject().getLibraryCollection().getLibraries().size() + " libraries in " + + (System.currentTimeMillis() - startTime) + " ms"); + + long buildStart = System.currentTimeMillis(); + + addSdk(model, "corretto-11", System.getProperty("java.home")); + + String url = "file://" + FileUtilRt.toSystemIndependentName(buildDir.resolve("out").toString()); + JpsJavaExtensionService.getInstance().getOrCreateProjectExtension(model.getProject()).setOutputUrl(url); + + System.setProperty(JpsGroovycRunner.GROOVYC_IN_PROCESS, "true"); + System.setProperty(GroovyRtConstants.GROOVYC_ASM_RESOLVING_ONLY, "false"); + System.setProperty(GlobalOptions.USE_DEFAULT_FILE_LOGGING_OPTION, "true"); + System.setProperty(GlobalOptions.LOG_DIR_OPTION, buildDir.resolve("log").toString()); + System.out.println("Log: " + System.getProperty(GlobalOptions.LOG_DIR_OPTION)); + + JpsModule module = model.getProject().getModules() + .stream() + .filter(m -> "intellij.idea.community.build".equals(m.getName())) + .findFirst().orElseThrow(); + + final boolean[] errors = {false}; + + Path dataStorageRoot = buildDir.resolve("jps-build-data"); + Standalone.runBuild( + () -> model, + dataStorageRoot.toFile(), + false, + // setOf("intellij.platform.util"), + ContainerUtil.set(module.getName()), + false, + Collections.emptyList(), + false, + msg -> { + BuildMessage.Kind kind = msg.getKind(); + //if (kind == BuildMessage.Kind.ERROR || kind == BuildMessage.Kind.INTERNAL_BUILDER_ERROR || kind == BuildMessage.Kind.PROGRESS) { + if (kind == BuildMessage.Kind.ERROR || kind == BuildMessage.Kind.INTERNAL_BUILDER_ERROR) { + System.out.println(kind + " " + msg.getMessageText()); + } + + if (kind == BuildMessage.Kind.ERROR || kind == BuildMessage.Kind.INTERNAL_BUILDER_ERROR) { + errors[0] = true; + } + } + ); + + System.out.println("Finished build in " + (System.currentTimeMillis() - buildStart) + " ms"); + + if (errors[0]) { + System.err.println("Build finished with errors"); + System.exit(1); + } + + JpsJavaDependenciesEnumerator enumerator = JpsJavaExtensionService + .dependencies(module) + .runtimeOnly() + .productionOnly() + .recursively() + .withoutSdk(); + + List roots = new ArrayList<>(); + for (File file : enumerator.classes().getRoots()) { + URL toURL = file.toURI().toURL(); + roots.add(toURL); + } + + try (URLClassLoader classloader = new URLClassLoader(roots.toArray(new URL[0]), ClassLoader.getSystemClassLoader())) { + Class mainClass = classloader.loadClass("org.jetbrains.intellij.build.ExampleGroovyMain"); + + MethodHandles.lookup() + .findStatic(mainClass, "main", MethodType.methodType(Void.TYPE, String[].class)) + .invokeExact(args); + } + } + + private static List readModulesFromReleaseFile(Path jdkDir) throws IOException { + Path releaseFile = jdkDir.resolve("release"); + Properties p = new Properties(); + try (InputStream is = Files.newInputStream(releaseFile)) { + p.load(is); + } + String jbrBaseUrl = URLUtil.JRT_PROTOCOL + URLUtil.SCHEME_SEPARATOR + + FileUtil.toSystemIndependentName(jdkDir.toFile().getAbsolutePath()) + + URLUtil.JAR_SEPARATOR; + String modules = p.getProperty("MODULES"); + return ContainerUtil.map(StringUtil.split(StringUtil.unquoteString(modules), " "), s -> jbrBaseUrl + s); + } + + private static void addSdk(JpsModel model, String sdkName, String sdkHome) throws IOException { + JpsJavaExtensionService.getInstance().addJavaSdk(model.getGlobal(), sdkName, sdkHome); + JpsLibrary additionalSdk = model.getGlobal().getLibraryCollection().findLibrary(sdkName); + if (additionalSdk == null) { + throw new IllegalStateException("SDK " + sdkHome + " was not found"); + } + + for (String moduleUrl : readModulesFromReleaseFile(Path.of(sdkHome))) { + additionalSdk.addRoot(moduleUrl, JpsOrderRootType.COMPILED); + } + } +}