Impossible to run applications with long command lines on windows

^KT-29352 Fixed
This commit is contained in:
Natalia Selezneva
2019-04-12 11:42:50 +03:00
parent dfa5f1f090
commit 3eda40394a
11 changed files with 190 additions and 35 deletions
@@ -344,6 +344,7 @@ public class KotlinRunConfiguration extends JetRunConfiguration {
JavaParametersUtil.configureModule(module, params, classPathType, jreHome);
setupJavaParameters(params);
params.setShortenCommandLine(null, module.getProject());
params.setMainClass(myConfiguration.getRunClass());
setupModulePath(params, module);
@@ -65,6 +65,7 @@ class KotlinConsoleKeeper(val project: Project) {
if (module != null) {
val classPath = JavaParametersBuilder.getModuleDependencies(module)
if (classPath.isNotEmpty()) {
javaParameters.setUseDynamicParameters(javaParameters.isDynamicClasspath)
javaParameters.programParametersList.add("-cp")
javaParameters.programParametersList.add(
classPath.joinToString(File.pathSeparator)
@@ -5,11 +5,13 @@
package org.jetbrains.kotlin.idea.util
import com.intellij.execution.ShortenCommandLine
import com.intellij.execution.configurations.JavaParameters
import com.intellij.openapi.compiler.ex.CompilerPathsEx
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdkType
import com.intellij.openapi.projectRoots.JdkUtil
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.projectRoots.SimpleJavaSdkType
import com.intellij.openapi.roots.ModuleRootManager
@@ -29,9 +31,20 @@ class JavaParametersBuilder(private val project: Project) {
if (jdk == null && setDefaultSdk) {
this.jdk = SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome())
}
this.setShortenCommandLine(getDefaultShortenCommandLineMethod(jdk?.homePath), project)
}
}
/**
* This method is partially copied from IDEA sources but doesn't check presence of dynamic.classpath property
* because we want to shorten command line for scratches and repl anyway
* @see [com.intellij.execution.ShortenCommandLine.getDefaultMethod]
*/
private fun getDefaultShortenCommandLineMethod(rootPath: String?): ShortenCommandLine {
if (rootPath != null && JdkUtil.isModularRuntime(rootPath)) return ShortenCommandLine.ARGS_FILE
return if (JdkUtil.useClasspathJar()) ShortenCommandLine.MANIFEST else ShortenCommandLine.CLASSPATH_FILE
}
fun withMainClassName(name: String?): JavaParametersBuilder {
mainClassName = name
return this
+6
View File
@@ -0,0 +1,6 @@
package some.test
fun main(args: Array<String>) {
}
@@ -6,10 +6,12 @@
package org.jetbrains.kotlin.idea.repl
import com.intellij.execution.console.LanguageConsoleImpl
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.testFramework.PlatformTestCase
import com.intellij.util.ui.UIUtil
import org.jetbrains.kotlin.console.KotlinConsoleKeeper
import org.jetbrains.kotlin.console.KotlinConsoleRunner
import org.jetbrains.kotlin.idea.run.createLibraryWithLongPaths
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.junit.Test
import kotlin.reflect.KMutableProperty0
@@ -82,6 +84,16 @@ class IdeReplExecutionTest : PlatformTestCase() {
assertFalse(consoleRunner.processHandler.isProcessTerminated, "Process accidentally terminated")
}
@Test
fun testLongCommandLine() {
ModuleRootModificationUtil.addDependency(module, createLibraryWithLongPaths(project))
consoleRunner.dispose()
consoleRunner = KotlinConsoleKeeper.getInstance(project).run(module)!!
testRunPossibility()
}
@Test fun testOnePlusOne() = testSimpleCommand("1 + 1", "2")
@Test fun testPrintlnText() = "Hello, console world!".let { testSimpleCommand("println(\"$it\")", it) }
@Test fun testDivisionByZeroException() = testSimpleCommand("1 / 0", "java.lang.ArithmeticException: / by zero")
@@ -133,6 +133,20 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
Assert.assertTrue(javaParameters.classPath.rootDirs.contains(moduleWithDependencySrcDir))
}
fun testLongCommandLine() {
val myModule = configureModule(moduleDirPath("module"), getTestProject().baseDir).module
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, addJdk(testRootDisposable, ::mockJdk))
ModuleRootModificationUtil.addDependency(myModule, createLibraryWithLongPaths(project))
val kotlinRunConfiguration = createConfigurationFromMain("some.test.main")
kotlinRunConfiguration.setModule(myModule)
val javaParameters = getJavaRunParameters(kotlinRunConfiguration)
val commandLine = javaParameters.toCommandLine().commandLineString
Assert.assertTrue(commandLine.length < javaParameters.classPath.pathList.joinToString().length)
}
fun testClassesAndObjects() {
doTest(ConfigLibraryUtil::configureKotlinRuntimeAndSdk)
}
@@ -134,6 +134,20 @@ class RunConfigurationTest: KotlinCodeInsightTestCase() {
Assert.assertTrue(javaParameters.classPath.rootDirs.contains(moduleWithDependencySrcDir))
}
fun testLongCommandLine() {
val myModule = configureModule(moduleDirPath("module"), getTestProject().baseDir).module
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, addJdk(testRootDisposable, ::mockJdk))
ModuleRootModificationUtil.addDependency(myModule, createLibraryWithLongPaths(project))
val kotlinRunConfiguration = createConfigurationFromMain("some.test.main")
kotlinRunConfiguration.setModule(myModule)
val javaParameters = getJavaRunParameters(kotlinRunConfiguration)
val commandLine = javaParameters.toCommandLine().commandLineString
Assert.assertTrue(commandLine.length < javaParameters.classPath.pathList.joinToString().length)
}
fun testClassesAndObjects() {
doTest(ConfigLibraryUtil::configureKotlinRuntimeAndSdk)
}
@@ -17,8 +17,16 @@ import com.intellij.execution.configurations.RunProfile
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.runners.ExecutionEnvironmentBuilder
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiElement
import com.intellij.testFramework.MapDataContext
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.junit.Assert
fun getJavaRunParameters(configuration: RunConfiguration): JavaParameters {
@@ -42,6 +50,31 @@ fun createConfigurationFromElement(element: PsiElement, save: Boolean = false):
return runnerAndConfigurationSettings!!.configuration
}
fun createLibraryWithLongPaths(project: Project): Library {
val maxCommandlineLengthWindows = 24500
val maxFilenameLengthWindows = 245
return runWriteAction {
val modifiableModel = ProjectLibraryTable.getInstance(project).modifiableModel
val library = try {
modifiableModel.createLibrary("LibraryWithLongPaths", null)
} finally {
modifiableModel.commit()
}
with(library.modifiableModel) {
for (i in 0..maxCommandlineLengthWindows / maxFilenameLengthWindows) {
val tmpFile = VirtualFileManager.constructUrl(
LocalFileSystem.getInstance().protocol,
FileUtil.createTempFile("file$i", "a".repeat(maxFilenameLengthWindows)).path
)
addRoot(tmpFile, OrderRootType.CLASSES)
}
commit()
}
return@runWriteAction library
}
}
private object MockExecutor : DefaultRunExecutor() {
override fun getId() = DefaultRunExecutor.EXECUTOR_ID
@@ -88,15 +88,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
val sourceFile = File(testDataPath, fileName)
val fileText = sourceFile.readText()
val scratchFile = ScratchRootType.getInstance().createScratchFile(
project,
sourceFile.name,
KotlinLanguage.INSTANCE,
fileText,
ScratchFileService.Option.create_if_missing
) ?: error("Couldn't create scratch file ${sourceFile.path}")
myFixture.openFileInEditor(scratchFile)
val scratchFile = createScratchFile(sourceFile.name, fileText)
ScriptDependenciesManager.updateScriptDependenciesSynchronously(scratchFile, project)
@@ -115,16 +107,6 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
launchScratch(scratchFile)
UIUtil.dispatchAllInvocationEvents()
val start = System.currentTimeMillis()
// wait until output is displayed in editor or for 1 minute
while (ScratchCompilationSupport.isAnyInProgress() && (System.currentTimeMillis() - start) < 60000) {
Thread.sleep(100)
}
UIUtil.dispatchAllInvocationEvents()
val doc = PsiDocumentManager.getInstance(project).getDocument(psiFile) ?: error("Document for ${psiFile.name} is null")
val actualOutput = StringBuilder(psiFile.text)
@@ -152,13 +134,36 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
KotlinTestUtils.assertEqualsToFile(expectedFile, actualOutput.toString())
}
private fun launchScratch(scratchFile: VirtualFile) {
protected fun createScratchFile(name: String, text: String): VirtualFile {
val scratchFile = ScratchRootType.getInstance().createScratchFile(
project,
name,
KotlinLanguage.INSTANCE,
text,
ScratchFileService.Option.create_if_missing
) ?: error("Couldn't create scratch file")
myFixture.openFileInEditor(scratchFile)
return scratchFile
}
protected fun launchScratch(scratchFile: VirtualFile) {
val action = RunScratchAction()
val e = getActionEvent(scratchFile, action)
action.beforeActionPerformedUpdate(e)
Assert.assertTrue(e.presentation.isEnabled && e.presentation.isVisible)
action.actionPerformed(e)
UIUtil.dispatchAllInvocationEvents()
val start = System.currentTimeMillis()
// wait until output is displayed in editor or for 1 minute
while (ScratchCompilationSupport.isAnyInProgress() && (System.currentTimeMillis() - start) < 60000) {
Thread.sleep(100)
}
UIUtil.dispatchAllInvocationEvents()
}
private fun getActionEvent(virtualFile: VirtualFile, action: AnAction): TestActionEvent {
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.scratch
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
import com.intellij.openapi.roots.libraries.Library
import org.jetbrains.kotlin.idea.run.createLibraryWithLongPaths
import org.jetbrains.kotlin.idea.scratch.output.InlayScratchFileRenderer
import org.jetbrains.kotlin.idea.util.application.runWriteAction
class CustomScratchRunActionTest : AbstractScratchRunActionTest() {
fun testLongCommandLineWithRepl() {
assertEquals("RESULT: res0: kotlin.Int = 1", getOutput(true))
}
fun testLongCommandLine() {
assertEquals("RESULT: 1", getOutput(false))
}
private fun getOutput(isRepl: Boolean): String {
val fileText = "1"
val scratchFile = createScratchFile("scratch_1.kts", fileText)
val (editor, scratchPanel) = getEditorWithScratchPanel(myManager, scratchFile) ?: error("Couldn't find scratch panel")
scratchPanel.scratchFile.saveOptions {
copy(isRepl = isRepl, isInteractiveMode = false)
}
scratchPanel.setModule(myFixture.module)
launchScratch(scratchFile)
return editor.editor.inlayModel.getInlineElementsInRange(0, fileText.length)
.map { it.renderer }
.filterIsInstance<InlayScratchFileRenderer>()
.joinToString().trim()
}
private val library: Library by lazy {
createLibraryWithLongPaths(project)
}
override fun setUp() {
super.setUp()
ModuleRootModificationUtil.addDependency(myFixture.module, library)
}
override fun tearDown() {
removeLibraryWithLongPaths()
super.tearDown()
}
private fun removeLibraryWithLongPaths() {
runWriteAction {
val modifiableModel = ProjectLibraryTable.getInstance(project).modifiableModel
try {
modifiableModel.removeLibrary(library)
} finally {
modifiableModel.commit()
}
}
}
}
@@ -5,9 +5,6 @@
package org.jetbrains.kotlin.idea.scratch
import com.intellij.ide.scratch.ScratchFileService
import com.intellij.ide.scratch.ScratchRootType
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.scratch.ui.ScratchTopPanel
import org.junit.Assert
import javax.swing.JCheckBox
@@ -17,18 +14,7 @@ import kotlin.reflect.full.declaredMemberProperties
class ScratchOptionsSaveTest : AbstractScratchRunActionTest() {
fun testOptionsSaveOnClosingFile() {
val fileText = "val a = 1"
val scratchFile = ScratchRootType.getInstance().createScratchFile(
project,
"scratch_1.kts",
KotlinLanguage.INSTANCE,
fileText,
ScratchFileService.Option.create_if_missing
) ?: error("Couldn't create scratch file")
myManager.openFile(scratchFile, true)
val scratchFile = createScratchFile("scratch_1.kts", "val a = 1")
val (_, scratchPanelBeforeClosingFile) = getEditorWithScratchPanel(myManager, scratchFile) ?: error("Couldn't find scratch panel")
Assert.assertEquals(