in sources/amper-cli/src/org/jetbrains/amper/tasks/jvm/JvmCompileTask.kt [133:271]
override suspend fun run(dependenciesResult: List<TaskResult>, executionContext: TaskGraphExecutionContext): TaskResult {
require(fragments.isNotEmpty()) {
"fragments list is empty for jvm compile task, module=${module.userReadableName}"
}
logger.debug("compile ${module.userReadableName} -- ${fragments.userReadableList()}")
val mavenDependencies = dependenciesResult
.filterIsInstance<ResolveExternalDependenciesTask.Result>()
.singleOrNull()
?: error("Expected one and only one dependency on (${ResolveExternalDependenciesTask.Result::class.java.simpleName}) input, but got: ${dependenciesResult.joinToString { it.javaClass.simpleName }}")
val compileModuleDependencies = dependenciesResult.filterIsInstance<Result>()
val javaAnnotationProcessorClasspath = dependenciesResult
.filterIsInstance<JavaAnnotationProcessorClasspathTask.Result>()
.singleOrNull()
?.processorClasspath
?: emptyList()
val productionJvmCompileResult = if (isTest) {
compileModuleDependencies.firstOrNull { it.module == module && !it.isTest }
?: error("jvm compilation result from production compilation result was not found for module=${module.userReadableName}, task=$taskName")
} else null
val userSettings = fragments.singleLeafFragment().serializableCompilationSettings()
val additionalClasspath = dependenciesResult.filterIsInstance<AdditionalClasspathProvider>().flatMap { it.compileClasspath }
val classpath =
compileModuleDependencies.flatMap { it.classesOutputRoots } + mavenDependencies.compileClasspath + additionalClasspath
// Collect additional source roots.
val additionalArtifactSources = additionalKotlinJavaSourceDirs.map { artifact ->
SourceRoot(
fragmentName = artifact.fragmentName,
path = artifact.path,
)
}
val additionalSourceRootsFromMaven = dependenciesResult
.filterIsInstance<MavenPhaseResult>()
.flatMap { it.sourceRoots }
.distinctBy { it.path } // Need to remove duplicates, because a same path can be provided by multiple providers.
val additionalSources = additionalArtifactSources + additionalSourceRootsFromMaven
val additionalResources = additionalResourcesDirs.map { artifact ->
SourceRoot(
fragmentName = artifact.fragmentName,
path = artifact.path,
)
}
val jdk = jdkProvider.getJdkOrUserError(jdkSettings = module.jdkSettings)
val javaAnnotationProcessorsGeneratedDir =
fragments.singleLeafFragment().javaAnnotationProcessingGeneratedSourcesPath(buildOutputRoot.path)
val inputValues = mapOf(
"jdk.version" to jdk.version,
"jdk.home" to jdk.homeDir.pathString,
"user.settings" to Json.encodeToString(userSettings),
"task.output.root" to taskOutputRoot.pathString,
"target.platforms" to module.leafPlatforms.map { it.name }.sorted().joinToString(),
"java.annotation.processor.generated.dir" to javaAnnotationProcessorsGeneratedDir.pathString
)
val sources = fragments.flatMap { it.sourceRoots }.map { it.toAbsolutePath() } + additionalSources.map { it.path }
val resources = fragments.map { it.resourcesPath }.map { it.toAbsolutePath() } + additionalResources.map { it.path }
val inputFiles = sources + resources + classpath + javaAnnotationProcessorClasspath
val result = incrementalCache.execute(taskName.name, inputValues, inputFiles) {
cleanDirectory(javaAnnotationProcessorsGeneratedDir)
if (!shouldCompileJavaIncrementally(userSettings.java, javaAnnotationProcessorClasspath)) {
cleanDirectory(taskOutputRoot)
}
javaCompilerOutputRoot.createDirectories()
kotlinCompilerOutputRoot.createDirectories()
resourcesRoot.createDirectories()
val nonEmptySourceDirs = sources
.filter {
when {
it.isDirectory() -> it.listDirectoryEntries().isNotEmpty()
it.exists() ->
error("Source directory at '$it' exists, but it's not a directory, this is currently unsupported")
else -> false
}
}
val outputPaths = mutableListOf<Path>()
outputPaths.add(javaCompilerOutputRoot.toAbsolutePath())
outputPaths.add(kotlinCompilerOutputRoot.toAbsolutePath())
if (nonEmptySourceDirs.isNotEmpty()) {
compileSources(
jdk = jdk,
sourceDirectories = nonEmptySourceDirs,
additionalSources = additionalSources,
userSettings = userSettings,
classpath = classpath,
friendPaths = productionJvmCompileResult?.classesOutputRoots.orEmpty(),
javaAnnotationProcessorClasspath = javaAnnotationProcessorClasspath,
javaAnnotationProcessorsGeneratedDir = javaAnnotationProcessorsGeneratedDir,
tempRoot = tempRoot,
)
if (javaAnnotationProcessorsGeneratedDir.exists()) {
outputPaths.add(javaAnnotationProcessorsGeneratedDir)
}
} else {
logger.debug("No sources were found for ${fragments.identificationPhrase()}, skipping compilation")
}
val presentResources = resources.filter { it.exists() }
for (resource in presentResources) {
val dest = if (resource.isDirectory()) {
resourcesRoot
} else {
resourcesRoot / resource.fileName
}
logger.debug("Copying resources from '{}' to '{}'...", resource, dest)
// if we compile incrementally, then we don't clean the output dir => overwrite instead of failing that a file exists
val overwrite = shouldCompileJavaIncrementally(userSettings.java, javaAnnotationProcessorClasspath)
BuildPrimitives.copy(from = resource, to = dest, overwrite = overwrite)
}
return@execute IncrementalCache.ExecutionResult(outputPaths)
}
return Result(
classesOutputRoots = listOf(
javaCompilerOutputRoot,
kotlinCompilerOutputRoot,
resourcesRoot
).map { it.toAbsolutePath() },
module = module,
isTest = isTest,
changes = result.changes,
)
}