Kotlinc: catch FileNotFoundException caused by problematic destination.
This commit is contained in:
committed by
Alexander Udalov
parent
149282a888
commit
28452fc38e
@@ -23,13 +23,24 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
fun OutputFileCollection.writeAll(outputDir: File, report: ((file: OutputFile, sources: List<File>, output: File) -> Unit)?) {
|
||||
for (file in asList()) {
|
||||
val sources = file.sourceFiles
|
||||
val output = File(outputDir, file.relativePath)
|
||||
report?.invoke(file, sources, output)
|
||||
FileUtil.writeToFile(output, file.asByteArray())
|
||||
try {
|
||||
FileUtil.writeToFile(output, file.asByteArray())
|
||||
} catch (e: FileNotFoundException) {
|
||||
if (outputDir.isDirectory) {
|
||||
// output directory exists
|
||||
throw NoPermissionException("error while writing $output (Permission denied)", e)
|
||||
}
|
||||
// Failed to create directory, possibly due to lack of write permission or clash with existing file.
|
||||
// In both cases, the directory will not exist, so for the sake of simplicity, we treat them same way.
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +49,16 @@ fun OutputFileCollection.writeAllTo(outputDir: File) {
|
||||
}
|
||||
|
||||
fun OutputFileCollection.writeAll(outputDir: File, messageCollector: MessageCollector, reportOutputFiles: Boolean) {
|
||||
if (!reportOutputFiles) writeAllTo(outputDir)
|
||||
else writeAll(outputDir) { _, sources, output ->
|
||||
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
|
||||
try {
|
||||
if (!reportOutputFiles) writeAllTo(outputDir)
|
||||
else writeAll(outputDir) { _, sources, output ->
|
||||
messageCollector.report(CompilerMessageSeverity.OUTPUT, OutputMessageUtil.formatOutputMessage(sources, output))
|
||||
}
|
||||
} catch (e: NoPermissionException) {
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, e.message!!)
|
||||
} catch (e: FileNotFoundException) {
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, "directory not found: $outputDir")
|
||||
}
|
||||
}
|
||||
|
||||
private class NoPermissionException(message: String, cause: Throwable?) : IllegalStateException(message, cause)
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile;
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleChunk;
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser;
|
||||
@@ -104,16 +105,24 @@ public class CompileEnvironmentUtil {
|
||||
}
|
||||
|
||||
public static void writeToJar(
|
||||
File jarPath, boolean jarRuntime, boolean noReflect, boolean resetJarTimestamps, FqName mainClass, OutputFileCollection outputFiles
|
||||
File jarPath,
|
||||
boolean jarRuntime,
|
||||
boolean noReflect,
|
||||
boolean resetJarTimestamps,
|
||||
FqName mainClass,
|
||||
OutputFileCollection outputFiles,
|
||||
MessageCollector messageCollector
|
||||
) {
|
||||
FileOutputStream outputStream = null;
|
||||
try {
|
||||
// we should try to create the output dir first
|
||||
jarPath.getParentFile().mkdirs();
|
||||
outputStream = new FileOutputStream(jarPath);
|
||||
doWriteToJar(outputFiles, outputStream, mainClass, jarRuntime, noReflect, resetJarTimestamps);
|
||||
outputStream.close();
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new CompileEnvironmentException("Invalid jar path " + jarPath, e);
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, "Invalid jar path: " + jarPath, null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw ExceptionUtilsKt.rethrow(e);
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
val includeRuntime = configuration.get(JVMConfigurationKeys.INCLUDE_RUNTIME, false)
|
||||
val noReflect = configuration.get(JVMConfigurationKeys.NO_REFLECT, false)
|
||||
val resetJarTimestamps = !configuration.get(JVMConfigurationKeys.NO_RESET_JAR_TIMESTAMPS, false)
|
||||
CompileEnvironmentUtil.writeToJar(jarPath, includeRuntime, noReflect, resetJarTimestamps, mainClassFqName, outputFiles)
|
||||
CompileEnvironmentUtil.writeToJar(jarPath, includeRuntime, noReflect, resetJarTimestamps, mainClassFqName, outputFiles, messageCollector)
|
||||
if (reportOutputFiles) {
|
||||
val message = OutputMessageUtil.formatOutputMessage(outputFiles.asList().flatMap { it.sourceFiles }.distinct(), jarPath)
|
||||
messageCollector.report(OUTPUT, message)
|
||||
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
ERR:
|
||||
error: directory not found: [Temp]/clashingFile
|
||||
|
||||
Return code: 1
|
||||
+1
@@ -0,0 +1 @@
|
||||
class Test
|
||||
+1
@@ -0,0 +1 @@
|
||||
Return code: 0
|
||||
@@ -0,0 +1 @@
|
||||
class Test
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
ERR:
|
||||
error: error while writing [Temp]/noPermissionDir/Test.class (Permission denied)
|
||||
|
||||
Return code: 1
|
||||
@@ -0,0 +1 @@
|
||||
class Test
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
ERR:
|
||||
error: invalid jar path: [Temp]/clashingFile/test.jar
|
||||
|
||||
Return code: 1
|
||||
+1
@@ -0,0 +1 @@
|
||||
class Test
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
ERR:
|
||||
error: invalid jar path: [Temp]/noPermissionDir/test.jar
|
||||
|
||||
Return code: 1
|
||||
@@ -0,0 +1 @@
|
||||
class A
|
||||
@@ -201,4 +201,50 @@ public class CompilerSmokeTest extends CompilerSmokeTestBase {
|
||||
runCompiler("noReflect.compile", "-include-runtime", "-no-reflect", "noReflect.kt", "-d", jar));
|
||||
run("noReflect.run", "-cp", jar, "noReflect.NoReflectKt");
|
||||
}
|
||||
|
||||
// related to KT-14772, destination is not a jar, and clashing with an existing file
|
||||
public void testDestinationDirClashingWithExistingFile() throws Exception {
|
||||
String outputDir = tmpdir.getAbsolutePath() + File.separator + "clashingFile";
|
||||
File file = new File(outputDir);
|
||||
file.createNewFile();
|
||||
runCompiler("test.compile", "test.kt", "-d", outputDir);
|
||||
}
|
||||
|
||||
// related to KT-18184, destination is not a jar, and permission denied
|
||||
public void testDestinationDirNoPermission() throws Exception {
|
||||
String outputDir = tmpdir.getAbsolutePath() + File.separator + "noPermissionDir";
|
||||
File file = new File(outputDir, "Test.class");
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
// file.getParentFile().setReadOnly(); // won't work on Windows
|
||||
file.setReadOnly(); // So we use this one as an alternative
|
||||
runCompiler("test.compile", "test.kt", "-d", outputDir);
|
||||
}
|
||||
|
||||
// related to KT-18184, destination is a jar, and output directory does not exist, we should try to create
|
||||
// output directory for it.
|
||||
public void testDestinationDirDoesNotExist() throws Exception {
|
||||
String jar = tmpdir.getAbsolutePath() + File.separator + "nonExistingDir" + File.separator + "test.jar";
|
||||
runCompiler("test.compile", "test.kt", "-d", jar);
|
||||
}
|
||||
|
||||
// related to KT-18184, destination is a jar, and output directory does not exist, and failed to created
|
||||
// output directory due to clash with existing file.
|
||||
public void testDestinationJarClashingWithExistingFile() throws Exception {
|
||||
String jar = tmpdir.getAbsolutePath() + File.separator + "clashingFile" + File.separator + "test.jar";
|
||||
File file = new File(jar);
|
||||
file.getParentFile().createNewFile();
|
||||
runCompiler("test.compile", "test.kt", "-d", jar);
|
||||
}
|
||||
|
||||
// related to KT-18184, Destination is a jar, and output directory exist, and permission denied to write jar.
|
||||
public void testDestinationJarNoPermission() throws Exception {
|
||||
String outputDir = tmpdir.getAbsolutePath() + File.separator + "noPermissionDir";
|
||||
File jar = new File(outputDir, "test.jar");
|
||||
jar.getParentFile().mkdirs();
|
||||
jar.createNewFile();
|
||||
// jar.getParentFile().setReadOnly(); // won't work on Windows
|
||||
jar.setReadOnly(); // So we use this one as an alternative
|
||||
runCompiler("test.compile", "test.kt", "-d", jar.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user