Merge Android Studio EE Canary 9

GitOrigin-RevId: 0050a742aebbf8ecbcd3a76198a8a8e7059c6604
This commit is contained in:
Andrei Kuznetsov
2022-08-12 16:32:07 +00:00
committed by intellij-monorepo-bot
75 changed files with 1035 additions and 812 deletions
+1 -2
View File
@@ -17,5 +17,4 @@ edu/dependencies/.gradle
edu/dependencies/build
native/**/build/
stale_outputs_checked
/android
/tools/ideTestingFramework/intellij.tools.ide.starter
/android
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="aia-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/proto/30.2.0.0/proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/proto/221.0.9.0/proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="android-test-plugin-host-device-info-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libstudio.android-test-plugin-host-device-info-proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libstudio.android-test-plugin-host-device-info-proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libstudio.android-test-plugin-host-device-info-proto/30.2.0.0/libstudio.android-test-plugin-host-device-info-proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libstudio.android-test-plugin-host-device-info-proto/221.0.9.0/libstudio.android-test-plugin-host-device-info-proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="baksmali" type="repository">
<properties include-transitive-deps="false" maven-id="org.smali:baksmali:2.2.4" />
<properties include-transitive-deps="false" maven-id="org.smali:baksmali:2.5.2" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/smali/baksmali/2.2.4/baksmali-2.2.4.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/smali/baksmali/2.5.2/baksmali-2.5.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -9
View File
@@ -1,15 +1,8 @@
<component name="libraryTable">
<library name="dexlib2" type="repository">
<properties maven-id="org.smali:dexlib2:2.2.4">
<exclude>
<dependency maven-id="com.beust:jcommander" />
<dependency maven-id="com.google.code.findbugs:jsr305" />
<dependency maven-id="com.google.guava:guava" />
</exclude>
</properties>
<properties include-transitive-deps="false" maven-id="org.smali:dexlib2:2.5.2" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/smali/dexlib2/2.2.4/dexlib2-2.2.4.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/smali/util/2.2.4/util-2.2.4.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/smali/dexlib2/2.5.2/dexlib2-2.5.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="emulator-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:emulator_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:emulator_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/emulator_java_proto/30.2.0.0/emulator_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/emulator_java_proto/221.0.9.0/emulator_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+11
View File
@@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="ffmpeg" type="repository">
<properties maven-id="org.bytedeco:ffmpeg:5.0-1.5.7" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+41
View File
@@ -0,0 +1,41 @@
<component name="libraryTable">
<library name="ffmpeg-platform" type="repository">
<properties maven-id="org.bytedeco:ffmpeg-platform:5.0-1.5.7" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg-platform/5.0-1.5.7/ffmpeg-platform-5.0-1.5.7.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp-platform/1.5.7/javacpp-platform-1.5.7.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-android-arm.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-android-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-android-x86.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-android-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-ios-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-ios-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-linux-armhf.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-linux-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-linux-ppc64le.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-linux-x86.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-linux-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-macosx-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-macosx-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-windows-x86.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/javacpp/1.5.7/javacpp-1.5.7-windows-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-android-arm.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-android-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-android-x86.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-android-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-linux-x86.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-linux-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-linux-armhf.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-linux-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-linux-ppc64le.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-macosx-arm64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-macosx-x86_64.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-windows-x86.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/bytedeco/ffmpeg/5.0-1.5.7/ffmpeg-5.0-1.5.7-windows-x86_64.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="layout_inspector_compose_java_proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_compose_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_compose_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_compose_java_proto/30.2.0.0/layout_inspector_compose_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_compose_java_proto/221.0.9.0/layout_inspector_compose_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="layout_inspector_snapshot_java_proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_snapshot_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_snapshot_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_snapshot_java_proto/30.2.0.0/layout_inspector_snapshot_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_snapshot_java_proto/221.0.9.0/layout_inspector_snapshot_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="layout_inspector_view_java_proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_view_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_view_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_view_java_proto/30.2.0.0/layout_inspector_view_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_view_java_proto/221.0.9.0/layout_inspector_view_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="layoutinspector-skia-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_skia_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:layout_inspector_skia_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_skia_java_proto/30.2.0.0/layout_inspector_skia_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/layout_inspector_skia_java_proto/221.0.9.0/layout_inspector_skia_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="layoutlib" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:jb-layoutlib-jdk11:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:jb-layoutlib-jdk11:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/jb-layoutlib-jdk11/30.2.0.0/jb-layoutlib-jdk11-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/jb-layoutlib-jdk11/221.0.9.0/jb-layoutlib-jdk11-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="libam-instrumentation-data-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libam-instrumentation-data-proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libam-instrumentation-data-proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libam-instrumentation-data-proto/30.2.0.0/libam-instrumentation-data-proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libam-instrumentation-data-proto/221.0.9.0/libam-instrumentation-data-proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="libapp-processes-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libapp-processes-proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libapp-processes-proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libapp-processes-proto/30.2.0.0/libapp-processes-proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libapp-processes-proto/221.0.9.0/libapp-processes-proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="network_inspector_java_proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:network_inspector_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:network_inspector_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/network_inspector_java_proto/30.2.0.0/network_inspector_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/network_inspector_java_proto/221.0.9.0/network_inspector_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="perfetto-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:perfetto-protos:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:perfetto-protos:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/perfetto-protos/30.2.0.0/perfetto-protos-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/perfetto-protos/221.0.9.0/perfetto-protos-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="sqlite-inspector-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:sqlite_inspector_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:sqlite_inspector_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/sqlite_inspector_proto/30.2.0.0/sqlite_inspector_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/sqlite_inspector_proto/221.0.9.0/sqlite_inspector_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="studio-analytics-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libstudio.proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:libstudio.proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libstudio.proto/30.2.0.0/libstudio.proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/libstudio.proto/221.0.9.0/libstudio.proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="studio-grpc" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:studio-grpc:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:studio-grpc:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/studio-grpc/30.2.0.0/studio-grpc-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/studio-grpc/221.0.9.0/studio-grpc-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="studio-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:studio-proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:studio-proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/studio-proto/30.2.0.0/studio-proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/studio-proto/221.0.9.0/studio-proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+2 -2
View File
@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="transport-proto" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:transport_java_proto:30.2.0.0" />
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps.android.tools.base:transport_java_proto:221.0.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/transport_java_proto/30.2.0.0/transport_java_proto-30.2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/android/tools/base/transport_java_proto/221.0.9.0/transport_java_proto-221.0.9.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
+66 -49
View File
@@ -317,11 +317,14 @@
</component>
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/android/analytics/analytics.iml" filepath="$PROJECT_DIR$/android/analytics/analytics.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/analytics-crash.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/analytics-crash.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/analytics-shared.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/analytics-shared.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/analytics-tracker.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/analytics-tracker.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.adblib.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.adblib.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-crash.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-crash.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-shared.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-shared.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.adblib.ddmlibcompatibility.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.adblib.ddmlibcompatibility.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.adblib.tools.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.adblib.tools.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-testing.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-testing.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-tracker.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analytics-tracker.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analyzer.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.analyzer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.android-annotations.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.android-annotations.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.binary-resources.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.binary-resources.iml" />
@@ -329,18 +332,12 @@
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.chunkio.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.chunkio.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.common.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.common.testfixtures.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.common.testfixtures.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-baseLibrary.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-baseLibrary.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-baseLibrarySupport.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-baseLibrarySupport.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-compiler.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-compiler.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-compilerCommon.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.db-compilerCommon.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.ddmlib.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.ddmlib.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.deployer.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.deployer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.draw9patch.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.draw9patch.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.dvlib.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.dvlib.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.dynamic-layout-inspector.common.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.dynamic-layout-inspector.common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.fakeadbserver.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.fakeadbserver.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.flags.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.flags.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.layoutinspector.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.layoutinspector.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.layoutlib-api.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.layoutlib-api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.lint-api.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.lint-api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.lint-checks.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.lint-checks.iml" />
@@ -349,7 +346,6 @@
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.manifest-parser.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.manifest-parser.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.mlkit-common.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.mlkit-common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.ninepatch.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.ninepatch.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.perf-logger.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.perf-logger.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.perflib.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.perflib.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.pixelprobe.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.pixelprobe.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.repository.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.repository.iml" />
@@ -357,57 +353,63 @@
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.sdk-common.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.sdk-common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.sdklib.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.sdklib.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.testutils.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.testutils.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.threading-agent-callback.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.threading-agent-callback.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.tracer.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.tracer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.usb-devices.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.usb-devices.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.wizardTemplate.impl.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.wizardTemplate.impl.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.wizardTemplate.plugin.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.wizardTemplate.plugin.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.zipflinger.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/android.sdktools.zipflinger.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/api/app-inspection.api.iml" filepath="$PROJECT_DIR$/android/app-inspection/api/app-inspection.api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/ide/app-inspection.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/ide/app-inspection.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/ide/app-inspection.ide.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/ide/app-inspection.ide.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspector/api/app-inspection.inspector.api.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspector/api/app-inspection.inspector.api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspector/ide/app-inspection.inspector.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspector/ide/app-inspection.inspector.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/ide/app-inspection.inspectors.backgroundtask.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/ide/app-inspection.inspectors.backgroundtask.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/model/app-inspection.inspectors.backgroundtask.model.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/model/app-inspection.inspectors.backgroundtask.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/app-inspection.inspectors.backgroundtask.view.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/app-inspection.inspectors.backgroundtask.view.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/app-inspection.inspectors.backgroundtask.view.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/app-inspection.inspectors.backgroundtask.view.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/database/app-inspection.inspectors.database.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/database/app-inspection.inspectors.database.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/database/app-inspection.inspectors.database.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/database/app-inspection.inspectors.database.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/app-inspection.inspectors.network.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/app-inspection.inspectors.network.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/app-inspection.inspectors.network.ide.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/app-inspection.inspectors.network.ide.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/model/app-inspection.inspectors.network.model.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/model/app-inspection.inspectors.network.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/view/app-inspection.inspectors.network.view.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/view/app-inspection.inspectors.network.view.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/view/app-inspection.inspectors.network.view.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/view/app-inspection.inspectors.network.view.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/ide/app-inspection.inspectors.workmanager.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/ide/app-inspection.inspectors.workmanager.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/model/app-inspection.inspectors.workmanager.model.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/model/app-inspection.inspectors.workmanager.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/app-inspection.inspectors.workmanager.view.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/app-inspection.inspectors.workmanager.view.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/app-inspection.inspectors.workmanager.view.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/app-inspection.inspectors.workmanager.view.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/as-driver/agent/as-driver.agent.iml" filepath="$PROJECT_DIR$/android/as-driver/agent/as-driver.agent.iml" />
<module fileurl="file://$PROJECT_DIR$/android/as-driver/utils/as-driver.utils.iml" filepath="$PROJECT_DIR$/android/as-driver/utils/as-driver.utils.iml" />
<module fileurl="file://$PROJECT_DIR$/android/assistant/assistant.iml" filepath="$PROJECT_DIR$/android/assistant/assistant.iml" />
<module fileurl="file://$PROJECT_DIR$/android/assistant/assistant-test.iml" filepath="$PROJECT_DIR$/android/assistant/assistant-test.iml" />
<module fileurl="file://$PROJECT_DIR$/android/codenavigation/codenavigation.iml" filepath="$PROJECT_DIR$/android/codenavigation/codenavigation.iml" />
<module fileurl="file://$PROJECT_DIR$/android/connection-assistant/connection-assistant.iml" filepath="$PROJECT_DIR$/android/connection-assistant/connection-assistant.iml" />
<module fileurl="file://$PROJECT_DIR$/android/connection-assistant/connection-assistant-test.iml" filepath="$PROJECT_DIR$/android/connection-assistant/connection-assistant-test.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/db-baseLibrary.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/db-baseLibrary.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/db-baseLibrarySupport.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/db-baseLibrarySupport.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/db-compiler.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/db-compiler.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/db-compilerCommon.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/db-compilerCommon.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/dynamic-layout-inspector.common.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/dynamic-layout-inspector.common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-adb/intellij.android.adb.iml" filepath="$PROJECT_DIR$/android/android-adb/intellij.android.adb.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-adb/intellij.android.adb.tests.iml" filepath="$PROJECT_DIR$/android/android-adb/intellij.android.adb.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-adb-ui/intellij.android.adb.ui.iml" filepath="$PROJECT_DIR$/android/android-adb-ui/intellij.android.adb.ui.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-adb-ui/intellij.android.adb.ui.tests.iml" filepath="$PROJECT_DIR$/android/android-adb-ui/intellij.android.adb.ui.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/swingp/intellij.android.adt.swingp.iml" filepath="$PROJECT_DIR$/android/swingp/intellij.android.adt.swingp.iml" />
<module fileurl="file://$PROJECT_DIR$/android/adt-testutils/intellij.android.adt.testutils.iml" filepath="$PROJECT_DIR$/android/adt-testutils/intellij.android.adt.testutils.iml" />
<module fileurl="file://$PROJECT_DIR$/android/adt-ui/intellij.android.adt.ui.iml" filepath="$PROJECT_DIR$/android/adt-ui/intellij.android.adt.ui.iml" />
<module fileurl="file://$PROJECT_DIR$/android/adt-ui-model/intellij.android.adt.ui.model.iml" filepath="$PROJECT_DIR$/android/adt-ui-model/intellij.android.adt.ui.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-layout-inspector/intellij.android.android-layout-inspector.iml" filepath="$PROJECT_DIR$/android/android-layout-inspector/intellij.android.android-layout-inspector.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-layout-inspector/intellij.android.android-layout-inspector-test.iml" filepath="$PROJECT_DIR$/android/android-layout-inspector/intellij.android.android-layout-inspector-test.iml" />
<module fileurl="file://$PROJECT_DIR$/android/androidx-integration-tests/intellij.android.androidx-integration-tests.iml" filepath="$PROJECT_DIR$/android/androidx-integration-tests/intellij.android.androidx-integration-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/apkanalyzer/intellij.android.apkanalyzer.iml" filepath="$PROJECT_DIR$/android/apkanalyzer/intellij.android.apkanalyzer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/api/intellij.android.app-inspection.api.iml" filepath="$PROJECT_DIR$/android/app-inspection/api/intellij.android.app-inspection.api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/ide/intellij.android.app-inspection.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/ide/intellij.android.app-inspection.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/ide/intellij.android.app-inspection.ide.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/ide/intellij.android.app-inspection.ide.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspector/api/intellij.android.app-inspection.inspector.api.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspector/api/intellij.android.app-inspection.inspector.api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspector/ide/intellij.android.app-inspection.inspector.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspector/ide/intellij.android.app-inspection.inspector.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/ide/intellij.android.app-inspection.inspectors.backgroundtask.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/ide/intellij.android.app-inspection.inspectors.backgroundtask.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/model/intellij.android.app-inspection.inspectors.backgroundtask.model.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/model/intellij.android.app-inspection.inspectors.backgroundtask.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/intellij.android.app-inspection.inspectors.backgroundtask.view.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/intellij.android.app-inspection.inspectors.backgroundtask.view.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/intellij.android.app-inspection.inspectors.backgroundtask.view.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/backgroundtask/view/intellij.android.app-inspection.inspectors.backgroundtask.view.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/database/intellij.android.app-inspection.inspectors.database.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/database/intellij.android.app-inspection.inspectors.database.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/database/intellij.android.app-inspection.inspectors.database.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/database/intellij.android.app-inspection.inspectors.database.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/intellij.android.app-inspection.inspectors.network.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/intellij.android.app-inspection.inspectors.network.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/intellij.android.app-inspection.inspectors.network.ide.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/ide/intellij.android.app-inspection.inspectors.network.ide.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/model/intellij.android.app-inspection.inspectors.network.model.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/model/intellij.android.app-inspection.inspectors.network.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/view/intellij.android.app-inspection.inspectors.network.view.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/view/intellij.android.app-inspection.inspectors.network.view.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/network/view/intellij.android.app-inspection.inspectors.network.view.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/network/view/intellij.android.app-inspection.inspectors.network.view.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/ide/intellij.android.app-inspection.inspectors.workmanager.ide.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/ide/intellij.android.app-inspection.inspectors.workmanager.ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/model/intellij.android.app-inspection.inspectors.workmanager.model.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/model/intellij.android.app-inspection.inspectors.workmanager.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/intellij.android.app-inspection.inspectors.workmanager.view.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/intellij.android.app-inspection.inspectors.workmanager.view.iml" />
<module fileurl="file://$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/intellij.android.app-inspection.inspectors.workmanager.view.tests.iml" filepath="$PROJECT_DIR$/android/app-inspection/inspectors/workmanager/view/intellij.android.app-inspection.inspectors.workmanager.view.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/artwork/intellij.android.artwork.iml" filepath="$PROJECT_DIR$/android/artwork/intellij.android.artwork.iml" />
<module fileurl="file://$PROJECT_DIR$/android/assistant/intellij.android.assistant.iml" filepath="$PROJECT_DIR$/android/assistant/intellij.android.assistant.iml" />
<module fileurl="file://$PROJECT_DIR$/android/assistant/intellij.android.assistant-test.iml" filepath="$PROJECT_DIR$/android/assistant/intellij.android.assistant-test.iml" />
<module fileurl="file://$PROJECT_DIR$/android/bleak/intellij.android.bleak.iml" filepath="$PROJECT_DIR$/android/bleak/intellij.android.bleak.iml" />
<module fileurl="file://$PROJECT_DIR$/android/build-attribution/intellij.android.build-attribution.iml" filepath="$PROJECT_DIR$/android/build-attribution/intellij.android.build-attribution.iml" />
<module fileurl="file://$PROJECT_DIR$/android/build-attribution/intellij.android.build-attribution.tests.iml" filepath="$PROJECT_DIR$/android/build-attribution/intellij.android.build-attribution.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/build-common/intellij.android.buildCommon.iml" filepath="$PROJECT_DIR$/android/build-common/intellij.android.buildCommon.iml" />
<module fileurl="file://$PROJECT_DIR$/android/codenavigation/intellij.android.codenavigation.iml" filepath="$PROJECT_DIR$/android/codenavigation/intellij.android.codenavigation.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-common/intellij.android.common.iml" filepath="$PROJECT_DIR$/android/android-common/intellij.android.common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/intellij.android.compose-common/intellij.android.compose-common.iml" filepath="$PROJECT_DIR$/android/intellij.android.compose-common/intellij.android.compose-common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/compose-designer/intellij.android.compose-designer.iml" filepath="$PROJECT_DIR$/android/compose-designer/intellij.android.compose-designer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/compose-designer/intellij.android.compose-designer.integration.iml" filepath="$PROJECT_DIR$/android/compose-designer/intellij.android.compose-designer.integration.iml" />
<module fileurl="file://$PROJECT_DIR$/android/compose-designer/intellij.android.compose-designer.tests.iml" filepath="$PROJECT_DIR$/android/compose-designer/intellij.android.compose-designer.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/compose-ide-plugin/intellij.android.compose-ide-plugin.iml" filepath="$PROJECT_DIR$/android/compose-ide-plugin/intellij.android.compose-ide-plugin.iml" />
<module fileurl="file://$PROJECT_DIR$/android/compose-ide-plugin/intellij.android.compose-ide-plugin.tests.iml" filepath="$PROJECT_DIR$/android/compose-ide-plugin/intellij.android.compose-ide-plugin.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/connection-assistant/intellij.android.connection-assistant.iml" filepath="$PROJECT_DIR$/android/connection-assistant/intellij.android.connection-assistant.iml" />
<module fileurl="file://$PROJECT_DIR$/android/connection-assistant/intellij.android.connection-assistant-test.iml" filepath="$PROJECT_DIR$/android/connection-assistant/intellij.android.connection-assistant-test.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/intellij.android.core.iml" filepath="$PROJECT_DIR$/android/android/intellij.android.core.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/intellij.android.core.agp-integration-tests.iml" filepath="$PROJECT_DIR$/android/android/intellij.android.core.agp-integration-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/intellij.android.core.tests.iml" filepath="$PROJECT_DIR$/android/android/intellij.android.core.tests.iml" />
@@ -426,6 +428,10 @@
<module fileurl="file://$PROJECT_DIR$/android/designer/intellij.android.designer.tests.iml" filepath="$PROJECT_DIR$/android/designer/intellij.android.designer.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/device-explorer/intellij.android.device-explorer.iml" filepath="$PROJECT_DIR$/android/device-explorer/intellij.android.device-explorer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/device-explorer/intellij.android.device-explorer.tests.iml" filepath="$PROJECT_DIR$/android/device-explorer/intellij.android.device-explorer.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/device-manager/intellij.android.device-manager.iml" filepath="$PROJECT_DIR$/android/device-manager/intellij.android.device-manager.iml" />
<module fileurl="file://$PROJECT_DIR$/android/device-manager/intellij.android.device-manager.tests.iml" filepath="$PROJECT_DIR$/android/device-manager/intellij.android.device-manager.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/device-monitor/intellij.android.device-monitor.iml" filepath="$PROJECT_DIR$/android/device-monitor/intellij.android.device-monitor.iml" />
<module fileurl="file://$PROJECT_DIR$/android/device-monitor/intellij.android.device-monitor.tests.iml" filepath="$PROJECT_DIR$/android/device-monitor/intellij.android.device-monitor.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/emulator/intellij.android.emulator.iml" filepath="$PROJECT_DIR$/android/emulator/intellij.android.emulator.iml" />
<module fileurl="file://$PROJECT_DIR$/android/emulator/intellij.android.emulator.tests.iml" filepath="$PROJECT_DIR$/android/emulator/intellij.android.emulator.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/gradle-tooling/studio-gradle-tooling-api/intellij.android.gradle-tooling.api.iml" filepath="$PROJECT_DIR$/android/gradle-tooling/studio-gradle-tooling-api/intellij.android.gradle-tooling.api.iml" />
@@ -434,12 +440,12 @@
<module fileurl="file://$PROJECT_DIR$/android/gradle-dsl-kotlin/intellij.android.gradle.dsl.kotlin.iml" filepath="$PROJECT_DIR$/android/gradle-dsl-kotlin/intellij.android.gradle.dsl.kotlin.iml" />
<module fileurl="file://$PROJECT_DIR$/android/gradle-dsl/intellij.android.gradle.dsl.tests.iml" filepath="$PROJECT_DIR$/android/gradle-dsl/intellij.android.gradle.dsl.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/gradle-dsl/intellij.android.gradle.dsl.testutils.iml" filepath="$PROJECT_DIR$/android/gradle-dsl/intellij.android.gradle.dsl.testutils.iml" />
<module fileurl="file://$PROJECT_DIR$/android/gradle-dsl-toml/intellij.android.gradle.dsl.toml.iml" filepath="$PROJECT_DIR$/android/gradle-dsl-toml/intellij.android.gradle.dsl.toml.iml" />
<module fileurl="file://$PROJECT_DIR$/android/ide-perf-tests/intellij.android.ide-perf-tests.iml" filepath="$PROJECT_DIR$/android/ide-perf-tests/intellij.android.ide-perf-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/idea-integration-tests/intellij.android.ideaIntegrationTests.iml" filepath="$PROJECT_DIR$/android/idea-integration-tests/intellij.android.ideaIntegrationTests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/inspectors-common/api/intellij.android.inspectors-common.api.iml" filepath="$PROJECT_DIR$/android/inspectors-common/api/intellij.android.inspectors-common.api.iml" />
<module fileurl="file://$PROJECT_DIR$/android/inspectors-common/api-ide/intellij.android.inspectors-common.api-ide.iml" filepath="$PROJECT_DIR$/android/inspectors-common/api-ide/intellij.android.inspectors-common.api-ide.iml" />
<module fileurl="file://$PROJECT_DIR$/android/inspectors-common/ui/intellij.android.inspectors-common.ui.iml" filepath="$PROJECT_DIR$/android/inspectors-common/ui/intellij.android.inspectors-common.ui.iml" />
<module fileurl="file://$PROJECT_DIR$/android/kotlin-integration/intellij.android.kotlin-integration-tests.iml" filepath="$PROJECT_DIR$/android/kotlin-integration/intellij.android.kotlin-integration-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/jps-model/intellij.android.jps.model.iml" filepath="$PROJECT_DIR$/android/jps-model/intellij.android.jps.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-kotlin/android-extensions-idea/intellij.android.kotlin.extensions.iml" filepath="$PROJECT_DIR$/android/android-kotlin/android-extensions-idea/intellij.android.kotlin.extensions.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-kotlin/android-extensions-idea-common/intellij.android.kotlin.extensions.common.iml" filepath="$PROJECT_DIR$/android/android-kotlin/android-extensions-idea-common/intellij.android.kotlin.extensions.common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-kotlin/idea-android/intellij.android.kotlin.idea.iml" filepath="$PROJECT_DIR$/android/android-kotlin/idea-android/intellij.android.kotlin.idea.iml" />
@@ -456,13 +462,11 @@
<module fileurl="file://$PROJECT_DIR$/android/layoutlib-loader/intellij.android.layoutlib-loader.iml" filepath="$PROJECT_DIR$/android/layoutlib-loader/intellij.android.layoutlib-loader.iml" />
<module fileurl="file://$PROJECT_DIR$/android/layoutlib/intellij.android.layoutlib.tests.iml" filepath="$PROJECT_DIR$/android/layoutlib/intellij.android.layoutlib.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-lint/intellij.android.lint.iml" filepath="$PROJECT_DIR$/android/android-lint/intellij.android.lint.iml" />
<module fileurl="file://$PROJECT_DIR$/android/lint/intellij.android.lint.common.iml" filepath="$PROJECT_DIR$/android/lint/intellij.android.lint.common.iml" />
<module fileurl="file://$PROJECT_DIR$/android/lint/tests/intellij.android.lint.common.tests.iml" filepath="$PROJECT_DIR$/android/lint/tests/intellij.android.lint.common.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-lint/intellij.android.lint.tests.iml" filepath="$PROJECT_DIR$/android/android-lint/intellij.android.lint.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/logcat/intellij.android.logcat.iml" filepath="$PROJECT_DIR$/android/logcat/intellij.android.logcat.iml" />
<module fileurl="file://$PROJECT_DIR$/android/logcat/intellij.android.logcat.tests.iml" filepath="$PROJECT_DIR$/android/logcat/intellij.android.logcat.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/mlkit/intellij.android.mlkit.iml" filepath="$PROJECT_DIR$/android/mlkit/intellij.android.mlkit.iml" />
<module fileurl="file://$PROJECT_DIR$/android/mlkit/intellij.android.mlkit.tests.iml" filepath="$PROJECT_DIR$/android/mlkit/intellij.android.mlkit.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/native-symbolizer/intellij.android.native-symbolizer.iml" filepath="$PROJECT_DIR$/android/native-symbolizer/intellij.android.native-symbolizer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/nav/editor/intellij.android.nav.editor.iml" filepath="$PROJECT_DIR$/android/nav/editor/intellij.android.nav.editor.iml" />
<module fileurl="file://$PROJECT_DIR$/android/nav/editor/intellij.android.nav.editor.tests.iml" filepath="$PROJECT_DIR$/android/nav/editor/intellij.android.nav.editor.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/nav/safeargs/intellij.android.nav.safeargs.iml" filepath="$PROJECT_DIR$/android/nav/safeargs/intellij.android.nav.safeargs.iml" />
@@ -472,7 +476,6 @@
<module fileurl="file://$PROJECT_DIR$/android/android-npw/intellij.android.newProjectWizard.iml" filepath="$PROJECT_DIR$/android/android-npw/intellij.android.newProjectWizard.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-npw/intellij.android.newProjectWizard.tests.iml" filepath="$PROJECT_DIR$/android/android-npw/intellij.android.newProjectWizard.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/observable/intellij.android.observable.iml" filepath="$PROJECT_DIR$/android/observable/intellij.android.observable.iml" />
<module fileurl="file://$PROJECT_DIR$/android/observable-demo/intellij.android.observable-demo.iml" filepath="$PROJECT_DIR$/android/observable-demo/intellij.android.observable-demo.iml" />
<module fileurl="file://$PROJECT_DIR$/android/observable-ui/intellij.android.observable.ui.iml" filepath="$PROJECT_DIR$/android/observable-ui/intellij.android.observable.ui.iml" />
<module fileurl="file://$PROJECT_DIR$/android/old-agp-tests/intellij.android.old-agp-tests.iml" filepath="$PROJECT_DIR$/android/old-agp-tests/intellij.android.old-agp-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-plugin/intellij.android.plugin.iml" filepath="$PROJECT_DIR$/android/android-plugin/intellij.android.plugin.iml" />
@@ -499,6 +502,7 @@
<module fileurl="file://$PROJECT_DIR$/android/sdk-updates/intellij.android.sdkUpdates.tests.iml" filepath="$PROJECT_DIR$/android/sdk-updates/intellij.android.sdkUpdates.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/server-flags/intellij.android.server-flags.iml" filepath="$PROJECT_DIR$/android/server-flags/intellij.android.server-flags.iml" />
<module fileurl="file://$PROJECT_DIR$/android/smali/intellij.android.smali.iml" filepath="$PROJECT_DIR$/android/smali/intellij.android.smali.iml" />
<module fileurl="file://$PROJECT_DIR$/android/studio/integration/intellij.android.studio.integration/intellij.android.studio.integration.iml" filepath="$PROJECT_DIR$/android/studio/integration/intellij.android.studio.integration/intellij.android.studio.integration.iml" />
<module fileurl="file://$PROJECT_DIR$/android/studio/tests/intellij.android.studio.tests.iml" filepath="$PROJECT_DIR$/android/studio/tests/intellij.android.studio.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/sync-perf-tests/intellij.android.sync-perf-tests.iml" filepath="$PROJECT_DIR$/android/sync-perf-tests/intellij.android.sync-perf-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-templates/intellij.android.templates.iml" filepath="$PROJECT_DIR$/android/android-templates/intellij.android.templates.iml" />
@@ -506,13 +510,17 @@
<module fileurl="file://$PROJECT_DIR$/android/android-test-framework/intellij.android.testFramework.iml" filepath="$PROJECT_DIR$/android/android-test-framework/intellij.android.testFramework.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-test-retention/intellij.android.testRetention.iml" filepath="$PROJECT_DIR$/android/android-test-retention/intellij.android.testRetention.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-test-retention/intellij.android.testRetention.tests.iml" filepath="$PROJECT_DIR$/android/android-test-retention/intellij.android.testRetention.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/threading-checker/intellij.android.threading-checker.iml" filepath="$PROJECT_DIR$/android/threading-checker/intellij.android.threading-checker.iml" />
<module fileurl="file://$PROJECT_DIR$/android/threading-checker/intellij.android.threading-checker.tests.iml" filepath="$PROJECT_DIR$/android/threading-checker/intellij.android.threading-checker.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android-transport/intellij.android.transport.iml" filepath="$PROJECT_DIR$/android/android-transport/intellij.android.transport.iml" />
<module fileurl="file://$PROJECT_DIR$/android/transport-database/intellij.android.transportDatabase.iml" filepath="$PROJECT_DIR$/android/transport-database/intellij.android.transportDatabase.iml" />
<module fileurl="file://$PROJECT_DIR$/android/utp/intellij.android.utp.iml" filepath="$PROJECT_DIR$/android/utp/intellij.android.utp.iml" />
<module fileurl="file://$PROJECT_DIR$/android/whats-new-assistant/intellij.android.whats-new-assistant.iml" filepath="$PROJECT_DIR$/android/whats-new-assistant/intellij.android.whats-new-assistant.iml" />
<module fileurl="file://$PROJECT_DIR$/android/whats-new-assistant/intellij.android.whats-new-assistant-test.iml" filepath="$PROJECT_DIR$/android/whats-new-assistant/intellij.android.whats-new-assistant-test.iml" />
<module fileurl="file://$PROJECT_DIR$/android/wear-pairing/intellij.android.wear-pairing.iml" filepath="$PROJECT_DIR$/android/wear-pairing/intellij.android.wear-pairing.iml" />
<module fileurl="file://$PROJECT_DIR$/android/wear-pairing/intellij.android.wear-pairing.tests.iml" filepath="$PROJECT_DIR$/android/wear-pairing/intellij.android.wear-pairing.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/wizard/intellij.android.wizard.iml" filepath="$PROJECT_DIR$/android/wizard/intellij.android.wizard.iml" />
<module fileurl="file://$PROJECT_DIR$/android/wizard-model/intellij.android.wizard.model.iml" filepath="$PROJECT_DIR$/android/wizard-model/intellij.android.wizard.model.iml" />
<module fileurl="file://$PROJECT_DIR$/android/wizard/intellij.android.wizard.tests.iml" filepath="$PROJECT_DIR$/android/wizard/intellij.android.wizard.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/intellij.android.wizardTemplate.impl.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/intellij.android.wizardTemplate.impl.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/intellij.android.wizardTemplate.plugin.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/intellij.android.wizardTemplate.plugin.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/ant/intellij.ant.iml" filepath="$PROJECT_DIR$/plugins/ant/intellij.ant.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/ant/jps-plugin/intellij.ant.jps.iml" filepath="$PROJECT_DIR$/plugins/ant/jps-plugin/intellij.ant.jps.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/color-schemes/all-hallows-eve-color-scheme/intellij.color.scheme.all_hallows_eve.iml" filepath="$PROJECT_DIR$/plugins/color-schemes/all-hallows-eve-color-scheme/intellij.color.scheme.all_hallows_eve.iml" />
@@ -708,6 +716,8 @@
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/intellij.kotlin.plugin.community.main.iml" filepath="$PROJECT_DIR$/plugins/kotlin/intellij.kotlin.plugin.community.main.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/laf/macos/intellij.laf.macos.iml" filepath="$PROJECT_DIR$/plugins/laf/macos/intellij.laf.macos.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/laf/win10/intellij.laf.win10.iml" filepath="$PROJECT_DIR$/plugins/laf/win10/intellij.laf.win10.iml" />
<module fileurl="file://$PROJECT_DIR$/android/lint/intellij.lint.iml" filepath="$PROJECT_DIR$/android/lint/intellij.lint.iml" />
<module fileurl="file://$PROJECT_DIR$/android/lint/tests/intellij.lint.tests.iml" filepath="$PROJECT_DIR$/android/lint/tests/intellij.lint.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/lombok/intellij.lombok.iml" filepath="$PROJECT_DIR$/plugins/lombok/intellij.lombok.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/lombok/generated/intellij.lombok.generated.iml" filepath="$PROJECT_DIR$/plugins/lombok/generated/intellij.lombok.generated.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/markdown/intellij.markdown.iml" filepath="$PROJECT_DIR$/plugins/markdown/intellij.markdown.iml" />
@@ -1022,6 +1032,7 @@
<module fileurl="file://$PROJECT_DIR$/plugins/xslt-debugger/engine/impl/intellij.xslt.debugger.impl.rt.iml" filepath="$PROJECT_DIR$/plugins/xslt-debugger/engine/impl/intellij.xslt.debugger.impl.rt.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/xslt-debugger/engine/intellij.xslt.debugger.rt.iml" filepath="$PROJECT_DIR$/plugins/xslt-debugger/engine/intellij.xslt.debugger.rt.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/yaml/intellij.yaml.iml" filepath="$PROJECT_DIR$/plugins/yaml/intellij.yaml.iml" />
<module fileurl="file://$PROJECT_DIR$/android/kotlin-integration/kotlin-integration-tests.iml" filepath="$PROJECT_DIR$/android/kotlin-integration/kotlin-integration-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/all-tests/kotlin.all-tests.iml" filepath="$PROJECT_DIR$/plugins/kotlin/all-tests/kotlin.all-tests.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/base/analysis/kotlin.base.analysis.iml" filepath="$PROJECT_DIR$/plugins/kotlin/base/analysis/kotlin.base.analysis.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/base/analysis-api-providers/kotlin.base.analysis-api-providers.iml" filepath="$PROJECT_DIR$/plugins/kotlin/base/analysis-api-providers/kotlin.base.analysis-api-providers.iml" />
@@ -1204,6 +1215,12 @@
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/util/test-generator/kotlin.util.test-generator.iml" filepath="$PROJECT_DIR$/plugins/kotlin/util/test-generator/kotlin.util.test-generator.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/util/test-generator-fe10/kotlin.util.test-generator-fe10.iml" filepath="$PROJECT_DIR$/plugins/kotlin/util/test-generator-fe10/kotlin.util.test-generator-fe10.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/kotlin/util/test-generator-fir/kotlin.util.test-generator-fir.iml" filepath="$PROJECT_DIR$/plugins/kotlin/util/test-generator-fir/kotlin.util.test-generator-fir.iml" />
<module fileurl="file://$PROJECT_DIR$/android/native-symbolizer/native-symbolizer.iml" filepath="$PROJECT_DIR$/android/native-symbolizer/native-symbolizer.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/perf-logger.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/perf-logger.iml" />
<module fileurl="file://$PROJECT_DIR$/android/android/prebuilts/sdktools/usb-devices.iml" filepath="$PROJECT_DIR$/android/android/prebuilts/sdktools/usb-devices.iml" />
<module fileurl="file://$PROJECT_DIR$/android/utp/utp.iml" filepath="$PROJECT_DIR$/android/utp/utp.iml" />
<module fileurl="file://$PROJECT_DIR$/android/whats-new-assistant/whats-new-assistant.iml" filepath="$PROJECT_DIR$/android/whats-new-assistant/whats-new-assistant.iml" />
<module fileurl="file://$PROJECT_DIR$/android/whats-new-assistant/whats-new-assistant-test.iml" filepath="$PROJECT_DIR$/android/whats-new-assistant/whats-new-assistant-test.iml" />
</modules>
</component>
</project>
@@ -1,6 +1,5 @@
### Starter for IntelliJ IDEA based IDE's
#### Overview
Starter helps you write tests/code, that will start IntelliJ-based IDE from installer in external process.
@@ -14,7 +13,6 @@ Aside from that, you may find useful functionality as below:
* reporting of artifacts to CI (optional)
* run a test with a profiler (not yet included)
#### Supported products
* IDEA
@@ -26,7 +24,6 @@ Aside from that, you may find useful functionality as below:
* RubyMine
* Android Studio
##### How to setup
Configure maven repositories in your `build.gradle` file
@@ -48,6 +45,7 @@ OR
`maven { url = "https://www.jetbrains.com/intellij-repository/nightly" }`
But don't forget to change accordingly version of the packages as such:
* nightly -> LATEST-TRUNK-SNAPSHOT
* snapshots -> LATEST-EAP-SNAPSHOT
* releases -> semver package version
@@ -80,8 +78,6 @@ compileTestKotlin {
```
##### Run with JUnit4
[Example of simple test, that will download IntelliJ IDEA and start import of gradle project](https://github.com/JetBrains/intellij-ide-starter/tree/master/testSrc/com/intellij/ide/starter/tests/examples/junit4)
@@ -92,10 +88,10 @@ You should create appropriate classes in your tests for JUnit4StarterRule, IdeaC
[Example of simple test, that will download IntelliJ IDEA and start import of gradle project](https://github.com/JetBrains/intellij-ide-starter/tree/master/testSrc/com/intellij/ide/starter/tests/examples/junit5)
##### Available commands from plugins
Dependency `performance-testing-commands`
- waitForSmartMode()
- flushIndexes()
- setupProjectSdk(sdkName: String, sdkType: String, sdkPath: String)
@@ -132,9 +128,11 @@ Dependency `performance-testing-commands`
- ... **TBD**
Dependency `performance-testing-maven-commands`
- importMavenProject()
Dependency `performance-testing-gradle-commands`
- importGradleProject()
#### What behaviour might be extended / modified
@@ -146,6 +144,7 @@ For example, you might write your own implementation of CIServer and provide it
NOTE: Be sure to use the same version of Kodein, that is used in `build.gradle` for starter project.
E.g:
```
di = DI {
extend(di)
@@ -2,14 +2,16 @@
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="3" platform="JVM 11" allPlatforms="JVM [11]" useProjectSettings="false">
<configuration version="5" platform="JVM 11" allPlatforms="JVM [11]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-version -Xjvm-default=enable -Xopt-in=kotlin.time.ExperimentalTime" />
<option name="additionalArguments" value="-version -Xjvm-default=enable -opt-in=kotlin.time.ExperimentalTime" />
</compilerSettings>
<compilerArguments>
<option name="jvmTarget" value="11" />
<option name="languageVersion" value="1.7" />
<option name="apiVersion" value="1.7" />
<stringArguments>
<stringArg name="jvmTarget" arg="11" />
<stringArg name="apiVersion" arg="1.7" />
<stringArg name="languageVersion" arg="1.7" />
</stringArguments>
</compilerArguments>
</configuration>
</facet>
@@ -0,0 +1,11 @@
# JVM TI agent that logs loading and preparation stages of class lifecycle
# Set JAVA_HOME to JBR 17 location
# Usage VM Options: -agentpath:/var/tmp/libvmtrace.so=output.log
# Original source: https://github.com/odnoklassniki/jvmti-tools#vmtrace
build-linux:
g++ -O2 -fPIC -shared -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -olibvmtrace.so vmtrace.cpp
build-macos:
g++ -O2 -fPIC -shared -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/darwin -olibvmtrace.dylib vmtrace.cpp
@@ -0,0 +1,119 @@
/*
* Copyright 2019 Odnoklassniki Ltd, Mail.Ru Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Original source: https://github.com/odnoklassniki/jvmti-tools#vmtrace
#include <jvmti.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
static FILE* out;
static jrawMonitorID vmtrace_lock;
static jlong start_time;
static void trace(jvmtiEnv* jvmti, const char* fmt, ...) {
jlong current_time;
jvmti->GetTime(&current_time);
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
jvmti->RawMonitorEnter(vmtrace_lock);
fprintf(out, "[%.5f] %s\n", (current_time - start_time) / 1000000000.0, buf);
jvmti->RawMonitorExit(vmtrace_lock);
}
static char* fix_class_name(char* class_name) {
// Strip 'L' and ';' from class signature
class_name[strlen(class_name) - 1] = 0;
return class_name + 1;
}
class ClassName {
private:
jvmtiEnv* _jvmti;
char* _name;
public:
ClassName(jvmtiEnv* jvmti, jclass klass) : _jvmti(jvmti), _name(NULL) {
_jvmti->GetClassSignature(klass, &_name, NULL);
}
~ClassName() {
_jvmti->Deallocate((unsigned char*) _name);
}
char* name() {
return _name == NULL ? NULL : fix_class_name(_name);
}
};
void JNICALL ClassFileLoadHook(jvmtiEnv* jvmti, JNIEnv* env,
jclass class_being_redefined, jobject loader,
const char* name, jobject protection_domain,
jint data_len, const unsigned char* data,
jint* new_data_len, unsigned char** new_data) {
trace(jvmti, "Loading class: %s (%d bytes)", name, data_len);
}
void JNICALL ClassPrepare(jvmtiEnv* jvmti, JNIEnv* env,
jthread thread, jclass klass) {
ClassName cn(jvmti, klass);
trace(jvmti, "Class prepared: %s", cn.name());
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
if (options == NULL || !options[0]) {
out = stderr;
} else if ((out = fopen(options, "w")) == NULL) {
fprintf(stderr, "Cannot open output file: %s\n", options);
return 1;
}
jvmtiEnv* jvmti;
vm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_0);
jvmti->CreateRawMonitor("vmtrace_lock", &vmtrace_lock);
jvmti->GetTime(&start_time);
trace(jvmti, "VMTrace started");
jvmtiCapabilities capabilities = {0};
capabilities.can_generate_all_class_hook_events = 1;
jvmti->AddCapabilities(&capabilities);
jvmtiEventCallbacks callbacks = {0};
callbacks.ClassFileLoadHook = ClassFileLoadHook;
callbacks.ClassPrepare = ClassPrepare;
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
return 0;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) {
if (out != NULL && out != stderr) {
fclose(out);
}
}
@@ -1,6 +1,6 @@
<application>
<component name="GeneralSettings">
<option name="useSafeWrite" value="false" />
<option name="useSafeWrite" value="false"/>
<option name="confirmExit" value="false"/>
<option name="showTipsOnStartup" value="false"/>
</component>
@@ -1,10 +1,10 @@
package com.intellij.ide.starter
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.ide.IDETestContext
import com.intellij.ide.starter.path.GlobalPaths
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.FileSystem
import com.intellij.ide.starter.utils.HttpClient
@@ -71,32 +71,32 @@ fun downloadLatestAndroidSdk(javaHome: Path): Path {
home.toFile().mkdirs()
/// https://stackoverflow.com/questions/38096225/automatically-accept-all-sdk-licences
/// sending "yes" to the process in the STDIN :(
exec(presentablePurpose = "android-sdk-licenses",
workDir = home,
environmentVariables = envVariablesWithJavaHome,
args = listOf(sdkManager.toString(), "--sdk_root=$home", "--licenses"),
stderrRedirect = ExecOutputRedirect.ToStdOut("[sdkmanager-err]"),
stdInBytes = "yes\n".repeat(10).toByteArray(), // it asks the confirmation at least two times
timeout = 15.minutes
)
ProcessExecutor(presentableName = "android-sdk-licenses",
workDir = home,
environmentVariables = envVariablesWithJavaHome,
args = listOf(sdkManager.toString(), "--sdk_root=$home", "--licenses"),
stderrRedirect = ExecOutputRedirect.ToStdOut("[sdkmanager-err]"),
stdInBytes = "yes\n".repeat(10).toByteArray(), // it asks the confirmation at least two times
timeout = 15.minutes
).start()
//loading SDK
exec(presentablePurpose = "android-sdk-loading",
workDir = home,
environmentVariables = envVariablesWithJavaHome,
args = listOf(sdkManager.toString(), "--sdk_root=$home", "--list"),
stderrRedirect = ExecOutputRedirect.ToStdOut("[sdkmanager-err]"),
timeout = 15.minutes
)
ProcessExecutor(presentableName = "android-sdk-loading",
workDir = home,
environmentVariables = envVariablesWithJavaHome,
args = listOf(sdkManager.toString(), "--sdk_root=$home", "--list"),
stderrRedirect = ExecOutputRedirect.ToStdOut("[sdkmanager-err]"),
timeout = 15.minutes
).start()
//loading SDK
exec(presentablePurpose = "android-sdk-installing",
workDir = home,
environmentVariables = envVariablesWithJavaHome,
args = listOf(sdkManager.toString(), "--sdk_root=$home", "--install", "--verbose") + packages,
stderrRedirect = ExecOutputRedirect.ToStdOut("[sdkmanager-err]"),
timeout = 15.minutes
)
ProcessExecutor(presentableName = "android-sdk-installing",
workDir = home,
environmentVariables = envVariablesWithJavaHome,
args = listOf(sdkManager.toString(), "--sdk_root=$home", "--install", "--verbose") + packages,
stderrRedirect = ExecOutputRedirect.ToStdOut("[sdkmanager-err]"),
timeout = 15.minutes
).start()
return home
}
catch (t: Throwable) {
@@ -148,13 +148,15 @@ fun IDETestContext.downloadAndroidPluginProject(): IDETestContext {
val stdout = ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToString()
exec(
ProcessExecutor(
"git-clone-android-plugin",
workDir = projectHome, timeout = 10.minutes,
args = scriptContent.split(" "),
stdoutRedirect = stdout,
stderrRedirect = stderr
)
).start()
logOutput(stdout.read().trim())
}
return this
@@ -2,7 +2,6 @@ package com.intellij.ide.starter.bus
import com.intellij.ide.starter.utils.catchAll
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.filterNotNull
@@ -23,8 +23,9 @@ inline fun <reified T : Any> FlowBus.getFlow() = getFlow(T::class.java)
* @param callback The callback function
* @return This instance of [EventsReceiver] for chaining
*/
inline fun <reified T : Any> EventsReceiver.subscribe(skipRetained: Boolean = false, noinline callback: suspend (event: T) -> Unit): EventsReceiver {
return subscribeTo(T::class.java, skipRetained, callback)
inline fun <reified T : Any> EventsReceiver.subscribe(skipRetained: Boolean = false,
noinline callback: suspend (event: T) -> Unit): EventsReceiver {
return subscribeTo(T::class.java, skipRetained, callback)
}
/**
@@ -36,5 +37,5 @@ inline fun <reified T : Any> EventsReceiver.subscribe(skipRetained: Boolean = fa
* @see [subscribe]
*/
inline fun <reified T : Any> EventsReceiver.subscribe(callback: EventCallback<T>, skipRetained: Boolean = false): EventsReceiver {
return subscribeTo(T::class.java, callback, skipRetained)
return subscribeTo(T::class.java, callback, skipRetained)
}
@@ -0,0 +1,13 @@
Copyright 2021 Robert Kosakowski
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -3,22 +3,22 @@ package com.intellij.ide.starter.community
import org.apache.http.client.utils.URIBuilder
data class ProductInfoRequestParameters(
val code: String,
val type: String = "release",
val type: String,
val snapshot: String = "release",
// e.g "2022.2"
val majorVersion: String = "",
// e.g "221.5591.52",
val build: String = "",
val buildNumber: String = "",
// e.g "2022.1.1"
val version: String = ""
val versionNumber: String = ""
) {
fun toUriQuery(): URIBuilder {
val builder = URIBuilder()
// API seems to filter only by code and type. It doesn't respond to majorVersion, build or version params
if (code.isNotBlank()) builder.addParameter("code", code)
if (type.isNotBlank()) builder.addParameter("type", type)
if (type.isNotBlank()) builder.addParameter("code", type)
if (snapshot.isNotBlank()) builder.addParameter("type", snapshot)
return builder
}
@@ -21,19 +21,19 @@ object PublicIdeDownloader : IdeDownloader {
if (filteringParams.majorVersion.isNotBlank()) return sorted.first { it.majorVersion == filteringParams.majorVersion }
// find latest release / eap, if no specific params were provided
if (filteringParams.version.isBlank() && filteringParams.build.isBlank()) return sorted.first()
if (filteringParams.versionNumber.isBlank() && filteringParams.buildNumber.isBlank()) return sorted.first()
if (filteringParams.version.isNotBlank()) return sorted.first { it.version == filteringParams.version }
if (filteringParams.build.isNotBlank()) return sorted.first { it.build == filteringParams.build }
if (filteringParams.versionNumber.isNotBlank()) return sorted.first { it.version == filteringParams.versionNumber }
if (filteringParams.buildNumber.isNotBlank()) return sorted.first { it.build == filteringParams.buildNumber }
throw NoSuchElementException("Couldn't find specified release by parameters $filteringParams")
}
override fun downloadIdeInstaller(ideInfo: IdeInfo, installerDirectory: Path): IdeInstaller {
val params = ProductInfoRequestParameters(code = ideInfo.productCode,
type = ideInfo.buildType,
build = ideInfo.buildNumber,
version = ideInfo.version)
val params = ProductInfoRequestParameters(type = ideInfo.productCode,
snapshot = ideInfo.buildType,
buildNumber = ideInfo.buildNumber,
versionNumber = ideInfo.version)
val releaseInfoMap = JetBrainsDataServiceClient.getReleases(params)
if (releaseInfoMap.size != 1) throw RuntimeException("Only one product can be downloaded at once. Found ${releaseInfoMap.keys}")
@@ -0,0 +1,9 @@
package com.intellij.ide.starter.coroutine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
val supervisorScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
val simpleScope = CoroutineScope(Job() + Dispatchers.IO)
@@ -16,6 +16,7 @@ import com.intellij.ide.starter.report.publisher.ReportPublisher
import com.intellij.ide.starter.report.publisher.impl.ConsoleTestResultPublisher
import com.intellij.ide.starter.report.publisher.impl.QodanaTestResultPublisher
import com.intellij.ide.starter.runner.CodeBuilderHost
import com.intellij.ide.starter.runner.CurrentTestMethod
import com.intellij.ide.starter.utils.logOutput
import org.kodein.di.DI
import org.kodein.di.bindFactory
@@ -40,7 +41,7 @@ var di = DI {
bindFactory { testContext: IDETestContext -> PluginConfigurator(testContext) }
bindSingleton<IdeDownloader> { PublicIdeDownloader }
bindFactory<IdeInfo, IdeInstallator> { ideInfo ->
if (ideInfo.productCode == "AI") {
if (ideInfo.productCode == IdeProductProvider.AI.productCode) {
AndroidInstaller()
}
else {
@@ -50,6 +51,7 @@ var di = DI {
bindFactory<IDETestContext, BuildToolProvider> { testContext: IDETestContext -> BuildToolDefaultProvider(testContext) }
bindSingleton<List<ReportPublisher>> { listOf(ConsoleTestResultPublisher, QodanaTestResultPublisher) }
bindSingleton<IdeProduct> { IdeProductImp }
bindSingleton<CurrentTestMethod> { CurrentTestMethod }
}.apply {
logOutput("DI was initialized")
}
@@ -1,269 +0,0 @@
package com.intellij.ide.starter.exec
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.catchAll
import com.intellij.ide.starter.utils.logError
import com.intellij.ide.starter.utils.logOutput
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
import kotlin.io.path.div
import kotlin.io.path.exists
import kotlin.io.path.readText
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
private fun redirectProcessOutput(
process: Process,
outOrErrStream: Boolean,
redirectOutput: ExecOutputRedirect
): Thread {
val inputStream = if (outOrErrStream) process.inputStream else process.errorStream
return thread(start = true, isDaemon = true, name = "Redirect " + (if (outOrErrStream) "stdout" else "stderr")) {
val reader = inputStream.bufferedReader()
redirectOutput.open()
try {
while (true) {
val line = try {
reader.readLine() ?: break
}
catch (e: IOException) {
break
}
redirectOutput.redirectLine(line)
}
}
finally {
redirectOutput.close()
}
}
}
private fun redirectProcessInput(process: Process, inputBytes: ByteArray): Thread? {
if (inputBytes.isEmpty()) {
catchAll { process.outputStream.close() }
return null
}
return thread(start = true, isDaemon = true, name = "Redirect input") {
catchAll {
process.outputStream.use {
it.write(inputBytes)
}
}
}
}
private fun ProcessBuilder.actualizeEnvVariables(environmentVariables: Map<String, String> = System.getenv(),
onlyEnrichExistedEnvVariables: Boolean = false): ProcessBuilder {
val processEnvironment = environment()
if (processEnvironment == environmentVariables) return this
environmentVariables.filter { it.value == null }.forEach { logError("Env variable: ${it.key} has null value ${it.value}") }
val notNullValues = environmentVariables.filter { it.value != null }
// env variables enrichment
processEnvironment.putAll(notNullValues)
if (!onlyEnrichExistedEnvVariables) {
val missingKeys = processEnvironment.keys - notNullValues.keys
missingKeys.forEach { key -> processEnvironment.remove(key) }
}
return this
}
/**
* Creates new process and wait for it's completion
*/
@Throws(ExecTimeoutException::class)
fun exec(
presentablePurpose: String,
workDir: Path?,
timeout: Duration = 10.minutes,
environmentVariables: Map<String, String> = System.getenv(),
args: List<String>,
errorDiagnosticFiles: List<Path> = emptyList(),
stdoutRedirect: ExecOutputRedirect = ExecOutputRedirect.NoRedirect,
stderrRedirect: ExecOutputRedirect = ExecOutputRedirect.NoRedirect,
onProcessCreated: (Process, Long) -> Unit = { _, _ -> },
onBeforeKilled: (Process, Long) -> Unit = { _, _ -> },
stdInBytes: ByteArray = byteArrayOf(),
onlyEnrichExistedEnvVariables: Boolean = false
) {
logOutput(buildString {
appendLine("Running external process for `$presentablePurpose`")
appendLine(" Working directory: $workDir")
appendLine(" Arguments: [${args.joinToString()}]")
appendLine(" STDOUT will be redirected to: $stdoutRedirect")
appendLine(" STDERR will be redirected to: $stderrRedirect")
append(" STDIN is empty: " + stdInBytes.isEmpty())
})
require(args.isNotEmpty()) { "Arguments must be not empty to start external process" }
val processBuilder = ProcessBuilder()
.directory(workDir?.toFile())
.command(*args.toTypedArray())
.redirectInput(ProcessBuilder.Redirect.PIPE)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.actualizeEnvVariables(environmentVariables, onlyEnrichExistedEnvVariables)
logOutput(
"""
Process: `$presentablePurpose`
Arguments: ${args.joinToString(separator = " ")}
Environment variables: [${processBuilder.environment().entries.joinToString { "${it.key}=${it.value}" }}]
""".trimIndent())
val process = processBuilder.start()
val processId = process.pid()
catchAll {
logOutput(" ... started external process `$presentablePurpose` with process ID = $processId")
onProcessCreated(process, processId)
}
val inputThread = redirectProcessInput(process, stdInBytes)
val stdoutThread = redirectProcessOutput(process, true, stdoutRedirect)
val stderrThread = redirectProcessOutput(process, false, stderrRedirect)
val threads = listOfNotNull(inputThread, stdoutThread, stderrThread)
fun killProcess() {
catchAll { onBeforeKilled(process, processId) }
catchAll { process.descendants().forEach { catchAll { it.destroyForcibly() } } }
catchAll { process.destroy() }
catchAll { process.destroyForcibly() }
catchAll { threads.forEach { it.interrupt() } }
}
val stopper = Runnable {
logOutput(
" ... terminating process `$presentablePurpose` by request from external process (either SIGTERM or SIGKILL is caught) ...")
killProcess()
}
val stopperThread = Thread(stopper, "process-shutdown-hook")
try {
Runtime.getRuntime().addShutdownHook(stopperThread)
}
catch (e: IllegalStateException) {
logError("Process: $presentablePurpose. Shutdown hook cannot be added because: ${e.message}")
}
try {
if (!runCatching { process.waitFor(timeout.inWholeSeconds, TimeUnit.SECONDS) }.getOrDefault(false)) {
stopperThread.apply {
start()
join(20.seconds.inWholeMilliseconds)
}
throw ExecTimeoutException(args.joinToString(" "), timeout)
}
}
finally {
catchAll { Runtime.getRuntime().removeShutdownHook(stopperThread) }
}
threads.forEach { catchAll { it.join() } }
val code = process.exitValue()
if (code != 0) {
val linesLimit = 100
logOutput(" ... failed external process `$presentablePurpose` with exit code $code")
val message = buildString {
appendLine("External process `$presentablePurpose` failed with code $code")
for (diagnosticFile in errorDiagnosticFiles.filter { it.exists() && Files.size(it) > 0 }) {
appendLine(diagnosticFile.fileName.toString())
appendLine(diagnosticFile.readText().lines().joinToString(System.lineSeparator()) { " $it" })
}
stderrRedirect.read().lines().apply {
take(linesLimit).dropWhile { it.trim().isBlank() }.let { lines ->
if (lines.isNotEmpty()) {
appendLine(" FIRST $linesLimit lines of the standard error stream")
lines.forEach { appendLine(" $it") }
}
}
if (size > linesLimit) {
appendLine("...")
takeLast(linesLimit).dropWhile { it.trim().isBlank() }.let { lines ->
if (lines.isNotEmpty()) {
appendLine(" LAST $linesLimit lines of the standard error stream")
lines.forEach { appendLine(" $it") }
}
}
}
}
stdoutRedirect.read().lines().takeLast(linesLimit).dropWhile { it.trim().isEmpty() }.let { lines ->
if (lines.isNotEmpty()) {
appendLine(" LAST $linesLimit lines of the standard output stream")
lines.forEach { appendLine(" $it") }
}
}
}
error(message)
}
logOutput(" ... successfully finished external process for `$presentablePurpose` with exit code 0")
}
class ExecTimeoutException(private val processName: String,
private val timeout: Duration) : RuntimeException() {
override val message
get() = "Failed to wait for the process `$processName` to complete in $timeout"
}
fun executeScript(fileNameToExecute: String, projectDirPath: Path) {
val stdout = ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToString()
exec(
presentablePurpose = "Executing of $fileNameToExecute",
workDir = projectDirPath,
timeout = 20.minutes,
args = listOf(fileNameToExecute),
stdoutRedirect = stdout,
stderrRedirect = stderr
)
val commit = stdout.read().trim()
val error = stderr.read().trim()
logOutput("Stdout of command execution $commit")
logOutput("Stderr of command execution $error")
}
fun execGradlew(pathToProject: Path, args: List<String>) {
val stdout = ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToString()
val command = when (SystemInfo.isWindows) {
true -> (pathToProject / "gradlew.bat").toString()
false -> "./gradlew"
}
if (!SystemInfo.isWindows) {
exec(
presentablePurpose = "chmod gradlew",
workDir = pathToProject,
timeout = 1.minutes,
args = listOf("chmod", "+x", "gradlew"),
stdoutRedirect = stdout,
stderrRedirect = stderr
)
}
exec(
presentablePurpose = "Gradle Format",
workDir = pathToProject,
timeout = 1.minutes,
args = listOf(command) + args,
stdoutRedirect = stdout,
stderrRedirect = stderr
)
}
@@ -1,235 +0,0 @@
package com.intellij.ide.starter.ide;
import java.util.Arrays;
// code has been borrowed from Intellij Community sources
// Some parts, that requires dependency on Community, were removed
public class BuildNumber implements Comparable<BuildNumber> {
private static final String STAR = "*";
private static final String SNAPSHOT = "SNAPSHOT";
private static final String FALLBACK_VERSION = "999.SNAPSHOT";
public static final int SNAPSHOT_VALUE = Integer.MAX_VALUE;
private final String myProductCode;
private final int[] myComponents;
public BuildNumber(String productCode, int baselineVersion, int buildNumber) {
this(productCode, new int[]{baselineVersion, buildNumber});
}
public BuildNumber(String productCode, int... components) {
myProductCode = productCode;
myComponents = components;
}
private static boolean isPlaceholder(String value) {
return "__BUILD_NUMBER__".equals(value) || "__BUILD__".equals(value);
}
public String getProductCode() {
return myProductCode;
}
public int getBaselineVersion() {
return myComponents[0];
}
public int[] getComponents() {
return myComponents.clone();
}
public boolean isSnapshot() {
for (int value : myComponents) {
if (value == SNAPSHOT_VALUE) {
return true;
}
}
return false;
}
public BuildNumber withoutProductCode() {
return myProductCode.isEmpty() ? this : new BuildNumber("", myComponents);
}
public String asString() {
return asString(true, true);
}
public String asStringWithoutProductCode() {
return asString(false, true);
}
public String asStringWithoutProductCodeAndSnapshot() {
return asString(false, false);
}
private String asString(boolean includeProductCode, boolean withSnapshotMarker) {
StringBuilder builder = new StringBuilder();
if (includeProductCode && !myProductCode.isEmpty()) {
builder.append(myProductCode).append('-');
}
for (int each : myComponents) {
if (each != SNAPSHOT_VALUE) {
builder.append(each);
}
else if (withSnapshotMarker) {
builder.append(SNAPSHOT);
}
builder.append('.');
}
if (builder.charAt(builder.length() - 1) == '.') {
builder.setLength(builder.length() - 1);
}
return builder.toString();
}
public static BuildNumber fromPluginsCompatibleBuild() {
return fromString(getPluginsCompatibleBuild());
}
/**
* Attempts to parse build number from the specified string.
* Returns {@code null} if the string is not a valid build number.
*/
public static BuildNumber fromStringOrNull(String version) {
try {
return fromString(version);
}
catch (RuntimeException ignored) {
return null;
}
}
public static BuildNumber fromString(String version) {
if (version == null) {
return null;
}
version = version.trim();
return fromString(version, null, null);
}
public static BuildNumber fromStringWithProductCode(String version, String productCode) {
return fromString(version, null, productCode);
}
public static BuildNumber fromString(String version, String pluginName, String productCodeIfAbsentInVersion) {
if (version.isEmpty()) return null;
String code = version;
int productSeparator = code.indexOf('-');
String productCode;
if (productSeparator > 0) {
productCode = code.substring(0, productSeparator);
code = code.substring(productSeparator + 1);
}
else {
productCode = productCodeIfAbsentInVersion != null ? productCodeIfAbsentInVersion : "";
}
int baselineVersionSeparator = code.indexOf('.');
if (baselineVersionSeparator > 0) {
String baselineVersionString = code.substring(0, baselineVersionSeparator);
if (baselineVersionString.trim().isEmpty()) {
return null;
}
String[] stringComponents = code.split("\\.");
int[] intComponentsList = new int[stringComponents.length];
for (int i = 0, n = stringComponents.length; i < n; i++) {
String stringComponent = stringComponents[i];
int comp = parseBuildNumber(version, stringComponent, pluginName);
intComponentsList[i] = comp;
if (comp == SNAPSHOT_VALUE && (i + 1) != n) {
intComponentsList = Arrays.copyOf(intComponentsList, i + 1);
break;
}
}
return new BuildNumber(productCode, intComponentsList);
}
else {
int buildNumber = parseBuildNumber(version, code, pluginName);
if (buildNumber <= 2000) {
// it's probably a baseline, not a build number
return new BuildNumber(productCode, buildNumber, 0);
}
int baselineVersion = getBaseLineForHistoricBuilds(buildNumber);
return new BuildNumber(productCode, baselineVersion, buildNumber);
}
}
private static int parseBuildNumber(String version, String code, String pluginName) {
if (SNAPSHOT.equals(code) || isPlaceholder(code) || STAR.equals(code)) {
return SNAPSHOT_VALUE;
}
try {
return Integer.parseInt(code);
}
catch (NumberFormatException e) {
throw new RuntimeException("Invalid version number: " + version + "; plugin name: " + pluginName);
}
}
@Override
public int compareTo(BuildNumber o) {
int[] c1 = myComponents;
int[] c2 = o.myComponents;
for (int i = 0; i < Math.min(c1.length, c2.length); i++) {
if (c1[i] == c2[i] && c1[i] == SNAPSHOT_VALUE) return 0;
if (c1[i] == SNAPSHOT_VALUE) return 1;
if (c2[i] == SNAPSHOT_VALUE) return -1;
int result = c1[i] - c2[i];
if (result != 0) return result;
}
return c1.length - c2.length;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BuildNumber that = (BuildNumber)o;
if (!myProductCode.equals(that.myProductCode)) return false;
return Arrays.equals(myComponents, that.myComponents);
}
@Override
public int hashCode() {
int result = myProductCode.hashCode();
result = 31 * result + Arrays.hashCode(myComponents);
return result;
}
@Override
public String toString() {
return asString();
}
// http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html
private static int getBaseLineForHistoricBuilds(int bn) {
if (bn >= 10000) return 88; // Maia, 9x builds
if (bn >= 9500) return 85; // 8.1 builds
if (bn >= 9100) return 81; // 8.0.x builds
if (bn >= 8000) return 80; // 8.0, including pre-release builds
if (bn >= 7500) return 75; // 7.0.2+
if (bn >= 7200) return 72; // 7.0 final
if (bn >= 6900) return 69; // 7.0 pre-M2
if (bn >= 6500) return 65; // 7.0 pre-M1
if (bn >= 6000) return 60; // 6.0.2+
if (bn >= 5000) return 55; // 6.0 branch, including all 6.0 EAP builds
if (bn >= 4000) return 50; // 5.1 branch
return 40;
}
private static String getPluginsCompatibleBuild() {
return System.getProperty("idea.plugins.compatible.build");
}
}
@@ -5,7 +5,10 @@ import com.intellij.ide.starter.ci.CIServer
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.ide.command.CommandChain
import com.intellij.ide.starter.ide.command.MarshallableCommand
import com.intellij.ide.starter.models.*
import com.intellij.ide.starter.models.IDEStartResult
import com.intellij.ide.starter.models.TestCase
import com.intellij.ide.starter.models.VMOptions
import com.intellij.ide.starter.models.andThen
import com.intellij.ide.starter.path.IDEDataPaths
import com.intellij.ide.starter.plugins.PluginConfigurator
import com.intellij.ide.starter.profiler.ProfilerType
@@ -21,6 +24,7 @@ import org.kodein.di.newInstance
import org.w3c.dom.Node
import org.w3c.dom.NodeList
import java.io.FileOutputStream
import java.nio.file.Files
import java.nio.file.Path
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.TransformerFactory
@@ -202,6 +206,14 @@ data class IDETestContext(
paths.logsDir.toFile().deleteRecursively()
}
fun wipeReportDir() = apply {
logOutput("Cleaning report dir for $this at $paths")
Files.walk(paths.reportsDir)
.filter { Files.isRegularFile(it) }
.map { it.toFile() }
.forEach { it.delete() }
}
fun wipeProjectsDir() = apply {
val path = paths.systemDir / "projects"
logOutput("Cleaning project cache dir for $this at $path")
@@ -336,19 +348,19 @@ data class IDETestContext(
): IDEStartResult {
val updatedContext = this.copy(testName = "${this.testName}/warmup")
val result = updatedContext.runIDE(
patchVMOptions = {
val warmupReports = IDEStartupReports(paths.reportsDir)
patchVMOptions = {
this.run {
if (storeClassReport) {
this.enableStartupPerformanceLog(warmupReports).enableClassLoadingReport(
paths.reportsDir / "class-report.txt").patchVMOptions()
this.enableClassLoadingReport(paths.reportsDir / "class-report.txt")
}
else {
this
}
},
commands = testCase.commands.plus(commands),
runTimeout = runTimeout
)
}.patchVMOptions()
},
commands = testCase.commands.plus(commands),
runTimeout = runTimeout
)
updatedContext.publishArtifact(this.paths.reportsDir)
return result
}
@@ -1,9 +1,9 @@
package com.intellij.ide.starter.ide
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.path.GlobalPaths
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.utils.FileSystem
import com.intellij.ide.starter.utils.HttpClient
import com.intellij.ide.starter.utils.catchAll
@@ -41,13 +41,14 @@ object IdeArchiveExtractor {
val mountDir = File(dmgFile.path + "-mount${System.currentTimeMillis()}")
try {
exec(presentablePurpose = "hdiutil",
workDir = target,
timeout = 10.minutes,
stderrRedirect = ExecOutputRedirect.ToStdOut("hdiutil"),
stdoutRedirect = ExecOutputRedirect.ToStdOut("hdiutil"),
args = listOf("hdiutil", "attach", "-readonly", "-noautoopen", "-noautofsck", "-nobrowse", "-mountpoint", "$mountDir",
"$dmgFile"))
ProcessExecutor(presentableName = "hdiutil",
workDir = target,
timeout = 10.minutes,
stderrRedirect = ExecOutputRedirect.ToStdOut("hdiutil"),
stdoutRedirect = ExecOutputRedirect.ToStdOut("hdiutil"),
args = listOf("hdiutil", "attach", "-readonly", "-noautoopen", "-noautofsck", "-nobrowse", "-mountpoint", "$mountDir",
"$dmgFile")
).start()
}
catch (t: Throwable) {
dmgFile.delete()
@@ -59,24 +60,26 @@ object IdeArchiveExtractor {
?: error("Failed to find the only one .app folder in $dmgFile")
val targetAppDir = target / appDir.name
exec(
presentablePurpose = "copy-dmg",
ProcessExecutor(
presentableName = "copy-dmg",
workDir = target,
timeout = 10.minutes,
stderrRedirect = ExecOutputRedirect.ToStdOut("cp"),
args = listOf("cp", "-R", "$appDir", "$targetAppDir"))
args = listOf("cp", "-R", "$appDir", "$targetAppDir")
).start()
return targetAppDir
}
finally {
catchAll {
exec(
presentablePurpose = "hdiutil",
ProcessExecutor(
presentableName = "hdiutil",
workDir = target,
timeout = 10.minutes,
stdoutRedirect = ExecOutputRedirect.ToStdOut("hdiutil"),
stderrRedirect = ExecOutputRedirect.ToStdOut("hdiutil"),
args = listOf("hdiutil", "detach", "-force", "$mountDir"))
args = listOf("hdiutil", "detach", "-force", "$mountDir")
).start()
}
}
}
@@ -97,11 +100,11 @@ object IdeArchiveExtractor {
val severZipToolExe = sevenZipTool.resolve("7z.exe")
targetDir.mkdirs()
exec(
presentablePurpose = "unpack-zip",
ProcessExecutor(
presentableName = "unpack-zip",
workDir = targetDir.toPath(),
timeout = 10.minutes,
args = listOf(severZipToolExe.toAbsolutePath().toString(), "x", "-y", "-o$targetDir", exeFile.path)
)
).start()
}
}
@@ -3,5 +3,8 @@ package com.intellij.ide.starter.ide
import com.intellij.ide.starter.models.IdeInfo
interface IdeInstallator {
/**
* @return <Build Number, InstalledIde>
*/
fun install(ideInfo: IdeInfo): Pair<String, InstalledIde>
}
@@ -35,5 +35,8 @@ object IdeProductProvider {
/** PyCharm Professional */
val PY: IdeInfo = di.direct.instance<IdeProduct>().PY
/** CLion */
val CL: IdeInfo = di.direct.instance<IdeProduct>().CL
fun getProducts(): List<IdeInfo> = IdeProductProvider::class.declaredMemberProperties.map { it.get(IdeProductProvider) as IdeInfo }
}
@@ -1,8 +1,8 @@
package com.intellij.ide.starter.ide
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.models.VMOptions
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.callJavaVersion
import com.intellij.ide.starter.utils.logOutput
@@ -18,9 +18,10 @@ class LinuxIdeDistribution : IdeDistribution() {
val toolName = "xvfb-run"
val homePath = Path(System.getProperty("user.home")).toAbsolutePath()
exec("xvfb-run", homePath, timeout = 5.seconds, args = listOf("which", toolName),
stdoutRedirect = ExecOutputRedirect.ToStdOut("xvfb-run-out"),
stderrRedirect = ExecOutputRedirect.ToStdOut("xvfb-run-err"))
ProcessExecutor("xvfb-run", homePath, timeout = 5.seconds, args = listOf("which", toolName),
stdoutRedirect = ExecOutputRedirect.ToStdOut("xvfb-run-out"),
stderrRedirect = ExecOutputRedirect.ToStdOut("xvfb-run-err")
).start()
toolName
}
@@ -27,4 +27,7 @@ interface IdeProduct {
/** PyCharm Professional */
val PY: IdeInfo
/** CLion */
val CL: IdeInfo
}
@@ -63,4 +63,11 @@ object IdeProductImp : IdeProduct {
platformPrefix = "Python",
executableFileName = "pycharm"
)
/** CLion */
override val CL: IdeInfo = IdeInfo(
productCode = "CL",
platformPrefix = "CLion",
executableFileName = "clion"
)
}
@@ -16,13 +16,10 @@ data class TestCase(
fun withCommands(commands: Iterable<MarshallableCommand> = this.commands): TestCase = copy(commands = commands.toList())
/** Project in this case will be reused between tests */
fun markNotReusable(): TestCase = markReusable(false)
/** On each test run the project will be unpacked again.
* This guarantees that there is not side effects from previous test runs
**/
fun markReusable(isReusable: Boolean = true) = copy(projectInfo = (projectInfo as ProjectInfo).copy(isReusable = isReusable))
fun markNotReusable(): TestCase = copy(projectInfo = (projectInfo as ProjectInfo).copy(isReusable = false))
/**
* [buildNumber] - EAP build number to download
@@ -108,6 +108,16 @@ data class VMOptions(
.addSystemProperty("idea.record.classpath.info", "true")
}
fun enableVmtraceClassLoadingReport(filePath: Path): VMOptions {
if (!VMTrace.isSupported) return this
val vmTraceFile = VMTrace.vmTraceFile
return this
.addSystemProperty("idea.log.vmtrace.file", filePath)
.addLine("-agentpath:${vmTraceFile.toAbsolutePath()}=${filePath.toAbsolutePath()}")
}
fun configureLoggers(
debugLoggers: List<String> = emptyList(),
traceLoggers: List<String> = emptyList()
@@ -0,0 +1,36 @@
package com.intellij.ide.starter.models
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.openapi.util.io.FileUtilRt
import java.nio.file.Files
import java.nio.file.Path
/**
* Holds path to libvmtrace.so on disk.
*/
object VMTrace {
val vmTraceFile: Path
val isSupported: Boolean
get() = SystemInfo.isLinux || SystemInfo.isMac
init {
if (isSupported) {
val resourceName = when {
SystemInfo.isLinux -> "/libvmtrace.so"
SystemInfo.isMac && !SystemInfo.isAarch64 -> "/libvmtrace.dylib"
SystemInfo.isMac && SystemInfo.isAarch64 -> "/libvmtrace-aarch64.dylib"
else -> throw UnsupportedOperationException("Unsupported platform for libvmtrace")
}
vmTraceFile = Files.createTempFile("libvmtrace", "." + FileUtilRt.getExtension(resourceName))
val vmTraceBytes = VMOptions::class.java.getResourceAsStream(resourceName)!!
.use { it.readAllBytes() }
Files.write(vmTraceFile, vmTraceBytes)
}
else {
vmTraceFile = Path.of("unsupported-platform-libvmtrace")
}
}
}
@@ -25,14 +25,14 @@ abstract class GlobalPaths(val checkoutDir: Path) {
false -> intelliJOutDirectory // Local run
}
open val testHomePath:Path = intelliJOutDirectory.resolve("perf-startup").createDirectories()
open val testHomePath: Path = intelliJOutDirectory.resolve("perf-startup").createDirectories()
val installersDirectory = (testHomePath / "installers").createDirectories()
val testsDirectory = (testHomePath / "tests").createDirectories()
private val cacheDirectory: Path = if (di.direct.instance<CIServer>().isBuildRunningOnCI &&
!System.getProperty("agent.persistent.cache").isNullOrEmpty()
!System.getProperty("agent.persistent.cache").isNullOrEmpty()
) {
(Paths.get(System.getProperty("agent.persistent.cache"), "perf-tests-cache")).createDirectories()
}
@@ -60,7 +60,8 @@ open class PluginConfigurator(val testContext: IDETestContext) {
logError("Plugin $pluginId downloading failed, skipping")
return@apply
}
} else {
}
else {
FileSystem.unpack(downloadedPlugin, testContext.paths.pluginsDir)
}
logOutput("Plugin $pluginId setup finished")
@@ -1,6 +1,6 @@
package com.intellij.ide.starter.exec
package com.intellij.ide.starter.process.exec
import com.intellij.ide.starter.exec.ExecOutputRedirect.*
import com.intellij.ide.starter.process.exec.ExecOutputRedirect.*
import com.intellij.ide.starter.utils.logOutput
import java.io.File
import java.io.PrintWriter
@@ -0,0 +1,9 @@
package com.intellij.ide.starter.process.exec
import kotlin.time.Duration
class ExecTimeoutException(private val processName: String,
private val timeout: Duration) : RuntimeException() {
override val message
get() = "Failed to wait for the process `$processName` to complete in $timeout"
}
@@ -0,0 +1,228 @@
package com.intellij.ide.starter.process.exec
import com.intellij.ide.starter.coroutine.supervisorScope
import com.intellij.ide.starter.utils.catchAll
import com.intellij.ide.starter.utils.logError
import com.intellij.ide.starter.utils.logOutput
import kotlinx.coroutines.*
import kotlinx.coroutines.future.await
import java.io.IOException
import java.lang.Runnable
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
import kotlin.io.path.exists
import kotlin.io.path.readText
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
class ProcessExecutor(val presentableName: String,
val workDir: Path?,
val timeout: Duration = 10.minutes,
val environmentVariables: Map<String, String> = System.getenv(),
val args: List<String>,
val errorDiagnosticFiles: List<Path> = emptyList(),
val stdoutRedirect: ExecOutputRedirect = ExecOutputRedirect.NoRedirect,
val stderrRedirect: ExecOutputRedirect = ExecOutputRedirect.NoRedirect,
val onProcessCreated: suspend (Process, Long) -> Unit = { _, _ -> },
val onBeforeKilled: suspend (Process, Long) -> Unit = { _, _ -> },
val stdInBytes: ByteArray = byteArrayOf(),
val onlyEnrichExistedEnvVariables: Boolean = false) {
private fun redirectProcessOutput(
process: Process,
outOrErrStream: Boolean,
redirectOutput: ExecOutputRedirect
): Thread {
val inputStream = if (outOrErrStream) process.inputStream else process.errorStream
return thread(start = true, isDaemon = true, name = "Redirect " + (if (outOrErrStream) "stdout" else "stderr")) {
val reader = inputStream.bufferedReader()
redirectOutput.open()
try {
while (true) {
val line = try {
reader.readLine() ?: break
}
catch (e: IOException) {
break
}
redirectOutput.redirectLine(line)
}
}
finally {
redirectOutput.close()
}
}
}
private fun redirectProcessInput(process: Process, inputBytes: ByteArray): Thread? {
if (inputBytes.isEmpty()) {
catchAll { process.outputStream.close() }
return null
}
return thread(start = true, isDaemon = true, name = "Redirect input") {
catchAll {
process.outputStream.use {
it.write(inputBytes)
}
}
}
}
private fun ProcessBuilder.actualizeEnvVariables(environmentVariables: Map<String, String> = System.getenv(),
onlyEnrichExistedEnvVariables: Boolean = false): ProcessBuilder {
val processEnvironment = environment()
if (processEnvironment == environmentVariables) return this
environmentVariables.filter { it.value == null }.forEach { logError("Env variable: ${it.key} has null value ${it.value}") }
val notNullValues = environmentVariables.filter { it.value != null }
// env variables enrichment
processEnvironment.putAll(notNullValues)
if (!onlyEnrichExistedEnvVariables) {
val missingKeys = processEnvironment.keys - notNullValues.keys
missingKeys.forEach { key -> processEnvironment.remove(key) }
}
return this
}
private fun killProcessGracefully(process: ProcessHandle) {
process.destroy()
runBlocking { withTimeout(20.seconds) { process.onExit().await() } }
process.destroyForcibly()
}
private fun analyzeProcessExit(process: Process) {
val code = process.exitValue()
if (code != 0) {
val linesLimit = 100
logOutput(" ... failed external process `$presentableName` with exit code $code")
val message = buildString {
appendLine("External process `$presentableName` failed with code $code")
for (diagnosticFile in errorDiagnosticFiles.filter { it.exists() && Files.size(it) > 0 }) {
appendLine(diagnosticFile.fileName.toString())
appendLine(diagnosticFile.readText().lines().joinToString(System.lineSeparator()) { " $it" })
}
stderrRedirect.read().lines().apply {
take(linesLimit).dropWhile { it.trim().isBlank() }.let { lines ->
if (lines.isNotEmpty()) {
appendLine(" FIRST $linesLimit lines of the standard error stream")
lines.forEach { appendLine(" $it") }
}
}
if (size > linesLimit) {
appendLine("...")
takeLast(linesLimit).dropWhile { it.trim().isBlank() }.let { lines ->
if (lines.isNotEmpty()) {
appendLine(" LAST $linesLimit lines of the standard error stream")
lines.forEach { appendLine(" $it") }
}
}
}
}
stdoutRedirect.read().lines().takeLast(linesLimit).dropWhile { it.trim().isEmpty() }.let { lines ->
if (lines.isNotEmpty()) {
appendLine(" LAST $linesLimit lines of the standard output stream")
lines.forEach { appendLine(" $it") }
}
}
}
error(message)
}
logOutput(" ... successfully finished external process for `$presentableName` with exit code 0")
}
/**
* Creates new process and wait for it's completion
*/
@Throws(ExecTimeoutException::class)
fun start() {
logOutput(buildString {
appendLine("Running external process for `$presentableName`")
appendLine(" Working directory: $workDir")
appendLine(" Arguments: [${args.joinToString()}]")
appendLine(" STDOUT will be redirected to: $stdoutRedirect")
appendLine(" STDERR will be redirected to: $stderrRedirect")
append(" STDIN is empty: " + stdInBytes.isEmpty())
})
require(args.isNotEmpty()) { "Arguments must be not empty to start external process" }
val processBuilder = ProcessBuilder()
.directory(workDir?.toFile())
.command(*args.toTypedArray())
.redirectInput(ProcessBuilder.Redirect.PIPE)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.actualizeEnvVariables(environmentVariables, onlyEnrichExistedEnvVariables)
logOutput(
"""
Process: `$presentableName`
Arguments: ${args.joinToString(separator = " ")}
Environment variables: [${processBuilder.environment().entries.joinToString { "${it.key}=${it.value}" }}]
""".trimIndent())
val process = processBuilder.start()
val processId = process.pid()
val onProcessCreatedJob: Job = supervisorScope.launch {
logOutput(" ... started external process `$presentableName` with process ID = $processId")
onProcessCreated(process, processId)
}
val inputThread = redirectProcessInput(process, stdInBytes)
val stdoutThread = redirectProcessOutput(process, true, stdoutRedirect)
val stderrThread = redirectProcessOutput(process, false, stderrRedirect)
val ioThreads = listOfNotNull(inputThread, stdoutThread, stderrThread)
fun killProcess() {
catchAll { runBlocking { onProcessCreatedJob.cancelAndJoin() } }
catchAll { runBlocking { withTimeout(1.minutes) { onBeforeKilled(process, processId) } } }
process.descendants().forEach { catchAll { killProcessGracefully(it) } }
catchAll { killProcessGracefully(process.toHandle()) }
catchAll { ioThreads.forEach { it.interrupt() } }
}
val stopper = Runnable {
logOutput(
" ... terminating process `$presentableName` by request from external process (either SIGTERM or SIGKILL is caught) ...")
killProcess()
}
val stopperThread = Thread(stopper, "process-shutdown-hook")
try {
Runtime.getRuntime().addShutdownHook(stopperThread)
}
catch (e: IllegalStateException) {
logError("Process: $presentableName. Shutdown hook cannot be added because: ${e.message}")
}
try {
if (!runCatching { process.waitFor(timeout.inWholeSeconds, TimeUnit.SECONDS) }.getOrDefault(false)) {
stopperThread.apply {
start()
join(20.seconds.inWholeMilliseconds)
}
throw ExecTimeoutException(args.joinToString(" "), timeout)
}
}
finally {
catchAll { Runtime.getRuntime().removeShutdownHook(stopperThread) }
}
ioThreads.forEach { catchAll { it.join() } }
analyzeProcessExit(process)
}
}
@@ -0,0 +1,58 @@
package com.intellij.ide.starter.process.exec
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.logOutput
import java.nio.file.Path
import kotlin.io.path.div
import kotlin.time.Duration.Companion.minutes
fun executeScript(fileNameToExecute: String, projectDirPath: Path) {
val stdout = ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToString()
ProcessExecutor(
presentableName = "Executing of $fileNameToExecute",
workDir = projectDirPath,
timeout = 20.minutes,
args = listOf(fileNameToExecute),
stdoutRedirect = stdout,
stderrRedirect = stderr
).start()
val commit = stdout.read().trim()
val error = stderr.read().trim()
logOutput("Stdout of command execution $commit")
logOutput("Stderr of command execution $error")
}
fun execGradlew(pathToProject: Path, args: List<String>) {
val stdout = ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToString()
val command = when (SystemInfo.isWindows) {
true -> (pathToProject / "gradlew.bat").toString()
false -> "./gradlew"
}
if (!SystemInfo.isWindows) {
ProcessExecutor(
presentableName = "chmod gradlew",
workDir = pathToProject,
timeout = 1.minutes,
args = listOf("chmod", "+x", "gradlew"),
stdoutRedirect = stdout,
stderrRedirect = stderr
).start()
}
ProcessExecutor(
presentableName = "Gradle Format",
workDir = pathToProject,
timeout = 1.minutes,
args = listOf(command) + args,
stdoutRedirect = stdout,
stderrRedirect = stderr
).start()
}
@@ -1,9 +1,9 @@
package com.intellij.ide.starter.process
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.path.GlobalPaths
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.catchAll
import com.intellij.ide.starter.utils.logOutput
@@ -46,11 +46,13 @@ fun killOutdatedProcessesOnUnix(commandsToSearch: Iterable<String> = listOf("/pe
fun dumpListOfProcessesOnMacOS(): List<MacOsProcessMetaInfo> {
check(SystemInfo.isMac)
val stdoutRedirect = ExecOutputRedirect.ToString()
exec("ps",
di.direct.instance<GlobalPaths>().testsDirectory,
timeout = 1.minutes,
args = listOf("ps", "-ax"),
stdoutRedirect = stdoutRedirect)
ProcessExecutor("ps",
di.direct.instance<GlobalPaths>().testsDirectory,
timeout = 1.minutes,
args = listOf("ps", "-ax"),
stdoutRedirect = stdoutRedirect
).start()
val processLines = stdoutRedirect.read().lines().drop(1).map { it.trim() }.filterNot { it.isBlank() }
//PID TTY TIME CMD
// 1 ?? 0:43.67 /sbin/launchd
@@ -75,11 +77,13 @@ fun dumpListOfProcessesOnMacOS(): List<MacOsProcessMetaInfo> {
fun dumpListOfProcessesOnLinux(): List<LinuxProcessMetaInfo> {
check(SystemInfo.isLinux)
val stdoutRedirect = ExecOutputRedirect.ToString()
exec("ps",
di.direct.instance<GlobalPaths>().testsDirectory,
timeout = 1.minutes,
args = listOf("ps", "-aux"),
stdoutRedirect = stdoutRedirect)
ProcessExecutor("ps",
di.direct.instance<GlobalPaths>().testsDirectory,
timeout = 1.minutes,
args = listOf("ps", "-aux"),
stdoutRedirect = stdoutRedirect
).start()
val processLines = stdoutRedirect.read().lines().drop(1).map { it.trim() }.filterNot { it.isBlank() }
//USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
//root 823 0.0 0.0 1576524 8128 ? Ssl дек01 0:08 /usr/bin/containerd
@@ -111,14 +115,14 @@ private fun killProcessOnUnix(pid: Int) {
check(SystemInfo.isUnix)
logOutput("Killing process $pid")
exec(
ProcessExecutor(
"kill-process-$pid",
di.direct.instance<GlobalPaths>().testsDirectory,
timeout = 1.minutes,
args = listOf("kill", "-9", pid.toString()),
stdoutRedirect = ExecOutputRedirect.ToStdOut("[kill-$pid-out]"),
stderrRedirect = ExecOutputRedirect.ToStdOut("[kill-$pid-err]")
)
).start()
}
/**
@@ -135,14 +139,15 @@ fun getJavaProcessId(javaHome: Path, workDir: Path, originalProcessId: Long, ori
val stdout = ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToString()
exec(
ProcessExecutor(
"jcmd-run",
workDir,
timeout = 1.minutes,
args = listOf(javaHome.resolve("bin/jcmd").toAbsolutePath().toString()),
stdoutRedirect = stdout,
stderrRedirect = stderr
)
).start()
val mergedOutput = stdout.read() + "\n" + stderr.read()
val candidates = arrayListOf<Long>()
val candidatesFromProcessHandle = arrayListOf<Long>()
@@ -213,14 +218,14 @@ fun collectJavaThreadDump(
val command = listOf(jstackPath.toAbsolutePath().toString(), "-l", javaProcessId.toString())
exec(
ProcessExecutor(
"jstack",
workDir,
timeout = 1.minutes,
args = command,
stdoutRedirect = ExecOutputRedirect.ToFile(dumpFile.toFile()),
stderrRedirect = ExecOutputRedirect.ToStdOut("[jstack-err]")
)
).start()
if (includeStdout) {
logOutput("jstack output:\n${dumpFile.toFile().readLines().joinToString("\n")}")
@@ -229,13 +234,14 @@ fun collectJavaThreadDump(
fun destroyGradleDaemonProcessIfExists() {
val stdout = ExecOutputRedirect.ToString()
exec(
ProcessExecutor(
"get jps process",
workDir = null,
timeout = 30.seconds,
args = listOf("jps", "-l"),
stdoutRedirect = stdout
)
).start()
logOutput("List of java processes: " + stdout.read())
if (stdout.read().contains("GradleDaemon")) {
@@ -2,6 +2,7 @@ package com.intellij.ide.starter.report
import com.intellij.ide.starter.ci.CIServer
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.runner.CurrentTestMethod
import com.intellij.ide.starter.utils.convertToHashCodeWithOnlyLetters
import com.intellij.ide.starter.utils.generifyErrorMessage
import org.kodein.di.direct
@@ -14,11 +15,18 @@ import kotlin.io.path.listDirectoryEntries
object ErrorReporter {
private const val MAX_TEST_NAME_LENGTH = 250
private fun getTestMethodName(): String {
val method = di.direct.instance<CurrentTestMethod>().get()
return if (method == null) "" else "${method.declaringClass.name}.${method.name}"
}
/**
* Sort things out from errors directories, written by performance testing plugin
* Take a look at [com.jetbrains.performancePlugin.ProjectLoaded.reportErrorsFromMessagePool]
*/
fun reportErrorsAsFailedTests(scriptErrorsDir: Path, contextName: String): List<Pair<File, File>> {
val testMethodName = getTestMethodName().ifEmpty { contextName }
return if (scriptErrorsDir.isDirectory()) {
val errorsDirectories = scriptErrorsDir.listDirectoryEntries()
@@ -30,7 +38,7 @@ object ErrorReporter {
val messageText = generifyErrorMessage(messageFile.readText().trim())
val stackTraceContent = stacktraceFile.readText().trim()
var testName: String
val testName: String
val onlyLettersHash = convertToHashCodeWithOnlyLetters(generifyErrorMessage(stackTraceContent).hashCode())
@@ -44,7 +52,7 @@ object ErrorReporter {
}
val stackTrace = """
Test: $contextName
Test: $testMethodName
$stackTraceContent
""".trimIndent().trimMargin().trim()
@@ -9,7 +9,7 @@ import com.intellij.ide.starter.report.sarif.TestContextToQodanaSarifMapper
object QodanaTestResultPublisher : ReportPublisher {
override fun publish(ideStartResult: IDEStartResult) {
QodanaClient.report(TestContextToQodanaSarifMapper.map(ideStartResult))
QodanaClient.report(TestContextToQodanaSarifMapper.map(ideStartResult))
}
}
@@ -23,6 +23,7 @@ fun taxa(init: ReportingDescriptor.() -> Unit): ReportingDescriptor {
taxa.init()
return taxa
}
fun invocation(init: Invocation.() -> Unit): Invocation {
val invocation = Invocation()
invocation.init()
@@ -11,7 +11,7 @@ object TestContextToQodanaSarifMapper {
fun map(ideStartResult: IDEStartResult): SarifReport {
val defaultReportPath = this::class.java.classLoader.getResource("sarif/qodana.sarif.json")?.path
if(defaultReportPath==null) throw RuntimeException("Default report doesn' exits")
if (defaultReportPath == null) throw RuntimeException("Default report doesn' exits")
val sarifReport = SarifUtil.readReport(Path.of(defaultReportPath))
return sarifReport(sarifReport) {
@@ -0,0 +1,27 @@
package com.intellij.ide.starter.runner
import java.lang.reflect.Method
import java.util.concurrent.atomic.AtomicReference
/**
* Container, that pass around test method reference
*/
object CurrentTestMethod {
private lateinit var testMethod: AtomicReference<Method>
fun set(method: Method) {
if (this::testMethod.isInitialized) {
testMethod.set(method)
}
else {
testMethod = AtomicReference(method)
}
}
fun get(): Method? {
return if (this::testMethod.isInitialized) {
testMethod.get()
}
else null
}
}
@@ -3,9 +3,6 @@ package com.intellij.ide.starter.runner
import com.intellij.ide.starter.bus.EventState
import com.intellij.ide.starter.bus.StarterBus
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.ExecTimeoutException
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.ide.CodeInjector
import com.intellij.ide.starter.ide.IDETestContext
import com.intellij.ide.starter.ide.command.MarshallableCommand
@@ -14,12 +11,16 @@ import com.intellij.ide.starter.models.VMOptions
import com.intellij.ide.starter.models.andThen
import com.intellij.ide.starter.process.collectJavaThreadDump
import com.intellij.ide.starter.process.destroyGradleDaemonProcessIfExists
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ExecTimeoutException
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.process.getJavaProcessId
import com.intellij.ide.starter.profiler.ProfilerInjector
import com.intellij.ide.starter.profiler.ProfilerType
import com.intellij.ide.starter.report.ErrorReporter
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.*
import kotlinx.coroutines.delay
import org.kodein.di.direct
import org.kodein.di.instance
import java.io.Closeable
@@ -27,8 +28,10 @@ import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.concurrent.thread
import kotlin.io.path.*
import kotlin.io.path.absolutePathString
import kotlin.io.path.createDirectories
import kotlin.io.path.div
import kotlin.io.path.listDirectoryEntries
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
@@ -45,7 +48,7 @@ data class IDERunContext(
val commands: Iterable<MarshallableCommand> = listOf(),
val codeBuilder: (CodeInjector.() -> Unit)? = null,
val runTimeout: Duration = 10.minutes,
val traceStacksEvery: Duration = 10.minutes,
val dumpThreadInterval: Duration = 10.minutes,
val useStartupScript: Boolean = true,
val closeHandlers: List<IDERunCloseContext.() -> Unit> = listOf(),
val verboseOutput: Boolean = false,
@@ -72,12 +75,12 @@ data class IDERunContext(
fun addCompletionHandler(handler: IDERunCloseContext.() -> Unit) = this.copy(closeHandlers = closeHandlers + handler)
fun uploadProfileResultsToTeamCity(profilerSnapshotsDir: Path, artifactName: String) =
fun uploadProfilerResultsToCIServer(profilerSnapshotsDir: Path, artifactName: String) =
this.addCompletionHandler {
testContext.publishArtifact(source = profilerSnapshotsDir, artifactName = artifactName)
}
fun installProfiler(): IDERunContext {
private fun installProfiler(): IDERunContext {
return when (val profilerType = testContext.profilerType) {
ProfilerType.ASYNC, ProfilerType.YOURKIT -> {
val profiler = di.direct.instance<ProfilerInjector>(tag = profilerType)
@@ -91,7 +94,7 @@ data class IDERunContext(
}
}
// TODO: refactor this
// TODO: refactor this https://youtrack.jetbrains.com/issue/AT-18/Simplify-refactor-code-for-starting-IDE-in-IdeRunContext
private fun prepareToRunIDE(): IDEStartResult {
StarterBus.post(IdeLaunchEvent(EventState.BEFORE, this))
@@ -109,7 +112,7 @@ data class IDERunContext(
val stdout = if (verboseOutput) ExecOutputRedirect.ToStdOut("[ide-${contextName}-out]") else ExecOutputRedirect.ToString()
val stderr = ExecOutputRedirect.ToStdOut("[ide-${contextName}-err]")
var successfulRun = true
var isRunSuccessful = true
val host by lazy { di.direct.instance<CodeInjector>() }
try {
@@ -182,8 +185,8 @@ data class IDERunContext(
File(finalArgs.first()).setExecutable(true)
val executionTime = measureTime {
exec(
presentablePurpose = "run-ide-$contextName",
ProcessExecutor(
presentableName = "run-ide-$contextName",
workDir = startConfig.workDir,
environmentVariables = extendedEnvVariablesWithJavaHome,
timeout = runTimeout,
@@ -193,17 +196,16 @@ data class IDERunContext(
stderrRedirect = stderr,
onProcessCreated = { process, pid ->
val javaProcessId by lazy { getJavaProcessId(jdkHome, startConfig.workDir, pid, process) }
thread(name = "jstack-${testContext.testName}", isDaemon = true) {
var cnt = 0
while (process.isAlive) {
Thread.sleep(traceStacksEvery.inWholeMilliseconds)
if (!process.isAlive) break
val monitoringThreadDumpDir = logsDir.resolve("monitoring-thread-dumps").createDirectories()
val dumpFile = logsDir.resolve("threadDump-${++cnt}-${System.currentTimeMillis()}" + ".txt")
logOutput("Dumping threads to $dumpFile")
logOutput(Runtime.getRuntime().getRuntimeInfo())
catchAll { collectJavaThreadDump(jdkHome, startConfig.workDir, javaProcessId, dumpFile, false) }
}
var cnt = 0
while (process.isAlive) {
delay(dumpThreadInterval)
if (!process.isAlive) break
val dumpFile = monitoringThreadDumpDir.resolve("threadDump-${++cnt}-${System.currentTimeMillis()}" + ".txt")
logOutput("Dumping threads to $dumpFile")
catchAll { collectJavaThreadDump(jdkHome, startConfig.workDir, javaProcessId, dumpFile, false) }
}
},
onBeforeKilled = { process, pid ->
@@ -212,7 +214,7 @@ data class IDERunContext(
if (collectNativeThreads) {
val fileToStoreNativeThreads = logsDir.resolve("native-thread-dumps.txt")
startProfileNativeThreads(javaProcessId.toString())
Thread.sleep(15.seconds.inWholeMilliseconds)
delay(15.seconds)
stopProfileNativeThreads(javaProcessId.toString(), fileToStoreNativeThreads.toAbsolutePath().toString())
}
val dumpFile = logsDir.resolve("threadDump-before-kill-${System.currentTimeMillis()}" + ".txt")
@@ -220,7 +222,7 @@ data class IDERunContext(
}
takeScreenshot(logsDir)
}
)
).start()
}
logOutput("IDE run $contextName completed in $executionTime")
@@ -247,7 +249,7 @@ data class IDERunContext(
return IDEStartResult(runContext = this, executionTime = executionTime, vmOptionsDiff = vmOptionsDiff, logsDir = logsDir)
}
catch (t: Throwable) {
successfulRun = false
isRunSuccessful = false
if (t is ExecTimeoutException && !expectedKill) {
error("Timeout of IDE run $contextName for $runTimeout")
}
@@ -281,14 +283,14 @@ data class IDERunContext(
}.forEach { it.toFile().deleteRecursively() }
ErrorReporter.reportErrorsAsFailedTests(logsDir / "script-errors", contextName)
val (artifactPath, artifactName) = if (successfulRun) contextName to "logs" else "run/$contextName" to "crash"
testContext.publishArtifact(logsDir, artifactPath, formatArtifactName(artifactName, testContext.testName))
publishArtifacts(isRunSuccessful)
if (codeBuilder != null) {
host.tearDown(testContext)
}
val closeContext = object : IDERunCloseContext {
override val wasRunSuccessful: Boolean = successfulRun
override val wasRunSuccessful: Boolean = isRunSuccessful
}
closeHandlers.forEach {
@@ -307,9 +309,24 @@ data class IDERunContext(
}
}
private fun publishArtifacts(isRunSuccessful: Boolean) {
// publish artifacts to directory with a test in any case
testContext.publishArtifact(
source = testContext.paths.logsDir,
artifactPath = contextName,
artifactName = formatArtifactName("logs", testContext.testName)
)
if (!isRunSuccessful)
testContext.publishArtifact(
source = testContext.paths.logsDir,
artifactPath = "_crashes/$contextName",
artifactName = formatArtifactName("crash", testContext.testName)
)
}
fun runIDE(): IDEStartResult {
return installProfiler()
.prepareToRunIDE()
return installProfiler().prepareToRunIDE()
}
private fun deleteSavedAppStateOnMac() {
@@ -1,5 +1,7 @@
package com.intellij.ide.starter.runner
import com.intellij.ide.starter.bus.EventState
import com.intellij.ide.starter.bus.StarterBus
import com.intellij.ide.starter.ci.CIServer
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.ide.*
@@ -22,13 +24,11 @@ import kotlin.io.path.div
interface TestContainer<T> : Closeable {
val ciServer: CIServer
var useLatestDownloadedIdeBuild: Boolean
val allContexts: MutableList<IDETestContext>
var testContext: IDETestContext
val setupHooks: MutableList<IDETestContext.() -> IDETestContext>
override fun close() {
for (context in allContexts) {
catchAll { context.paths.close() }
}
catchAll { testContext.paths.close() }
logOutput("TestContainer $this disposed")
}
@@ -48,6 +48,9 @@ interface TestContainer<T> : Closeable {
useLatestDownloadedIdeBuild = true
} as T
/**
* @return <Build Number, InstalledIde>
*/
fun resolveIDE(ideInfo: IdeInfo): Pair<String, InstalledIde> {
return di.direct.factory<IdeInfo, IdeInstallator>().invoke(ideInfo).install(ideInfo)
}
@@ -63,10 +66,8 @@ interface TestContainer<T> : Closeable {
}
/** Starting point to run your test */
fun initializeTestRunner(testName: String, testCase: TestCase): IDETestContext {
check(allContexts.none { it.testName == testName }) { "Test $testName is already initialized. Use another name." }
fun initializeTestContext(testName: String, testCase: TestCase): IDETestContext {
logOutput("Resolving IDE build for $testName...")
val (buildNumber, ide) = resolveIDE(testCase.ideInfo)
require(ide.productCode == testCase.ideInfo.productCode) { "Product code of $ide must be the same as for $testCase" }
@@ -78,16 +79,15 @@ interface TestContainer<T> : Closeable {
logOutput("IDE to run for $testName: $ide")
val projectHome = testCase.projectInfo?.downloadAndUnpackProject()
val context = IDETestContext(paths, ide, testCase, testName, projectHome, patchVMOptions = { this }, ciServer = ciServer)
allContexts += context
testContext = IDETestContext(paths, ide, testCase, testName, projectHome, patchVMOptions = { this }, ciServer = ciServer)
val baseContext = when (testCase.ideInfo == IdeProductProvider.AI) {
true -> context
testContext = when (testCase.ideInfo == IdeProductProvider.AI) {
true -> testContext
.addVMOptionsPatch {
overrideDirectories(paths)
.withEnv("STUDIO_VM_OPTIONS", ide.patchedVMOptionsFile.toString())
}
false -> context
false -> testContext
.disableInstantIdeShutdown()
.disableFusSendingOnIdeClose()
.disableJcef()
@@ -101,8 +101,12 @@ interface TestContainer<T> : Closeable {
}
}
return setupHooks
.fold(baseContext.updateGeneralSettings()) { acc, hook -> acc.hook() }
val contextWithAppliedHooks = setupHooks
.fold(testContext.updateGeneralSettings()) { acc, hook -> acc.hook() }
.apply { installPerformanceTestingPluginIfMissing(this) }
StarterBus.post(TestContextInitializedEvent(EventState.AFTER, contextWithAppliedHooks))
return contextWithAppliedHooks
}
}
@@ -9,6 +9,7 @@ import org.kodein.di.instance
class TestContainerImpl(
override val ciServer: CIServer = di.direct.instance(),
override var useLatestDownloadedIdeBuild: Boolean = false,
override val allContexts: MutableList<IDETestContext> = mutableListOf(),
override val setupHooks: MutableList<IDETestContext.() -> IDETestContext> = mutableListOf()
) : TestContainer<TestContainerImpl>
) : TestContainer<TestContainerImpl> {
override lateinit var testContext: IDETestContext
}
@@ -0,0 +1,7 @@
package com.intellij.ide.starter.runner
import com.intellij.ide.starter.bus.Event
import com.intellij.ide.starter.bus.EventState
import com.intellij.ide.starter.ide.IDETestContext
class TestContextInitializedEvent(state: EventState, testContext: IDETestContext) : Event<IDETestContext>(state, testContext)
@@ -0,0 +1,44 @@
package com.intellij.ide.starter.runner
import com.intellij.ide.starter.ide.IDETestContext
import com.intellij.ide.starter.utils.catchAll
import com.intellij.ide.starter.utils.logOutput
import com.intellij.util.io.exists
import java.util.*
class TestWatcherActions {
private val _onFailureActions: MutableList<(IDETestContext) -> Unit> = Collections.synchronizedList(mutableListOf())
val onFailureActions: List<(IDETestContext) -> Unit>
get() = synchronized(_onFailureActions) { _onFailureActions.toList() }
private val _onFinishedActions: MutableList<(IDETestContext) -> Unit> = Collections.synchronizedList(mutableListOf())
val onFinishedActions: List<(IDETestContext) -> Unit>
get() = synchronized(_onFinishedActions) { _onFinishedActions.toList() }
companion object {
/** Archive and add to test artifact entire ide's `system` dir */
fun getSystemDirAsArtifactAction(): (IDETestContext) -> Unit = { testContext ->
catchAll {
logOutput("Archive with system directory created and will be published to artifacts")
testContext.publishArtifact(source = testContext.paths.systemDir, artifactName = "testSystemDirSnapshot.zip")
val ideaDirPath = testContext.resolvedProjectHome.resolve(".idea")
if (ideaDirPath.exists()) {
logOutput("Archive with .idea dir created and will be published to artifacts")
testContext.publishArtifact(source = ideaDirPath, artifactName = ".idea.zip")
}
}
}
}
fun addOnFailureAction(action: (IDETestContext) -> Unit): TestWatcherActions {
synchronized(_onFailureActions) { _onFailureActions.add(action) }
return this
}
fun addOnFinishedAction(action: (IDETestContext) -> Unit): TestWatcherActions {
synchronized(_onFinishedActions) { _onFinishedActions.add(action) }
return this
}
}
@@ -73,18 +73,22 @@ object JdkDownloaderFacade {
}
private fun downloadJdkItem(jdk: JdkItem, predicate: JdkPredicate): JdkItemPaths {
val targetJdkHome = when (predicate) {
JdkPredicate.forWSL() -> {
if (SystemInfo.isWindows && WslDistributionManager.getInstance().installedDistributions.isNotEmpty()) {
val wslDistribution = WslDistributionManager.getInstance().installedDistributions[0]
Path.of(wslDistribution.getWindowsPath("/tmp/jdks/${jdk.installFolderName}"))
}
else {
throw WslDistributionNotFoundException()
}
val targetJdkHome: Path
// hack for wsl on windows
if (predicate == JdkPredicate.forWSL() && SystemInfo.isWindows && WslDistributionManager.getInstance().installedDistributions.isNotEmpty()) {
try {
val wslDistribution = WslDistributionManager.getInstance().installedDistributions[0]
targetJdkHome = Path.of(wslDistribution.getWindowsPath("/tmp/jdks/${jdk.installFolderName}"))
}
catch (_: Exception) {
throw WslDistributionNotFoundException(predicate)
}
else -> di.direct.instance<GlobalPaths>().getCacheDirectoryFor("jdks").resolve(jdk.installFolderName)
}
else {
targetJdkHome = di.direct.instance<GlobalPaths>().getCacheDirectoryFor("jdks").resolve(jdk.installFolderName)
}
val targetHomeMarker = targetJdkHome.resolve("home.link")
logOutput("Checking JDK at $targetJdkHome")
@@ -19,6 +19,8 @@ object SystemInfo {
val isUnix = !isWindows
val isXWindow = isUnix && !isMac
val isAarch64: Boolean = OS_ARCH == "aarch64"
private fun getRtVersion(fallback: String): String? {
val rtVersion = System.getProperty("java.runtime.version")
return if (Character.isDigit(rtVersion[0])) rtVersion else fallback
@@ -1,9 +1,9 @@
package com.intellij.ide.starter.utils
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.path.GlobalPaths
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.system.SystemInfo
import org.kodein.di.instance
import org.rauschig.jarchivelib.ArchiveFormat
@@ -129,13 +129,13 @@ object FileSystem {
}
else if (SystemInfo.isLinux || SystemInfo.isMac) {
Files.createDirectories(targetDir)
exec(
presentablePurpose = "extract-tar",
ProcessExecutor(
presentableName = "extract-tar",
workDir = targetDir,
timeout = 10.minutes,
stderrRedirect = ExecOutputRedirect.ToStdOut("tar"),
args = listOf("tar", "-z", "-x", "-f", tarFile.toAbsolutePath().toString(), "-C", targetDir.toAbsolutePath().toString())
)
).start()
}
}
catch (e: Exception) {
@@ -1,7 +1,7 @@
package com.intellij.ide.starter.utils
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import java.io.IOException
import java.nio.file.Path
import java.nio.file.Paths
@@ -15,12 +15,14 @@ object Git {
@Throws(IOException::class, InterruptedException::class)
private fun getLocalGitBranch(): String {
val stdout = ExecOutputRedirect.ToString()
exec(
ProcessExecutor(
"git-local-branch-get",
workDir = null, timeout = 1.minutes,
args = listOf("git", "rev-parse", "--abbrev-ref", "HEAD"),
stdoutRedirect = stdout
)
).start()
return stdout.read().trim()
}
@@ -41,12 +43,12 @@ object Git {
val stdout = ExecOutputRedirect.ToString()
try {
exec(
ProcessExecutor(
"git-repo-root-get",
workDir = null, timeout = 1.minutes,
args = listOf("git", "rev-parse", "--show-toplevel", "HEAD"),
stdoutRedirect = stdout
)
).start()
}
catch (e: Exception) {
val workDir = Paths.get("").toAbsolutePath()
@@ -11,6 +11,7 @@ import kotlin.io.path.name
fun String.hyphenateTestName(): String {
fun hyphenateString(input: String) = input
.replace(Regex("( )+"), "-")
.replace(" ", "-").trim()
.replaceFirstChar { it.lowercase(Locale.getDefault()) }.toCharArray()
.map {
@@ -1,9 +1,9 @@
package com.intellij.ide.starter.utils
import com.intellij.ide.starter.di.di
import com.intellij.ide.starter.exec.ExecOutputRedirect
import com.intellij.ide.starter.exec.exec
import com.intellij.ide.starter.path.GlobalPaths
import com.intellij.ide.starter.process.exec.ExecOutputRedirect
import com.intellij.ide.starter.process.exec.ProcessExecutor
import com.intellij.ide.starter.system.SystemInfo
import org.kodein.di.direct
import org.kodein.di.instance
@@ -31,13 +31,18 @@ fun getThrowableText(t: Throwable): String {
return writer.buffer.toString()
}
inline fun catchAll(action: () -> Unit) {
/**
* In case of success - return T
* In case of error - print error to stderr and return null
*/
inline fun <T> catchAll(action: () -> T): T? {
try {
action()
return action()
}
catch (t: Throwable) {
logError("CatchAll swallowed error: ${t.message}")
logError(getThrowableText(t))
return null
}
}
@@ -71,14 +76,14 @@ fun execJavaCmd(javaHome: Path, args: Iterable<String> = listOf()): List<String>
val processArguments = listOf(java.toString()).plus(args)
exec(
presentablePurpose = prefix,
ProcessExecutor(
presentableName = prefix,
workDir = javaHome,
timeout = 1.minutes,
args = processArguments,
stdoutRedirect = stdout,
stderrRedirect = stderr
)
).start()
val mergedOutput = listOf(stdout, stderr)
.flatMap { it.read().split(System.lineSeparator()) }
@@ -184,14 +189,14 @@ fun takeScreenshot(logsDir: Path) {
val toolPath = screenshotTool.resolve("$toolName.jar")
val javaPath = ProcessHandle.current().info().command().orElseThrow().toString()
exec(
presentablePurpose = "take-screenshot",
ProcessExecutor(
presentableName = "take-screenshot",
workDir = toolsDir,
timeout = 15.seconds,
args = mutableListOf(javaPath, "-jar", toolPath.absolutePathString(), screenshotFile.toString()),
environmentVariables = mapOf("DISPLAY" to ":88"),
onlyEnrichExistedEnvVariables = true
)
).start()
if (screenshotFile.exists()) {
logOutput("Screenshot saved in $screenshotFile")
@@ -204,32 +209,38 @@ fun takeScreenshot(logsDir: Path) {
fun startProfileNativeThreads(pid: String) {
if (!SystemInfo.isWindows) {
val toolsDir = di.direct.instance<GlobalPaths>().getCacheDirectoryFor("tools")
val toolName = "async-profiler-2.7-macos"
val toolName = when {
SystemInfo.isMac -> "async-profiler-2.7-macos"
SystemInfo.isLinux -> "async-profiler-2.7-linux-x64"
else -> error("Not supported OS")
}
val profiler = toolsDir / toolName
downloadAsyncProfilerIfNeeded(profiler, toolsDir)
givePermissionsToExecutables(profiler)
exec(
presentablePurpose = "start-profile",
ProcessExecutor(
presentableName = "start-profile",
workDir = profiler,
timeout = 15.seconds,
args = mutableListOf("./profiler.sh", "start", pid)
)
).start()
}
}
private fun givePermissionsToExecutables(profiler: Path) {
exec(
presentablePurpose = "give-permissions-to-jattach",
ProcessExecutor(
presentableName = "give-permissions-to-jattach",
workDir = profiler.resolve("build"),
timeout = 10.seconds,
args = mutableListOf("chmod", "+x", "jattach")
)
exec(
presentablePurpose = "give-permissions-to-profiler",
).start()
ProcessExecutor(
presentableName = "give-permissions-to-profiler",
workDir = profiler,
timeout = 10.seconds,
args = mutableListOf("chmod", "+x", "profiler.sh")
)
).start()
}
fun stopProfileNativeThreads(pid: String, fileToStoreInfo: String) {
@@ -237,12 +248,13 @@ fun stopProfileNativeThreads(pid: String, fileToStoreInfo: String) {
val toolsDir = di.direct.instance<GlobalPaths>().getCacheDirectoryFor("tools")
val toolName = "async-profiler-2.7-macos"
val profiler = toolsDir / toolName
exec(
presentablePurpose = "stop-profile",
ProcessExecutor(
presentableName = "stop-profile",
workDir = profiler,
timeout = 15.seconds,
args = mutableListOf("./profiler.sh", "stop", pid, "-f", fileToStoreInfo)
)
).start()
}
}
@@ -3,8 +3,9 @@ package com.intellij.ide.starter.wsl
import com.intellij.execution.wsl.WslDistributionManager
import com.intellij.ide.starter.system.SystemInfo
import com.intellij.ide.starter.utils.logOutput
import com.intellij.openapi.projectRoots.impl.jdkDownloader.JdkPredicate
class WslDistributionNotFoundException() : Exception() {
class WslDistributionNotFoundException(val jdkPredicate: JdkPredicate? = null) : Exception() {
override val message: String
get() {
val red = "\u001b[31m"
@@ -31,6 +32,7 @@ class WslDistributionNotFoundException() : Exception() {
appendLine("Can't run test on WSL")
appendLine("Current OS: ${SystemInfo.OS_NAME} ${SystemInfo.OS_VERSION}")
appendLine("WSL distributions installed: ${WslDistributionManager.getInstance().installedDistributions}")
jdkPredicate?.let { appendLine(jdkPredicate) }
}
}
}