Avoid removing target/classes dir during IC in Maven
#KT-21581 fixed
This commit is contained in:
+6
-5
@@ -9,7 +9,8 @@ public class IncrementalCompilationIT extends MavenITBase {
|
|||||||
MavenProject project = new MavenProject("kotlinSimple");
|
MavenProject project = new MavenProject("kotlinSimple");
|
||||||
project.exec("package")
|
project.exec("package")
|
||||||
.succeeded()
|
.succeeded()
|
||||||
.compiledKotlin("src/A.kt", "src/useA.kt", "src/Dummy.kt");
|
.fileExists("target/classes/test.properties")
|
||||||
|
.compiledKotlin("src/main/kotlin/A.kt", "src/main/kotlin/useA.kt", "src/main/kotlin/Dummy.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -27,7 +28,7 @@ public class IncrementalCompilationIT extends MavenITBase {
|
|||||||
MavenProject project = new MavenProject("kotlinSimple");
|
MavenProject project = new MavenProject("kotlinSimple");
|
||||||
project.exec("package");
|
project.exec("package");
|
||||||
|
|
||||||
File aKt = project.file("src/A.kt");
|
File aKt = project.file("src/main/kotlin/A.kt");
|
||||||
String original = "class A";
|
String original = "class A";
|
||||||
String replacement = "private class A";
|
String replacement = "private class A";
|
||||||
MavenTestUtils.replaceFirstInFile(aKt, original, replacement);
|
MavenTestUtils.replaceFirstInFile(aKt, original, replacement);
|
||||||
@@ -39,7 +40,7 @@ public class IncrementalCompilationIT extends MavenITBase {
|
|||||||
MavenTestUtils.replaceFirstInFile(aKt, replacement, original);
|
MavenTestUtils.replaceFirstInFile(aKt, replacement, original);
|
||||||
project.exec("package")
|
project.exec("package")
|
||||||
.succeeded()
|
.succeeded()
|
||||||
.compiledKotlin("src/A.kt", "src/useA.kt");
|
.compiledKotlin("src/main/kotlin/A.kt", "src/main/kotlin/useA.kt");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,12 +49,12 @@ public class IncrementalCompilationIT extends MavenITBase {
|
|||||||
MavenProject project = new MavenProject("kotlinSimple");
|
MavenProject project = new MavenProject("kotlinSimple");
|
||||||
project.exec("package");
|
project.exec("package");
|
||||||
|
|
||||||
File aKt = project.file("src/A.kt");
|
File aKt = project.file("src/main/kotlin/A.kt");
|
||||||
MavenTestUtils.replaceFirstInFile(aKt, "fun foo", "internal fun foo");
|
MavenTestUtils.replaceFirstInFile(aKt, "fun foo", "internal fun foo");
|
||||||
|
|
||||||
project.exec("package")
|
project.exec("package")
|
||||||
.succeeded()
|
.succeeded()
|
||||||
.compiledKotlin("src/A.kt", "src/useA.kt");
|
.compiledKotlin("src/main/kotlin/A.kt", "src/main/kotlin/useA.kt");
|
||||||
|
|
||||||
// todo rebuild and compare output
|
// todo rebuild and compare output
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -110,4 +110,14 @@ class MavenExecutionResult {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MavenExecutionResult fileExists(@NotNull final String path) throws Exception {
|
||||||
|
return check(new Action<MavenExecutionResult>() {
|
||||||
|
@Override
|
||||||
|
public void run(MavenExecutionResult execResult) {
|
||||||
|
File file = new File(workingDir, path);
|
||||||
|
Assert.assertTrue(file + " does not exist", file.exists());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||||
|
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@@ -40,7 +42,6 @@
|
|||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
|
|
||||||
<sourceDirectory>${project.basedir}/src</sourceDirectory>
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>kotlin-maven-plugin</artifactId>
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
example.property=101
|
||||||
+32
-6
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.maven;
|
package org.jetbrains.kotlin.maven;
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.psi.PsiJavaModule;
|
import com.intellij.psi.PsiJavaModule;
|
||||||
|
import kotlin.collections.MapsKt;
|
||||||
import org.apache.maven.plugin.MojoExecutionException;
|
import org.apache.maven.plugin.MojoExecutionException;
|
||||||
import org.apache.maven.plugin.MojoFailureException;
|
import org.apache.maven.plugin.MojoFailureException;
|
||||||
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||||
@@ -32,15 +34,15 @@ import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments;
|
|||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
|
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler;
|
||||||
import org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunnerKt;
|
import org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunnerKt;
|
||||||
|
import org.jetbrains.kotlin.maven.incremental.FileCopier;
|
||||||
import org.jetbrains.kotlin.maven.incremental.MavenICReporter;
|
import org.jetbrains.kotlin.maven.incremental.MavenICReporter;
|
||||||
import org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager;
|
import org.jetbrains.kotlin.maven.kapt.AnnotationProcessingManager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.nio.file.*;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.intellij.openapi.util.text.StringUtil.join;
|
import static com.intellij.openapi.util.text.StringUtil.join;
|
||||||
import static org.jetbrains.kotlin.maven.Util.filterClassPath;
|
import static org.jetbrains.kotlin.maven.Util.filterClassPath;
|
||||||
@@ -241,19 +243,43 @@ public class K2JVMCompileMojo extends KotlinCompileMojoBase<K2JVMCompilerArgumen
|
|||||||
File cachesDir = getCachesDir();
|
File cachesDir = getCachesDir();
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
cachesDir.mkdirs();
|
cachesDir.mkdirs();
|
||||||
|
String destination = arguments.getDestination();
|
||||||
|
assert destination != null : "output is not specified!";
|
||||||
|
File classesDir = new File(destination);
|
||||||
|
File kotlinClassesDir = new File(cachesDir, "classes");
|
||||||
|
File snapshotsFile = new File(cachesDir, "snapshots.bin");
|
||||||
|
String classpath = arguments.getClasspath();
|
||||||
MavenICReporter icReporter = MavenICReporter.get(getLog());
|
MavenICReporter icReporter = MavenICReporter.get(getLog());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
arguments.setDestination(kotlinClassesDir.getAbsolutePath());
|
||||||
|
if (classpath != null) {
|
||||||
|
List<String> filteredClasspath = new ArrayList<>();
|
||||||
|
for (String path : classpath.split(File.pathSeparator)) {
|
||||||
|
if (!classesDir.equals(new File(path))) {
|
||||||
|
filteredClasspath.add(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arguments.setClasspath(StringUtil.join(filteredClasspath, File.pathSeparator));
|
||||||
|
}
|
||||||
|
|
||||||
IncrementalJvmCompilerRunnerKt.makeIncrementally(cachesDir, sourceRoots, arguments, messageCollector, icReporter);
|
IncrementalJvmCompilerRunnerKt.makeIncrementally(cachesDir, sourceRoots, arguments, messageCollector, icReporter);
|
||||||
|
|
||||||
int compiledKtFilesCount = icReporter.getCompiledKotlinFiles().size();
|
int compiledKtFilesCount = icReporter.getCompiledKotlinFiles().size();
|
||||||
getLog().info("Compiled " + icReporter.getCompiledKotlinFiles().size() + " Kotlin files using incremental compiler");
|
getLog().info("Compiled " + icReporter.getCompiledKotlinFiles().size() + " Kotlin files using incremental compiler");
|
||||||
|
|
||||||
|
if (!messageCollector.hasErrors()) {
|
||||||
|
(new FileCopier(getLog())).syncDirs(kotlinClassesDir, classesDir, snapshotsFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
return ExitCode.INTERNAL_ERROR;
|
return ExitCode.INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
arguments.setDestination(destination);
|
||||||
|
arguments.setClasspath(classpath);
|
||||||
|
}
|
||||||
|
|
||||||
if (messageCollector.hasErrors()) {
|
if (messageCollector.hasErrors()) {
|
||||||
return ExitCode.COMPILATION_ERROR;
|
return ExitCode.COMPILATION_ERROR;
|
||||||
|
|||||||
+147
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 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.maven.incremental;
|
||||||
|
|
||||||
|
import org.apache.maven.plugin.logging.Log;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class FileCopier {
|
||||||
|
private final static int VERSION = 0;
|
||||||
|
|
||||||
|
private final Log log;
|
||||||
|
|
||||||
|
public FileCopier(Log log) {
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void syncDirs(@NotNull File from, @NotNull File to, @NotNull File snapshotsStorageFile) {
|
||||||
|
try {
|
||||||
|
syncDirsImpl(from, to, snapshotsStorageFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not copy Kotlin files from " + from + " to " + to, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncDirsImpl(
|
||||||
|
@NotNull File sourceBaseFile,
|
||||||
|
@NotNull File targetBaseFile,
|
||||||
|
@NotNull File snapshotsStorageFile
|
||||||
|
) throws IOException {
|
||||||
|
// snapshots are stored as relative paths (to source or target base)
|
||||||
|
Map<String, FileSnapshot> previousSnapshots = readFileSnapshots(snapshotsStorageFile);
|
||||||
|
|
||||||
|
Path sourceBase = Paths.get(sourceBaseFile.getPath()).normalize();
|
||||||
|
Path targetBase = Paths.get(targetBaseFile.getPath()).normalize();
|
||||||
|
Map<String, FileSnapshot> newSnapshots = new HashMap<>();
|
||||||
|
for (Path path : Files.walk(sourceBase).collect(Collectors.toList())) {
|
||||||
|
if (!Files.isRegularFile(path)) continue;
|
||||||
|
|
||||||
|
String relativePath = sourceBase.relativize(path).toString();
|
||||||
|
|
||||||
|
File file = path.toFile();
|
||||||
|
FileSnapshot snapshot = new FileSnapshot(file.lastModified(), file.length());
|
||||||
|
|
||||||
|
// remove current files from previousSnapshots map so only removed files would remain in previousSnapshots
|
||||||
|
FileSnapshot prevSnapshot = previousSnapshots.remove(relativePath);
|
||||||
|
if (!snapshot.equals(prevSnapshot)) {
|
||||||
|
Path target = targetBase.resolve(relativePath);
|
||||||
|
if (!Files.isDirectory(target)) {
|
||||||
|
Files.deleteIfExists(target);
|
||||||
|
Files.createDirectories(target.getParent());
|
||||||
|
Files.copy(path, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Copied " + path + " to " + target);
|
||||||
|
}
|
||||||
|
newSnapshots.put(relativePath, snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String removedPath : previousSnapshots.keySet()) {
|
||||||
|
Path target = targetBase.resolve(removedPath);
|
||||||
|
log.debug("Deleted " + target + " as it is no longer present in " + sourceBase);
|
||||||
|
if (Files.isRegularFile(target)) {
|
||||||
|
Files.delete(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSnapshots(newSnapshots, snapshotsStorageFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFileSnapshots(@NotNull Map<String, FileSnapshot> snapshots, @NotNull File outputFile) {
|
||||||
|
try (ObjectOutputStream output = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)))) {
|
||||||
|
output.writeInt(VERSION);
|
||||||
|
output.writeInt(snapshots.size());
|
||||||
|
for (Map.Entry<String, FileSnapshot> entry : snapshots.entrySet()) {
|
||||||
|
String path = entry.getKey();
|
||||||
|
output.writeUTF(path);
|
||||||
|
FileSnapshot snapshot = entry.getValue();
|
||||||
|
output.writeLong(snapshot.lastModified);
|
||||||
|
output.writeLong(snapshot.size);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("Couldn't write copied files list to " + outputFile, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Map<String, FileSnapshot> readFileSnapshots(@NotNull File inputFile) {
|
||||||
|
Map<String, FileSnapshot> snapshots = new HashMap<>();
|
||||||
|
if (!inputFile.isFile()) return snapshots;
|
||||||
|
|
||||||
|
try (ObjectInputStream input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(inputFile)))) {
|
||||||
|
int version = input.readInt();
|
||||||
|
if (version != VERSION) return snapshots;
|
||||||
|
|
||||||
|
int size = input.readInt();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
String path = input.readUTF();
|
||||||
|
long lastModified = input.readLong();
|
||||||
|
long fileSize = input.readLong();
|
||||||
|
snapshots.put(path, new FileSnapshot(lastModified, fileSize));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("Couldn't read copied files list from " + inputFile, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snapshots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FileSnapshot {
|
||||||
|
final long lastModified;
|
||||||
|
final long size;
|
||||||
|
|
||||||
|
private FileSnapshot(long lastModified, long size) {
|
||||||
|
this.lastModified = lastModified;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
FileSnapshot that = (FileSnapshot) o;
|
||||||
|
|
||||||
|
if (lastModified != that.lastModified) return false;
|
||||||
|
return size == that.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = (int) (lastModified ^ (lastModified >>> 32));
|
||||||
|
result = 31 * result + (int) (size ^ (size >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user