Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support .srcjar files as source roots #3649

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
addCommonSourceFiles(arg)
}

if (File(arg).isDirectory) {
if (arg.endsWith(".srcjar") || File(arg).isDirectory) {
addJavaSourceRoot(JavaRootPath(arg, args.javaPackagePrefix))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ class KotlinCoreEnvironment private constructor(
is JvmModulePathRoot ->
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Java module root")
is JavaSourceRoot ->
findExistingRoot(root, "Java source root")
if (root.file.isFile && root.file.path.endsWith(".srcjar")) findJarRoot(root.file)
else findExistingRoot(root, "Java source root")
else ->
throw IllegalStateException("Unexpected root: $root")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ package org.jetbrains.kotlin.cli.jvm.compiler
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager
import com.intellij.util.io.URLUtil.JAR_SEPARATOR
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
Expand All @@ -21,7 +23,6 @@ import org.jetbrains.kotlin.extensions.PreprocessedFileCreator
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
import java.io.File

fun CompilerConfiguration.report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation? = null) {
get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)?.report(severity, message, location)
Expand All @@ -33,8 +34,9 @@ fun createSourceFilesFromSourceRoots(
sourceRoots: List<KotlinSourceRoot>,
reportLocation: CompilerMessageLocation? = null
): MutableList<KtFile> {
val localFileSystem = VirtualFileManager.getInstance()
.getFileSystem(StandardFileSystems.FILE_PROTOCOL)
val fileManager = VirtualFileManager.getInstance()
val localFileSystem = fileManager.getFileSystem(StandardFileSystems.FILE_PROTOCOL)
val jarFileSystem = fileManager.getFileSystem(StandardFileSystems.JAR_PROTOCOL)
val psiManager = PsiManager.getInstance(project)

val processedFiles = hashSetOf<VirtualFile>()
Expand All @@ -43,7 +45,7 @@ fun createSourceFilesFromSourceRoots(
val virtualFileCreator = PreprocessedFileCreator(project)

for ((sourceRootPath, isCommon) in sourceRoots) {
val vFile = localFileSystem.findFileByPath(sourceRootPath)
var vFile = localFileSystem.findFileByPath(sourceRootPath)
if (vFile == null) {
val message = "Source file or directory not found: $sourceRootPath"

Expand All @@ -57,16 +59,24 @@ fun createSourceFilesFromSourceRoots(
continue
}

if (!vFile.isDirectory && vFile.fileType != KotlinFileType.INSTANCE) {

val isFile = !vFile.isDirectory
if (isFile && vFile.path.endsWith(".srcjar")) {
vFile = jarFileSystem.findFileByPath(vFile.path + JAR_SEPARATOR)
if (vFile == null) {
configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a valid srcjar: $sourceRootPath", reportLocation)
continue
}
} else if (isFile && vFile.fileType != KotlinFileType.INSTANCE) {
configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation)
continue
}

for (file in File(sourceRootPath).walkTopDown()) {
if (!file.isFile) continue
VfsUtilCore.processFilesRecursively(vFile) { child ->
if (child.isDirectory) return@processFilesRecursively true

val virtualFile = localFileSystem.findFileByPath(file.absolutePath)?.let(virtualFileCreator::create)
if (virtualFile != null && processedFiles.add(virtualFile)) {
val virtualFile = virtualFileCreator.create(child)
if (processedFiles.add(virtualFile)) {
val psiFile = psiManager.findFile(virtualFile)
if (psiFile is KtFile) {
result.add(psiFile)
Expand All @@ -75,6 +85,7 @@ fun createSourceFilesFromSourceRoots(
}
}
}
return@processFilesRecursively true
}
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/testData/integration/smoke/srcjar/Bar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class Bar {
public static void bar() {
System.out.println("bar");
}
}
3 changes: 3 additions & 0 deletions compiler/testData/integration/smoke/srcjar/Foo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fun foo() {
println("foo")
}
4 changes: 4 additions & 0 deletions compiler/testData/integration/smoke/srcjar/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fun main() {
foo()
Bar.bar()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Return code: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.integration

import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

/**
* Tests the ability to compile sources contained in .srcjar files.
* This is useful in build systems like Bazel, where .srcjar files are used to hold generated sources.
*/
class CompilerSrcjarTest : CompilerSmokeTestBase() {
fun testSrcjar() {
val tmp = KotlinTestUtils.tmpDir("CompilerSrcjarTest.testSrcjar.tmp")
val src = File(testDataDir)

val main = File(src, "Main.kt")
val foo = File(src, "Foo.kt")
val bar = File(src, "Bar.java")

runCompiler("normal.compile", main.absolutePath, foo.absolutePath, bar.absolutePath, "-d", tmp.absolutePath)

val foobar = File(tmp, "FooBar.srcjar")
ZipOutputStream(foobar.outputStream().buffered()).use { srcjar ->
srcjar.addZipEntry(foo.name, foo.readBytes())
srcjar.addZipEntry(bar.name, bar.readBytes())
}

runCompiler("srcjar.compile", main.absolutePath, foobar.absolutePath, "-d", tmp.absolutePath)
}

private fun ZipOutputStream.addZipEntry(name: String, content: ByteArray) {
putNextEntry(ZipEntry(name))
write(content)
closeEntry()
}
}