mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
AT-126 Open-source performance plugin
Split performance plugin into core (and move it to community), async and YK. Move Cache Value Profiler to separate plugin. GitOrigin-RevId: 80e68080197e86d40c76be45d5438ec0eee39818
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3f60eaf4d8
commit
1196257bd0
Generated
-19
@@ -1,19 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="kodein-di-jvm" type="repository">
|
||||
<properties maven-id="org.kodein.di:kodein-di-jvm:7.15.0">
|
||||
<exclude>
|
||||
<dependency maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8" />
|
||||
<dependency maven-id="org.jetbrains.kotlin:kotlin-stdlib-common" />
|
||||
</exclude>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/kodein/di/kodein-di-jvm/7.15.0/kodein-di-jvm-7.15.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/kodein/type/kaverit-jvm/2.2.1-kotlin-1.7.20-RC/kaverit-jvm-2.2.1-kotlin-1.7.20-RC.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/kodein/di/kodein-di-jvm/7.15.0/kodein-di-jvm-7.15.0-sources.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/org/kodein/type/kaverit-jvm/2.2.1-kotlin-1.7.20-RC/kaverit-jvm-2.2.1-kotlin-1.7.20-RC-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</component>
|
||||
Generated
-14
@@ -1,14 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="qodana-sarif" type="repository">
|
||||
<properties maven-id="com.jetbrains.qodana:qodana-sarif:0.2.1">
|
||||
<exclude>
|
||||
<dependency maven-id="com.google.code.gson:gson" />
|
||||
</exclude>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/jetbrains/qodana/qodana-sarif/0.2.1/qodana-sarif-0.2.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+1
-4
@@ -774,6 +774,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/package-search/gradle/tooling/intellij.packageSearch.gradle.tooling.iml" filepath="$PROJECT_DIR$/plugins/package-search/gradle/tooling/intellij.packageSearch.gradle.tooling.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/package-search/kotlin/intellij.packageSearch.kotlin.iml" filepath="$PROJECT_DIR$/plugins/package-search/kotlin/intellij.packageSearch.kotlin.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/package-search/maven/intellij.packageSearch.maven.iml" filepath="$PROJECT_DIR$/plugins/package-search/maven/intellij.packageSearch.maven.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/performanceTesting/intellij.performanceTesting.iml" filepath="$PROJECT_DIR$/plugins/performanceTesting/intellij.performanceTesting.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/analysis-api/intellij.platform.analysis.iml" filepath="$PROJECT_DIR$/platform/analysis-api/intellij.platform.analysis.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/analysis-impl/intellij.platform.analysis.impl.iml" filepath="$PROJECT_DIR$/platform/analysis-impl/intellij.platform.analysis.impl.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/platform/boot/intellij.platform.boot.iml" filepath="$PROJECT_DIR$/platform/boot/intellij.platform.boot.iml" />
|
||||
@@ -1032,10 +1033,6 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/toml/core/intellij.toml.core.iml" filepath="$PROJECT_DIR$/plugins/toml/core/intellij.toml.core.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/toml/json/intellij.toml.json.iml" filepath="$PROJECT_DIR$/plugins/toml/json/intellij.toml.json.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/toml/core/src/test/intellij.toml.tests.iml" filepath="$PROJECT_DIR$/plugins/toml/core/src/test/intellij.toml.tests.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.metricsCollector/intellij.tools.ide.metricsCollector.iml" filepath="$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.metricsCollector/intellij.tools.ide.metricsCollector.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.starter/intellij.tools.ide.starter.iml" filepath="$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.starter/intellij.tools.ide.starter.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.starter.junit4/intellij.tools.ide.starter.junit4.iml" filepath="$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.starter.junit4/intellij.tools.ide.starter.junit4.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.starter.junit5/intellij.tools.ide.starter.junit5.iml" filepath="$PROJECT_DIR$/tools/ideTestingFramework/intellij.tools.ide.starter.junit5/intellij.tools.ide.starter.junit5.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jps/antLayout/intellij.tools.jps.antTasks.iml" filepath="$PROJECT_DIR$/jps/antLayout/intellij.tools.jps.antTasks.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jps/standalone-builder/intellij.tools.jps.build.standalone.iml" filepath="$PROJECT_DIR$/jps/standalone-builder/intellij.tools.jps.build.standalone.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/launcher-generator/intellij.tools.launcherGenerator.iml" filepath="$PROJECT_DIR$/tools/launcher-generator/intellij.tools.launcherGenerator.iml" />
|
||||
|
||||
@@ -26,11 +26,7 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
"intellij.platform.debugger.testFramework",
|
||||
"intellij.platform.vcs.testFramework",
|
||||
"intellij.platform.externalSystem.testFramework",
|
||||
"intellij.maven.testFramework",
|
||||
"intellij.tools.ide.starter",
|
||||
"intellij.tools.ide.metricsCollector",
|
||||
"intellij.tools.ide.starter.junit4",
|
||||
"intellij.tools.ide.starter.junit5"
|
||||
"intellij.maven.testFramework"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -198,5 +198,6 @@
|
||||
<orderEntry type="module" module-name="intellij.fullLine" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.fullLine.java" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.fullLine.kotlin" scope="RUNTIME" />
|
||||
<orderEntry type="module" module-name="intellij.performanceTesting" scope="RUNTIME" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -70,6 +70,7 @@ object CommunityRepositoryModules {
|
||||
spec.withModule("intellij.xml.langInjection", "IntelliLang.jar")
|
||||
spec.withModule("intellij.java.langInjection.jps")
|
||||
},
|
||||
plugin(listOf("intellij.performanceTesting")),
|
||||
plugin("intellij.tasks.core") { spec ->
|
||||
spec.directoryName = "tasks"
|
||||
spec.withModule("intellij.tasks")
|
||||
|
||||
@@ -192,6 +192,7 @@ open class StartupManagerImpl(private val project: Project) : StartupManagerEx()
|
||||
val pluginId = adapter.pluginDescriptor.pluginId
|
||||
if (!isCorePlugin(adapter.pluginDescriptor) && pluginId.idString != "com.jetbrains.performancePlugin"
|
||||
&& pluginId.idString != "com.intellij.clion-makefile"
|
||||
&& pluginId.idString != "com.jetbrains.performancePlugin.yourkit"
|
||||
&& pluginId.idString != "com.intellij.clion-swift"
|
||||
&& pluginId.idString != "com.intellij.appcode"
|
||||
&& pluginId.idString != "com.intellij.clion-compdb"
|
||||
|
||||
+703
@@ -0,0 +1,703 @@
|
||||
/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */
|
||||
|
||||
package com.jetbrains.performancePlugin.lang.lexer;
|
||||
|
||||
import com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.TokenType;
|
||||
import com.intellij.lexer.FlexLexer;
|
||||
|
||||
|
||||
/**
|
||||
* This class is a scanner generated by
|
||||
* <a href="http://www.jflex.de/">JFlex</a> 1.7.0
|
||||
* from the specification file <tt>IJPerf.flex</tt>
|
||||
*/
|
||||
class IJPerfLexer implements FlexLexer {
|
||||
|
||||
/** This character denotes the end of file */
|
||||
public static final int YYEOF = -1;
|
||||
|
||||
/** initial size of the lookahead buffer */
|
||||
private static final int ZZ_BUFFERSIZE = 16384;
|
||||
|
||||
/** lexical states */
|
||||
public static final int YYINITIAL = 0;
|
||||
public static final int WAITING_INPUT = 2;
|
||||
public static final int WAITING_TEXT = 4;
|
||||
public static final int WAITING_LAST_OPTION = 6;
|
||||
|
||||
/**
|
||||
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
|
||||
* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
|
||||
* at the beginning of a line
|
||||
* l is of the form l = 2*k, k a non negative integer
|
||||
*/
|
||||
private static final int ZZ_LEXSTATE[] = {
|
||||
0, 0, 1, 1, 2, 2, 3, 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Translates characters to character classes
|
||||
* Chosen bits are [12, 6, 3]
|
||||
* Total runtime size is 15696 bytes
|
||||
*/
|
||||
public static int ZZ_CMAP(int ch) {
|
||||
return ZZ_CMAP_A[(ZZ_CMAP_Y[(ZZ_CMAP_Z[ch>>9]<<6)|((ch>>3)&0x3f)]<<3)|(ch&0x7)];
|
||||
}
|
||||
|
||||
/* The ZZ_CMAP_Z table has 2176 entries */
|
||||
static final char ZZ_CMAP_Z[] = zzUnpackCMap(
|
||||
"\1\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1"+
|
||||
"\20\5\21\1\22\1\23\1\24\1\21\14\25\1\26\50\25\1\27\2\25\1\30\1\31\1\32\1\33"+
|
||||
"\25\25\1\34\20\21\1\35\1\36\1\37\1\40\1\41\1\42\1\43\1\44\1\45\1\46\1\47\1"+
|
||||
"\21\1\50\1\51\1\52\1\53\1\54\1\55\1\56\1\21\1\25\1\57\1\60\5\21\2\25\1\61"+
|
||||
"\7\21\1\25\1\62\20\21\1\25\1\63\1\21\1\64\13\25\1\65\1\25\1\66\22\21\1\67"+
|
||||
"\1\70\4\21\1\71\11\21\1\72\1\73\1\74\1\75\1\21\1\76\2\21\1\77\3\21\1\100\2"+
|
||||
"\21\1\101\10\21\123\25\1\102\7\25\1\103\1\104\12\25\1\105\15\25\1\106\6\21"+
|
||||
"\1\25\1\107\u0582\21\1\110\u017f\21");
|
||||
|
||||
/* The ZZ_CMAP_Y table has 4672 entries */
|
||||
static final char ZZ_CMAP_Y[] = zzUnpackCMap(
|
||||
"\1\0\1\1\1\0\1\2\1\3\1\4\1\5\1\6\1\7\2\0\1\10\1\7\2\0\1\11\1\12\3\0\1\13\1"+
|
||||
"\14\1\15\1\16\2\0\1\17\3\0\1\17\71\0\1\20\1\0\1\21\1\22\1\23\1\24\2\22\16"+
|
||||
"\0\1\25\1\26\1\27\1\30\2\0\1\31\11\0\1\32\21\0\1\31\1\33\24\0\1\7\3\0\1\17"+
|
||||
"\1\34\1\7\4\0\1\35\1\7\4\0\1\32\1\36\1\22\3\0\2\37\1\22\1\40\1\41\1\0\1\42"+
|
||||
"\10\0\1\5\1\43\14\0\1\44\1\32\1\0\1\45\1\5\1\46\1\22\1\35\7\0\1\47\14\0\1"+
|
||||
"\21\1\22\1\5\1\50\4\0\1\40\1\16\5\0\1\40\2\22\3\0\1\2\1\0\1\37\6\22\2\0\1"+
|
||||
"\25\1\40\2\22\1\51\21\0\1\52\1\5\1\7\1\0\1\44\1\53\1\54\2\0\1\45\1\55\1\56"+
|
||||
"\1\53\1\57\1\35\1\60\1\52\1\5\1\2\1\61\1\62\1\63\1\54\2\0\1\45\1\64\1\65\1"+
|
||||
"\63\1\66\1\34\1\67\1\70\1\5\1\40\1\22\1\62\1\32\1\31\2\0\1\45\1\71\1\56\1"+
|
||||
"\32\1\72\1\73\1\22\1\52\1\5\1\34\1\7\1\62\1\53\1\54\2\0\1\45\1\71\1\56\1\53"+
|
||||
"\1\66\1\74\1\60\1\52\1\5\1\34\1\22\1\75\1\76\1\77\1\100\1\61\1\76\1\0\1\20"+
|
||||
"\1\76\1\77\1\101\1\22\1\70\1\5\1\22\1\34\1\44\1\25\1\45\2\0\1\45\1\0\1\102"+
|
||||
"\1\25\1\77\1\103\1\37\1\52\1\5\2\22\1\44\1\25\1\45\2\0\1\45\1\44\1\56\1\25"+
|
||||
"\1\77\1\103\1\27\1\52\1\5\1\104\1\22\1\44\1\25\1\45\5\0\1\25\1\105\1\51\1"+
|
||||
"\35\1\52\1\5\1\22\1\33\1\75\1\0\1\17\1\33\2\0\1\31\1\106\1\17\1\107\1\110"+
|
||||
"\1\0\1\70\1\5\1\111\1\22\1\7\6\0\1\63\1\0\1\17\1\5\1\112\4\22\1\113\1\114"+
|
||||
"\1\51\1\7\1\115\1\75\1\0\1\72\1\110\1\40\1\5\1\116\4\22\1\73\2\22\1\21\1\5"+
|
||||
"\1\112\1\117\1\120\1\0\1\7\3\0\1\23\1\7\1\0\1\25\2\0\1\7\3\0\1\23\1\27\7\22"+
|
||||
"\10\0\1\5\1\112\10\0\1\5\1\121\4\0\1\32\1\15\5\0\1\122\51\0\1\77\1\17\1\77"+
|
||||
"\5\0\1\77\4\0\1\77\1\17\1\77\1\0\1\17\7\0\1\77\10\0\1\47\4\22\2\0\2\22\12"+
|
||||
"\0\2\40\1\7\114\0\1\53\2\0\1\7\2\0\1\37\11\0\1\76\1\0\1\73\1\0\1\25\1\23\1"+
|
||||
"\22\2\0\1\23\1\22\2\0\1\2\1\22\1\0\1\25\1\123\1\22\12\0\1\124\1\125\1\5\1"+
|
||||
"\112\3\22\1\126\1\5\1\112\13\0\1\22\5\0\1\37\10\0\1\40\1\22\3\0\1\17\1\0\1"+
|
||||
"\2\1\0\1\2\1\70\1\5\3\0\1\40\1\23\1\22\5\0\1\2\3\0\1\21\1\5\1\112\4\22\3\0"+
|
||||
"\1\2\7\0\1\17\3\0\1\53\1\5\1\112\1\5\1\112\1\35\1\22\1\0\1\40\10\22\11\0\1"+
|
||||
"\2\1\5\1\112\1\22\1\127\1\2\1\22\6\0\1\5\1\50\6\0\1\2\1\22\7\0\1\22\1\5\1"+
|
||||
"\130\1\5\1\50\3\0\1\40\1\0\1\73\10\22\1\122\4\0\1\21\37\0\1\31\42\0\2\40\4"+
|
||||
"\0\2\40\1\0\1\131\3\0\1\40\6\0\1\25\1\110\1\132\1\23\1\133\1\2\1\0\1\23\1"+
|
||||
"\132\1\23\1\22\1\127\3\22\1\134\1\22\1\35\1\73\1\22\1\135\1\22\1\25\1\0\1"+
|
||||
"\34\1\35\2\22\1\0\1\23\4\0\2\22\1\0\1\23\1\136\1\0\1\73\1\22\1\107\1\33\1"+
|
||||
"\106\1\137\1\24\1\140\1\0\1\56\1\141\1\142\2\22\5\0\1\73\116\22\5\0\1\17\5"+
|
||||
"\0\1\17\20\0\1\23\1\127\1\2\1\22\4\0\1\32\1\15\7\0\1\35\1\22\1\35\2\0\1\17"+
|
||||
"\1\22\10\17\4\0\5\22\1\35\72\22\1\141\3\22\1\7\1\0\1\137\1\23\1\7\11\0\1\17"+
|
||||
"\1\143\1\7\12\0\1\122\1\141\4\0\1\17\1\7\12\0\1\17\2\22\3\0\1\37\6\22\170"+
|
||||
"\0\1\40\11\22\75\0\1\37\2\22\21\0\1\23\10\22\5\0\1\40\41\0\1\23\2\0\1\5\1"+
|
||||
"\144\2\22\6\0\1\51\1\32\16\0\1\21\3\22\1\35\1\0\1\33\14\0\1\54\3\0\1\17\1"+
|
||||
"\0\7\22\1\35\6\0\2\22\1\73\6\0\1\2\1\22\10\0\1\40\1\22\1\5\1\112\3\0\1\145"+
|
||||
"\1\5\1\50\3\0\1\40\4\0\1\2\1\22\3\0\1\23\10\0\1\73\1\35\1\5\1\112\2\0\1\5"+
|
||||
"\1\146\6\0\1\17\1\22\1\0\1\40\1\5\1\112\2\0\1\17\1\33\10\0\1\37\2\22\1\125"+
|
||||
"\2\0\1\147\1\22\3\150\1\22\2\17\5\0\1\122\1\40\1\22\17\0\1\151\1\5\1\112\64"+
|
||||
"\0\1\2\1\22\2\0\1\17\1\127\5\0\1\2\40\22\55\0\1\40\15\0\1\21\4\22\1\17\1\22"+
|
||||
"\1\127\1\141\1\0\1\45\1\17\1\110\1\152\15\0\1\21\3\22\1\127\54\0\1\40\2\22"+
|
||||
"\10\0\1\33\6\0\5\22\1\0\1\23\2\0\2\22\2\0\1\61\2\22\1\141\3\22\1\34\1\25\20"+
|
||||
"\0\1\53\1\135\1\22\1\5\1\112\1\7\2\0\1\63\1\7\2\0\1\37\1\74\12\0\1\17\3\33"+
|
||||
"\1\153\1\154\2\22\1\155\1\0\1\44\2\0\1\17\2\0\1\156\1\0\1\40\1\0\1\40\4\22"+
|
||||
"\17\0\1\37\10\22\6\0\1\23\20\22\1\15\20\22\3\0\1\23\6\0\1\73\1\22\1\73\3\22"+
|
||||
"\4\0\1\22\1\141\3\0\1\37\5\0\1\37\3\0\1\40\4\0\1\2\1\0\1\137\5\22\23\0\1\40"+
|
||||
"\1\5\1\112\4\0\1\2\4\0\1\2\5\0\1\22\6\0\1\2\23\22\46\0\1\17\1\22\2\0\1\40"+
|
||||
"\1\22\1\0\23\22\1\40\1\45\4\0\1\32\1\157\2\0\1\40\1\22\2\0\1\17\1\22\3\0\1"+
|
||||
"\17\10\22\2\0\1\151\1\22\2\0\1\40\1\22\3\0\1\21\10\22\7\0\1\74\10\22\1\160"+
|
||||
"\1\51\1\44\1\7\2\0\1\2\1\63\4\22\3\0\1\23\3\0\1\23\4\22\1\0\1\7\2\0\1\17\3"+
|
||||
"\22\6\0\1\40\1\22\2\0\1\40\1\22\2\0\1\37\1\22\2\0\1\21\15\22\11\0\1\73\6\22"+
|
||||
"\6\0\1\37\1\22\6\0\1\37\41\22\10\0\1\17\3\22\1\70\1\5\1\22\1\35\7\0\1\161"+
|
||||
"\2\22\3\0\1\73\1\5\1\112\6\0\1\162\1\5\2\22\4\0\1\163\1\22\10\0\1\23\1\153"+
|
||||
"\1\5\1\164\4\22\2\0\1\31\4\0\1\27\10\22\1\17\1\140\1\0\1\32\1\0\1\73\7\0\1"+
|
||||
"\37\1\5\1\112\1\44\1\53\1\54\2\0\1\45\1\71\1\56\1\53\1\66\1\101\1\141\1\133"+
|
||||
"\2\23\21\22\11\0\1\37\1\5\1\112\4\22\10\0\1\32\1\22\1\5\1\112\24\22\6\0\1"+
|
||||
"\40\1\0\1\73\2\22\1\40\4\22\10\0\1\165\1\22\1\5\1\112\4\22\7\0\1\22\1\5\1"+
|
||||
"\112\6\22\3\0\1\102\1\0\1\2\1\5\1\112\54\22\10\0\1\5\1\112\1\22\1\35\40\22"+
|
||||
"\7\0\1\17\1\35\1\22\6\0\1\133\2\0\1\21\4\22\7\0\1\73\40\22\1\0\1\45\4\0\1"+
|
||||
"\17\1\0\1\73\1\22\1\5\1\112\2\22\1\33\3\0\1\33\2\0\1\7\1\17\11\22\1\17\1\31"+
|
||||
"\4\0\1\17\1\166\1\0\1\22\1\0\1\21\24\22\63\0\1\21\14\22\15\0\1\17\2\22\30"+
|
||||
"\0\1\2\27\22\5\0\1\17\72\22\10\0\1\17\67\22\7\0\1\73\3\0\1\17\1\5\1\112\14"+
|
||||
"\22\3\0\1\40\1\23\1\22\6\0\1\17\1\22\1\2\1\22\1\5\1\112\1\127\2\0\1\141\2"+
|
||||
"\0\56\22\10\0\1\23\1\22\5\0\1\17\1\22\1\35\2\0\10\22\1\21\3\22\75\0\1\23\2"+
|
||||
"\22\36\0\1\37\41\22\43\0\1\17\12\22\61\0\1\2\40\22\15\0\1\37\1\0\1\23\1\0"+
|
||||
"\1\73\1\0\1\154\1\2\127\22\1\141\1\102\2\0\1\47\1\2\3\22\1\13\22\22\1\153"+
|
||||
"\67\22\12\0\1\25\10\0\1\25\1\167\1\170\1\0\1\171\1\44\7\0\1\32\1\47\2\25\3"+
|
||||
"\0\1\172\1\110\1\33\1\45\51\0\1\40\3\0\1\45\2\0\1\122\3\0\1\122\2\0\1\25\3"+
|
||||
"\0\1\25\2\0\1\17\3\0\1\17\3\0\1\45\3\0\1\45\2\0\1\122\1\52\6\5\6\0\1\17\1"+
|
||||
"\127\5\0\1\23\1\15\1\22\1\135\2\22\1\127\1\7\1\0\52\22\1\17\2\0\1\54\1\152"+
|
||||
"\1\37\72\22\30\0\1\23\1\22\1\17\5\22\11\0\1\37\1\5\1\112\24\22\1\44\3\0\1"+
|
||||
"\113\1\7\1\122\1\173\1\107\1\174\1\113\1\131\1\113\2\122\1\67\1\0\1\31\1\0"+
|
||||
"\1\2\1\62\1\31\1\0\1\2\50\22\32\0\1\17\5\22\106\0\1\23\1\22\33\0\1\40\120"+
|
||||
"\0\1\21\1\22\146\0\1\73\3\22\3\0\1\40\74\22\1\34\3\22\14\0\20\22\36\0\2\22");
|
||||
|
||||
/* The ZZ_CMAP_A table has 1000 entries */
|
||||
static final char ZZ_CMAP_A[] = zzUnpackCMap(
|
||||
"\11\14\1\4\1\2\1\1\1\5\1\3\6\14\4\0\1\4\1\0\1\12\1\0\1\14\1\6\6\0\1\10\1\17"+
|
||||
"\1\22\1\20\12\21\1\16\2\0\1\7\3\0\12\14\1\0\1\13\2\0\4\14\1\0\1\11\2\0\6\14"+
|
||||
"\1\15\2\14\2\0\4\14\4\0\1\14\2\0\1\14\7\0\1\14\4\0\1\14\5\0\7\14\1\0\2\14"+
|
||||
"\4\0\4\14\16\0\5\14\7\0\1\14\1\0\1\14\1\0\5\14\1\0\2\14\2\0\4\14\1\0\1\14"+
|
||||
"\6\0\1\14\1\0\3\14\1\0\1\14\1\0\4\14\1\0\13\14\1\0\1\14\2\0\6\14\1\0\1\14"+
|
||||
"\15\0\1\14\1\0\2\14\1\0\2\14\1\0\4\14\5\0\6\14\5\0\1\14\4\0\3\14\1\0\1\14"+
|
||||
"\3\0\2\21\4\0\6\14\1\0\4\14\1\0\6\14\2\21\3\14\2\0\4\14\2\0\3\14\2\21\6\14"+
|
||||
"\4\0\10\14\2\0\2\21\5\14\2\0\2\14\2\0\6\14\1\0\1\14\3\0\4\14\2\0\5\14\2\0"+
|
||||
"\4\14\5\0\2\14\1\0\1\14\3\0\2\14\4\0\3\14\1\0\6\14\4\0\2\14\1\0\2\14\1\0\2"+
|
||||
"\14\1\0\2\14\2\0\1\14\1\0\3\14\2\0\3\14\3\0\4\14\1\0\1\14\7\0\2\21\1\14\1"+
|
||||
"\0\2\14\1\0\5\14\1\0\3\14\2\0\1\14\15\0\2\14\2\0\2\14\1\0\6\14\3\0\3\14\1"+
|
||||
"\0\4\14\3\0\2\14\1\0\1\14\1\0\3\14\6\0\3\14\3\0\3\14\5\0\2\14\2\0\2\14\5\0"+
|
||||
"\1\14\1\0\5\14\1\0\4\14\1\0\1\14\4\0\1\14\4\0\6\14\1\0\1\14\3\0\2\14\4\0\2"+
|
||||
"\21\7\0\2\14\1\0\1\14\2\0\2\14\1\0\1\14\2\0\1\14\3\0\3\14\1\0\1\14\1\0\1\14"+
|
||||
"\2\21\2\0\4\14\5\0\1\14\1\0\1\14\1\0\1\14\4\0\2\14\2\21\4\14\2\0\3\14\1\0"+
|
||||
"\5\14\1\0\2\14\4\0\4\14\3\0\1\14\3\0\3\14\5\0\4\14\4\0\5\14\2\21\3\0\3\14"+
|
||||
"\1\0\1\14\1\0\1\14\1\0\1\14\1\0\1\14\2\0\3\14\1\0\6\14\2\0\2\14\2\1\5\14\5"+
|
||||
"\0\1\14\4\0\1\14\3\0\3\14\1\0\5\14\2\0\1\14\1\0\4\14\1\0\1\14\5\0\5\14\4\0"+
|
||||
"\1\14\2\0\2\14\2\0\3\14\2\21\2\14\7\0\1\14\1\0\1\14\2\0\2\21\5\14\3\0\5\14"+
|
||||
"\2\0\6\14\1\0\3\14\1\0\2\14\2\0\2\14\1\0\2\14\1\0\2\14\2\0\3\14\3\0\2\14\3"+
|
||||
"\0\2\14\2\0\3\14\4\0\3\14\1\0\2\14\1\0\2\14\3\0\1\14\2\0\5\14\1\0\2\14\1\0"+
|
||||
"\3\14\2\0\1\14\2\0\5\14\1\0\2\21\4\14\2\0\1\14\1\0\2\21\1\14\1\0\1\14\3\0"+
|
||||
"\1\14\3\0\1\14\5\0\1\14\1\0\2\14\1\0\1\14\2\0\1\14\2\0\2\14\2\0\4\14\1\0\4"+
|
||||
"\14\1\0\1\14\1\0\5\14\1\0\4\14\2\0\1\14\1\0\1\14\5\0\1\14\1\0\1\14\1\0\3\14");
|
||||
|
||||
/**
|
||||
* Translates DFA states to action switch labels.
|
||||
*/
|
||||
private static final int [] ZZ_ACTION = zzUnpackAction();
|
||||
|
||||
private static final String ZZ_ACTION_PACKED_0 =
|
||||
"\4\0\2\1\1\2\2\3\1\4\1\2\1\5\1\3"+
|
||||
"\1\6\1\4\1\2\1\4\1\7\2\10\1\4\1\11"+
|
||||
"\1\12\1\11\1\13\1\4\1\0\1\4\4\0\1\6"+
|
||||
"\1\4\1\0\1\4\2\2\1\14\3\0\2\4";
|
||||
|
||||
private static int [] zzUnpackAction() {
|
||||
int [] result = new int[44];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackAction(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates a state to a row index in the transition table
|
||||
*/
|
||||
private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
|
||||
|
||||
private static final String ZZ_ROWMAP_PACKED_0 =
|
||||
"\0\0\0\23\0\46\0\71\0\114\0\137\0\162\0\205"+
|
||||
"\0\230\0\253\0\276\0\321\0\344\0\367\0\u010a\0\u011d"+
|
||||
"\0\u0130\0\u0143\0\u0156\0\46\0\u0169\0\u017c\0\230\0\230"+
|
||||
"\0\230\0\u018f\0\u01a2\0\276\0\u01b5\0\u01c8\0\u01db\0\344"+
|
||||
"\0\u01ee\0\u0201\0\u0214\0\u011d\0\u0169\0\u018f\0\u0227\0\u023a"+
|
||||
"\0\u024d\0\u0260\0\u0273\0\u0286";
|
||||
|
||||
private static int [] zzUnpackRowMap() {
|
||||
int [] result = new int[44];
|
||||
int offset = 0;
|
||||
offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackRowMap(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int high = packed.charAt(i++) << 16;
|
||||
result[j++] = high | packed.charAt(i++);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* The transition table of the DFA
|
||||
*/
|
||||
private static final int [] ZZ_TRANS = zzUnpackTrans();
|
||||
|
||||
private static final String ZZ_TRANS_PACKED_0 =
|
||||
"\1\5\1\6\1\7\1\6\2\7\1\10\5\11\1\5"+
|
||||
"\1\6\1\11\1\5\2\11\1\5\1\12\1\13\1\7"+
|
||||
"\1\13\1\14\1\7\4\11\1\15\1\16\1\17\1\20"+
|
||||
"\1\11\1\21\1\16\1\22\1\21\1\23\1\24\1\7"+
|
||||
"\3\24\7\23\1\24\5\23\1\12\1\25\1\7\1\25"+
|
||||
"\1\26\1\7\1\11\1\27\1\30\1\31\1\15\1\16"+
|
||||
"\1\17\1\32\1\11\1\21\1\16\1\22\1\21\2\5"+
|
||||
"\1\0\1\5\6\0\1\5\1\0\2\5\1\0\1\5"+
|
||||
"\1\0\1\5\1\0\1\5\1\6\1\7\1\6\2\7"+
|
||||
"\4\0\1\5\1\0\1\5\1\6\1\0\1\5\1\0"+
|
||||
"\1\5\2\0\5\7\7\0\1\7\5\0\2\5\1\0"+
|
||||
"\1\5\2\0\1\33\5\0\2\5\1\0\1\5\2\0"+
|
||||
"\1\5\23\0\2\12\1\0\1\12\6\0\1\12\1\0"+
|
||||
"\2\12\1\0\1\12\1\0\1\12\1\0\1\12\1\34"+
|
||||
"\1\7\1\34\2\7\4\0\1\12\1\0\1\12\1\34"+
|
||||
"\1\0\1\12\1\0\1\12\2\0\3\7\1\14\1\7"+
|
||||
"\7\0\1\7\11\0\1\35\6\0\1\36\2\37\1\0"+
|
||||
"\2\35\1\37\1\35\12\0\1\40\1\16\2\41\1\0"+
|
||||
"\2\16\1\41\1\16\2\12\1\0\1\12\6\0\1\42"+
|
||||
"\1\41\2\17\1\43\1\21\1\41\1\17\1\16\1\12"+
|
||||
"\1\34\1\7\1\34\2\7\4\0\1\42\1\41\1\17"+
|
||||
"\1\44\1\43\1\21\1\41\1\17\1\16\2\12\1\0"+
|
||||
"\1\12\6\0\1\42\1\16\2\17\1\0\1\21\1\16"+
|
||||
"\1\17\1\16\12\0\1\40\3\41\1\43\1\16\1\41"+
|
||||
"\1\22\1\16\2\23\1\0\20\23\1\12\1\45\1\7"+
|
||||
"\1\45\2\7\4\0\1\12\1\0\1\12\1\45\1\0"+
|
||||
"\1\12\1\0\1\12\2\0\3\7\1\26\1\7\7\0"+
|
||||
"\1\7\5\0\1\12\1\45\1\7\1\45\2\7\4\0"+
|
||||
"\1\42\1\41\1\17\1\46\1\43\1\21\1\41\1\17"+
|
||||
"\1\16\2\5\1\0\1\5\3\0\1\47\4\0\2\5"+
|
||||
"\1\0\1\5\2\0\1\5\4\0\1\35\5\0\1\16"+
|
||||
"\3\35\1\0\4\35\4\0\1\35\5\0\1\16\1\50"+
|
||||
"\2\35\1\0\4\35\4\0\1\35\5\0\1\16\1\51"+
|
||||
"\2\37\1\52\1\35\1\51\1\37\1\35\12\0\1\40"+
|
||||
"\3\41\1\43\1\16\2\41\1\16\2\12\1\0\1\12"+
|
||||
"\1\35\5\0\1\12\1\36\2\53\1\0\1\54\1\35"+
|
||||
"\1\53\1\35\13\0\1\41\2\16\1\43\1\16\1\41"+
|
||||
"\2\16\2\47\2\0\17\47\4\0\1\35\5\0\1\16"+
|
||||
"\1\35\2\37\1\0\2\35\1\37\1\35\4\0\1\35"+
|
||||
"\5\0\1\16\1\51\2\35\1\52\1\35\1\51\2\35"+
|
||||
"\4\0\1\35\6\0\1\51\2\35\1\52\1\35\1\51"+
|
||||
"\2\35\2\12\1\0\1\12\1\35\5\0\1\21\1\51"+
|
||||
"\2\53\1\52\1\54\1\51\1\53\1\35\2\12\1\0"+
|
||||
"\1\12\1\35\5\0\1\21\1\35\2\54\1\0\1\54"+
|
||||
"\1\35\1\54\1\35";
|
||||
|
||||
private static int [] zzUnpackTrans() {
|
||||
int [] result = new int[665];
|
||||
int offset = 0;
|
||||
offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackTrans(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
value--;
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/* error codes */
|
||||
private static final int ZZ_UNKNOWN_ERROR = 0;
|
||||
private static final int ZZ_NO_MATCH = 1;
|
||||
private static final int ZZ_PUSHBACK_2BIG = 2;
|
||||
|
||||
/* error messages for the codes above */
|
||||
private static final String[] ZZ_ERROR_MSG = {
|
||||
"Unknown internal scanner error",
|
||||
"Error: could not match input",
|
||||
"Error: pushback value was too large"
|
||||
};
|
||||
|
||||
/**
|
||||
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
|
||||
*/
|
||||
private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
|
||||
|
||||
private static final String ZZ_ATTRIBUTE_PACKED_0 =
|
||||
"\4\0\4\1\1\11\15\1\3\11\1\1\1\0\1\1"+
|
||||
"\4\0\2\1\1\0\4\1\3\0\2\1";
|
||||
|
||||
private static int [] zzUnpackAttribute() {
|
||||
int [] result = new int[44];
|
||||
int offset = 0;
|
||||
offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int zzUnpackAttribute(String packed, int offset, int [] result) {
|
||||
int i = 0; /* index in packed string */
|
||||
int j = offset; /* index in unpacked array */
|
||||
int l = packed.length();
|
||||
while (i < l) {
|
||||
int count = packed.charAt(i++);
|
||||
int value = packed.charAt(i++);
|
||||
do result[j++] = value; while (--count > 0);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/** the input device */
|
||||
private java.io.Reader zzReader;
|
||||
|
||||
/** the current state of the DFA */
|
||||
private int zzState;
|
||||
|
||||
/** the current lexical state */
|
||||
private int zzLexicalState = YYINITIAL;
|
||||
|
||||
/** this buffer contains the current text to be matched and is
|
||||
the source of the yytext() string */
|
||||
private CharSequence zzBuffer = "";
|
||||
|
||||
/** the textposition at the last accepting state */
|
||||
private int zzMarkedPos;
|
||||
|
||||
/** the current text position in the buffer */
|
||||
private int zzCurrentPos;
|
||||
|
||||
/** startRead marks the beginning of the yytext() string in the buffer */
|
||||
private int zzStartRead;
|
||||
|
||||
/** endRead marks the last character in the buffer, that has been read
|
||||
from input */
|
||||
private int zzEndRead;
|
||||
|
||||
/**
|
||||
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
|
||||
*/
|
||||
private boolean zzAtBOL = true;
|
||||
|
||||
/** zzAtEOF == true <=> the scanner is at the EOF */
|
||||
private boolean zzAtEOF;
|
||||
|
||||
/** denotes if the user-EOF-code has already been executed */
|
||||
private boolean zzEOFDone;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new scanner
|
||||
*
|
||||
* @param in the java.io.Reader to read input from.
|
||||
*/
|
||||
IJPerfLexer(java.io.Reader in) {
|
||||
this.zzReader = in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unpacks the compressed character translation table.
|
||||
*
|
||||
* @param packed the packed character translation table
|
||||
* @return the unpacked character translation table
|
||||
*/
|
||||
private static char [] zzUnpackCMap(String packed) {
|
||||
int size = 0;
|
||||
for (int i = 0, length = packed.length(); i < length; i += 2) {
|
||||
size += packed.charAt(i);
|
||||
}
|
||||
char[] map = new char[size];
|
||||
int i = 0; /* index in packed string */
|
||||
int j = 0; /* index in unpacked array */
|
||||
while (i < packed.length()) {
|
||||
int count = packed.charAt(i++);
|
||||
char value = packed.charAt(i++);
|
||||
do map[j++] = value; while (--count > 0);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public final int getTokenStart() {
|
||||
return zzStartRead;
|
||||
}
|
||||
|
||||
public final int getTokenEnd() {
|
||||
return getTokenStart() + yylength();
|
||||
}
|
||||
|
||||
public void reset(CharSequence buffer, int start, int end, int initialState) {
|
||||
zzBuffer = buffer;
|
||||
zzCurrentPos = zzMarkedPos = zzStartRead = start;
|
||||
zzAtEOF = false;
|
||||
zzAtBOL = true;
|
||||
zzEndRead = end;
|
||||
yybegin(initialState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refills the input buffer.
|
||||
*
|
||||
* @return {@code false}, iff there was new input.
|
||||
*
|
||||
* @exception java.io.IOException if any I/O-Error occurs
|
||||
*/
|
||||
private boolean zzRefill() throws java.io.IOException {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current lexical state.
|
||||
*/
|
||||
public final int yystate() {
|
||||
return zzLexicalState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enters a new lexical state
|
||||
*
|
||||
* @param newState the new lexical state
|
||||
*/
|
||||
public final void yybegin(int newState) {
|
||||
zzLexicalState = newState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the text matched by the current regular expression.
|
||||
*/
|
||||
public final CharSequence yytext() {
|
||||
return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the character at position {@code pos} from the
|
||||
* matched text.
|
||||
*
|
||||
* It is equivalent to yytext().charAt(pos), but faster
|
||||
*
|
||||
* @param pos the position of the character to fetch.
|
||||
* A value from 0 to yylength()-1.
|
||||
*
|
||||
* @return the character at position pos
|
||||
*/
|
||||
public final char yycharat(int pos) {
|
||||
return zzBuffer.charAt(zzStartRead+pos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the length of the matched text region.
|
||||
*/
|
||||
public final int yylength() {
|
||||
return zzMarkedPos-zzStartRead;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reports an error that occurred while scanning.
|
||||
*
|
||||
* In a wellformed scanner (no or only correct usage of
|
||||
* yypushback(int) and a match-all fallback rule) this method
|
||||
* will only be called with things that "Can't Possibly Happen".
|
||||
* If this method is called, something is seriously wrong
|
||||
* (e.g. a JFlex bug producing a faulty scanner etc.).
|
||||
*
|
||||
* Usual syntax/scanner level error handling should be done
|
||||
* in error fallback rules.
|
||||
*
|
||||
* @param errorCode the code of the errormessage to display
|
||||
*/
|
||||
private void zzScanError(int errorCode) {
|
||||
String message;
|
||||
try {
|
||||
message = ZZ_ERROR_MSG[errorCode];
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
|
||||
}
|
||||
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pushes the specified amount of characters back into the input stream.
|
||||
*
|
||||
* They will be read again by then next call of the scanning method
|
||||
*
|
||||
* @param number the number of characters to be read again.
|
||||
* This number must not be greater than yylength()!
|
||||
*/
|
||||
public void yypushback(int number) {
|
||||
if ( number > yylength() )
|
||||
zzScanError(ZZ_PUSHBACK_2BIG);
|
||||
|
||||
zzMarkedPos -= number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contains user EOF-code, which will be executed exactly once,
|
||||
* when the end of file is reached
|
||||
*/
|
||||
private void zzDoEOF() {
|
||||
if (!zzEOFDone) {
|
||||
zzEOFDone = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resumes scanning until the next regular expression is matched,
|
||||
* the end of input is encountered or an I/O-Error occurs.
|
||||
*
|
||||
* @return the next token
|
||||
* @exception java.io.IOException if any I/O-Error occurs
|
||||
*/
|
||||
public IElementType advance() throws java.io.IOException {
|
||||
int zzInput;
|
||||
int zzAction;
|
||||
|
||||
// cached fields:
|
||||
int zzCurrentPosL;
|
||||
int zzMarkedPosL;
|
||||
int zzEndReadL = zzEndRead;
|
||||
CharSequence zzBufferL = zzBuffer;
|
||||
|
||||
int [] zzTransL = ZZ_TRANS;
|
||||
int [] zzRowMapL = ZZ_ROWMAP;
|
||||
int [] zzAttrL = ZZ_ATTRIBUTE;
|
||||
|
||||
while (true) {
|
||||
zzMarkedPosL = zzMarkedPos;
|
||||
|
||||
zzAction = -1;
|
||||
|
||||
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
|
||||
|
||||
zzState = ZZ_LEXSTATE[zzLexicalState];
|
||||
|
||||
// set up zzAction for empty match case:
|
||||
int zzAttributes = zzAttrL[zzState];
|
||||
if ( (zzAttributes & 1) == 1 ) {
|
||||
zzAction = zzState;
|
||||
}
|
||||
|
||||
|
||||
zzForAction: {
|
||||
while (true) {
|
||||
|
||||
if (zzCurrentPosL < zzEndReadL) {
|
||||
zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/);
|
||||
zzCurrentPosL += Character.charCount(zzInput);
|
||||
}
|
||||
else if (zzAtEOF) {
|
||||
zzInput = YYEOF;
|
||||
break zzForAction;
|
||||
}
|
||||
else {
|
||||
// store back cached positions
|
||||
zzCurrentPos = zzCurrentPosL;
|
||||
zzMarkedPos = zzMarkedPosL;
|
||||
boolean eof = zzRefill();
|
||||
// get translated positions and possibly new buffer
|
||||
zzCurrentPosL = zzCurrentPos;
|
||||
zzMarkedPosL = zzMarkedPos;
|
||||
zzBufferL = zzBuffer;
|
||||
zzEndReadL = zzEndRead;
|
||||
if (eof) {
|
||||
zzInput = YYEOF;
|
||||
break zzForAction;
|
||||
}
|
||||
else {
|
||||
zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/);
|
||||
zzCurrentPosL += Character.charCount(zzInput);
|
||||
}
|
||||
}
|
||||
int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ];
|
||||
if (zzNext == -1) break zzForAction;
|
||||
zzState = zzNext;
|
||||
|
||||
zzAttributes = zzAttrL[zzState];
|
||||
if ( (zzAttributes & 1) == 1 ) {
|
||||
zzAction = zzState;
|
||||
zzMarkedPosL = zzCurrentPosL;
|
||||
if ( (zzAttributes & 8) == 8 ) break zzForAction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// store back cached position
|
||||
zzMarkedPos = zzMarkedPosL;
|
||||
|
||||
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
|
||||
zzAtEOF = true;
|
||||
zzDoEOF();
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
|
||||
case 1:
|
||||
{ yybegin(WAITING_INPUT); return IJPerfElementTypes.COMMAND;
|
||||
}
|
||||
// fall through
|
||||
case 13: break;
|
||||
case 2:
|
||||
{ yybegin(YYINITIAL); return TokenType.WHITE_SPACE;
|
||||
}
|
||||
// fall through
|
||||
case 14: break;
|
||||
case 3:
|
||||
{ return TokenType.BAD_CHARACTER;
|
||||
}
|
||||
// fall through
|
||||
case 15: break;
|
||||
case 4:
|
||||
{ yybegin(WAITING_LAST_OPTION); return IJPerfElementTypes.IDENTIFIER;
|
||||
}
|
||||
// fall through
|
||||
case 16: break;
|
||||
case 5:
|
||||
{ yybegin(WAITING_LAST_OPTION); return TokenType.WHITE_SPACE;
|
||||
}
|
||||
// fall through
|
||||
case 17: break;
|
||||
case 6:
|
||||
{ yybegin(WAITING_LAST_OPTION); return IJPerfElementTypes.FILE_PATH;
|
||||
}
|
||||
// fall through
|
||||
case 18: break;
|
||||
case 7:
|
||||
{ yybegin(WAITING_LAST_OPTION); return IJPerfElementTypes.NUMBER;
|
||||
}
|
||||
// fall through
|
||||
case 19: break;
|
||||
case 8:
|
||||
{ yybegin(YYINITIAL); return IJPerfElementTypes.TEXT;
|
||||
}
|
||||
// fall through
|
||||
case 20: break;
|
||||
case 9:
|
||||
{ yybegin(WAITING_LAST_OPTION); return IJPerfElementTypes.OPTIONS_SEPARATOR;
|
||||
}
|
||||
// fall through
|
||||
case 21: break;
|
||||
case 10:
|
||||
{ yybegin(WAITING_LAST_OPTION); return IJPerfElementTypes.ASSIGNMENT_OPERATOR;
|
||||
}
|
||||
// fall through
|
||||
case 22: break;
|
||||
case 11:
|
||||
{ yybegin(WAITING_TEXT); return IJPerfElementTypes.PIPE;
|
||||
}
|
||||
// fall through
|
||||
case 23: break;
|
||||
case 12:
|
||||
{ yybegin(YYINITIAL); return IJPerfElementTypes.COMMENT;
|
||||
}
|
||||
// fall through
|
||||
case 24: break;
|
||||
default:
|
||||
zzScanError(ZZ_NO_MATCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.parser;
|
||||
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.lang.PsiBuilder.Marker;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import static com.intellij.lang.parser.GeneratedParserUtilBase.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.lang.PsiParser;
|
||||
import com.intellij.lang.LightPsiParser;
|
||||
|
||||
@SuppressWarnings({"SimplifiableIfStatement", "UnusedAssignment"})
|
||||
public class IJPerfParser implements PsiParser, LightPsiParser {
|
||||
|
||||
public ASTNode parse(IElementType t, PsiBuilder b) {
|
||||
parseLight(t, b);
|
||||
return b.getTreeBuilt();
|
||||
}
|
||||
|
||||
public void parseLight(IElementType t, PsiBuilder b) {
|
||||
boolean r;
|
||||
b = adapt_builder_(t, b, this, null);
|
||||
Marker m = enter_section_(b, 0, _COLLAPSE_, null);
|
||||
r = parse_root_(t, b);
|
||||
exit_section_(b, 0, m, t, r, true, TRUE_CONDITION);
|
||||
}
|
||||
|
||||
protected boolean parse_root_(IElementType t, PsiBuilder b) {
|
||||
return parse_root_(t, b, 0);
|
||||
}
|
||||
|
||||
static boolean parse_root_(IElementType t, PsiBuilder b, int l) {
|
||||
return scriptFile(b, l + 1);
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// commandName optionList?
|
||||
public static boolean commandLine(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "commandLine")) return false;
|
||||
if (!nextTokenIs(b, COMMAND)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = commandName(b, l + 1);
|
||||
r = r && commandLine_1(b, l + 1);
|
||||
exit_section_(b, m, COMMAND_LINE, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// optionList?
|
||||
private static boolean commandLine_1(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "commandLine_1")) return false;
|
||||
optionList(b, l + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// COMMAND
|
||||
public static boolean commandName(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "commandName")) return false;
|
||||
if (!nextTokenIs(b, COMMAND)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = consumeToken(b, COMMAND);
|
||||
exit_section_(b, m, COMMAND_NAME, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// NUMBER PIPE TEXT
|
||||
public static boolean delayTypingOption(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "delayTypingOption")) return false;
|
||||
if (!nextTokenIs(b, NUMBER)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = consumeTokens(b, 0, NUMBER, PIPE, TEXT);
|
||||
exit_section_(b, m, DELAY_TYPING_OPTION, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// NUMBER OPTIONS_SEPARATOR NUMBER
|
||||
public static boolean gotoOption(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "gotoOption")) return false;
|
||||
if (!nextTokenIs(b, NUMBER)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = consumeTokens(b, 0, NUMBER, OPTIONS_SEPARATOR, NUMBER);
|
||||
exit_section_(b, m, GOTO_OPTION, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// simpleOption | gotoOption | delayTypingOption | FILE_PATH | NUMBER
|
||||
public static boolean option(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "option")) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b, l, _NONE_, OPTION, "<option>");
|
||||
r = simpleOption(b, l + 1);
|
||||
if (!r) r = gotoOption(b, l + 1);
|
||||
if (!r) r = delayTypingOption(b, l + 1);
|
||||
if (!r) r = consumeToken(b, FILE_PATH);
|
||||
if (!r) r = consumeToken(b, NUMBER);
|
||||
exit_section_(b, l, m, r, false, null);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// option (OPTIONS_SEPARATOR option)*
|
||||
public static boolean optionList(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "optionList")) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b, l, _NONE_, OPTION_LIST, "<option list>");
|
||||
r = option(b, l + 1);
|
||||
r = r && optionList_1(b, l + 1);
|
||||
exit_section_(b, l, m, r, false, null);
|
||||
return r;
|
||||
}
|
||||
|
||||
// (OPTIONS_SEPARATOR option)*
|
||||
private static boolean optionList_1(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "optionList_1")) return false;
|
||||
while (true) {
|
||||
int c = current_position_(b);
|
||||
if (!optionList_1_0(b, l + 1)) break;
|
||||
if (!empty_element_parsed_guard_(b, "optionList_1", c)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// OPTIONS_SEPARATOR option
|
||||
private static boolean optionList_1_0(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "optionList_1_0")) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = consumeToken(b, OPTIONS_SEPARATOR);
|
||||
r = r && option(b, l + 1);
|
||||
exit_section_(b, m, null, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// statement*
|
||||
static boolean scriptFile(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "scriptFile")) return false;
|
||||
while (true) {
|
||||
int c = current_position_(b);
|
||||
if (!statement(b, l + 1)) break;
|
||||
if (!empty_element_parsed_guard_(b, "scriptFile", c)) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// IDENTIFIER (ASSIGNMENT_OPERATOR (IDENTIFIER|NUMBER|FILE_PATH))?
|
||||
public static boolean simpleOption(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "simpleOption")) return false;
|
||||
if (!nextTokenIs(b, IDENTIFIER)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = consumeToken(b, IDENTIFIER);
|
||||
r = r && simpleOption_1(b, l + 1);
|
||||
exit_section_(b, m, SIMPLE_OPTION, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// (ASSIGNMENT_OPERATOR (IDENTIFIER|NUMBER|FILE_PATH))?
|
||||
private static boolean simpleOption_1(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "simpleOption_1")) return false;
|
||||
simpleOption_1_0(b, l + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ASSIGNMENT_OPERATOR (IDENTIFIER|NUMBER|FILE_PATH)
|
||||
private static boolean simpleOption_1_0(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "simpleOption_1_0")) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b);
|
||||
r = consumeToken(b, ASSIGNMENT_OPERATOR);
|
||||
r = r && simpleOption_1_0_1(b, l + 1);
|
||||
exit_section_(b, m, null, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// IDENTIFIER|NUMBER|FILE_PATH
|
||||
private static boolean simpleOption_1_0_1(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "simpleOption_1_0_1")) return false;
|
||||
boolean r;
|
||||
r = consumeToken(b, IDENTIFIER);
|
||||
if (!r) r = consumeToken(b, NUMBER);
|
||||
if (!r) r = consumeToken(b, FILE_PATH);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* ********************************************************** */
|
||||
// commandLine|COMMENT
|
||||
public static boolean statement(PsiBuilder b, int l) {
|
||||
if (!recursion_guard_(b, l, "statement")) return false;
|
||||
if (!nextTokenIs(b, "<statement>", COMMAND, COMMENT)) return false;
|
||||
boolean r;
|
||||
Marker m = enter_section_(b, l, _NONE_, STATEMENT, "<statement>");
|
||||
r = commandLine(b, l + 1);
|
||||
if (!r) r = consumeToken(b, COMMENT);
|
||||
exit_section_(b, l, m, r, false, null);
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfCommandLine extends PsiElement {
|
||||
|
||||
@NotNull
|
||||
IJPerfCommandName getCommandName();
|
||||
|
||||
@Nullable
|
||||
IJPerfOptionList getOptionList();
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
|
||||
public interface IJPerfCommandName extends PsiNameIdentifierOwner {
|
||||
|
||||
PsiElement setName(@NotNull String name);
|
||||
|
||||
String getName();
|
||||
|
||||
PsiElement getNameIdentifier();
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfDelayTypingOption extends PsiElement {
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.jetbrains.performancePlugin.lang.psi.impl.*;
|
||||
|
||||
public interface IJPerfElementTypes {
|
||||
|
||||
IElementType COMMAND_LINE = new IJPerfElementType("COMMAND_LINE");
|
||||
IElementType COMMAND_NAME = new IJPerfElementType("COMMAND_NAME");
|
||||
IElementType DELAY_TYPING_OPTION = new IJPerfElementType("DELAY_TYPING_OPTION");
|
||||
IElementType GOTO_OPTION = new IJPerfElementType("GOTO_OPTION");
|
||||
IElementType OPTION = new IJPerfElementType("OPTION");
|
||||
IElementType OPTION_LIST = new IJPerfElementType("OPTION_LIST");
|
||||
IElementType SIMPLE_OPTION = new IJPerfElementType("SIMPLE_OPTION");
|
||||
IElementType STATEMENT = new IJPerfElementType("STATEMENT");
|
||||
|
||||
IElementType ASSIGNMENT_OPERATOR = new IJPerfTokenType("ASSIGNMENT_OPERATOR");
|
||||
IElementType COMMAND = new IJPerfTokenType("COMMAND");
|
||||
IElementType COMMENT = new IJPerfTokenType("COMMENT");
|
||||
IElementType FILE_PATH = new IJPerfTokenType("FILE_PATH");
|
||||
IElementType IDENTIFIER = new IJPerfTokenType("IDENTIFIER");
|
||||
IElementType NUMBER = new IJPerfTokenType("NUMBER");
|
||||
IElementType OPTIONS_SEPARATOR = new IJPerfTokenType("OPTIONS_SEPARATOR");
|
||||
IElementType PIPE = new IJPerfTokenType("PIPE");
|
||||
IElementType TEXT = new IJPerfTokenType("TEXT");
|
||||
|
||||
class Factory {
|
||||
public static PsiElement createElement(ASTNode node) {
|
||||
IElementType type = node.getElementType();
|
||||
if (type == COMMAND_LINE) {
|
||||
return new IJPerfCommandLineImpl(node);
|
||||
}
|
||||
else if (type == COMMAND_NAME) {
|
||||
return new IJPerfCommandNameImpl(node);
|
||||
}
|
||||
else if (type == DELAY_TYPING_OPTION) {
|
||||
return new IJPerfDelayTypingOptionImpl(node);
|
||||
}
|
||||
else if (type == GOTO_OPTION) {
|
||||
return new IJPerfGotoOptionImpl(node);
|
||||
}
|
||||
else if (type == OPTION) {
|
||||
return new IJPerfOptionImpl(node);
|
||||
}
|
||||
else if (type == OPTION_LIST) {
|
||||
return new IJPerfOptionListImpl(node);
|
||||
}
|
||||
else if (type == SIMPLE_OPTION) {
|
||||
return new IJPerfSimpleOptionImpl(node);
|
||||
}
|
||||
else if (type == STATEMENT) {
|
||||
return new IJPerfStatementImpl(node);
|
||||
}
|
||||
throw new AssertionError("Unknown element type: " + type);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfGotoOption extends PsiElement {
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfOption extends PsiElement {
|
||||
|
||||
@Nullable
|
||||
IJPerfDelayTypingOption getDelayTypingOption();
|
||||
|
||||
@Nullable
|
||||
IJPerfGotoOption getGotoOption();
|
||||
|
||||
@Nullable
|
||||
IJPerfSimpleOption getSimpleOption();
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfOptionList extends PsiElement {
|
||||
|
||||
@NotNull
|
||||
List<IJPerfOption> getOptionList();
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfSimpleOption extends PsiElement {
|
||||
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
|
||||
public interface IJPerfStatement extends PsiElement {
|
||||
|
||||
@Nullable
|
||||
IJPerfCommandLine getCommandLine();
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi;
|
||||
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
|
||||
public class IJPerfVisitor extends PsiElementVisitor {
|
||||
|
||||
public void visitCommandLine(@NotNull IJPerfCommandLine o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitCommandName(@NotNull IJPerfCommandName o) {
|
||||
visitPsiNameIdentifierOwner(o);
|
||||
}
|
||||
|
||||
public void visitDelayTypingOption(@NotNull IJPerfDelayTypingOption o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitGotoOption(@NotNull IJPerfGotoOption o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitOption(@NotNull IJPerfOption o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitOptionList(@NotNull IJPerfOptionList o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitSimpleOption(@NotNull IJPerfSimpleOption o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitStatement(@NotNull IJPerfStatement o) {
|
||||
visitPsiElement(o);
|
||||
}
|
||||
|
||||
public void visitPsiNameIdentifierOwner(@NotNull PsiNameIdentifierOwner o) {
|
||||
visitElement(o);
|
||||
}
|
||||
|
||||
public void visitPsiElement(@NotNull PsiElement o) {
|
||||
visitElement(o);
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfCommandLineImpl extends ASTWrapperPsiElement implements IJPerfCommandLine {
|
||||
|
||||
public IJPerfCommandLineImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitCommandLine(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public IJPerfCommandName getCommandName() {
|
||||
return findNotNullChildByClass(IJPerfCommandName.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IJPerfOptionList getOptionList() {
|
||||
return findChildByClass(IJPerfOptionList.class);
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfCommandNameImpl extends ASTWrapperPsiElement implements IJPerfCommandName {
|
||||
|
||||
public IJPerfCommandNameImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitCommandName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NotNull String name) {
|
||||
return IJPerfPsiImplUtil.setName(this, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return IJPerfPsiImplUtil.getName(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getNameIdentifier() {
|
||||
return IJPerfPsiImplUtil.getNameIdentifier(this);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfDelayTypingOptionImpl extends ASTWrapperPsiElement implements IJPerfDelayTypingOption {
|
||||
|
||||
public IJPerfDelayTypingOptionImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitDelayTypingOption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfGotoOptionImpl extends ASTWrapperPsiElement implements IJPerfGotoOption {
|
||||
|
||||
public IJPerfGotoOptionImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitGotoOption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfOptionImpl extends ASTWrapperPsiElement implements IJPerfOption {
|
||||
|
||||
public IJPerfOptionImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitOption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IJPerfDelayTypingOption getDelayTypingOption() {
|
||||
return findChildByClass(IJPerfDelayTypingOption.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IJPerfGotoOption getGotoOption() {
|
||||
return findChildByClass(IJPerfGotoOption.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IJPerfSimpleOption getSimpleOption() {
|
||||
return findChildByClass(IJPerfSimpleOption.class);
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfOptionListImpl extends ASTWrapperPsiElement implements IJPerfOptionList {
|
||||
|
||||
public IJPerfOptionListImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitOptionList(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<IJPerfOption> getOptionList() {
|
||||
return PsiTreeUtil.getChildrenOfTypeAsList(this, IJPerfOption.class);
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfSimpleOptionImpl extends ASTWrapperPsiElement implements IJPerfSimpleOption {
|
||||
|
||||
public IJPerfSimpleOptionImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitSimpleOption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// This is a generated file. Not intended for manual editing.
|
||||
package com.jetbrains.performancePlugin.lang.psi.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.jetbrains.annotations.*;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import static com.jetbrains.performancePlugin.lang.psi.IJPerfElementTypes.*;
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.jetbrains.performancePlugin.lang.psi.*;
|
||||
|
||||
public class IJPerfStatementImpl extends ASTWrapperPsiElement implements IJPerfStatement {
|
||||
|
||||
public IJPerfStatementImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
public void accept(@NotNull IJPerfVisitor visitor) {
|
||||
visitor.visitStatement(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof IJPerfVisitor) accept((IJPerfVisitor)visitor);
|
||||
else super.accept(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IJPerfCommandLine getCommandLine() {
|
||||
return findChildByClass(IJPerfCommandLine.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-stdlib-jdk8" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.analysis" />
|
||||
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="cli-parser" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.diagnostic" />
|
||||
<orderEntry type="library" name="StreamEx" level="project" />
|
||||
<orderEntry type="library" name="jackson" level="project" />
|
||||
<orderEntry type="library" name="jackson-module-kotlin" level="project" />
|
||||
<orderEntry type="library" name="jackson-databind" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
<orderEntry type="module" module-name="intellij.platform.execution.impl" />
|
||||
<orderEntry type="module-library">
|
||||
<library name="github.oshi.core" type="repository">
|
||||
<properties maven-id="com.github.oshi:oshi-core:6.2.2">
|
||||
<exclude>
|
||||
<dependency maven-id="net.java.dev.jna:jna-platform" />
|
||||
<dependency maven-id="net.java.dev.jna:jna" />
|
||||
<dependency maven-id="org.slf4j:slf4j-api" />
|
||||
</exclude>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/oshi/oshi-core/6.2.2/oshi-core-6.2.2.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/github/oshi/oshi-core/6.2.2/oshi-core-6.2.2-sources.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="library" name="Guava" level="project" />
|
||||
<orderEntry type="library" name="opentelemetry" level="project" />
|
||||
<orderEntry type="library" name="kotlinx-coroutines-jdk8" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.diagnostic.telemetry" />
|
||||
<orderEntry type="module" module-name="intellij.platform.vcs.log.impl" />
|
||||
<orderEntry type="module" module-name="intellij.platform.vcs.log" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,81 @@
|
||||
<idea-plugin package="com.jetbrains.performancePlugin">
|
||||
<id>com.jetbrains.performancePlugin</id>
|
||||
<name>Performance Testing</name>
|
||||
<vendor>JetBrains</vendor>
|
||||
<category>Other Tools</category>
|
||||
<resource-bundle>messages.PerformanceTestingBundle</resource-bundle>
|
||||
|
||||
<description><![CDATA[
|
||||
Plugin for automated execution of test scripts, capturing performance snapshots
|
||||
and gathering performance statistics.
|
||||
]]></description>
|
||||
|
||||
<dependencies>
|
||||
<plugin id="com.intellij.modules.lang"/>
|
||||
</dependencies>
|
||||
|
||||
<actions>
|
||||
<group id="StartProfileGroup">
|
||||
<add-to-group group-id="HelpDiagnosticTools" anchor="last"/>
|
||||
</group>
|
||||
<group id="IndexingDiagnosticGroup">
|
||||
<action class="com.jetbrains.performancePlugin.actions.OpenIndexingDiagnosticsAction" id="performancePlugin.OpenIndexingDiagnosticsAction"/>
|
||||
<add-to-group group-id="HelpDiagnosticTools" anchor="after" relative-to-action="CollectTroubleshootingInformation"/>
|
||||
</group>
|
||||
<group id="DiagnosticGroup">
|
||||
<separator/>
|
||||
<action class="com.jetbrains.performancePlugin.actions.ExecuteScriptAction" id="performancePlugin.ExecuteScriptAction"/>
|
||||
<separator/>
|
||||
<add-to-group group-id="HelpDiagnosticTools" anchor="last"/>
|
||||
</group>
|
||||
</actions>
|
||||
|
||||
<extensionPoints>
|
||||
<extensionPoint interface="com.jetbrains.performancePlugin.CommandProvider" name="commandProvider" dynamic="true"/>
|
||||
<extensionPoint interface="com.jetbrains.performancePlugin.RunCallbackHandler" name="runCallbackHandler"/>
|
||||
<extensionPoint interface="com.jetbrains.performancePlugin.profilers.SnapshotOpener" name="snapshotOpener" dynamic="true"/>
|
||||
<extensionPoint interface="com.jetbrains.performancePlugin.profilers.Profiler" name="profiler" dynamic="true"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<troubleInfoCollector implementation="com.jetbrains.performancePlugin.PerformanceTroubleInfoCollector"/>
|
||||
<troubleInfoCollector implementation="com.jetbrains.performancePlugin.utils.HardwareCollector"/>
|
||||
|
||||
<fileType name="IntegrationPerformanceTest"
|
||||
implementationClass="com.jetbrains.performancePlugin.lang.IJPerfFileType"
|
||||
fieldName="INSTANCE" language="IntegrationPerformanceTest" extensions="ijperf"/>
|
||||
|
||||
<lang.parserDefinition language="IntegrationPerformanceTest"
|
||||
implementationClass="com.jetbrains.performancePlugin.lang.IJPerfParserDefinition"/>
|
||||
|
||||
<lang.syntaxHighlighterFactory language="IntegrationPerformanceTest"
|
||||
implementationClass="com.jetbrains.performancePlugin.lang.IJPerfSyntaxHighlighterFactory"/>
|
||||
|
||||
<completion.contributor language="IntegrationPerformanceTest"
|
||||
implementationClass="com.jetbrains.performancePlugin.lang.completion.IJPerfCompletionContributor"/>
|
||||
|
||||
<annotator language="IntegrationPerformanceTest" implementationClass="com.jetbrains.performancePlugin.lang.inspections.IJPerfStartStopProfileInspection"/>
|
||||
|
||||
<documentationProvider implementation="com.jetbrains.performancePlugin.lang.doc.IJPerfDocumentationProvider"/>
|
||||
|
||||
<startupActivity implementation="com.jetbrains.performancePlugin.ProjectLoaded"/>
|
||||
<postStartupActivity implementation="com.jetbrains.performancePlugin.PerformanceTestTotalTimeTimer" />
|
||||
<applicationInitializedListener implementation="com.jetbrains.performancePlugin.ProjectLoaded"/>
|
||||
|
||||
<notificationGroup id="PerformancePlugin" displayType="BALLOON" bundle="messages.PerformanceTestingBundle" key="notification.group.performance.plugin"/>
|
||||
<registryKey key="performance.plugin.playback.runner.useDirectActionCall" description="Setup PlaybackRunner to use direct action calls over key strokes for actions in Playback framework" defaultValue="false" restartRequired="false"/>
|
||||
</extensions>
|
||||
|
||||
<applicationListeners>
|
||||
<listener class="com.jetbrains.performancePlugin.ProjectLoaded$MyAppLifecycleListener" topic="com.intellij.ide.AppLifecycleListener"/>
|
||||
</applicationListeners>
|
||||
<projectListeners>
|
||||
<listener class="com.jetbrains.performancePlugin.ProjectIndexingComponent"
|
||||
topic="com.intellij.openapi.project.DumbService$DumbModeListener"/>
|
||||
</projectListeners>
|
||||
|
||||
<extensions defaultExtensionNs="com.jetbrains.performancePlugin">
|
||||
<commandProvider implementation="com.jetbrains.performancePlugin.BaseCommandProvider"/>
|
||||
<runCallbackHandler implementation="com.jetbrains.performancePlugin.BaseRunCallbackHandler"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<title>
|
||||
Command runs code inspection using custom tool
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Syntax: %InspectCodeEx [parameters]
|
||||
</p>
|
||||
<p>
|
||||
Example: %InspectCodeEx -directory app -toolShortName RubyResolve
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<title>Command to add file to project</title>
|
||||
<body>
|
||||
<p>
|
||||
Create file in project. File name and path to project get from parameters.
|
||||
</p>
|
||||
<p>
|
||||
Example: %addFile C:\Users\username\intellij, fileName.java
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<title>Command invokes alt+enter combination</title>
|
||||
<body>
|
||||
<p>
|
||||
Simulate invocation of alt+enter and pressing item in the list defined by parameter.
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %altEnter [parameters]
|
||||
</p>
|
||||
<p>
|
||||
Example: %altEnter Find cause
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<title>Command builds all modules in a project</title>
|
||||
<body>
|
||||
<p>
|
||||
builds all modules in a project. There are two modes: BUILD and REBUILD
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %buildProject [mode]
|
||||
</p>
|
||||
<p>
|
||||
Example: %buildProject REBUILD
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<title>Command checks whether an opened document in the editor has errors</title>
|
||||
<body>
|
||||
<p>
|
||||
Simulate analyzing of document on errors (red code). The command finds only ERROR severity
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %checkOnRedCode
|
||||
</p>
|
||||
<p>
|
||||
Example: %checkOnRedCode
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>Command invalidates indexes</title>
|
||||
<body>
|
||||
<p>
|
||||
Simulate invocation of 'Invalidate caches' action
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<title>Command compares stored indices with indices on the disk</title>
|
||||
<body>
|
||||
<p>
|
||||
Compares the stored indices with the last created indices, which are in the current moment on the disk.
|
||||
The folder with the stored indices should be defined by the parameter '-Dcompare.indices.command.stored.indexes.directory'.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<title>Command types text with some delay between typing</title>
|
||||
<body>
|
||||
<p>
|
||||
Text and delay are being set as parameters
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %delayType <delay in ms>|<Text to type>
|
||||
</p>
|
||||
<p>
|
||||
Example: %delayType 150|Sample text for typing scenario
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<title>Command to delete file from project</title>
|
||||
<body>
|
||||
<p>
|
||||
Delete file from project if file exists. File name and path to project get from parameters.
|
||||
</p>
|
||||
<p>
|
||||
Example: %deleteFile C:\Users\username\intellij, fileName.java
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<title>Command invokes simple completion</title>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<title>Command runs highlighting pass</title>
|
||||
<body>
|
||||
Runs all highlighting passes. Can't be invoked multiple times in a row since it drops caches before run.
|
||||
<p>
|
||||
Example: %doHighlighting
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>Command runs local inspection</title>
|
||||
<body>
|
||||
<p>
|
||||
Runs local inspection using <i>DaemonCodeAnalyzer</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>Command exits app</title>
|
||||
<body>
|
||||
<p>
|
||||
Closes IDE
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<title>Command to test how long does it take to open context menu in project view</title>
|
||||
<body>
|
||||
Command to test how long does it take to open context menu in project view.
|
||||
The popup won't be shown but all heavy methods that may cause context menu long load will be invoked
|
||||
<p>
|
||||
Example: %expandProjectMenu
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<title>
|
||||
Command looks for psi element usages
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Looks for and count psi usages of element under caret
|
||||
</p>
|
||||
<p>
|
||||
Example: %findUsages
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<title>
|
||||
Command switches to another branch
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Call from the project dir git checkout command in command line
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %gitCheckout [branch]
|
||||
</p>
|
||||
<p>
|
||||
Example: %gitCheckout master
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<title>
|
||||
Command puts caret to the line and column
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Puts the caret to the location defined by parameters
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %goto <line> <column>
|
||||
</p>
|
||||
<p>
|
||||
Example: %goto 25 17
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<title>
|
||||
Command runs 'Inspect code' action
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Run 'Inspect code' command in context defined by parameters
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %inspectCode [directory]
|
||||
</p>
|
||||
<p>
|
||||
Example: %inspectCode src
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>
|
||||
Command dumps memory
|
||||
</title>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<title>
|
||||
Command opens file
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Example: %openFile MyClass.php
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<html>
|
||||
<title>Command to open a new project</title>
|
||||
<body>
|
||||
To open a project in the current frame closing the current one:
|
||||
<p>
|
||||
Example: %openProject C:\Users\username\intellij
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
To open a project in a new frame and don't close the current one:
|
||||
<p>
|
||||
Example: %openProject C:\Users\username\intellij false
|
||||
</p>
|
||||
|
||||
If you do the following:
|
||||
%openProject /tmp/a false
|
||||
%openProject /tmp/b false
|
||||
%openProject /tmp/a false
|
||||
|
||||
In the end, the same project a will be active and there will be 2 window frames.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<title>
|
||||
Command simulates pressing a keyboard key
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Only defined set of key is supported for now: "ENTER", "BACKSPACE", "TAB" and "ESCAPE"
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %pressKey <KEY>
|
||||
</p>
|
||||
<p>
|
||||
Example: %pressKey ENTER
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<title>Command declares project used for test</title>
|
||||
<body>
|
||||
Name of project that is being used for test
|
||||
<p>
|
||||
Command must be followed by project name and optionally by project archive</b>.
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %%project <projetName> [projectArchive]
|
||||
</p>
|
||||
<p>
|
||||
Example: %%project mpdf mpdf-5.6.zip
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>
|
||||
Command reformats project
|
||||
</title>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<title>Command to reload project files from disk</title>
|
||||
<body>
|
||||
<p>
|
||||
Command to reload project files from disk.
|
||||
</p>
|
||||
<p>
|
||||
Example: %reloadFiles
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>
|
||||
|
||||
</title>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<title>
|
||||
Command runs specified configuration
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Command runs specified configuration if configuration is absent prints all available for the project.
|
||||
There are two modes: TILL_STARTED and TILL_TERMINATED
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %runConfiguration [mode] <configurationName>
|
||||
</p>
|
||||
<p>
|
||||
Example: %runConfiguration TILL_STARTED IDEA
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<html>
|
||||
<title>
|
||||
Command runs single inspection
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Runs single inspection by short name
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %runSingleInspection <name>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<title>Command calls search everywhere with the given text and tab</title>
|
||||
<body>
|
||||
<p>
|
||||
Simulate calling search everywhere action with a given text and specified tab.
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %searchEverywhere [tab]|[text]
|
||||
</p>
|
||||
<p>
|
||||
Example: %searchEverywhere symbol|EditorIm
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<title>Command to select file in project view</title>
|
||||
<body>
|
||||
Command to select file in project view.
|
||||
<p>
|
||||
Example: %selectFileInProjectView MyClass.php
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>
|
||||
|
||||
</title>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<title>Command starts async or yourkit profiler</title>
|
||||
<body>
|
||||
<p>
|
||||
Command starts async or yourkit profiler based on system property <i>integrationTests.profiler</i>.
|
||||
</p>
|
||||
<p>
|
||||
Command must be followed by activity name and optionally by parameters
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %startProfile <activityName> [parameters]
|
||||
</p>
|
||||
<p>
|
||||
Example: %startProfile magento_inspection event=alloc
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>
|
||||
|
||||
</title>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html>
|
||||
<title>Command stops profiler</title>
|
||||
<body>
|
||||
<p>
|
||||
Command stops async or yourkit profiler based on system property <i>integrationTests.profiler</i>.
|
||||
</p>
|
||||
<p>
|
||||
In case when yourkit profiler was used parameters are ignored
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %stopProfile [parameters]
|
||||
</p>
|
||||
<p>
|
||||
Example: %stopProfile collapsed,flamegraph,traces=5000
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>Command stores created indices</title>
|
||||
<body>
|
||||
<p>
|
||||
Stores created during indexing indices in the defined by the parameter '-Dstore.indices.command.stored.indexes.dump.directory' directory.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<title>
|
||||
Command takes screenshot
|
||||
</title>
|
||||
<body>
|
||||
<p>
|
||||
Takes JPG screenshot of current screen to specified file.
|
||||
</p>
|
||||
<p>
|
||||
Syntax: %takeScreenshot <fullPathToFile>
|
||||
</p>
|
||||
<p>
|
||||
Example: %takeScreenshot ./myScreenshot.jpg
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<title>
|
||||
|
||||
</title>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
profiling.compress.snapshot.progress=Compressing snapshot
|
||||
profiling.capture.snapshot.success=Captured snapshot ''{0}'' is placed in user home directory.
|
||||
profiling.capture.snapshot.error=Failed to capture snapshot: {0}
|
||||
profiling.capture.snapshot.action.showInFolder=Show in {0}
|
||||
profiling.capture.snapshot.action.open=Open
|
||||
|
||||
command.goto.finish=GoTo was executed
|
||||
command.inspection.extension=No files with extension:
|
||||
command.inspection.finish=Inspection was executed
|
||||
command.inspection.finish.result=with {0} found problems
|
||||
command.file.not.found=File not found: {0}
|
||||
command.file.opened=File opened successfully: {0}
|
||||
command.reformat.finish=Reformat was executed
|
||||
command.start.error=Start profile should contain key: %startProfile <key>
|
||||
command.build.finish=Build finished successfully
|
||||
command.build.finish.with.errors=Build finished with errors
|
||||
command.build.finish.with.compilation.errors=Build finished with compilation errors
|
||||
|
||||
startup.noscript=Script file {0} doesn''t exist.
|
||||
startup.silent=Performance Plugin is in silent mode
|
||||
startup.script.read.error=Script file can\'t be read.
|
||||
|
||||
callback.stop=Performance Plugin was stopped
|
||||
|
||||
summary.action=&Open Support Request
|
||||
summary.link=https://intellij-support.jetbrains.com/anonymous_requests/new
|
||||
summary.link.rider=https://rider-support.jetbrains.com/hc/en-us/requests/new
|
||||
|
||||
finish.path=Snapshot path is: {0}
|
||||
finish.title=Snapshot Was Captured
|
||||
finish.open=&Open Snapshot in {0}
|
||||
|
||||
delay.notification.title=Performance Plugin finished execution
|
||||
delay.notification.message=Total time: {0} ms \n Average delay: {1} ms Max delay: {2} ms
|
||||
|
||||
command.singleInspection.noinspection=Cannot run inspection, inspection doesn''t exists {0}
|
||||
|
||||
select.scenario=Please select &scenario:
|
||||
executor.title=Performance Issue Reporter
|
||||
execute.script.button=&Execute
|
||||
typing.scenario=Typing
|
||||
formatting.scenario=Formatting
|
||||
local.inspection.scenario=Local Inspection
|
||||
input.below.parameters.for.async.profiler=Input below parameters for async profiler
|
||||
|
||||
action.performancePlugin.ExecuteScriptAction.text=Execute Performance Script\u2026
|
||||
action.performancePlugin.ExecuteScriptAction.description=Execute performance test script
|
||||
action.performancePlugin.OpenIndexingDiagnosticsAction.text=Open Indexing Diagnostics
|
||||
action.performancePlugin.OpenIndexingDiagnosticsAction.description=Open Indexing Diagnostics for the current project
|
||||
|
||||
comparing.indexes=Comparing Indexes\u2026
|
||||
storing.indexes=Storing indexes\u2026
|
||||
flushing.indexes=Flushing indexes\u2026
|
||||
storing.indexes.copying=Copying current indexes\u2026
|
||||
checking.shared.indexes=Checking Shared Indexes\u2026
|
||||
checking.shared.indexes.collecting.shared.files=Collecting files available in shared indexes\u2026
|
||||
checking.shared.indexes.collecting.all.indexed.files=Collecting all indexed files\u2026
|
||||
compare.indexes.comparing.index=Comparing current and stored indexes of {0}\u2026
|
||||
compare.indexes.comparing.forward.index=Comparing forward index of the current and stored indexes of {0}\u2026
|
||||
compare.indexes.comparing.inverted.index=Comparing inverted index of the current and stored indexes of {0}\u2026
|
||||
compare.indexes.comparing.inverted.index.collecting.keys=Collecting keys of the inverted index\u2026
|
||||
compare.indexes.resolving.files=Resolving files for comparison\u2026
|
||||
compare.indexes.preparing.indexes=Preparing indexes\u2026
|
||||
button.text.cancel=Not Now
|
||||
|
||||
filetype.ijperformance.test.description=Script of integration performance test
|
||||
filetype.ijperformance.test.display.name=ijperf script
|
||||
|
||||
task.title.executing.performance.script=Executing performance script
|
||||
|
||||
dumping.project.files=Dumping Project Files\u2026
|
||||
comparing.project.files=Comparing Project Files\u2026
|
||||
comparing.project.files.for.0=Comparing Project Files for {0}\u2026
|
||||
|
||||
intention.add.stopcommand=Add `%stopProfile` command
|
||||
inspection.message.activity.started.but.never.closed.with.stopprofile=`{0}` activity started, but never closed with `%stopProfile`
|
||||
inspection.message.two.startprofile.commands.cant.follow.each.other=`%startProfile` commands can''t follow each other. Add `%stopProfile` before `{0}`
|
||||
notification.group.performance.plugin=IDE self-profiling
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.jetbrains.performancePlugin.commands.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class BaseCommandProvider implements CommandProvider {
|
||||
@Override
|
||||
public @NotNull Map<String, CreateCommand> getCommands() {
|
||||
return Map.<String, CreateCommand>ofEntries(
|
||||
Map.entry(RunConfigurationCommand.PREFIX, RunConfigurationCommand::new),
|
||||
Map.entry(TakeScreenshotCommand.PREFIX, TakeScreenshotCommand::new),
|
||||
Map.entry(OpenFileCommand.PREFIX, OpenFileCommand::new),
|
||||
Map.entry(StartProfileCommand.PREFIX, StartProfileCommand::new),
|
||||
Map.entry(StopProfileCommand.PREFIX, StopProfileCommand::new),
|
||||
Map.entry(InspectionCommand.PREFIX, InspectionCommand::new),
|
||||
Map.entry(InspectionCommandEx.PREFIX, InspectionCommandEx::new),
|
||||
Map.entry(ReformatCommand.PREFIX, ReformatCommand::new),
|
||||
Map.entry(GoToCommand.PREFIX, GoToCommand::new),
|
||||
Map.entry(DoLocalInspection.PREFIX, DoLocalInspection::new),
|
||||
Map.entry(CompletionCommand.PREFIX, CompletionCommand::new),
|
||||
Map.entry(DelayTypeCommand.PREFIX, DelayTypeCommand::new),
|
||||
Map.entry(ReplaceTextCommand.PREFIX, ReplaceTextCommand::new),
|
||||
Map.entry(ExitAppCommand.PREFIX, ExitAppCommand::new),
|
||||
Map.entry(ExitAppWithTimeoutCommand.PREFIX, ExitAppWithTimeoutCommand::new),
|
||||
Map.entry(OpenFileWithTerminateCommand.PREFIX, OpenFileWithTerminateCommand::new),
|
||||
Map.entry(WaitForSmartCommand.PREFIX, WaitForSmartCommand::new),
|
||||
Map.entry(WaitForVcsLogCommand.PREFIX, WaitForVcsLogCommand::new),
|
||||
Map.entry(WaitForAsyncRefreshCommand.PREFIX, WaitForAsyncRefreshCommand::new),
|
||||
Map.entry(SingleInspectionCommand.PREFIX, SingleInspectionCommand::new),
|
||||
Map.entry(StartPowerSave.PREFIX, StartPowerSave::new),
|
||||
Map.entry(StopPowerSave.PREFIX, StopPowerSave::new),
|
||||
Map.entry(MemoryDumpCommand.PREFIX, MemoryDumpCommand::new),
|
||||
Map.entry(CleanCaches.PREFIX, CleanCaches::new),
|
||||
Map.entry(FindUsagesCommand.PREFIX, FindUsagesCommand::new),
|
||||
Map.entry(EnterCommand.PREFIX, EnterCommand::new),
|
||||
Map.entry(ShowAltEnter.PREFIX, ShowAltEnter::new),
|
||||
Map.entry(SelectCommand.PREFIX, SelectCommand::new),
|
||||
Map.entry(CompareIndicesKt.PREFIX, CompareIndices::new),
|
||||
Map.entry(StoreIndices.PREFIX, StoreIndices::new),
|
||||
Map.entry(GitCheckoutCommand.PREFIX, GitCheckoutCommand::new),
|
||||
Map.entry(OpenProjectView.PREFIX, OpenProjectView::new),
|
||||
Map.entry(MoveDirectoryCommand.PREFIX, MoveDirectoryCommand::new),
|
||||
Map.entry(RunClassInPlugin.PREFIX, RunClassInPlugin::new),
|
||||
Map.entry(SetupProjectSdkCommand.PREFIX, SetupProjectSdkCommand::new),
|
||||
Map.entry(OpenProjectCommand.PREFIX, OpenProjectCommand::new),
|
||||
Map.entry(CodeAnalysisCommand.PREFIX, CodeAnalysisCommand::new),
|
||||
Map.entry(DumpProjectFiles.PREFIX, DumpProjectFiles::new),
|
||||
Map.entry(CompareProjectFiles.PREFIX, CompareProjectFiles::new),
|
||||
Map.entry(RecordCounterCollectorBaselinesCommand.PREFIX, RecordCounterCollectorBaselinesCommand::new),
|
||||
Map.entry(RecordStateCollectorsCommand.PREFIX, RecordStateCollectorsCommand::new),
|
||||
Map.entry(CreateAllServicesAndExtensionsCommand.PREFIX, CreateAllServicesAndExtensionsCommand::new),
|
||||
Map.entry(RecoveryActionCommand.PREFIX, RecoveryActionCommand::new),
|
||||
Map.entry(CorruptIndexesCommand.PREFIX, CorruptIndexesCommand::new),
|
||||
Map.entry(FlushIndexesCommand.PREFIX, FlushIndexesCommand::new),
|
||||
Map.entry(SearchEverywhereCommand.PREFIX, SearchEverywhereCommand::new),
|
||||
Map.entry(SelectFileInProjectViewCommand.PREFIX, SelectFileInProjectViewCommand::new),
|
||||
Map.entry(ExpandProjectMenuCommand.PREFIX, ExpandProjectMenuCommand::new),
|
||||
Map.entry(DoHighlighting.PREFIX, DoHighlighting::new),
|
||||
Map.entry(ReloadFilesCommand.PREFIX, ReloadFilesCommand::new),
|
||||
Map.entry(AddFileCommand.PREFIX, AddFileCommand::new),
|
||||
Map.entry(DeleteFileCommand.PREFIX, DeleteFileCommand::new),
|
||||
Map.entry(TestTipsAndFeaturesIntegrationCommand.PREFIX, TestTipsAndFeaturesIntegrationCommand::new),
|
||||
Map.entry(ExpandMainMenuCommand.PREFIX, ExpandMainMenuCommand::new),
|
||||
Map.entry(ExpandEditorMenuCommand.PREFIX, ExpandEditorMenuCommand::new),
|
||||
Map.entry(OpenRandomFileCommand.PREFIX, OpenRandomFileCommand::new)
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
|
||||
public class BaseRunCallbackHandler implements RunCallbackHandler {
|
||||
|
||||
@Override
|
||||
public void patchCommandCallback(Project project, ActionCallback callback) { }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.ui.playback.PlaybackRunner.StatusCallback;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public class CommandLogger implements StatusCallback {
|
||||
|
||||
@Override
|
||||
public void message(@Nullable PlaybackContext context, String text, Type type) {
|
||||
if (type == Type.error) {
|
||||
System.err.println(text);
|
||||
if (System.getProperty("testscript.filename") != null) {
|
||||
ApplicationManagerEx.getApplicationEx().exit(true, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
System.out.println(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface CommandProvider {
|
||||
ExtensionPointName<CommandProvider> EP_NAME = new ExtensionPointName<>("com.jetbrains.performancePlugin.commandProvider");
|
||||
|
||||
@NotNull Map<@NonNls String, CreateCommand> getCommands();
|
||||
|
||||
static @NotNull List<@NonNls String> getAllCommandNames() {
|
||||
return EP_NAME.getExtensionList().stream()
|
||||
.flatMap(e -> e.getCommands().keySet().stream()).toList();
|
||||
}
|
||||
|
||||
static @Nullable CreateCommand findCommandCreator(@NonNls @NotNull String commandName) {
|
||||
return EP_NAME.getExtensionList().stream()
|
||||
.map(provider -> provider.getCommands().get(commandName))
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.jetbrains.performancePlugin.ProjectLoaded.runScript;
|
||||
|
||||
public class CommandsRunner {
|
||||
|
||||
private static CommandsRunner myCommandsRunner;
|
||||
|
||||
private ActionCallback startActionCallback;
|
||||
|
||||
synchronized static CommandsRunner getInstance() {
|
||||
if (myCommandsRunner == null) {
|
||||
myCommandsRunner = new CommandsRunner();
|
||||
}
|
||||
return myCommandsRunner;
|
||||
}
|
||||
|
||||
//TODO: add methode with project in parameter? AT-114
|
||||
public static void doRunScript(@NotNull String text) {
|
||||
runScript(ProjectManager.getInstance().getOpenProjects()[0], text);
|
||||
}
|
||||
|
||||
public static void setStartActionCallback(ActionCallback actionCallback) {
|
||||
getInstance().startActionCallback = actionCallback;
|
||||
}
|
||||
|
||||
public static boolean areCommandsAfterStartFinished() {
|
||||
if (getInstance().startActionCallback == null) return false;
|
||||
return getInstance().startActionCallback.isDone();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.ui.playback.PlaybackCommand;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface CreateCommand {
|
||||
@NotNull
|
||||
PlaybackCommand invoke(@NotNull String command, int line);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
public interface OnEndListener<T> {
|
||||
|
||||
void onEnd(T t);
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.diagnostic.telemetry.IJTracer;
|
||||
import com.intellij.diagnostic.telemetry.TraceManager;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
|
||||
public class PerformanceTestSpan {
|
||||
public static final String SPAN_NAME = "performance_test";
|
||||
public final static IJTracer TRACER = TraceManager.INSTANCE.getTracer("performance-plugin");
|
||||
private static Span performanceTestSpan;
|
||||
private static Scope performanceScope;
|
||||
|
||||
static void startSpan() {
|
||||
performanceTestSpan = TRACER.spanBuilder(SPAN_NAME).setNoParent().startSpan();
|
||||
performanceScope = performanceTestSpan.makeCurrent();
|
||||
}
|
||||
|
||||
static void endSpan() {
|
||||
if (performanceScope != null) performanceScope.close();
|
||||
if (performanceTestSpan != null) performanceTestSpan.end();
|
||||
}
|
||||
|
||||
public static Context getContext(){
|
||||
if (performanceTestSpan != null) return Context.current().with(performanceTestSpan);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.ide.AppLifecycleListener;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class PerformanceTestTotalTimeTimer implements StartupActivity.DumbAware {
|
||||
public static final String TOTAL_TEST_TIMER_NAME = "test";
|
||||
|
||||
@Override
|
||||
public void runActivity(@NotNull Project project) {
|
||||
if (ProjectLoaded.TEST_SCRIPT_FILE_PATH != null) {
|
||||
Timer myTimer = new Timer();
|
||||
myTimer.start(TOTAL_TEST_TIMER_NAME, true);
|
||||
MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect();
|
||||
connection.subscribe(AppLifecycleListener.TOPIC, new AppLifecycleListener() {
|
||||
@Override
|
||||
public void appWillBeClosed(boolean isRestart) {
|
||||
myTimer.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.DynamicBundle;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class PerformanceTestingBundle extends DynamicBundle {
|
||||
@NonNls private static final String BUNDLE = "messages.PerformanceTestingBundle";
|
||||
private static final PerformanceTestingBundle INSTANCE = new PerformanceTestingBundle();
|
||||
|
||||
private PerformanceTestingBundle() { super(BUNDLE); }
|
||||
|
||||
@NotNull
|
||||
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
|
||||
return INSTANCE.getMessage(key, params);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
|
||||
return INSTANCE.getLazyMessage(key, params);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.troubleshooting.TroubleInfoCollector;
|
||||
import com.jetbrains.performancePlugin.utils.StatisticCollector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PerformanceTroubleInfoCollector implements TroubleInfoCollector {
|
||||
@NotNull
|
||||
@Override
|
||||
public String collectInfo(@NotNull Project project) {
|
||||
return "=====PERFORMANCE SUMMARY=====\n" + new StatisticCollector(project).collectMetrics(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Performance";
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.ide.plugins.CannotUnloadPluginException;
|
||||
import com.intellij.ide.plugins.DynamicPluginListener;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.openapi.extensions.PluginId;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.playback.PlaybackCommand;
|
||||
import com.intellij.openapi.ui.playback.PlaybackRunner;
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public final class PlaybackRunnerExtended extends PlaybackRunner {
|
||||
public static final String NOTIFICATION_GROUP = "PerformancePlugin";
|
||||
|
||||
private Project myProject;
|
||||
private boolean myStopped;
|
||||
private final DynamicPluginListener myDynamicPluginListener;
|
||||
|
||||
public PlaybackRunnerExtended(String script, StatusCallback callback, @NotNull Project project) {
|
||||
super(script, callback, Registry.is("performance.plugin.playback.runner.useDirectActionCall", false), false, true);
|
||||
setProject(project);
|
||||
myDynamicPluginListener = new DynamicPluginListener() {
|
||||
@Override
|
||||
public void checkUnloadPlugin(@NotNull IdeaPluginDescriptor pluginDescriptor) throws CannotUnloadPluginException {
|
||||
if (PluginId.getId("com.jetbrains.performancePlugin").equals(pluginDescriptor.getPluginId())) {
|
||||
throw new CannotUnloadPluginException("Cannot unload plugin during playback execution");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProject(@Nullable Project project) {
|
||||
myProject = project;
|
||||
|
||||
if (project != null && !project.isDefault()) {
|
||||
Disposer.register(project, () -> {
|
||||
if (project == myProject) {
|
||||
Disposer.dispose(myOnStop);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Project getProject() {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void subscribeListeners(MessageBusConnection connection) {
|
||||
super.subscribeListeners(connection);
|
||||
connection.subscribe(DynamicPluginListener.TOPIC, myDynamicPluginListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
myStopped = true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected PlaybackCommand createCommand(@NotNull String _command, int line, @NotNull File scriptDir) {
|
||||
String command = _command.replaceAll("[\r\n]+$", "");
|
||||
String[] cmdline = command.split("\\s+");
|
||||
PlaybackCommand playbackCommand = null;
|
||||
if (cmdline.length > 0) {
|
||||
String commandName = cmdline[0];
|
||||
CreateCommand createCommand = CommandProvider.findCommandCreator(commandName);
|
||||
if (createCommand != null) {
|
||||
playbackCommand = createCommand.invoke(command, line);
|
||||
if (playbackCommand instanceof AbstractCommand) {
|
||||
((AbstractCommand)playbackCommand).setScriptDir(scriptDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playbackCommand == null) {
|
||||
playbackCommand = super.createCommand(command, line, scriptDir);
|
||||
}
|
||||
return playbackCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionCallback run() {
|
||||
if (myStopped) {
|
||||
throw new IllegalStateException("PlaybackRunnerExtended can be run only once.");
|
||||
}
|
||||
ActionCallback callback = super.run();
|
||||
RunCallbackHandler.applyPatchesToCommandCallback(myProject, callback);
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.AlarmFactory;
|
||||
import com.jetbrains.performancePlugin.profilers.Profiler;
|
||||
import com.jetbrains.performancePlugin.profilers.ProfilersController;
|
||||
import com.jetbrains.performancePlugin.ui.FinishScriptDialog;
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class ProjectIndexingComponent implements DumbService.DumbModeListener {
|
||||
public static final String PROFILE_INDEXING_COMPONENT = "performancePlugin.isProfileIndexing";
|
||||
public static final String PROFILE_WITH_ASYNC = "performancePlugin.isProfileIndexingWithAsync";
|
||||
@NotNull private final Project project;
|
||||
private static final int TIMEOUT = 500;
|
||||
private final Alarm myAlarm = AlarmFactory.getInstance().create();
|
||||
|
||||
ProjectIndexingComponent(@NotNull Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteredDumbMode() {
|
||||
try {
|
||||
if (isProfilingEnabled()) {
|
||||
PropertiesComponent.getInstance(project).setValue(PROFILE_INDEXING_COMPONENT, false);
|
||||
PropertiesComponent.getInstance(project).setValue(PROFILE_WITH_ASYNC, false);
|
||||
Profiler.getCurrentProfilerHandler(project).startProfiling(project.getName(), new ArrayList<>());
|
||||
DumbService.getInstance(project).runReadActionInSmartMode(()->{
|
||||
runScriptAfterDumb(project);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
new ActionCallbackProfilerStopper().reject(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void runScriptAfterDumb(Project project) {
|
||||
DumbService.getInstance(project).smartInvokeLater(() -> myAlarm.addRequest(() -> {
|
||||
if (DumbService.isDumb(project)) {
|
||||
runScriptAfterDumb(project);
|
||||
}
|
||||
else {
|
||||
ProfilersController.getInstance();
|
||||
if (Profiler.isAnyProfilingStarted()) {
|
||||
try {
|
||||
ProfilersController.getInstance().getCurrentProfilerHandler().stopProfiling(new ArrayList<>());
|
||||
ProfilersController.getInstance().setStoppedByScript(true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
new ActionCallbackProfilerStopper().setRejected();
|
||||
}
|
||||
ApplicationManager.getApplication().invokeLater(() -> new FinishScriptDialog(project).show());
|
||||
}
|
||||
}
|
||||
}, TIMEOUT));
|
||||
}
|
||||
|
||||
private boolean isProfilingEnabled() {
|
||||
return PropertiesComponent.getInstance(project).getBoolean(PROFILE_INDEXING_COMPONENT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.diagnostic.AbstractMessage;
|
||||
import com.intellij.diagnostic.MessagePool;
|
||||
import com.intellij.diagnostic.ThreadDumper;
|
||||
import com.intellij.diagnostic.VMOptions;
|
||||
import com.intellij.diagnostic.startUpPerformanceReporter.StartUpPerformanceReporter;
|
||||
import com.intellij.ide.AppLifecycleListener;
|
||||
import com.intellij.ide.ApplicationInitializedListener;
|
||||
import com.intellij.ide.actions.RevealFileAction;
|
||||
import com.intellij.ide.lightEdit.LightEditService;
|
||||
import com.intellij.ide.lightEdit.LightEditorInfo;
|
||||
import com.intellij.ide.lightEdit.LightEditorListener;
|
||||
import com.intellij.idea.LoggerFactory;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.notification.Notifications;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.ExtensionNotApplicableException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.impl.CoreProgressManager;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.InitProjectActivityJavaShim;
|
||||
import com.intellij.openapi.ui.playback.PlaybackRunner;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.AlarmFactory;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.jetbrains.performancePlugin.commands.OpenProjectCommand;
|
||||
import com.jetbrains.performancePlugin.commands.TakeScreenshotCommand;
|
||||
import com.jetbrains.performancePlugin.profilers.ProfilersController;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@SuppressWarnings({"UseOfSystemOutOrSystemErr", "SpellCheckingInspection"})
|
||||
public final class ProjectLoaded extends InitProjectActivityJavaShim implements ApplicationInitializedListener {
|
||||
private static final Logger LOG = Logger.getInstance("PerformancePlugin");
|
||||
|
||||
private static final int TIMEOUT = 500;
|
||||
public static final String TEST_SCRIPT_FILE_PATH = System.getProperty("testscript.filename");
|
||||
|
||||
/**
|
||||
* If an IDE error occurs and this flag is true, a failure of a TeamCity test will be printed
|
||||
* to stdout using TeamCity Service Messages (see {@link #reportTeamCityFailedTestAndBuildProblem(String, String, String)}).
|
||||
* The name of the failed test will be inferred from the name of the script file
|
||||
* (its name without extension, see {@link #getTeamCityFailedTestName()}).
|
||||
*/
|
||||
private static final boolean MUST_REPORT_TEAMCITY_TEST_FAILURE_ON_IDE_ERROR = Boolean.parseBoolean(
|
||||
System.getProperty("testscript.must.report.teamcity.test.failure.on.error", "true")
|
||||
);
|
||||
|
||||
/**
|
||||
* If an IDE error occurs during test script execution, the IDE will exit.
|
||||
* This flag determines whether the status code of the exiting process will be 0 (if false) or 1 (if true).
|
||||
*/
|
||||
private static final boolean MUST_EXIT_PROCESS_WITH_NON_SUCCESS_CODE_ON_IDE_ERROR = Boolean.parseBoolean(
|
||||
System.getProperty("testscript.must.exist.process.with.non.success.code.on.ide.error", "false")
|
||||
);
|
||||
|
||||
private static final String INDEXING_PROFILER_PREFIX = "%%profileIndexing";
|
||||
private static ScheduledExecutorService screenshotExecutor;
|
||||
private final Alarm myAlarm = AlarmFactory.getInstance().create();
|
||||
|
||||
private static boolean ourScriptStarted;
|
||||
|
||||
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
|
||||
@Override
|
||||
public void runActivity(@NotNull Project project) {
|
||||
if (TEST_SCRIPT_FILE_PATH != null && !ourScriptStarted) {
|
||||
ourScriptStarted = true;
|
||||
if (System.getProperty("ide.performance.screenshot") != null) {
|
||||
registerScreenshotTaking(project, System.getProperty("ide.performance.screenshot"));
|
||||
}
|
||||
LOG.info("Start Execution");
|
||||
PerformanceTestSpan.startSpan();
|
||||
Pair<String, List<String>> profilerSettings = initializeProfilerSettingsForIndexing();
|
||||
if (profilerSettings != null) {
|
||||
try {
|
||||
ProfilersController.getInstance().getCurrentProfilerHandler()
|
||||
.startProfiling(profilerSettings.first, profilerSettings.second);
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.err.println("Start profile failed: " + e.getMessage());
|
||||
ApplicationManagerEx.getApplicationEx().exit(true, true);
|
||||
}
|
||||
}
|
||||
if (OpenProjectCommand.Companion.shouldOpenInSmartMode(project)) {
|
||||
runScriptAfterDumb(project);
|
||||
}
|
||||
else if (SystemProperties.getBooleanProperty("performance.execute.script.after.scanning", false)) {
|
||||
runScriptDuringIndexing(project);
|
||||
}
|
||||
else {
|
||||
runScriptFromFile(project);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
LOG.info(PerformanceTestingBundle.message("startup.silent"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerScreenshotTaking(@NotNull Project project, String fileName) {
|
||||
screenshotExecutor = ConcurrencyUtil.newSingleScheduledThreadExecutor("Performance plugin screenshoter");
|
||||
screenshotExecutor.scheduleWithFixedDelay(()-> {
|
||||
TakeScreenshotCommand.takeScreenshotOfFrame(project, fileName);
|
||||
}, 0, 1, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private static Pair<String, List<String>> initializeProfilerSettingsForIndexing() {
|
||||
try {
|
||||
List<String> lines = FileUtil.loadLines(getTestFile());
|
||||
for (String line : lines) {
|
||||
if (line.startsWith(INDEXING_PROFILER_PREFIX)) {
|
||||
String[] command = line.substring(INDEXING_PROFILER_PREFIX.length()).trim().split("\\s+", 2);
|
||||
String indexingActivity = command[0];
|
||||
List<String> profilingParameters = command.length > 1 ? Arrays.asList(command[1].trim().split(","))
|
||||
: new ArrayList<>();
|
||||
return new Pair<>(indexingActivity, profilingParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
System.err.println(PerformanceTestingBundle.message("startup.script.read.error"));
|
||||
ApplicationManagerEx.getApplicationEx().exit(true, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static File getTestFile() {
|
||||
File file = new File(TEST_SCRIPT_FILE_PATH);
|
||||
if (!file.isFile()) {
|
||||
System.err.println(PerformanceTestingBundle.message("startup.noscript", file.getAbsolutePath()));
|
||||
ApplicationManagerEx.getApplicationEx().exit(true, true);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
public static void reportErrorsFromMessagePool() {
|
||||
MessagePool messagePool = MessagePool.getInstance();
|
||||
List<AbstractMessage> ideErrors = messagePool.getFatalErrors(false, true);
|
||||
for (AbstractMessage message : ideErrors) {
|
||||
try {
|
||||
reportScriptError(message);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
finally {
|
||||
message.setRead(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String generifyErrorMessage(String originalMessage) {
|
||||
return originalMessage
|
||||
// text@3ba5aac, text => text<ID>, text
|
||||
.replaceAll("[$@#][A-Za-z0-9-_]+", "<ID>")
|
||||
|
||||
// java-design-patterns-master.db451f59 => java-design-patterns-master.<HASH>
|
||||
.replaceAll("[.]([A-Za-z]+[0-9]|[0-9]+[A-Za-z])[A-Za-z0-9]*", ".<HASH>")
|
||||
|
||||
// 0x01 => <HEX>
|
||||
.replaceAll("0x[0-9a-fA-F]+", "<HEX>")
|
||||
|
||||
// text1234text => text<NUM>text
|
||||
.replaceAll("[0-9]+", "<NUM>");
|
||||
}
|
||||
|
||||
private static void reportScriptError(@NotNull AbstractMessage errorMessage) throws IOException {
|
||||
Throwable throwable = errorMessage.getThrowable();
|
||||
|
||||
Throwable cause = throwable;
|
||||
String causeMessage = "";
|
||||
while (cause.getCause() != null) {
|
||||
cause = cause.getCause();
|
||||
causeMessage = cause.getMessage();
|
||||
}
|
||||
if (causeMessage == null || causeMessage.isEmpty()) {
|
||||
causeMessage = errorMessage.getMessage();
|
||||
if (causeMessage == null || causeMessage.isEmpty()) {
|
||||
String throwableMessage = getNonEmptyThrowableMessage(throwable);
|
||||
int index = throwableMessage.indexOf("\tat ");
|
||||
if (index != -1) {
|
||||
causeMessage = throwableMessage.substring(0, index);
|
||||
}
|
||||
else {
|
||||
causeMessage = throwableMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Path scriptErrorsDir = Paths.get(PathManager.getLogPath(), "script-errors");
|
||||
Files.createDirectories(scriptErrorsDir);
|
||||
|
||||
try (Stream<Path> stream = Files.walk(scriptErrorsDir)) {
|
||||
String finalCauseMessage = causeMessage;
|
||||
boolean isDuplicated = stream.filter(path -> path.getFileName().toString().equals("message.txt"))
|
||||
.anyMatch(path -> {
|
||||
try {
|
||||
return Files.readString(path).equals(finalCauseMessage);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
LOG.error(ex.getMessage());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (isDuplicated) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i < 1000; i++) {
|
||||
Path errorDir = scriptErrorsDir.resolve("error-" + i);
|
||||
if (Files.exists(errorDir)) {
|
||||
continue;
|
||||
}
|
||||
Files.createDirectories(errorDir);
|
||||
Files.writeString(errorDir.resolve("message.txt"), causeMessage);
|
||||
Files.writeString(errorDir.resolve("stacktrace.txt"), errorMessage.getThrowableText());
|
||||
|
||||
List<Attachment> attachments = errorMessage.getAllAttachments();
|
||||
for (int j = 0; j < attachments.size(); j++) {
|
||||
|
||||
Attachment attachment = attachments.get(j);
|
||||
writeAttachmentToErrorDir(attachment, errorDir.resolve(j + "-" + attachment.getName()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
LOG.error("Too many errors have been reported during script execution. See " + scriptErrorsDir);
|
||||
}
|
||||
|
||||
private static void writeAttachmentToErrorDir(Attachment attachment, Path path) {
|
||||
var executor = AppExecutorUtil.getAppScheduledExecutorService();
|
||||
var counter = new AtomicInteger(0);
|
||||
var isDone = new AtomicBoolean(false);
|
||||
|
||||
Path attachmentPath = Paths.get(attachment.getPath());
|
||||
try {
|
||||
Files.writeString(path, attachment.getDisplayText(), StandardOpenOption.APPEND, StandardOpenOption.CREATE);
|
||||
Files.writeString(path, System.lineSeparator(), StandardOpenOption.APPEND, StandardOpenOption.CREATE);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Failed to write attachment `display text`", e);
|
||||
}
|
||||
|
||||
var task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isDone.get()) return;
|
||||
|
||||
try (FileChannel channel = FileChannel.open(attachmentPath, StandardOpenOption.READ)) {
|
||||
channel.lock();
|
||||
|
||||
int bufferSize = 1024;
|
||||
if (bufferSize > channel.size()) {
|
||||
bufferSize = (int)channel.size();
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
|
||||
|
||||
try (var writer = Files.newByteChannel(path)) {
|
||||
while (channel.read(buffer) > 0) {
|
||||
writer.write(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
isDone.set(true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Failed to store attachment", e);
|
||||
}
|
||||
finally {
|
||||
if (counter.getAndIncrement() >= 5) {
|
||||
LOG.warn(String.format("Unable to store attachment %s %s to path %s",
|
||||
attachment.getName(), attachment.getPath(), path.toString()));
|
||||
isDone.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
executor.scheduleWithFixedDelay(task, 0, 200, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getNonEmptyThrowableMessage(@NotNull Throwable throwable) {
|
||||
if (throwable.getMessage() != null && !throwable.getMessage().isEmpty()) {
|
||||
return throwable.getMessage();
|
||||
}
|
||||
return throwable.getClass().getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getTeamCityFailedTestName() {
|
||||
return FileUtilRt.getNameWithoutExtension(getTestFile().getName());
|
||||
}
|
||||
|
||||
private static void reportTeamCityFailedTestAndBuildProblem(@NotNull String testName,
|
||||
@NotNull String failureMessage,
|
||||
@NotNull String failureDetails) {
|
||||
testName = generifyErrorMessage(testName);
|
||||
|
||||
System.out.printf("##teamcity[testFailed name='%s' message='%s' details='%s']\n",
|
||||
encodeStringForTC(testName),
|
||||
encodeStringForTC(failureMessage),
|
||||
encodeStringForTC(failureDetails));
|
||||
|
||||
System.out.printf("##teamcity[buildProblem description='%s' identity='%s'] ",
|
||||
encodeStringForTC(failureMessage),
|
||||
encodeStringForTC(testName));
|
||||
}
|
||||
|
||||
private static @NotNull String encodeStringForTC(@NotNull String line) {
|
||||
final int MAX_DESCRIPTION_LENGTH = 7_500;
|
||||
return line.substring(0, Math.min(MAX_DESCRIPTION_LENGTH, line.length())).
|
||||
replaceAll("\\|", "||").
|
||||
replaceAll("\\[", "|[").
|
||||
replaceAll("]", "|]").
|
||||
replaceAll("\n", "|n").
|
||||
replaceAll("'", "|'").
|
||||
replaceAll("\r", "|r");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentsInitialized() {
|
||||
if (ApplicationManagerEx.getApplicationEx().isLightEditMode()) {
|
||||
LightEditService.getInstance().getEditorManager().addListener(new LightEditorListener() {
|
||||
@Override
|
||||
public void afterSelect(@Nullable LightEditorInfo editorInfo) {
|
||||
StartUpPerformanceReporter.Companion.logStats("LightEditor");
|
||||
runActivity(Objects.requireNonNull(LightEditService.getInstance().getProject()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void runScriptAfterDumb(Project project) {
|
||||
DumbService.getInstance(project).smartInvokeLater(Context.current().wrap(() -> {
|
||||
myAlarm.addRequest(Context.current().wrap(() -> {
|
||||
if (DumbService.isDumb(project) || CoreProgressManager.getCurrentIndicators().size() != 0) {
|
||||
runScriptAfterDumb(project);
|
||||
}
|
||||
else {
|
||||
runScriptFromFile(project);
|
||||
}
|
||||
}), TIMEOUT);
|
||||
}));
|
||||
}
|
||||
|
||||
private void runScriptDuringIndexing(Project project) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(Context.current().wrap(() -> myAlarm.addRequest(Context.current().wrap(() -> {
|
||||
List<ProgressIndicator> indicators = CoreProgressManager.getCurrentIndicators();
|
||||
boolean indexingInProgress = false;
|
||||
for (ProgressIndicator indicator : indicators) {
|
||||
String indicatorText = indicator.getText();
|
||||
if (indicatorText != null && indicatorText.contains("Indexing")) {
|
||||
indexingInProgress = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (indexingInProgress) {
|
||||
runScriptFromFile(project);
|
||||
}
|
||||
else {
|
||||
runScriptDuringIndexing(project);
|
||||
}
|
||||
}), TIMEOUT)));
|
||||
}
|
||||
|
||||
public static void runScript(Project project, String script) {
|
||||
PlaybackRunner playback = new PlaybackRunnerExtended(script, new CommandLogger(), project);
|
||||
ActionCallback scriptCallback = playback.run();
|
||||
runScript(scriptCallback, project);
|
||||
}
|
||||
|
||||
private static void runScriptFromFile(Project project) {
|
||||
PlaybackRunner playback = new PlaybackRunnerExtended("%include " + getTestFile(), new CommandLogger(), project);
|
||||
playback.setScriptDir(getTestFile().getParentFile());
|
||||
ActionCallback scriptCallback = playback.run();
|
||||
CommandsRunner.setStartActionCallback(scriptCallback);
|
||||
runScript(scriptCallback, project);
|
||||
}
|
||||
|
||||
private static void runScript(ActionCallback scriptCallback, Project project) {
|
||||
scriptCallback
|
||||
.doWhenDone(() -> {
|
||||
LOG.info("Execution of the script has been finished successfully");
|
||||
})
|
||||
.doWhenRejected(errorMessage -> {
|
||||
String message = "IDE will be terminated because some errors are detected while running the startup script: " + errorMessage;
|
||||
if (MUST_REPORT_TEAMCITY_TEST_FAILURE_ON_IDE_ERROR) {
|
||||
String testName = getTeamCityFailedTestName();
|
||||
reportTeamCityFailedTestAndBuildProblem(testName, message, "");
|
||||
}
|
||||
|
||||
if (SystemProperties.getBooleanProperty("startup.performance.framework", false)) {
|
||||
storeFailureToFile(errorMessage);
|
||||
}
|
||||
|
||||
LOG.error(message);
|
||||
|
||||
String threadDump = "Thread dump before IDE termination:\n" + ThreadDumper.dumpThreadsToString();
|
||||
LOG.info(threadDump);
|
||||
|
||||
if (System.getProperty("ide.performance.screenshot.on.failure") != null) {
|
||||
TakeScreenshotCommand.takeScreenshotOfFrame(project, System.getProperty("ide.performance.screenshot.before.kill"));
|
||||
}
|
||||
|
||||
if (MUST_EXIT_PROCESS_WITH_NON_SUCCESS_CODE_ON_IDE_ERROR) {
|
||||
System.exit(1);
|
||||
}
|
||||
else {
|
||||
ApplicationManagerEx.getApplicationEx().exit(true, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void storeFailureToFile(String errorMessage) {
|
||||
try {
|
||||
Path logDir = Path.of(PathManager.getLogPath());
|
||||
String ideaLogContent = Files.readString(logDir.resolve(LoggerFactory.LOG_FILE_NAME));
|
||||
String substringBegin = ideaLogContent.substring(ideaLogContent.indexOf(errorMessage));
|
||||
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
|
||||
String date = timestamp.toString().substring(0, 10);
|
||||
int endIndex = substringBegin.indexOf(date);
|
||||
String errorMessageFromLog;
|
||||
if (endIndex != -1) {
|
||||
errorMessageFromLog = substringBegin.substring(0, endIndex);
|
||||
}
|
||||
else {
|
||||
errorMessageFromLog = substringBegin;
|
||||
}
|
||||
Path failureCause = logDir.resolve("failure_cause.txt");
|
||||
Files.writeString(failureCause, errorMessageFromLog);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOG.error(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static final class MyAppLifecycleListener implements AppLifecycleListener {
|
||||
MyAppLifecycleListener() {
|
||||
if (TEST_SCRIPT_FILE_PATH == null) {
|
||||
throw ExtensionNotApplicableException.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appFrameCreated(@NotNull List<String> commandLineArgs) {
|
||||
MessagePool messagePool = MessagePool.getInstance();
|
||||
LOG.info("Error watcher has started");
|
||||
messagePool.addListener(ProjectLoaded::reportErrorsFromMessagePool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appClosing() {
|
||||
var executor = screenshotExecutor;
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
PerformanceTestSpan.endSpan();
|
||||
reportErrorsFromMessagePool();
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
|
||||
public interface RunCallbackHandler {
|
||||
ExtensionPointName<RunCallbackHandler> EP_NAME = ExtensionPointName.create("com.jetbrains.performancePlugin.runCallbackHandler");
|
||||
|
||||
void patchCommandCallback(Project project, ActionCallback callback);
|
||||
|
||||
static void applyPatchesToCommandCallback(Project project, ActionCallback callback) {
|
||||
EP_NAME.getExtensionList().forEach(extension ->
|
||||
extension.patchCommandCallback(project, callback)
|
||||
);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.jetbrains.performancePlugin.utils.JvmRuntimeUtils;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SpanBuilderWithSystemInfoAttributes implements SpanBuilder {
|
||||
private final SpanBuilder spanBuilder;
|
||||
|
||||
public SpanBuilderWithSystemInfoAttributes(SpanBuilder spanBuilder) {
|
||||
this.spanBuilder = spanBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setParent(@NotNull Context context) {
|
||||
return spanBuilder.setParent(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setNoParent() {
|
||||
return spanBuilder.setNoParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder addLink(@NotNull SpanContext spanContext) {
|
||||
return spanBuilder.addLink(spanContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder addLink(@NotNull SpanContext spanContext, @NotNull Attributes attributes) {
|
||||
return spanBuilder.addLink(spanContext, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setAttribute(@NotNull String key, @NotNull String value) {
|
||||
return spanBuilder.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setAttribute(@NotNull String key, long value) {
|
||||
return spanBuilder.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setAttribute(@NotNull String key, double value) {
|
||||
return spanBuilder.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setAttribute(@NotNull String key, boolean value) {
|
||||
return spanBuilder.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SpanBuilder setAttribute(@NotNull AttributeKey<T> key, @NotNull T value) {
|
||||
return spanBuilder.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setSpanKind(@NotNull SpanKind spanKind) {
|
||||
return spanBuilder.setSpanKind(spanKind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanBuilder setStartTimestamp(long startTimestamp, @NotNull TimeUnit unit) {
|
||||
return spanBuilder.setStartTimestamp(startTimestamp, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span startSpan() {
|
||||
long jitTime = JvmRuntimeUtils.INSTANCE.getJitTime();
|
||||
long gcTime = JvmRuntimeUtils.INSTANCE.getGCTime();
|
||||
return new SpanWithOnEndListener(spanBuilder.startSpan(), span -> {
|
||||
span.setAttribute("jitTime", JvmRuntimeUtils.INSTANCE.getJitTime() - jitTime);
|
||||
span.setAttribute("gcTime", JvmRuntimeUtils.INSTANCE.getGCTime() - gcTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanContext;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class SpanWithOnEndListener implements Span {
|
||||
private final Span span;
|
||||
private final OnEndListener<? super Span> listener;
|
||||
|
||||
public SpanWithOnEndListener(Span span, OnEndListener<? super Span> listener) {
|
||||
this.span = span;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Span setAttribute(@NotNull AttributeKey<T> key, @NotNull T value) {
|
||||
return span.setAttribute(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span addEvent(@NotNull String name, @NotNull Attributes attributes) {
|
||||
return span.addEvent(name, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span addEvent(@NotNull String name, @NotNull Attributes attributes, long timestamp, @NotNull TimeUnit unit) {
|
||||
return span.addEvent(name, attributes, timestamp, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span setStatus(@NotNull StatusCode statusCode, @NotNull String description) {
|
||||
return span.setStatus(statusCode, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span recordException(@NotNull Throwable exception, @NotNull Attributes additionalAttributes) {
|
||||
return span.recordException(exception, additionalAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span updateName(@NotNull String name) {
|
||||
return span.updateName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
listener.onEnd(this);
|
||||
span.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(long timestamp, @NotNull TimeUnit unit) {
|
||||
listener.onEnd(this);
|
||||
span.end(timestamp, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanContext getSpanContext() {
|
||||
return span.getSpanContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecording() {
|
||||
return span.isRecording();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.jetbrains.performancePlugin;
|
||||
|
||||
import com.google.common.util.concurrent.AtomicDouble;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.sun.management.OperatingSystemMXBean;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import oshi.SystemInfo;
|
||||
import oshi.software.os.OSProcess;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.LongAccumulator;
|
||||
|
||||
public class Timer {
|
||||
public static final Timer instance = new Timer();
|
||||
|
||||
private String myActivityName = "default";
|
||||
private volatile long myStartTime;
|
||||
private volatile long myStopTime;
|
||||
private LongAccumulator myLongestDelay;
|
||||
private volatile double myHighestCPULoad;
|
||||
private volatile long myHighestRAMUsage;
|
||||
private final AtomicLong myTotalDelay = new AtomicLong();
|
||||
private final AtomicDouble myTotalCPULoad = new AtomicDouble();
|
||||
private final AtomicLong myTotalRAMUsage = new AtomicLong();
|
||||
private final AtomicLong myCounter = new AtomicLong();
|
||||
private final AtomicLong myHWCounter = new AtomicLong();
|
||||
private Span mySpan;
|
||||
private ScheduledExecutorService executor;
|
||||
private long totalTime;
|
||||
|
||||
public void start() {
|
||||
start("default", true);
|
||||
}
|
||||
|
||||
public void start(String activityName, boolean withSpan) {
|
||||
myActivityName = activityName;
|
||||
myStartTime = System.currentTimeMillis();
|
||||
myLongestDelay = new LongAccumulator(Math::max, 0);
|
||||
myHighestCPULoad = 0;
|
||||
myHighestRAMUsage = 0;
|
||||
myTotalRAMUsage.set(0);
|
||||
myTotalCPULoad.set(0);
|
||||
myTotalDelay.set(0);
|
||||
myCounter.set(0);
|
||||
myHWCounter.set(0);
|
||||
executor = ConcurrencyUtil.newSingleScheduledThreadExecutor("Performance plugin timer");
|
||||
|
||||
SystemInfo info = new SystemInfo();
|
||||
int processId = info.getOperatingSystem().getProcessId();
|
||||
OSProcess process = info.getOperatingSystem().getProcess(processId);
|
||||
executor.scheduleWithFixedDelay(() -> {
|
||||
long before = System.currentTimeMillis();
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
});
|
||||
long after = System.currentTimeMillis();
|
||||
long delay = after - before;
|
||||
myTotalDelay.addAndGet(delay);
|
||||
myCounter.incrementAndGet();
|
||||
myLongestDelay.accumulate(delay);
|
||||
}
|
||||
catch (InterruptedException | InvocationTargetException ignored) {
|
||||
}
|
||||
}, 0, 50, TimeUnit.MILLISECONDS);
|
||||
|
||||
OperatingSystemMXBean bean = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
|
||||
executor.scheduleWithFixedDelay(() -> {
|
||||
myHWCounter.incrementAndGet();
|
||||
double cpuLoad = bean.getProcessCpuLoad();
|
||||
if (cpuLoad > 0 && cpuLoad <= 1) {
|
||||
myTotalCPULoad.addAndGet(cpuLoad);
|
||||
if (myHighestCPULoad < cpuLoad) myHighestCPULoad = cpuLoad;
|
||||
}
|
||||
|
||||
long ramUsage = process.getResidentSetSize();
|
||||
myTotalRAMUsage.addAndGet(ramUsage);
|
||||
if (myHighestRAMUsage < ramUsage) myHighestRAMUsage = ramUsage;
|
||||
}, 0, 1, TimeUnit.SECONDS);
|
||||
|
||||
if(withSpan) {
|
||||
String spanName = activityName.equals("default") ? "timer" : activityName;
|
||||
// We need to set parent or null since it's part of general startup activity
|
||||
//noinspection DataFlowIssue Parent can be null.
|
||||
mySpan = PerformanceTestSpan.TRACER.spanBuilder(spanName).setParent(PerformanceTestSpan.getContext()).startSpan();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if(mySpan != null) {
|
||||
mySpan.setAttribute("max_awt_delay", getLongestDelay());
|
||||
mySpan.setAttribute("average_awt_delay", getAverageDelay());
|
||||
mySpan.end();
|
||||
}
|
||||
myStopTime = System.currentTimeMillis();
|
||||
totalTime = myStopTime - myStartTime;
|
||||
executor.shutdownNow();
|
||||
}
|
||||
|
||||
public void reportToTeamCity() {
|
||||
logValue(myActivityName, totalTime);
|
||||
logValue(myActivityName + " | Total Time Execution", totalTime);
|
||||
logValue(myActivityName + " | Responsiveness", getLongestDelay());
|
||||
logValue(myActivityName + " | Average Responsiveness", getAverageDelay());
|
||||
logValue(myActivityName + " | Average RAM Usage", getAverageRAMUsage());
|
||||
logValue(myActivityName + " | Average CPU Usage", getAverageCPULoad());
|
||||
logValue(myActivityName + " | Max RAM Usage", myHighestRAMUsage);
|
||||
logValue(myActivityName + " | Max CPU Usage", myHighestCPULoad);
|
||||
}
|
||||
|
||||
public long getLongestDelay() {
|
||||
return myLongestDelay.get();
|
||||
}
|
||||
|
||||
public long getTotalTime() {
|
||||
return totalTime;
|
||||
}
|
||||
|
||||
public long getStopTime() {
|
||||
return myStopTime;
|
||||
}
|
||||
|
||||
public double getAverageCPULoad() {
|
||||
long counterValue = myHWCounter.get();
|
||||
return counterValue != 0 ? myTotalCPULoad.get() / counterValue : 0.0;
|
||||
}
|
||||
|
||||
public int getAverageRAMUsage() {
|
||||
long counterValue = myHWCounter.get();
|
||||
return counterValue != 0 ? (int)(myTotalRAMUsage.get() / counterValue) : 0;
|
||||
}
|
||||
|
||||
public long getAverageDelay() {
|
||||
long counterValue = myCounter.get();
|
||||
return counterValue != 0 ? myTotalDelay.get() / counterValue : 0;
|
||||
}
|
||||
|
||||
public String getActivityName() {
|
||||
return myActivityName;
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return executor != null && !executor.isShutdown();
|
||||
}
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
private static void logValue(String key, long value) {
|
||||
if (value >= 0L) {
|
||||
System.out.printf("##teamcity[buildStatisticValue key='%s' value='%d']", key, value);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
private static void logValue(String key, double value) {
|
||||
if (value >= 0L) {
|
||||
System.out.printf("##teamcity[buildStatisticValue key='%s' value='%f']", key, value);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.jetbrains.performancePlugin.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.jetbrains.performancePlugin.ui.ExecuteScriptDialog;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class ExecuteScriptAction extends AnAction implements DumbAware {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ExecuteScriptDialog executeScriptDialog = new ExecuteScriptDialog(project);
|
||||
executeScriptDialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ActionUpdateThread getActionUpdateThread() {
|
||||
return ActionUpdateThread.BGT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
e.getPresentation().setEnabledAndVisible(e.getProject() != null);
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.jetbrains.performancePlugin.actions;
|
||||
|
||||
import com.intellij.ide.BrowserUtil;
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.indexing.diagnostic.IndexDiagnosticDumper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
final class OpenIndexingDiagnosticsAction extends AnAction implements DumbAware {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
Project project = e.getProject();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
Path reportHtml = IndexDiagnosticDumper.Companion.getProjectDiagnosticDirectory(project).resolve("report.html");
|
||||
BrowserUtil.browse(reportHtml);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ActionUpdateThread getActionUpdateThread() {
|
||||
return ActionUpdateThread.BGT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(@NotNull AnActionEvent e) {
|
||||
e.getPresentation().setEnabledAndVisible(e.getProject() != null);
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.application.WriteAction
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.util.ActionCallback
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.jetbrains.performancePlugin.utils.AbstractCallbackBasedCommand
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class AbstractFileCommand(text: String, line: Int) : AbstractCallbackBasedCommand(text, line, true) {
|
||||
protected fun execute(path: Path, callback: ActionCallback, f: (VirtualFile) -> Any) {
|
||||
val virtualFile = VirtualFileManager.getInstance().findFileByNioPath(path)
|
||||
if (virtualFile == null) {
|
||||
callback.reject("Directory or file by ${path} path from parameters was not found.")
|
||||
return
|
||||
}
|
||||
WriteAction.runAndWait<IOException> {
|
||||
f(virtualFile)
|
||||
}
|
||||
callback.setDone()
|
||||
}
|
||||
|
||||
protected fun isCommandParametersRight(input: ArrayList<String>): Boolean {
|
||||
return !(input.size < 2 || input.size > 2 || input[0] == "" || input[1] == "")
|
||||
}
|
||||
}
|
||||
|
||||
class AddFileCommand(text: String, line: Int) : AbstractFileCommand(text, line) {
|
||||
@Throws(Exception::class)
|
||||
override fun execute(callback: ActionCallback,
|
||||
context: PlaybackContext) {
|
||||
val input = extractCommandList(PREFIX, ",")
|
||||
if (!isCommandParametersRight(input)) {
|
||||
callback.reject("Command $PREFIX should have 2 non empty parameters (1 - path to directory, 2 - file name) with delimiter ','.")
|
||||
return
|
||||
}
|
||||
if (VirtualFileManager.getInstance().findFileByNioPath(Paths.get(input[0], input[1])) != null) {
|
||||
callback.reject("File by ${Paths.get(input[0], input[1])} path from parameters already exists.")
|
||||
return
|
||||
}
|
||||
LOG.info("Add file ${input[1]} ${input[0]}")
|
||||
super.execute(Paths.get(input[0]), callback) { virtualFile: VirtualFile -> virtualFile.createChildData(null, input[1]) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(AddFileCommand::class.java)
|
||||
const val PREFIX: @NonNls String = CMD_PREFIX + "addFile"
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.jetbrains.performancePlugin.commands;
|
||||
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.stubs.StubIndex;
|
||||
import com.intellij.psi.stubs.StubIndexEx;
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
|
||||
public class CleanCaches extends AbstractCommand {
|
||||
|
||||
public static final String PREFIX = CMD_PREFIX + "cleanCaches";
|
||||
|
||||
public CleanCaches(@NotNull String text, int line) {
|
||||
super(text, line);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull Promise<Object> _execute(@NotNull PlaybackContext context) {
|
||||
final ActionCallback actionCallback = new ActionCallbackProfilerStopper();
|
||||
WriteAction.runAndWait(() -> {
|
||||
Project project = context.getProject();
|
||||
PsiManager.getInstance(project).dropResolveCaches();
|
||||
PsiManager.getInstance(project).dropPsiCaches();
|
||||
((StubIndexEx)StubIndex.getInstance()).cleanCaches();
|
||||
((PersistentFSImpl)PersistentFS.getInstance()).incStructuralModificationCount();
|
||||
actionCallback.setDone();
|
||||
});
|
||||
return Promises.toPromise(actionCallback);
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.toPromise
|
||||
|
||||
|
||||
class CodeAnalysisCommand(text: String, line: Int) : AbstractCommand(text, line) {
|
||||
|
||||
companion object {
|
||||
const val PREFIX = CMD_PREFIX + "codeAnalysis"
|
||||
|
||||
private val LOG = Logger.getInstance(CodeAnalysisCommand::class.java)
|
||||
}
|
||||
|
||||
override fun _execute(context: PlaybackContext): Promise<Any?> {
|
||||
val actionCallback = ActionCallbackProfilerStopper()
|
||||
val project = context.project
|
||||
val commandArgs = extractCommandArgument(PREFIX).split(" ", limit = 2)
|
||||
val commandType = commandArgs[0]
|
||||
DumbService.getInstance(project).waitForSmartMode()
|
||||
val busConnection = project.messageBus.connect()
|
||||
|
||||
|
||||
busConnection.subscribe(DaemonCodeAnalyzer.DAEMON_EVENT_TOPIC, object : DaemonCodeAnalyzer.DaemonListener {
|
||||
override fun daemonFinished() {
|
||||
val myDaemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(project) as DaemonCodeAnalyzerImpl
|
||||
val editor = FileEditorManager.getInstance(project).selectedTextEditor
|
||||
require(editor != null)
|
||||
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.document)
|
||||
require(psiFile != null)
|
||||
if (myDaemonCodeAnalyzer.isErrorAnalyzingFinished(psiFile)) {
|
||||
busConnection.disconnect()
|
||||
when (commandType) {
|
||||
"CHECK_ON_RED_CODE" -> {
|
||||
val errorsOnHighlighting =
|
||||
DaemonCodeAnalyzerImpl.getHighlights(editor.document, HighlightSeverity.ERROR, project)
|
||||
if (errorsOnHighlighting.size > 0) {
|
||||
val errorMessages = StringBuilder("Analysis on red code detected some errors: " + errorsOnHighlighting.size)
|
||||
errorsOnHighlighting.forEach {
|
||||
errorMessages.append("\n").append(it.description)
|
||||
}
|
||||
actionCallback.reject(errorMessages.toString())
|
||||
}
|
||||
else {
|
||||
context.message("Analysis on red code performed successfully", line)
|
||||
actionCallback.setDone()
|
||||
}
|
||||
}
|
||||
"WARNINGS_ANALYSIS" -> {
|
||||
val warningsOnHighlighting = DaemonCodeAnalyzerImpl.getHighlights(editor.document, HighlightSeverity.WARNING, project)
|
||||
if (warningsOnHighlighting.size > 0) {
|
||||
val warnings = StringBuilder("Highlighting detected some warnings: " + warningsOnHighlighting.size)
|
||||
for (warning in warningsOnHighlighting) {
|
||||
warnings.append("\n").append(warning.description)
|
||||
}
|
||||
LOG.info(warnings.toString())
|
||||
val args = when (commandArgs.size > 1) {
|
||||
true -> commandArgs[1].split(",")
|
||||
false -> listOf()
|
||||
}
|
||||
if (args.isNotEmpty()) {
|
||||
args.forEach {
|
||||
var found = false
|
||||
for (warning in warningsOnHighlighting) {
|
||||
if (warning.description.contains(it)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
actionCallback.reject("Highlighting did not detect the warning $it")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!actionCallback.isRejected) {
|
||||
actionCallback.setDone()
|
||||
}
|
||||
}
|
||||
else {
|
||||
actionCallback.reject("Highlighting did not detect any warning")
|
||||
}
|
||||
}
|
||||
else -> error("Wrong type of code analysis: $commandType")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
DumbService.getInstance(project).smartInvokeLater {
|
||||
PsiManager.getInstance(project).dropPsiCaches()
|
||||
context.message("Code highlighting started", line)
|
||||
DaemonCodeAnalyzer.getInstance(project).restart()
|
||||
}
|
||||
return actionCallback.toPromise()
|
||||
}
|
||||
}
|
||||
|
||||
+686
@@ -0,0 +1,686 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.concurrency.JobLauncher
|
||||
import com.intellij.diagnostic.AttachmentFactory
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.diagnostic.Attachment
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.stubs.SerializationManagerImpl
|
||||
import com.intellij.psi.stubs.SerializedStubTree
|
||||
import com.intellij.psi.stubs.StubForwardIndexExternalizer
|
||||
import com.intellij.psi.stubs.StubUpdatingIndex
|
||||
import com.intellij.util.Processor
|
||||
import com.intellij.util.Processors
|
||||
import com.intellij.util.SystemProperties
|
||||
import com.intellij.util.indexing.*
|
||||
import com.intellij.util.indexing.diagnostic.dump.IndexContentDiagnostic
|
||||
import com.intellij.util.indexing.diagnostic.dump.IndexContentDiagnosticDumper
|
||||
import com.intellij.util.indexing.diagnostic.dump.paths.IndexedFilePath
|
||||
import com.intellij.util.indexing.diagnostic.dump.paths.IndexedFilePaths
|
||||
import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePaths
|
||||
import com.intellij.util.indexing.diagnostic.dump.paths.hasPresentablePathMatching
|
||||
import com.intellij.util.indexing.impl.storage.DefaultIndexStorageLayout
|
||||
import com.intellij.util.indexing.impl.storage.VfsAwareMapReduceIndex
|
||||
import com.intellij.util.indexing.impl.storage.VfsAwareMapReduceIndex.IndexerIdHolder
|
||||
import com.intellij.util.io.readText
|
||||
import com.intellij.util.progress.ConcurrentTasksProgressManager
|
||||
import com.jetbrains.performancePlugin.PerformanceTestingBundle
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper
|
||||
import com.jetbrains.performancePlugin.utils.errors.ErrorCollector
|
||||
import com.jetbrains.performancePlugin.utils.errors.ToDirectoryWritingErrorCollector
|
||||
import com.jetbrains.performancePlugin.utils.indexes.CurrentIndexedFileResolver
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.toPromise
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
internal const val PREFIX = AbstractCommand.CMD_PREFIX + "compareIndices"
|
||||
private val LOG = Logger.getInstance(CompareIndices::class.java)
|
||||
|
||||
/**
|
||||
* Fully compares two indexes built for the same project: the *stored* index and the *current* index,
|
||||
* which were built for the *old project* and the *new project*, respectively.
|
||||
* The old project is the same as the current project except that it might have been located in another directory.
|
||||
* All files' contents of the old project are equivalent to the current project.
|
||||
*
|
||||
* The stored index was dumped on disk with [StoreIndices] command.
|
||||
* The stored index may contain data irrelevant to the old project (that extra data may have belonged to an irrelevant project).
|
||||
* The [StoreIndices] command provides list of files that belonged to the old project (see [IndexContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds]).
|
||||
*
|
||||
* The current index is available in the currently running IDE via [FileBasedIndex] API.
|
||||
*
|
||||
* All data belonging to the old project's index must also be present in the current project's index:
|
||||
* all triplets `(file, key, value)` of the stored index, which belonged to the old project,
|
||||
* must be present in the current index and belong to the current project.
|
||||
*
|
||||
* The current index must not contain extra data for the current project files, as compared to the stored index.
|
||||
* But the current index is allowed to contain extra data for irrelevant files.
|
||||
*/
|
||||
internal class CompareIndices(text: String, line: Int) : AbstractCommand(text, line) {
|
||||
|
||||
private companion object {
|
||||
private const val LIMIT_OF_ERRORS_PER_COLLECTOR = 100
|
||||
}
|
||||
|
||||
override fun _execute(context: PlaybackContext): Promise<Any?> {
|
||||
val actionCallback = ActionCallbackProfilerStopper()
|
||||
val storedIndexDir = getStoredIndicesDirectory()
|
||||
|
||||
val project = context.project
|
||||
DumbService.getInstance(project).smartInvokeLater {
|
||||
object : Task.Modal(project, PerformanceTestingBundle.message("comparing.indexes"), false) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
if (!StubForwardIndexExternalizer.USE_SHAREABLE_STUBS) {
|
||||
actionCallback.reject(
|
||||
"Index comparison available only with with -D${StubForwardIndexExternalizer.USE_SHAREABLE_STUBS_PROP}=true")
|
||||
return
|
||||
}
|
||||
try {
|
||||
compareIndexes(storedIndexDir, indicator, project)
|
||||
actionCallback.setDone()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
actionCallback.reject(e.message)
|
||||
}
|
||||
}
|
||||
}.queue()
|
||||
}
|
||||
return actionCallback.toPromise()
|
||||
}
|
||||
|
||||
private fun getStoredIndicesDirectory(): Path {
|
||||
val property = System.getProperty("compare.indices.command.stored.indexes.directory")
|
||||
return checkNotNull(property) { "Path to stored indices is not specified" }.let { Paths.get(it) }
|
||||
}
|
||||
|
||||
private fun getFailureDiagnosticDirectory(): Path {
|
||||
val property = System.getProperty("compare.indices.command.failure.diagnostic.directory")
|
||||
if (property != null) {
|
||||
return Paths.get(property)
|
||||
}
|
||||
return FileUtil.createTempDirectory("compare-indices", "failure").toPath()
|
||||
}
|
||||
|
||||
/**
|
||||
* Patterns of files to be ignored from comparison.
|
||||
* Can be used to ignore transient files that change every time the project is open.
|
||||
*
|
||||
* Examples:
|
||||
* - `<project home>/some/tvolatile-file.txt`
|
||||
* - `<project home>/build/\*`
|
||||
* - `*.txt`
|
||||
*/
|
||||
private val ignoredFilesPatterns: List<String> by lazy {
|
||||
val listPath = System.getProperty("compare.indices.list.of.files.to.ignore.from.comparison") ?: return@lazy emptyList<String>()
|
||||
val patterns = Paths.get(listPath).readText().lines().map { it.trim() }.filterNot { it.isEmpty() }
|
||||
LOG.info("The following files will be ignored from indexes comparison:\n" + patterns.joinToString(separator = "\n"))
|
||||
patterns
|
||||
}
|
||||
|
||||
private val ignoredPatternsForReporting: List<Pair<String, String>> by lazy {
|
||||
val fileWithPatterns = System.getProperty("compare.indices.list.of.patterns.to.ignore.from.reporting") ?: return@lazy emptyList()
|
||||
val patternsList = mutableListOf<Pair<String, String>>()
|
||||
Paths.get(fileWithPatterns).readText().lines().map { it.trim() }.filterNot { it.isEmpty() }.forEach {
|
||||
val attrs = it.split(" ")
|
||||
patternsList.add(Pair(attrs[0], attrs[1]))
|
||||
}
|
||||
LOG.info("The following patterns will be ignored from failure reporting: ")
|
||||
patternsList.forEach{ LOG.info("Files .${it.first} in index ${it.second}") }
|
||||
patternsList
|
||||
}
|
||||
|
||||
/**
|
||||
* File types for which Stub tree is not built (but only the forward index).
|
||||
* For all such file types [com.intellij.psi.stubs.SerializedStubTree] has [com.intellij.psi.stubs.SerializedStubTree.NO_STUB]
|
||||
* as result of [com.intellij.psi.stubs.SerializedStubTree.getStub].
|
||||
*/
|
||||
private val fileTypesWithNoStubTree: Set<String> by lazy {
|
||||
System.getProperty("compare.indices.file.types.with.no.stub.tree", "").split(",").filterNot { it.isEmpty() }.toSet()
|
||||
}
|
||||
|
||||
private fun compareIndexes(storedIndexDir: Path, indicator: ProgressIndicator, project: Project) {
|
||||
val failureDiagnosticDirectory = getFailureDiagnosticDirectory()
|
||||
(FileBasedIndex.getInstance() as FileBasedIndexImpl).flushIndexes()
|
||||
|
||||
indicator.text = IndexingBundle.message("index.content.diagnostic.reading")
|
||||
val storedIndexContentDiagnostic = IndexContentDiagnosticDumper.readFrom(StoreIndices.getFileForDiagnostic(storedIndexDir))
|
||||
val storedIndexedFileResolver = StoredIndexedFileResolver(storedIndexContentDiagnostic)
|
||||
|
||||
val filesErrorCollector = ToDirectoryWritingErrorCollector(
|
||||
"resolve-files",
|
||||
failureDiagnosticDirectory.resolve("files-resolution-errors"),
|
||||
LIMIT_OF_ERRORS_PER_COLLECTOR
|
||||
)
|
||||
val resolvedFiles = resolveFiles(storedIndexedFileResolver, filesErrorCollector, indicator, project)
|
||||
if (filesErrorCollector.numberOfErrors > 0) {
|
||||
throw IllegalArgumentException("Some files cannot be resolved. See <failure-diagnostics-dir>/files-resolution-errors")
|
||||
}
|
||||
|
||||
LOG.info("Stored index directory contains: ${StoreIndices.dumpDirectory(storedIndexDir)}")
|
||||
|
||||
val idsToCompare = FileBasedIndexExtension.EXTENSION_POINT_NAME.extensionList.asSequence()
|
||||
.filter {
|
||||
it.dependsOnFileContent()
|
||||
// https://youtrack.jetbrains.com/issue/IDEA-255298
|
||||
&& it.name.name != "HashFragmentIndex"
|
||||
}
|
||||
.map { it.name }.toList()
|
||||
|
||||
LOG.info("Comparing indexes concurrently")
|
||||
val errorCollectors = idsToCompare.associateWith {
|
||||
ToDirectoryWritingErrorCollector(
|
||||
it.name,
|
||||
failureDiagnosticDirectory.resolve("errors-for-${it.name}"),
|
||||
LIMIT_OF_ERRORS_PER_COLLECTOR
|
||||
)
|
||||
}
|
||||
val finishedCounter = AtomicInteger()
|
||||
val comparisonTaskProgressManager = ConcurrentTasksProgressManager(indicator, idsToCompare.size)
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(idsToCompare, indicator, Processor { id ->
|
||||
val subIndicator = comparisonTaskProgressManager.createSubTaskIndicator(1)
|
||||
val (extension, disposable) = runReadAction { findFileBasedIndexExtension(id, storedIndexDir) }
|
||||
try {
|
||||
val errorCollector = errorCollectors.getValue(id)
|
||||
compareCurrentAndStoredIndexData(
|
||||
resolvedFiles,
|
||||
extension,
|
||||
storedIndexDir,
|
||||
subIndicator,
|
||||
errorCollector,
|
||||
project
|
||||
)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("Index comparison for ${id.name} has failed", e)
|
||||
}
|
||||
finally {
|
||||
runCatching { Disposer.dispose(disposable) }.onFailure { LOG.warn(it) }
|
||||
}
|
||||
LOG.info("Index comparison has finished for ${finishedCounter.incrementAndGet()} / ${idsToCompare.size}")
|
||||
true
|
||||
})
|
||||
|
||||
val failedIndexes = errorCollectors.filterValues { it.numberOfErrors > 0 }.map { it.key }
|
||||
if (failedIndexes.isNotEmpty()) {
|
||||
throw RuntimeException(
|
||||
"Comparison has failed for indexes [${failedIndexes.joinToString { it.name }}]. Details are saved to $failureDiagnosticDirectory")
|
||||
}
|
||||
LOG.info("Success. All indices are equal: ${idsToCompare.joinToString { it.name }}")
|
||||
}
|
||||
|
||||
private fun findFileBasedIndexExtension(id: ID<*, *>, storedIndexDir: Path): Pair<FileBasedIndexExtension<*, *>, Disposable> {
|
||||
return if (id.name == "Stubs") {
|
||||
val storedSerializationManager = SerializationManagerImpl(storedIndexDir.resolve("rep.names"), true)
|
||||
// Stored indexes must have been dumped with -D${com.intellij.psi.stubs.StubForwardIndexExternalizer.USE_SHAREABLE_STUBS_PROP}=true option specified
|
||||
// to make stubs be serialized in shareable form (when [ID.getUniqueId()] is not serialized but the [ID.getName()] ID name is).
|
||||
val nameStorageDump = storedSerializationManager.dumpNameStorage()
|
||||
LOG.info("stored stub element name storage $nameStorageDump")
|
||||
val stubForwardIndexExternalizer = StubForwardIndexExternalizer.createFileLocalExternalizer()
|
||||
val storedStubUpdatingIndex = StubUpdatingIndex(stubForwardIndexExternalizer,
|
||||
storedSerializationManager) as FileBasedIndexExtension<*, *>
|
||||
storedStubUpdatingIndex to storedSerializationManager
|
||||
}
|
||||
else {
|
||||
val usualExtension = FileBasedIndexExtension.EXTENSION_POINT_NAME.findFirstSafe { ex -> ex.name == id }!!
|
||||
val emptyDisposable = Disposer.newDisposable()
|
||||
usualExtension to emptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private data class FileDescriptor(
|
||||
val originalFilePath: IndexedFilePath,
|
||||
val currentFile: VirtualFile
|
||||
)
|
||||
|
||||
private fun resolveFiles(
|
||||
storedIndexedFileResolver: StoredIndexedFileResolver,
|
||||
errorCollector: ErrorCollector,
|
||||
indicator: ProgressIndicator,
|
||||
project: Project
|
||||
): List<FileDescriptor> {
|
||||
val allCurrentFiles = CurrentIndexedFileResolver.getAllToBeIndexedFilesInProject(project, indicator).values.flatMapTo(
|
||||
hashSetOf()) { it }
|
||||
indicator.text = PerformanceTestingBundle.message("compare.indexes.resolving.files")
|
||||
indicator.isIndeterminate = false
|
||||
val fileDescriptors = Collections.synchronizedList(arrayListOf<FileDescriptor>())
|
||||
val finished = AtomicInteger()
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(
|
||||
storedIndexedFileResolver.originalIndexedFiles.toList(),
|
||||
indicator,
|
||||
Processor { originalFilePath ->
|
||||
if (ignoredFilesPatterns.any { originalFilePath.portableFilePath.hasPresentablePathMatching(it) }) {
|
||||
return@Processor true
|
||||
}
|
||||
val currentFile: VirtualFile = errorCollector.runCatchingError {
|
||||
storedIndexedFileResolver.findFileInCurrentProject(originalFilePath, project)
|
||||
} ?: return@Processor true
|
||||
indicator.fraction = finished.incrementAndGet().toDouble() / storedIndexedFileResolver.originalIndexedFiles.size
|
||||
indicator.text2 = currentFile.url
|
||||
if (currentFile in allCurrentFiles) {
|
||||
fileDescriptors += FileDescriptor(originalFilePath, currentFile)
|
||||
}
|
||||
true
|
||||
}
|
||||
)
|
||||
return fileDescriptors
|
||||
}
|
||||
|
||||
private fun <K, V> compareCurrentAndStoredIndexData(
|
||||
resolvedFiles: List<FileDescriptor>,
|
||||
extension: FileBasedIndexExtension<K, V>,
|
||||
storedIndexDir: Path,
|
||||
indicator: ProgressIndicator,
|
||||
errorCollector: ErrorCollector,
|
||||
project: Project
|
||||
) {
|
||||
val indexId = extension.name
|
||||
indicator.text = PerformanceTestingBundle.message("compare.indexes.comparing.index", indexId.name)
|
||||
indicator.text2 = PerformanceTestingBundle.message("compare.indexes.preparing.indexes")
|
||||
indicator.isIndeterminate = true
|
||||
|
||||
val fileBasedIndex = FileBasedIndex.getInstance() as FileBasedIndexImpl
|
||||
runReadAction { fileBasedIndex.ensureUpToDate(indexId, project, GlobalSearchScope.allScope(project)) }
|
||||
val currentIndex = fileBasedIndex.getIndex(indexId)
|
||||
|
||||
val storedIndex = openStoredIndex(storedIndexDir, extension)
|
||||
try {
|
||||
indicator.isIndeterminate = false
|
||||
indicator.fraction = 0.0
|
||||
indicator.text2 = ""
|
||||
|
||||
check(extension.needsForwardIndexWhenSharing() || extension !is SingleEntryFileBasedIndexExtension) {
|
||||
"Index ${indexId.name} is SingleEntryFileBasedIndexExtension and does not need forward index. " +
|
||||
"This is a wrong index because SingleEntryFileBasedIndexExtension by its nature effectively consists of only the forward index."
|
||||
}
|
||||
|
||||
if (extension.needsForwardIndexWhenSharing()) {
|
||||
compareForwardIndexes(extension, resolvedFiles, currentIndex, storedIndex, errorCollector, indicator, project)
|
||||
}
|
||||
if (extension !is SingleEntryFileBasedIndexExtension) {
|
||||
compareInvertedIndexes(extension, resolvedFiles, storedIndex, currentIndex, errorCollector, indicator, project)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
storedIndex.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> compareForwardIndexes(
|
||||
extension: FileBasedIndexExtension<K, V>,
|
||||
resolvedFiles: List<FileDescriptor>,
|
||||
currentIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
storedIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
errorCollector: ErrorCollector,
|
||||
indicator: ProgressIndicator,
|
||||
project: Project
|
||||
) {
|
||||
val indexId = extension.name
|
||||
indicator.text = PerformanceTestingBundle.message("compare.indexes.comparing.forward.index", indexId.name)
|
||||
for ((finished, resolvedFile) in resolvedFiles.withIndex()) {
|
||||
indicator.fraction = finished.toDouble() / resolvedFiles.size
|
||||
indicator.text2 = resolvedFile.currentFile.url
|
||||
compareFileData(resolvedFile, currentIndex, storedIndex, extension, errorCollector, project)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> compareInvertedIndexes(
|
||||
extension: FileBasedIndexExtension<K, V>,
|
||||
resolvedFiles: List<FileDescriptor>,
|
||||
storedIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
currentIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
errorCollector: ErrorCollector,
|
||||
indicator: ProgressIndicator,
|
||||
project: Project
|
||||
) {
|
||||
val indexId = extension.name
|
||||
indicator.text = PerformanceTestingBundle.message("compare.indexes.comparing.inverted.index", indexId.name)
|
||||
indicator.text2 = PerformanceTestingBundle.message("compare.indexes.comparing.inverted.index.collecting.keys")
|
||||
indicator.isIndeterminate = true
|
||||
|
||||
val allStoredKeys = hashSetOf<K>()
|
||||
errorCollector.runCatchingError {
|
||||
runReadAction {
|
||||
storedIndex.processAllKeys(Processors.cancelableCollectProcessor(allStoredKeys), GlobalSearchScope.allScope(project), null)
|
||||
}
|
||||
}
|
||||
|
||||
val allCurrentKeys = hashSetOf<K>()
|
||||
errorCollector.runCatchingError {
|
||||
runReadAction {
|
||||
currentIndex.processAllKeys(Processors.cancelableCollectProcessor(allCurrentKeys), GlobalSearchScope.allScope(project), null)
|
||||
}
|
||||
}
|
||||
|
||||
checkNoKeysAreMissing(extension, storedIndex, resolvedFiles, allStoredKeys, allCurrentKeys, errorCollector, project)
|
||||
|
||||
val originalFileIdToFileDescriptor = resolvedFiles.associateBy { it.originalFilePath.originalFileSystemId }
|
||||
indicator.isIndeterminate = false
|
||||
indicator.fraction = 0.0
|
||||
for ((index, storedKey: K) in allStoredKeys.withIndex()) {
|
||||
indicator.fraction = index.toDouble() / allStoredKeys.size
|
||||
|
||||
val storedFileIdToValue = errorCollector.runCatchingError {
|
||||
runReadAction { storedIndex.getData(storedKey!!).toMap() }
|
||||
} ?: continue
|
||||
|
||||
val currentFileIdToValue = errorCollector.runCatchingError {
|
||||
runReadAction { currentIndex.getData(storedKey!!).toMap() }
|
||||
} ?: continue
|
||||
|
||||
for ((storedFileId, storedValue) in storedFileIdToValue) {
|
||||
val fileDescriptor = originalFileIdToFileDescriptor[storedFileId] ?: continue
|
||||
val currentFileId = FileBasedIndexImpl.getFileId(fileDescriptor.currentFile)
|
||||
val currentValue = currentFileIdToValue[currentFileId]
|
||||
if (IndexDataComparer.areValuesTheSame(extension, storedValue, currentValue)) {
|
||||
continue
|
||||
}
|
||||
if (ignoredPatternsForReporting.isEmpty() || !isKnownError(extension, fileDescriptor.originalFilePath.portableFilePath.presentablePath)) {
|
||||
errorCollector.runCatchingError {
|
||||
val message = buildFileDataMismatchMessage(
|
||||
"Values mismatch for key ${IndexDataPresenter.getPresentableIndexKey(storedKey)}",
|
||||
extension,
|
||||
fileDescriptor,
|
||||
project
|
||||
)
|
||||
val attachments = arrayListOf<Attachment>()
|
||||
attachments += Attachment("expected-value.txt", IndexDataPresenter.getPresentableIndexValue(storedValue))
|
||||
attachments += Attachment("actual-value.txt", IndexDataPresenter.getPresentableIndexValue(currentValue))
|
||||
attachments += createAttachmentsForActualFile(fileDescriptor)
|
||||
throw RuntimeExceptionWithAttachments(message, *attachments.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> checkNoKeysAreMissing(
|
||||
extension: FileBasedIndexExtension<K, V>,
|
||||
storedIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
resolvedFiles: List<FileDescriptor>,
|
||||
allStoredKeys: Set<K>,
|
||||
allCurrentKeys: Set<K>,
|
||||
errorCollector: ErrorCollector,
|
||||
project: Project
|
||||
) {
|
||||
val missingKeys = allStoredKeys - allCurrentKeys
|
||||
if (missingKeys.isNotEmpty()) {
|
||||
val originalFileIdToFileDescriptor = resolvedFiles.associateBy { it.originalFilePath.originalFileSystemId }
|
||||
for (missingKey in missingKeys) {
|
||||
val storedFileIdToValue = errorCollector.runCatchingError {
|
||||
runReadAction { storedIndex.getData(missingKey!!).toMap().filterKeys { it in originalFileIdToFileDescriptor } }
|
||||
} ?: continue
|
||||
|
||||
if (storedFileIdToValue.isEmpty()) {
|
||||
continue
|
||||
}
|
||||
|
||||
val fileDescriptor = originalFileIdToFileDescriptor[storedFileIdToValue.entries.iterator().next().key]
|
||||
|
||||
if (ignoredPatternsForReporting.isEmpty() || !isKnownError(extension, IndexDataPresenter.getPresentableIndexKey(missingKey))) {
|
||||
if (!isKnownError(extension, fileDescriptor!!)) {
|
||||
errorCollector.runCatchingError {
|
||||
val message = buildString {
|
||||
appendLine(
|
||||
"Index ${extension.name.name}: key is unknown to actual index data: ${
|
||||
IndexDataPresenter.getPresentableIndexKey(missingKey)
|
||||
}"
|
||||
)
|
||||
appendLine("The key must be present in the index for the following files: ")
|
||||
for ((storedFileId, _) in storedFileIdToValue) {
|
||||
val fileDescriptor = originalFileIdToFileDescriptor[storedFileId] ?: continue
|
||||
appendLine(
|
||||
buildFileDataMismatchMessage(
|
||||
"Key is not available in the actual index for the file",
|
||||
extension,
|
||||
fileDescriptor,
|
||||
project
|
||||
).withIndent(" ")
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
|
||||
val attachments = arrayListOf<Attachment>()
|
||||
attachments += Attachment("key.txt", IndexDataPresenter.getPresentableIndexKey(missingKey))
|
||||
var nextMismatchedFileId = 1
|
||||
for ((storedFileId, storedValue) in storedFileIdToValue) {
|
||||
val fileDescriptor = originalFileIdToFileDescriptor[storedFileId] ?: continue
|
||||
val pathPrefix = "file-and-value-${nextMismatchedFileId++}/"
|
||||
attachments += Attachment("${pathPrefix}value.txt", IndexDataPresenter.getPresentableIndexValue(storedValue))
|
||||
attachments += createAttachmentsForActualFile(fileDescriptor, pathPrefix = pathPrefix)
|
||||
}
|
||||
throw RuntimeExceptionWithAttachments(message, *attachments.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <V> ValueContainer<V>.toMap(): Map</* File ID */ Int, V?> {
|
||||
val map = hashMapOf<Int, V>()
|
||||
forEach { fileId, value ->
|
||||
if (value != null) {
|
||||
map[fileId] = value
|
||||
}
|
||||
true
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun <K, V> openStoredIndex(storedIndexDir: Path,
|
||||
extension: FileBasedIndexExtension<K, V>): VfsAwareMapReduceIndex<K, V, IndexerIdHolder> {
|
||||
val propertyName = "index_root_path"
|
||||
val oldValue = System.setProperty(propertyName, storedIndexDir.toAbsolutePath().toString())
|
||||
try {
|
||||
return VfsAwareMapReduceIndex<K, V, IndexerIdHolder>(extension, DefaultIndexStorageLayout.getLayout(extension, true), null)
|
||||
}
|
||||
finally {
|
||||
SystemProperties.setProperty(propertyName, oldValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <K, V> compareFileData(
|
||||
fileDescriptor: FileDescriptor,
|
||||
currentIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
storedIndex: UpdatableIndex<K, V, FileContent, *>,
|
||||
extension: FileBasedIndexExtension<K, V>,
|
||||
errorCollector: ErrorCollector,
|
||||
project: Project
|
||||
) {
|
||||
val storedData: Map<K, V> = errorCollector.runCatchingError {
|
||||
runReadAction { storedIndex.getIndexedFileData(fileDescriptor.originalFilePath.originalFileSystemId) }
|
||||
} ?: return
|
||||
|
||||
val currentData: Map<K, V> = errorCollector.runCatchingError {
|
||||
runReadAction { currentIndex.getIndexedFileData(FileBasedIndex.getFileId(fileDescriptor.currentFile)) }
|
||||
} ?: return
|
||||
|
||||
errorCollector.runCatchingError {
|
||||
assertForwardIndexDataAreTheSameForFile(
|
||||
fileDescriptor,
|
||||
extension,
|
||||
storedData,
|
||||
currentData,
|
||||
project
|
||||
)
|
||||
} ?: return
|
||||
}
|
||||
|
||||
private fun <K, V> assertForwardIndexDataAreTheSameForFile(
|
||||
fileDescriptor: FileDescriptor,
|
||||
extension: FileBasedIndexExtension<K, V>,
|
||||
expectedData0: Map<K, V>,
|
||||
actualData0: Map<K, V>,
|
||||
project: Project
|
||||
) {
|
||||
val expectedData: Map<K, V>
|
||||
val actualData: Map<K, V>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
if (extension.name == StubUpdatingIndex.INDEX_ID && fileDescriptor.originalFilePath.fileType in fileTypesWithNoStubTree) {
|
||||
expectedData = expectedData0.mapValues { (it.value as SerializedStubTree).withoutStub() } as Map<K, V>
|
||||
actualData = actualData0.mapValues { (it.value as SerializedStubTree).withoutStub() } as Map<K, V>
|
||||
}
|
||||
else {
|
||||
expectedData = expectedData0
|
||||
actualData = actualData0
|
||||
}
|
||||
|
||||
if (IndexDataComparer.areIndexedDataOfFileTheSame(extension, expectedData, actualData)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ignoredPatternsForReporting.isEmpty() || !isKnownError(extension, fileDescriptor.originalFilePath.portableFilePath.presentablePath)) {
|
||||
val message = buildFileDataMismatchMessage(
|
||||
"Indexed data maps do not match for ${fileDescriptor.originalFilePath.portableFilePath.presentablePath}",
|
||||
extension,
|
||||
fileDescriptor,
|
||||
project
|
||||
)
|
||||
|
||||
val expectedDataAttachment = if (expectedData.isEmpty()) {
|
||||
Attachment("expected-data-is-empty.txt", "")
|
||||
}
|
||||
else {
|
||||
Attachment("expected-data.txt", IndexDataPresenter.getPresentableKeyValueMap(expectedData))
|
||||
}
|
||||
val actualDataAttachment = if (actualData.isEmpty()) {
|
||||
Attachment("actual-data-is-empty.txt", "")
|
||||
}
|
||||
else {
|
||||
Attachment("actual-data.txt", IndexDataPresenter.getPresentableKeyValueMap(actualData))
|
||||
}
|
||||
val attachments = arrayListOf(expectedDataAttachment, actualDataAttachment)
|
||||
|
||||
attachments += createAttachmentsForActualFile(fileDescriptor)
|
||||
attachments += createAttachmentsForExpectedFile(fileDescriptor)
|
||||
|
||||
throw RuntimeExceptionWithAttachments(message, *attachments.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
private fun isKnownError(extension: FileBasedIndexExtension<*, *>,
|
||||
fileNameOrIndexData: String): Boolean {
|
||||
val fileExtension = File(fileNameOrIndexData).extension
|
||||
ignoredPatternsForReporting.forEach {
|
||||
if (it.first == extension.name.name && it.second == fileExtension) {
|
||||
LOG.info("Reporting index mismatch of $fileNameOrIndexData in ${extension.name.name} extension is ignored")
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isKnownError(extension: FileBasedIndexExtension<*, *>,
|
||||
fileDescriptor: FileDescriptor): Boolean {
|
||||
val fileExtension = fileDescriptor.currentFile.extension
|
||||
ignoredPatternsForReporting.forEach {
|
||||
if (it.first == extension.name.name && it.second == fileExtension) {
|
||||
LOG.info("Reporting index mismatch of $fileExtension in ${extension.name.name} extension is ignored")
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun createAttachmentsForActualFile(fileDescriptor: FileDescriptor, pathPrefix: String = ""): List<Attachment> =
|
||||
findFileAndAllRelevantSiblings(fileDescriptor.currentFile).map { file ->
|
||||
AttachmentFactory.createAttachment("${pathPrefix}actual-file/${file.name}", file)
|
||||
}
|
||||
|
||||
private fun createAttachmentsForExpectedFile(fileDescriptor: FileDescriptor, pathPrefix: String = ""): List<Attachment> {
|
||||
val expectedFile = VirtualFileManager.getInstance().refreshAndFindFileByUrl(fileDescriptor.originalFilePath.originalFileUrl)
|
||||
return if (expectedFile != null) {
|
||||
findFileAndAllRelevantSiblings(expectedFile).map { file ->
|
||||
AttachmentFactory.createAttachment("${pathPrefix}expected-file/${file.name}", file)
|
||||
}
|
||||
}
|
||||
else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun buildFileDataMismatchMessage(
|
||||
reason: String,
|
||||
extension: FileBasedIndexExtension<*, *>,
|
||||
fileDescriptor: FileDescriptor,
|
||||
project: Project
|
||||
) = buildString {
|
||||
appendLine("Index mismatch ${extension.name.name} for ${fileDescriptor.originalFilePath.portableFilePath.presentablePath}: $reason")
|
||||
appendLine("File of expected data:")
|
||||
appendLine(fileDescriptor.originalFilePath.toString().withIndent(" "))
|
||||
appendLine("File of actual data:")
|
||||
val actualIndexedFilePath = IndexedFilePaths.createIndexedFilePath(fileDescriptor.currentFile, project)
|
||||
appendLine(actualIndexedFilePath.toString().withIndent(" "))
|
||||
if (doesFileHaveProvidedIndex(fileDescriptor.currentFile, extension, project)) {
|
||||
appendLine(" Index ${extension.name.name} of this file is provided by index infrastructure extension")
|
||||
}
|
||||
}
|
||||
|
||||
private fun doesFileHaveProvidedIndex(file: VirtualFile, extension: FileBasedIndexExtension<*, *>, project: Project): Boolean {
|
||||
val fileId = FileBasedIndex.getFileId(file)
|
||||
return FileBasedIndexInfrastructureExtension.EP_NAME.extensionList.asSequence()
|
||||
.mapNotNull { it.createFileIndexingStatusProcessor(project) }
|
||||
.any { it.hasIndexForFile(file, fileId, extension) }
|
||||
}
|
||||
|
||||
private fun findFileAndAllRelevantSiblings(file: VirtualFile): List<VirtualFile> {
|
||||
if (file.extension != "class") {
|
||||
return listOf(file)
|
||||
}
|
||||
val fullClassName = file.nameWithoutExtension
|
||||
val baseClassName = fullClassName.substringBefore("$")
|
||||
val parent = file.parent ?: return listOf(file)
|
||||
parent.refresh(false, true)
|
||||
return parent.children.orEmpty().filter {
|
||||
it.extension == "class" && (it.nameWithoutExtension == fullClassName || it.nameWithoutExtension.startsWith("$baseClassName$"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.withIndent(indent: String) = lineSequence().joinToString(separator = "\n") { "$indent$it" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to indexed files that belonged to the old project.
|
||||
*/
|
||||
private class StoredIndexedFileResolver(storedIndexContentDiagnostic: IndexContentDiagnostic) {
|
||||
|
||||
private val originalFileIdToIndexedFilePath: Map<Int, IndexedFilePath> =
|
||||
storedIndexContentDiagnostic.allIndexedFilePaths.associateBy { it.originalFileSystemId }
|
||||
|
||||
val originalIndexedFiles: Set<IndexedFilePath> =
|
||||
storedIndexContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds.values.asSequence().flatten()
|
||||
.mapNotNullTo(hashSetOf()) { originalFileIdToIndexedFilePath[it] }
|
||||
|
||||
fun findFileInCurrentProject(filePath: IndexedFilePath, currentProject: Project): VirtualFile {
|
||||
val currentFile = PortableFilePaths.findFileByPath(filePath.portableFilePath, currentProject)
|
||||
checkNotNull(currentFile) {
|
||||
buildString {
|
||||
appendLine("File corresponding to the old file system is not found in the current file system.")
|
||||
appendLine("Portable file path = ${filePath.portableFilePath.presentablePath}")
|
||||
appendLine("Original file URL = ${filePath.originalFileUrl}")
|
||||
appendLine("Original file ID = ${filePath.originalFileSystemId}")
|
||||
}
|
||||
}
|
||||
return currentFile
|
||||
}
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
import com.intellij.util.indexing.FileBasedIndexImpl
|
||||
import com.intellij.util.indexing.diagnostic.dump.IndexContentDiagnosticDumper
|
||||
import com.intellij.util.indexing.diagnostic.dump.paths.IndexedFilePath
|
||||
import com.intellij.util.indexing.diagnostic.dump.paths.hasPresentablePathMatching
|
||||
import com.intellij.util.io.readText
|
||||
import com.jetbrains.performancePlugin.PerformanceTestingBundle
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper
|
||||
import com.jetbrains.performancePlugin.utils.errors.ErrorCollector
|
||||
import com.jetbrains.performancePlugin.utils.errors.ToDirectoryWritingErrorCollector
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.toPromise
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
|
||||
class CompareProjectFiles(text: String, line: Int) : AbstractCommand(text, line) {
|
||||
companion object {
|
||||
const val PREFIX = CMD_PREFIX + "compareProjectFiles"
|
||||
private val LOG = Logger.getInstance(CompareProjectFiles::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
val expectedPath = Paths.get(args[0])
|
||||
val actualPath = Paths.get(args[1])
|
||||
compareProjectFiles(expectedPath, actualPath, actualPath.parent, ProgressIndicatorBase())
|
||||
}
|
||||
|
||||
private fun compareProjectFiles(
|
||||
expectedDirectory: Path,
|
||||
actualDirectory: Path,
|
||||
failureDiagnosticDirectory: Path,
|
||||
indicator: ProgressIndicator
|
||||
) {
|
||||
val expectedContentDiagnostic = IndexContentDiagnosticDumper.readFrom(StoreIndices.getFileForDiagnostic(expectedDirectory))
|
||||
val actualContentDiagnostic = IndexContentDiagnosticDumper.readFrom(StoreIndices.getFileForDiagnostic(actualDirectory))
|
||||
|
||||
val (expectedIteratorNames, expectedUnstableNames) = expectedContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds.keys.partition { name ->
|
||||
meaningfulDebugNames.any { name.startsWith(it) }
|
||||
}
|
||||
val (actualIteratorNames, actualUnstableNames) = actualContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds.keys.partition { name ->
|
||||
meaningfulDebugNames.any { name.startsWith(it) }
|
||||
}
|
||||
|
||||
val errorCollectors = arrayListOf<ErrorCollector>()
|
||||
|
||||
val collector = ToDirectoryWritingErrorCollector(
|
||||
"set-of-iterators",
|
||||
failureDiagnosticDirectory.resolve("errors-for-set-of-iterators"),
|
||||
100
|
||||
)
|
||||
errorCollectors.add(collector)
|
||||
collector.runCatchingError { compareSetsOfIndexableIterators(expectedIteratorNames, actualIteratorNames) }
|
||||
|
||||
val expectedFileIdToFile = expectedContentDiagnostic.allIndexedFilePaths.associateBy { it.originalFileSystemId }
|
||||
val actualFileIdToFile = actualContentDiagnostic.allIndexedFilePaths.associateBy { it.originalFileSystemId }
|
||||
|
||||
for (iteratorName in expectedIteratorNames) {
|
||||
val errorCollector = ToDirectoryWritingErrorCollector(
|
||||
iteratorName,
|
||||
failureDiagnosticDirectory.resolve("errors-for-${FileUtil.sanitizeFileName(iteratorName)}"),
|
||||
100
|
||||
)
|
||||
errorCollectors += errorCollector
|
||||
|
||||
indicator.text = PerformanceTestingBundle.message("comparing.project.files.for.0", iteratorName)
|
||||
val expectedIds = expectedContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds[iteratorName].orEmpty()
|
||||
val actualIds = actualContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds[iteratorName].orEmpty()
|
||||
compareSetsOfFiles(expectedIds, expectedFileIdToFile, actualIds, actualFileIdToFile, errorCollector, iteratorName)
|
||||
}
|
||||
|
||||
// Compare files from iterators with unstable names.
|
||||
val expectedUnstableIds = expectedUnstableNames.flatMap {
|
||||
expectedContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds.getValue(it)
|
||||
}
|
||||
val actualUnstableIds = actualUnstableNames.flatMap {
|
||||
actualContentDiagnostic.projectIndexedFileProviderDebugNameToFileIds.getValue(it)
|
||||
}
|
||||
val unstableIteratorsName = "iterators-with-unstable-names"
|
||||
val errorCollector = ToDirectoryWritingErrorCollector(
|
||||
unstableIteratorsName,
|
||||
failureDiagnosticDirectory.resolve("errors-for-$unstableIteratorsName"),
|
||||
100
|
||||
)
|
||||
errorCollectors += errorCollector
|
||||
compareSetsOfFiles(expectedUnstableIds, expectedFileIdToFile, actualUnstableIds, actualFileIdToFile, errorCollector,
|
||||
unstableIteratorsName)
|
||||
|
||||
if (errorCollectors.any { it.numberOfErrors > 0 }) {
|
||||
throw RuntimeException("Some errors during files comparison have been collected. See details in $failureDiagnosticDirectory")
|
||||
}
|
||||
|
||||
LOG.info("Success. Project files are equal")
|
||||
}
|
||||
|
||||
// There may be iterators with non-presentable and unstable debug names, like "com.intellij.javaee.ExternalResourcesRootsProvider@eeabcf4"
|
||||
// For such iterators we compare files as a whole set.
|
||||
private val meaningfulDebugNames = listOf("Module", "Library", "SDK", "JDK", "Synthetic library", "Go SDK module")
|
||||
|
||||
private fun compareSetsOfFiles(
|
||||
expectedIds: Iterable<Int>,
|
||||
expectedFileIdToFile: Map<Int, IndexedFilePath>,
|
||||
actualIds: Iterable<Int>,
|
||||
actualFileIdToFile: Map<Int, IndexedFilePath>,
|
||||
errorCollector: ToDirectoryWritingErrorCollector,
|
||||
iteratorName: String
|
||||
) {
|
||||
val expectedFiles = expectedIds
|
||||
.mapNotNull { expectedFileIdToFile[it] }
|
||||
.associateBy { it.portableFilePath }
|
||||
.filterKeys { file -> ignoredFilesPatterns.none { file.hasPresentablePathMatching(it) } }
|
||||
|
||||
val actualFiles = actualIds
|
||||
.mapNotNull { actualFileIdToFile[it] }
|
||||
.associateBy { it.portableFilePath }
|
||||
.filterKeys { file -> ignoredFilesPatterns.none { file.hasPresentablePathMatching(it) } }
|
||||
|
||||
val missingFilePaths = expectedFiles.keys - actualFiles.keys
|
||||
val redundantFilePaths = actualFiles.keys - expectedFiles.keys
|
||||
if (missingFilePaths.isNotEmpty() || redundantFilePaths.isNotEmpty()) {
|
||||
errorCollector.addError(RuntimeException(
|
||||
buildString {
|
||||
appendLine("The sets of indexed files for $iteratorName do not match")
|
||||
appendLine(" Missing file paths:")
|
||||
missingFilePaths.forEach { appendLine(" ${it.presentablePath}") }
|
||||
appendLine(" Redundant file paths:")
|
||||
redundantFilePaths.forEach { appendLine(" ${it.presentablePath}") }
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
if (errorCollector.numberOfErrors > 0) return
|
||||
|
||||
for (filePath in expectedFiles.keys) {
|
||||
val expectedIndexedFile = expectedFiles.getValue(filePath)
|
||||
val actualIndexedFile = actualFiles.getValue(filePath)
|
||||
// Ignore "originalFileSystemId" field. It is expected that original VFS IDs mismatch between IDE restarts.
|
||||
val expectedData = expectedIndexedFile.copy(originalFileSystemId = 0, originalFileUrl = "")
|
||||
val actualData = actualIndexedFile.copy(originalFileSystemId = 0, originalFileUrl = "")
|
||||
if (expectedData != actualData) {
|
||||
errorCollector.addError(RuntimeException(
|
||||
buildString {
|
||||
appendLine("Indexed file ${filePath.presentablePath} data mismatch")
|
||||
appendLine(" Expected:")
|
||||
appendLine(expectedIndexedFile.toString().lineSequence().joinToString("\n") { " $it" })
|
||||
appendLine(" Actual:")
|
||||
appendLine(actualIndexedFile.toString().lineSequence().joinToString("\n") { " $it" })
|
||||
})
|
||||
)
|
||||
}
|
||||
if (errorCollector.numberOfErrors > 100) break
|
||||
}
|
||||
}
|
||||
|
||||
private fun compareSetsOfIndexableIterators(
|
||||
expectedIteratorNames: List<String>,
|
||||
actualIteratorNames: List<String>
|
||||
) {
|
||||
val missingIteratorNames = expectedIteratorNames - actualIteratorNames
|
||||
val redundantIteratorNames = actualIteratorNames - expectedIteratorNames
|
||||
if (missingIteratorNames.isNotEmpty() || redundantIteratorNames.isNotEmpty()) {
|
||||
error(buildString {
|
||||
appendLine("The sets of indexable file iterators do not match")
|
||||
appendLine(" Missing iterators: [" + missingIteratorNames.joinToString() + "]")
|
||||
appendLine(" Redundant iterators: [" + redundantIteratorNames.joinToString() + "]")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private val ignoredFilesPatterns: List<String> by lazy {
|
||||
val listPath = System.getProperty("compare.project.files.list.of.files.to.ignore.from.comparison") ?: return@lazy emptyList<String>()
|
||||
val patterns = Paths.get(listPath).readText().lines().map { it.trim() }.filterNot { it.isEmpty() }
|
||||
LOG.info("The following files will be ignored from project files comparison:\n" + patterns.joinToString(separator = "\n"))
|
||||
patterns
|
||||
}
|
||||
}
|
||||
|
||||
override fun _execute(context: PlaybackContext): Promise<Any?> {
|
||||
val actionCallback = ActionCallbackProfilerStopper()
|
||||
|
||||
val input = text.substring(PREFIX.length).trim()
|
||||
|
||||
val index = input.split(" ")
|
||||
val expectedDirectory = Paths.get(index[0])
|
||||
val actualDirectory = Paths.get(index[1])
|
||||
|
||||
val failureDiagnosticDirectory = getFailureDiagnosticDirectory()
|
||||
|
||||
val project = context.project
|
||||
DumbService.getInstance(project).smartInvokeLater {
|
||||
object : Task.Modal(project, PerformanceTestingBundle.message("comparing.project.files"), false) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
try {
|
||||
(FileBasedIndex.getInstance() as FileBasedIndexImpl).flushIndexes()
|
||||
compareProjectFiles(expectedDirectory, actualDirectory, failureDiagnosticDirectory, indicator)
|
||||
actionCallback.setDone()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
LOG.error(e)
|
||||
actionCallback.reject(e.message)
|
||||
}
|
||||
}
|
||||
}.queue()
|
||||
}
|
||||
return actionCallback.toPromise()
|
||||
}
|
||||
|
||||
private fun getFailureDiagnosticDirectory(): Path {
|
||||
val property = System.getProperty("compare.project.files.command.failure.diagnostic.directory")
|
||||
if (property != null) {
|
||||
return Paths.get(property)
|
||||
}
|
||||
return FileUtil.createTempDirectory("compare-project-files", "failure").toPath()
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.jetbrains.performancePlugin.commands;
|
||||
|
||||
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionPhase;
|
||||
import com.intellij.codeInsight.completion.CompletionPhaseListener;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.StatusCode;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
|
||||
|
||||
public class CompletionCommand extends PerformanceCommand {
|
||||
|
||||
public static final String NAME = "doComplete";
|
||||
public static final String PREFIX = CMD_PREFIX + NAME;
|
||||
public static final String SPAN_NAME = "completion";
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(CompletionCommand.class);
|
||||
|
||||
public CompletionCommand(@NotNull String text, int line) {
|
||||
super(text, line);
|
||||
}
|
||||
|
||||
private CompletionType getCompletionType() {
|
||||
String completionTypeArg = getArgument(0);
|
||||
|
||||
switch (completionTypeArg) {
|
||||
case "SMART" -> {
|
||||
LOG.info(String.format("'%s' was passed as argument, so SMART completion will be used", completionTypeArg));
|
||||
return CompletionType.SMART;
|
||||
}
|
||||
//case "BASIC",
|
||||
default -> {
|
||||
LOG.info(String.format("'%s' was passed as argument, so BASIC completion will be used", completionTypeArg));
|
||||
return CompletionType.BASIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getArgument(int index){
|
||||
String[] completionArgs = extractCommandArgument(PREFIX).trim().toUpperCase().split(" ");
|
||||
if(completionArgs.length > index) {
|
||||
return completionArgs[index];
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull Promise<Object> _execute(final @NotNull PlaybackContext context) {
|
||||
final ActionCallback actionCallback = new ActionCallbackProfilerStopper();
|
||||
Disposable listenerDisposable = Disposer.newDisposable();
|
||||
Ref<Span> span = new Ref<>();
|
||||
Ref<Scope> scope = new Ref<>();
|
||||
ApplicationManager.getApplication().getMessageBus().connect(listenerDisposable)
|
||||
.subscribe(CompletionPhaseListener.TOPIC, new CompletionPhaseListener() {
|
||||
@Override
|
||||
public void completionPhaseChanged(boolean isCompletionRunning) {
|
||||
if (!isCompletionRunning && !CompletionServiceImpl.isPhase(CompletionPhase.CommittingDocuments.class)) {
|
||||
if (CompletionServiceImpl.getCurrentCompletionProgressIndicator() == null) {
|
||||
String description =
|
||||
"CompletionServiceImpl.getCurrentCompletionProgressIndicator() is null on " + CompletionServiceImpl.getCompletionPhase();
|
||||
span.get().setStatus(StatusCode.ERROR, description);
|
||||
actionCallback.reject(description);
|
||||
}
|
||||
else {
|
||||
int size = CompletionServiceImpl.getCurrentCompletionProgressIndicator().getLookup().getItems().size();
|
||||
span.get().setAttribute("number", size);
|
||||
span.get().end();
|
||||
scope.get().close();
|
||||
context.message("Number of elements: " + size, getLine());
|
||||
actionCallback.setDone();
|
||||
}
|
||||
Disposer.dispose(listenerDisposable);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(Context.current().wrap(() -> {
|
||||
Project project = context.getProject();
|
||||
Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
span.set(startSpan(SPAN_NAME));
|
||||
scope.set(span.get().makeCurrent());
|
||||
new CodeCompletionHandlerBase(getCompletionType(), true, false, true).invokeCompletion(project, editor);
|
||||
}));
|
||||
return Promises.toPromise(actionCallback);
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.toPromise
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.random.Random
|
||||
|
||||
class CorruptIndexesCommand(text: String, line: Int) : AbstractCommand(text, line) {
|
||||
|
||||
companion object {
|
||||
const val PREFIX = CMD_PREFIX + "corruptIndex"
|
||||
private val LOG = Logger.getInstance(CorruptIndexesCommand::class.java)
|
||||
}
|
||||
|
||||
override fun _execute(context: PlaybackContext): Promise<Any?> {
|
||||
val actionCallback = ActionCallbackProfilerStopper()
|
||||
val args = text.split(" ".toRegex()).toTypedArray()
|
||||
val path = when (args.size) {
|
||||
2 -> Paths.get(args[1])
|
||||
3 -> Paths.get(args[1], args[2])
|
||||
else -> error("There are more than 2 args")
|
||||
}
|
||||
if (path.toFile().isFile) {
|
||||
LOG.info("Corrupting file: $path")
|
||||
corruptFile(path.toFile())
|
||||
}
|
||||
else {
|
||||
LOG.info("Corrupting files in dir: $path")
|
||||
corruptFilesInDir(path)
|
||||
}
|
||||
actionCallback.setDone()
|
||||
return actionCallback.toPromise()
|
||||
}
|
||||
|
||||
private fun corruptFilesInDir(dir: Path) {
|
||||
val listOfFiles = dir.toFile().walkTopDown().filter { it.isFile }
|
||||
listOfFiles.forEach {
|
||||
corruptFile(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun corruptFile(file: File) {
|
||||
LOG.info("Corrupting file: ${file.absolutePath}")
|
||||
file.writeBytes(Random(42).nextBytes(100 * 1024 * 1024))
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.jetbrains.performancePlugin.commands;
|
||||
|
||||
import com.intellij.ide.plugins.CreateAllServicesAndExtensionsActionKt;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.jetbrains.performancePlugin.utils.AbstractCallbackBasedCommand;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class CreateAllServicesAndExtensionsCommand extends AbstractCallbackBasedCommand {
|
||||
|
||||
public static final @NonNls String PREFIX = CMD_PREFIX + "CreateAllServicesAndExtensions";
|
||||
|
||||
public CreateAllServicesAndExtensionsCommand(@NotNull String text, int line) {
|
||||
super(text, line, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(@NotNull ActionCallback callback,
|
||||
@NotNull PlaybackContext context) {
|
||||
if (ApplicationManager.getApplication().isInternal()) {
|
||||
try {
|
||||
CreateAllServicesAndExtensionsActionKt.performAction();
|
||||
callback.setDone();
|
||||
}
|
||||
catch (Exception e) {
|
||||
callback.reject(e.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
callback.reject("Internal mode is required for the '" + CreateAllServicesAndExtensionsActionKt.ACTION_ID + "' command." +
|
||||
"Please see https://plugins.jetbrains.com/docs/intellij/enabling-internal.html");
|
||||
}
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package com.jetbrains.performancePlugin.commands;
|
||||
|
||||
import com.intellij.diagnostic.telemetry.TraceUtil;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.ui.TypingTarget;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.ui.playback.commands.KeyCodeTypeCommand;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
import com.jetbrains.performancePlugin.PerformanceTestSpan;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.concurrency.AsyncPromise;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DelayTypeCommand extends KeyCodeTypeCommand {
|
||||
|
||||
public static final String PREFIX = CMD_PREFIX + "delayType";
|
||||
public static final char END_CHAR = '#';
|
||||
public static final String SPAN_NAME = "typing";
|
||||
private final ScheduledExecutorService myExecutor = ConcurrencyUtil.newSingleScheduledThreadExecutor("Performance plugin delayed type");
|
||||
|
||||
public DelayTypeCommand(@NotNull String text, int line) {
|
||||
super(text, line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Promise<Object> _execute(final @NotNull PlaybackContext context) {
|
||||
final AsyncPromise<Object> result = new AsyncPromise<>();
|
||||
|
||||
String input = extractCommandArgument(PREFIX);
|
||||
String[] delayText = input.split("\\|");
|
||||
final long delay = Integer.parseInt(delayText[0]);
|
||||
final String text = delayText[1] + END_CHAR;
|
||||
ApplicationManager.getApplication().executeOnPooledThread(Context.current().wrap(() -> {
|
||||
TraceUtil.runWithSpanThrows(PerformanceTestSpan.TRACER, SPAN_NAME, span -> {
|
||||
span.addEvent("Finding typing target");
|
||||
try {
|
||||
Waiter.checkCondition(() -> findTarget(context) != null).await(1, TimeUnit.MINUTES);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
span.recordException(e);
|
||||
result.setError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
CountDownLatch allScheduled = new CountDownLatch(1);
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char currentChar = text.charAt(i);
|
||||
myExecutor.schedule(() -> ApplicationManager.getApplication().invokeAndWait(Context.current().wrap(
|
||||
() -> {
|
||||
if (currentChar == END_CHAR) {
|
||||
allScheduled.countDown();
|
||||
myExecutor.shutdown();
|
||||
}
|
||||
else {
|
||||
span.addEvent("Calling find target second time in DelayTypeCommand");
|
||||
TypingTarget typingTarget = findTarget(context);
|
||||
if (typingTarget != null) {
|
||||
span.addEvent("Typing " + currentChar);
|
||||
typingTarget.type(String.valueOf(currentChar));
|
||||
}
|
||||
}
|
||||
})), i * delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
try {
|
||||
allScheduled.await();
|
||||
myExecutor.awaitTermination(1, TimeUnit.MINUTES);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
result.setError(e);
|
||||
}
|
||||
});
|
||||
result.setResult(null);
|
||||
}));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.util.ActionCallback
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.nio.file.Paths
|
||||
|
||||
class DeleteFileCommand(text: String, line: Int) : AbstractFileCommand(text, line) {
|
||||
@Throws(Exception::class)
|
||||
override fun execute(callback: ActionCallback,
|
||||
context: PlaybackContext) {
|
||||
val input = extractCommandList(PREFIX, ",")
|
||||
if (!isCommandParametersRight(input)) {
|
||||
callback.reject("Command ${PREFIX} should have 2 non empty parameters (1 - path to directory, 2 - file name) with delimiter ','.")
|
||||
return
|
||||
}
|
||||
LOG.info("Delete file " + input[1] + " " + input[0])
|
||||
super.execute(Paths.get(input[0], input[1]), callback) { virtualFile: VirtualFile -> virtualFile.delete(null) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(DeleteFileCommand::class.java)
|
||||
const val PREFIX: @NonNls String = CMD_PREFIX + "deleteFile"
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.jetbrains.performancePlugin.commands;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.intellij.codeInsight.daemon.impl.DefaultHighlightVisitorBasedInspection;
|
||||
import com.intellij.diagnostic.telemetry.TraceUtil;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||
import com.jetbrains.performancePlugin.PerformanceTestSpan;
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper;
|
||||
import io.opentelemetry.context.Context;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.intellij.psi.PsiManager.getInstance;
|
||||
|
||||
public final class DoHighlighting extends PerformanceCommand {
|
||||
public static final String NAME = "doHighlight";
|
||||
public static final String PREFIX = CMD_PREFIX + NAME;
|
||||
|
||||
public static final String SPAN_NAME = "highlighting";
|
||||
|
||||
public DoHighlighting(@NotNull String text, int line) {
|
||||
super(text, line);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Promise<Object> _execute(@NotNull PlaybackContext context) {
|
||||
ActionCallback actionCallback = new ActionCallbackProfilerStopper();
|
||||
ApplicationManager.getApplication().invokeAndWait(Context.current().wrap(() -> {
|
||||
boolean highlightErrorElements = true;
|
||||
boolean runAnnotators = true;
|
||||
Project project = context.getProject();
|
||||
final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
if (editor == null) {
|
||||
actionCallback.reject("Editor is not open");
|
||||
return;
|
||||
}
|
||||
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
if (psiFile == null) {
|
||||
actionCallback.reject("Missing PSI file in the editor");
|
||||
return;
|
||||
}
|
||||
getInstance(project).dropPsiCaches();
|
||||
ReadAction.nonBlocking(Context.current().wrap((Callable<Void>)() -> {
|
||||
Stopwatch timer = Stopwatch.createStarted();
|
||||
TraceUtil.runWithSpanThrows(PerformanceTestSpan.TRACER, SPAN_NAME, span -> {
|
||||
DefaultHighlightVisitorBasedInspection.runAnnotatorsInGeneralHighlighting(psiFile, highlightErrorElements, runAnnotators);
|
||||
span.setAttribute("lines", editor.getDocument().getLineCount());
|
||||
span.setAttribute("timeToLines", timer.stop().elapsed(TimeUnit.MILLISECONDS) / (Math.max(1, editor.getDocument().getLineCount())));
|
||||
});
|
||||
actionCallback.setDone();
|
||||
return null;
|
||||
})).submit(AppExecutorUtil.getAppExecutorService());
|
||||
}));
|
||||
return Promises.toPromise(actionCallback);
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.jetbrains.performancePlugin.commands;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.lang.annotation.HighlightSeverity;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.TypingTarget;
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext;
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.jetbrains.performancePlugin.PerformanceTestSpan;
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.api.trace.SpanBuilder;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.concurrency.Promise;
|
||||
import org.jetbrains.concurrency.Promises;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.openapi.ui.playback.commands.AlphaNumericTypeCommand.findTarget;
|
||||
import static com.intellij.psi.PsiManager.getInstance;
|
||||
|
||||
@SuppressWarnings("TestOnlyProblems")
|
||||
public final class DoLocalInspection extends AbstractCommand implements Disposable {
|
||||
public static final String PREFIX = CMD_PREFIX + "doLocalInspection";
|
||||
public static final String SPAN_NAME = "localInspections";
|
||||
|
||||
public DoLocalInspection(@NotNull String text, int line) {
|
||||
super(text, line);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Promise<Object> _execute(@NotNull PlaybackContext context) {
|
||||
ActionCallback actionCallback = new ActionCallbackProfilerStopper();
|
||||
Project project = context.getProject();
|
||||
DumbService.getInstance(project).waitForSmartMode();
|
||||
|
||||
ApplicationManager.getApplication().invokeAndWait(() -> {
|
||||
TypingTarget target = findTarget(context);
|
||||
if (target == null) {
|
||||
//actionCallback.reject("There is no focus in editor");
|
||||
}
|
||||
});
|
||||
if (actionCallback.isRejected()) {
|
||||
return Promises.toPromise(actionCallback);
|
||||
}
|
||||
MessageBusConnection busConnection = project.getMessageBus().connect();
|
||||
SpanBuilder span = PerformanceTestSpan.TRACER.spanBuilder(SPAN_NAME).setParent(PerformanceTestSpan.getContext());
|
||||
Ref<Span> spanRef = new Ref<>();
|
||||
Ref<Scope> scopeRef = new Ref<>();
|
||||
busConnection.subscribe(DaemonCodeAnalyzer.DAEMON_EVENT_TOPIC, new DaemonCodeAnalyzer.DaemonListener() {
|
||||
@Override
|
||||
public void daemonFinished() {
|
||||
DaemonCodeAnalyzerImpl myDaemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project);
|
||||
final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
assert editor != null;
|
||||
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
assert psiFile != null;
|
||||
if (myDaemonCodeAnalyzer.isErrorAnalyzingFinished(psiFile)) {
|
||||
List<HighlightInfo> errorsOnHighlighting =
|
||||
DaemonCodeAnalyzerImpl.getHighlights(editor.getDocument(), HighlightSeverity.ERROR, project);
|
||||
List<HighlightInfo> warningsOnHighlighting =
|
||||
DaemonCodeAnalyzerImpl.getHighlights(editor.getDocument(), HighlightSeverity.WARNING, project);
|
||||
List<HighlightInfo> weakWarningsOnHighlighting =
|
||||
DaemonCodeAnalyzerImpl.getHighlights(editor.getDocument(), HighlightSeverity.WEAK_WARNING, project);
|
||||
|
||||
StringBuilder finishMessage = new StringBuilder("Local inspections have been finished with: ");
|
||||
|
||||
span.setAttribute("Errors", errorsOnHighlighting.size());
|
||||
if (errorsOnHighlighting.size() > 0) {
|
||||
finishMessage.append("\n").append(new String("Errors: " + errorsOnHighlighting.size()));
|
||||
}
|
||||
for (HighlightInfo error : errorsOnHighlighting) {
|
||||
finishMessage.append("\n").append(new String(error.getText() + ": " + error.getDescription()));
|
||||
}
|
||||
|
||||
span.setAttribute("Warnings", warningsOnHighlighting.size());
|
||||
if (warningsOnHighlighting.size() > 0) {
|
||||
finishMessage.append("\n").append(new String("Warnings: " + warningsOnHighlighting.size()));
|
||||
}
|
||||
for (HighlightInfo warning : warningsOnHighlighting) {
|
||||
finishMessage.append("\n").append(new String(warning.getText() + ": " + warning.getDescription()));
|
||||
}
|
||||
|
||||
span.setAttribute("Weak Warnings", warningsOnHighlighting.size());
|
||||
if (weakWarningsOnHighlighting.size() > 0) {
|
||||
finishMessage.append("\n").append(new String("Weak Warnings: " + weakWarningsOnHighlighting.size()));
|
||||
}
|
||||
for (HighlightInfo weakWarning : weakWarningsOnHighlighting) {
|
||||
finishMessage.append("\n").append(new String(weakWarning.getText() + ": " + weakWarning.getDescription()));
|
||||
}
|
||||
spanRef.get().end();
|
||||
scopeRef.get().close();
|
||||
busConnection.disconnect();
|
||||
context.message(finishMessage.toString(), getLine());
|
||||
actionCallback.setDone();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
DumbService.getInstance(project).smartInvokeLater(() -> {
|
||||
getInstance(project).dropPsiCaches();
|
||||
context.message("Local inspections have been started", getLine());
|
||||
spanRef.set(span.startSpan());
|
||||
scopeRef.set(spanRef.get().makeCurrent());
|
||||
DaemonCodeAnalyzer.getInstance(project).restart();
|
||||
});
|
||||
|
||||
return Promises.toPromise(actionCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.jetbrains.performancePlugin.commands
|
||||
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.playback.PlaybackContext
|
||||
import com.intellij.openapi.ui.playback.commands.AbstractCommand
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
import com.intellij.util.indexing.FileBasedIndexImpl
|
||||
import com.intellij.util.indexing.diagnostic.dump.IndexContentDiagnosticDumper
|
||||
import com.jetbrains.performancePlugin.PerformanceTestingBundle
|
||||
import com.jetbrains.performancePlugin.utils.ActionCallbackProfilerStopper
|
||||
import org.jetbrains.concurrency.Promise
|
||||
import org.jetbrains.concurrency.toPromise
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
class DumpProjectFiles(text: String, line: Int) : AbstractCommand(text, line) {
|
||||
|
||||
override fun _execute(context: PlaybackContext): Promise<Any?> {
|
||||
val actionCallback = ActionCallbackProfilerStopper()
|
||||
|
||||
val dumpProjectFilesDir = getOrCreateDirectoryToDumpFiles()
|
||||
LOG.info("DumpFiles will be stored to $dumpProjectFilesDir")
|
||||
|
||||
val project = context.project
|
||||
DumbService.getInstance(project).smartInvokeLater {
|
||||
object : Task.Modal(project, PerformanceTestingBundle.message("dumping.project.files"), false) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
try {
|
||||
dumpProjectFiles(dumpProjectFilesDir, indicator, project)
|
||||
LOG.info("Project files has been successfully stored to $dumpProjectFilesDir")
|
||||
actionCallback.setDone()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
actionCallback.reject(e.message)
|
||||
}
|
||||
}
|
||||
}.queue()
|
||||
}
|
||||
return actionCallback.toPromise()
|
||||
}
|
||||
|
||||
private fun dumpProjectFiles(dumpDir: Path, indicator: ProgressIndicator, project: Project) {
|
||||
runReadAction { (FileBasedIndex.getInstance() as FileBasedIndexImpl).flushIndexes() }
|
||||
|
||||
indicator.isIndeterminate = true
|
||||
|
||||
val contentDiagnostic = IndexContentDiagnosticDumper.getIndexContentDiagnosticForProject(project, indicator)
|
||||
IndexContentDiagnosticDumper.writeTo(StoreIndices.getFileForDiagnostic(dumpDir), contentDiagnostic)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PREFIX = CMD_PREFIX + "dumpProjectFiles"
|
||||
|
||||
private val LOG = Logger.getInstance(DumpProjectFiles::class.java)
|
||||
|
||||
private fun getOrCreateDirectoryToDumpFiles(): Path {
|
||||
val property = System.getProperty("dump.project.files.directory")
|
||||
return if (property != null) {
|
||||
Paths.get(property)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
FileUtil.createTempDirectory("projectFiles_dumps", null).toPath()
|
||||
}
|
||||
catch (e: IOException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user