Added automatic backup for debugging incremental compilation.
This commit is contained in:
@@ -107,6 +107,10 @@
|
|||||||
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
||||||
</action>
|
</action>
|
||||||
|
|
||||||
|
<action id="CreateIncrementalCompilationBackup" class="org.jetbrains.jet.plugin.internal.makeBackup.CreateIncrementalCompilationBackup">
|
||||||
|
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
|
||||||
|
</action>
|
||||||
|
|
||||||
<action id="ExtractFunctionToScope" class="org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractFunctionToScopeAction"
|
<action id="ExtractFunctionToScope" class="org.jetbrains.jet.plugin.refactoring.extractFunction.ExtractFunctionToScopeAction"
|
||||||
text="Extract Function to _Scope...">
|
text="Extract Function to _Scope...">
|
||||||
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift M"/>
|
<keyboard-shortcut keymap="$default" first-keystroke="control alt shift M"/>
|
||||||
@@ -183,6 +187,7 @@
|
|||||||
<fileTypeFactory implementation="org.jetbrains.jet.plugin.JetFileFactory"/>
|
<fileTypeFactory implementation="org.jetbrains.jet.plugin.JetFileFactory"/>
|
||||||
|
|
||||||
<compileServer.plugin classpath="jps/kotlin-jps-plugin.jar;kotlin-runtime.jar;kotlin-plugin.jar"/>
|
<compileServer.plugin classpath="jps/kotlin-jps-plugin.jar;kotlin-runtime.jar;kotlin-plugin.jar"/>
|
||||||
|
<compiler.task execute="BEFORE" implementation="org.jetbrains.jet.plugin.internal.makeBackup.MakeBackupCompileTask"/>
|
||||||
|
|
||||||
<lang.syntaxHighlighterFactory key="jet" implementationClass="org.jetbrains.jet.plugin.highlighter.JetSyntaxHighlighterFactory"/>
|
<lang.syntaxHighlighterFactory key="jet" implementationClass="org.jetbrains.jet.plugin.highlighter.JetSyntaxHighlighterFactory"/>
|
||||||
<lang.braceMatcher language="jet" implementationClass="org.jetbrains.jet.plugin.JetPairMatcher"/>
|
<lang.braceMatcher language="jet" implementationClass="org.jetbrains.jet.plugin.JetPairMatcher"/>
|
||||||
|
|||||||
+181
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.plugin.internal.makeBackup
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.history.core.RevisionsCollector
|
||||||
|
import java.io.File
|
||||||
|
import com.intellij.history.integration.patches.PatchCreator
|
||||||
|
import com.intellij.history.integration.LocalHistoryImpl
|
||||||
|
import com.intellij.openapi.vcs.changes.Change
|
||||||
|
import com.intellij.openapi.application.PathManager
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import java.util.ArrayList
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
|
import com.intellij.openapi.progress.Task
|
||||||
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
|
import java.util.zip.ZipOutputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import com.intellij.util.io.ZipUtil
|
||||||
|
import com.intellij.ide.actions.ShowFilePathAction
|
||||||
|
import com.intellij.util.WaitForProgressToShow
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
|
||||||
|
public class CreateIncrementalCompilationBackup: AnAction("Create backup for debugging Kotlin incremental compilation") {
|
||||||
|
class object {
|
||||||
|
val BACKUP_DIR_NAME = ".backup"
|
||||||
|
val PATCHES_TO_CREATE = 5
|
||||||
|
|
||||||
|
val PATCHES_FRACTION = .25
|
||||||
|
val LOGS_FRACTION = .05
|
||||||
|
val ZIP_FRACTION = 1.0 - PATCHES_FRACTION - LOGS_FRACTION
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(e: AnActionEvent) {
|
||||||
|
e.getPresentation().setVisible(incrementalCompilationEnabled(e.getProject()!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
|
val project = e.getProject()!!
|
||||||
|
val projectBaseDir = File(project.getBaseDir()!!.getPath())
|
||||||
|
val backupDir = File(FileUtil.createTempDirectory("makeBackup", null), BACKUP_DIR_NAME)
|
||||||
|
|
||||||
|
ProgressManager.getInstance().run(
|
||||||
|
object : Task.Backgroundable(project, "Creating backup for debugging Kotlin incremental compilation", true) {
|
||||||
|
override fun run(indicator: ProgressIndicator) {
|
||||||
|
createPatches(backupDir, project, indicator)
|
||||||
|
copyLogs(backupDir, indicator)
|
||||||
|
|
||||||
|
zipProjectDir(backupDir, project, projectBaseDir, indicator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createPatches(backupDir: File, project: Project, indicator: ProgressIndicator) {
|
||||||
|
ApplicationManager.getApplication()!!.runReadAction(Runnable {
|
||||||
|
val localHistoryImpl = LocalHistoryImpl.getInstanceImpl()!!
|
||||||
|
val gateway = localHistoryImpl.getGateway()!!
|
||||||
|
val localHistoryFacade = localHistoryImpl.getFacade()
|
||||||
|
|
||||||
|
val revisionsCollector = RevisionsCollector(localHistoryFacade, gateway.createTransientRootEntry(), project.getBaseDir()!!.getPath(), project.getLocationHash(), null)
|
||||||
|
|
||||||
|
var patchesCreated = 0
|
||||||
|
|
||||||
|
val patchesDir = File(backupDir, "patches")
|
||||||
|
patchesDir.mkdirs()
|
||||||
|
|
||||||
|
val revisions = revisionsCollector.getResult()!!
|
||||||
|
for (rev in revisions) {
|
||||||
|
val label = rev.getLabel()
|
||||||
|
if (label != null && label.startsWith(HISTORY_LABEL_PREFIX)) {
|
||||||
|
val patchFile = File(patchesDir, label.trimLeading(HISTORY_LABEL_PREFIX) + ".patch")
|
||||||
|
|
||||||
|
indicator.setText("Creating patch $patchFile")
|
||||||
|
indicator.setFraction(PATCHES_FRACTION * patchesCreated / PATCHES_TO_CREATE)
|
||||||
|
|
||||||
|
val differences = revisions[0].getDifferencesWith(rev)!!
|
||||||
|
val changes = differences.map {
|
||||||
|
d ->
|
||||||
|
Change(d.getLeftContentRevision(gateway), d.getRightContentRevision(gateway))
|
||||||
|
}
|
||||||
|
|
||||||
|
PatchCreator.create(project, changes, patchFile.getPath(), false, null)
|
||||||
|
|
||||||
|
if (++patchesCreated >= PATCHES_TO_CREATE) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyLogs(backupDir: File, indicator: ProgressIndicator) {
|
||||||
|
indicator.setText("Copying logs")
|
||||||
|
indicator.setFraction(PATCHES_FRACTION)
|
||||||
|
|
||||||
|
val logsDir = File(backupDir, "logs")
|
||||||
|
FileUtil.copyDir(File(PathManager.getLogPath()), logsDir)
|
||||||
|
|
||||||
|
indicator.setFraction(PATCHES_FRACTION + LOGS_FRACTION)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun zipProjectDir(backupDir: File, project: Project, projectDir: File, indicator: ProgressIndicator) {
|
||||||
|
// files and relative paths
|
||||||
|
|
||||||
|
val files = ArrayList<Pair<File, String>>() // files and relative paths
|
||||||
|
var totalBytes = 0L
|
||||||
|
|
||||||
|
for (dir in listOf(projectDir, backupDir.getParentFile()!!)) {
|
||||||
|
FileUtil.processFilesRecursively(
|
||||||
|
dir,
|
||||||
|
/*processor*/ {
|
||||||
|
if (it!!.isFile()
|
||||||
|
&& !it.getName().endsWith(".hprof")
|
||||||
|
&& !(it.getName().startsWith("make_backup_") && it.getName().endsWith(".zip"))
|
||||||
|
) {
|
||||||
|
|
||||||
|
indicator.setText("Scanning project dir: $it")
|
||||||
|
|
||||||
|
files.add(Pair(it, FileUtil.getRelativePath(dir, it)!!))
|
||||||
|
totalBytes += it.length()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
/*directoryFilter*/ {
|
||||||
|
val name = it!!.getName()
|
||||||
|
name != ".git" && name != "out"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val backupFile = File(projectDir, "make_backup_" + SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(Date()) + ".zip")
|
||||||
|
|
||||||
|
|
||||||
|
val zos = ZipOutputStream(FileOutputStream(backupFile))
|
||||||
|
|
||||||
|
var processedBytes = 0L
|
||||||
|
|
||||||
|
zos.use {
|
||||||
|
for ((file, relativePath) in files) {
|
||||||
|
indicator.setText("Adding file to backup: $relativePath")
|
||||||
|
indicator.setFraction(PATCHES_FRACTION + LOGS_FRACTION + processedBytes.toDouble() / totalBytes * ZIP_FRACTION)
|
||||||
|
|
||||||
|
ZipUtil.addFileToZip(zos, file, relativePath, null, null)
|
||||||
|
|
||||||
|
processedBytes += file.length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtil.delete(backupDir)
|
||||||
|
|
||||||
|
WaitForProgressToShow.runOrInvokeLaterAboveProgress({
|
||||||
|
ShowFilePathAction.showDialog(
|
||||||
|
project,
|
||||||
|
"Successfully created backup " + backupFile.getAbsolutePath(),
|
||||||
|
"Created backup",
|
||||||
|
backupFile,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}, null, project)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.plugin.internal.makeBackup
|
||||||
|
|
||||||
|
import com.intellij.history.LocalHistory
|
||||||
|
import com.intellij.openapi.compiler.CompileTask
|
||||||
|
import com.intellij.openapi.compiler.CompileContext
|
||||||
|
import java.util.Random
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.compiler.CompilerWorkspaceConfiguration
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
|
||||||
|
val random = Random()
|
||||||
|
|
||||||
|
val HISTORY_LABEL_KEY = Key.create<String>("history label")
|
||||||
|
|
||||||
|
public class MakeBackupCompileTask: CompileTask {
|
||||||
|
override fun execute(context: CompileContext?): Boolean {
|
||||||
|
val project = context!!.getProject()!!
|
||||||
|
|
||||||
|
if (!incrementalCompilationEnabled(project)) return true
|
||||||
|
|
||||||
|
val localHistory = LocalHistory.getInstance()!!
|
||||||
|
val label = HISTORY_LABEL_PREFIX + Integer.toHexString(random.nextInt())
|
||||||
|
localHistory.putSystemLabel(project, label)
|
||||||
|
|
||||||
|
context.getCompileScope()!!.putUserData(HISTORY_LABEL_KEY, label)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun incrementalCompilationEnabled(project: Project): Boolean {
|
||||||
|
val compilerVmOptions = CompilerWorkspaceConfiguration.getInstance(project)!!.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS!!
|
||||||
|
return compilerVmOptions.contains("-Dkotlin.incremental.compilation=true")
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2014 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.plugin.internal.makeBackup
|
||||||
|
|
||||||
|
val HISTORY_LABEL_PREFIX = "build started "
|
||||||
@@ -50,10 +50,13 @@ import org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.runK2JsCompiler
|
|||||||
import org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.runK2JvmCompiler
|
import org.jetbrains.jet.compiler.runner.KotlinCompilerRunner.runK2JvmCompiler
|
||||||
import org.jetbrains.jet.utils.keysToMap
|
import org.jetbrains.jet.utils.keysToMap
|
||||||
import org.jetbrains.jps.incremental.ModuleLevelBuilder.ExitCode.*
|
import org.jetbrains.jps.incremental.ModuleLevelBuilder.ExitCode.*
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
|
||||||
public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
||||||
class object {
|
class object {
|
||||||
public val KOTLIN_BUILDER_NAME: String = "Kotlin Builder"
|
public val KOTLIN_BUILDER_NAME: String = "Kotlin Builder"
|
||||||
|
|
||||||
|
private val LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.BuildSession")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPresentableName() = KOTLIN_BUILDER_NAME
|
override fun getPresentableName() = KOTLIN_BUILDER_NAME
|
||||||
@@ -66,6 +69,11 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
|
|||||||
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
|
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
|
||||||
outputConsumer: ModuleLevelBuilder.OutputConsumer
|
outputConsumer: ModuleLevelBuilder.OutputConsumer
|
||||||
): ModuleLevelBuilder.ExitCode {
|
): ModuleLevelBuilder.ExitCode {
|
||||||
|
val historyLabel = context.getBuilderParameter("history label")
|
||||||
|
if (historyLabel != null) {
|
||||||
|
LOG.info("Label in local history: $historyLabel")
|
||||||
|
}
|
||||||
|
|
||||||
val messageCollector = MessageCollectorAdapter(context)
|
val messageCollector = MessageCollectorAdapter(context)
|
||||||
// Workaround for Android Studio
|
// Workaround for Android Studio
|
||||||
if (!isJavaPluginEnabled(context)) {
|
if (!isJavaPluginEnabled(context)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user