Skip to content

Commit

Permalink
Query project root from Maven/Gradle to determine the base directory …
Browse files Browse the repository at this point in the history
…for Java

* When using Java handler based build, query Maven/Gradle for the project root.
  • Loading branch information
Austin Brooks committed Apr 9, 2019
1 parent d4a0ef7 commit 6ec659c
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type" : "bugfix",
"description" : "Fix building of a Java Lambda handler failing due to unable to locate build.gradle/pom.xml Fixes #868, #857"
}
10 changes: 8 additions & 2 deletions intellijJVersions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ static def ideProfiles() {
version: "IC-2018.3.5",
plugins: [
"yaml",
"PythonCore:2018.3.183.4284.148"
"PythonCore:2018.3.183.4284.148",
"gradle",
"maven",
"properties" // Used by Maven
]
]
],
Expand All @@ -14,7 +17,10 @@ static def ideProfiles() {
version: "IC-2019.1",
plugins: [
"yaml",
"PythonCore:2019.1.191.6183.53"
"PythonCore:2019.1.191.6183.53",
"gradle",
"maven",
"properties" // Used by Maven
]
]
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package software.aws.toolkits.jetbrains.services.lambda.java

import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Before
import org.junit.Rule
import org.junit.Test
Expand Down Expand Up @@ -130,4 +131,24 @@ class JavaLambdaBuilderTest : BaseLambdaBuilderTest() {
"lib/aws-lambda-java-core-1.2.0.jar"
)
}

@Test
fun unsupportedSystem() {
val handlerPsi = projectRule.fixture.addClass(
"""
package com.example;
public class SomeClass {
public static String upperCase(String input) {
return input.toUpperCase();
}
}
""".trimIndent()
)

assertThatThrownBy {
buildLambda(projectRule.module, handlerPsi, Runtime.JAVA8, "com.example.SomeClass")
}.isInstanceOf(IllegalStateException::class.java)
.hasMessageEndingWith("is not managed by Maven or Gradle")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,36 @@

package software.aws.toolkits.jetbrains.services.lambda.java

import com.intellij.openapi.Disposable
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
import com.intellij.openapi.externalSystem.service.project.ExternalProjectRefreshCallback
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager
import com.intellij.openapi.externalSystem.settings.ExternalSystemSettingsListenerAdapter
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
import com.intellij.psi.PsiClass
import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.runInEdtAndWait
import com.intellij.util.io.isDirectory
import com.intellij.util.io.readBytes
import com.intellij.util.io.write
import org.jetbrains.idea.maven.project.MavenProjectsManager
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
import org.junit.Assert.fail
import software.aws.toolkits.core.utils.exists
import software.aws.toolkits.jetbrains.utils.rules.HeavyJavaCodeInsightTestFixtureRule
import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
Expand All @@ -17,7 +42,7 @@ import java.nio.file.Paths

internal fun HeavyJavaCodeInsightTestFixtureRule.setUpGradleProject(): PsiClass {
val fixture = this.fixture
fixture.addFileToModule(
val buildFile = fixture.addFileToModule(
this.module,
"build.gradle",
"""
Expand All @@ -34,12 +59,12 @@ internal fun HeavyJavaCodeInsightTestFixtureRule.setUpGradleProject(): PsiClass
testCompile 'junit:junit:4.12'
}
""".trimIndent()
)
).virtualFile

// Use our project's own Gradle version
copyGradleFiles(this)

return fixture.addClass(
val lambdaClass = fixture.addClass(
"""
package com.example;
Expand All @@ -50,6 +75,68 @@ internal fun HeavyJavaCodeInsightTestFixtureRule.setUpGradleProject(): PsiClass
}
""".trimIndent()
)

val jdkHome = IdeaTestUtil.requireRealJdkHome()
VfsRootAccess.allowRootAccess(fixture.testRootDisposable, jdkHome)
val jdkHomeDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(jdkHome)!!
val jdkName = "Gradle JDK"
val jdk = SdkConfigurationUtil.setupSdk(emptyArray(), jdkHomeDir, JavaSdk.getInstance(), false, null, jdkName)!!

WriteAction.runAndWait<Nothing> {
ProjectJdkTable.getInstance().addJdk(jdk)
}

Disposer.register(
fixture.testRootDisposable,
Disposable { WriteAction.runAndWait<Nothing> { ProjectJdkTable.getInstance().removeJdk(jdk) } })

ExternalSystemApiUtil.subscribe(
project,
GradleConstants.SYSTEM_ID,
object : ExternalSystemSettingsListenerAdapter<GradleProjectSettings>() {
override fun onProjectsLinked(settings: Collection<GradleProjectSettings>) {
super.onProjectsLinked(settings)
settings.first().gradleJvm = jdkName
}
})

val gradleProjectSettings = GradleProjectSettings().apply {
withQualifiedModuleNames()
externalProjectPath = buildFile.path
}

val externalSystemSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
externalSystemSettings.setLinkedProjectsSettings(setOf(gradleProjectSettings))

val error = Ref.create<String>()

val refreshCallback = object : ExternalProjectRefreshCallback {
override fun onSuccess(externalProject: DataNode<ProjectData>?) {
if (externalProject == null) {
System.err.println("Got null External project after import")
return
}
ServiceManager.getService(ProjectDataManager::class.java).importData(externalProject, project, true)
println("External project was successfully imported")
}

override fun onFailure(errorMessage: String, errorDetails: String?) {
error.set(errorMessage)
}
}

val importSpecBuilder = ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
.callback(refreshCallback)
.forceWhenUptodate()
.use(ProgressExecutionMode.MODAL_SYNC)

ExternalSystemUtil.refreshProjects(importSpecBuilder)

if (!error.isNull) {
fail("Import failed: " + error.get())
}

return lambdaClass
}

private fun copyGradleFiles(fixtureRule: HeavyJavaCodeInsightTestFixtureRule) {
Expand Down Expand Up @@ -101,7 +188,7 @@ private fun findGradlew(): Path {

internal fun HeavyJavaCodeInsightTestFixtureRule.setUpMavenProject(): PsiClass {
val fixture = this.fixture
fixture.addFileToModule(
val pomFile = fixture.addFileToModule(
this.module,
"pom.xml",
"""
Expand Down Expand Up @@ -133,9 +220,9 @@ internal fun HeavyJavaCodeInsightTestFixtureRule.setUpMavenProject(): PsiClass {
</dependencies>
</project>
""".trimIndent()
)
).virtualFile

return fixture.addClass(
val lambdaClass = fixture.addClass(
"""
package com.example;
Expand All @@ -146,4 +233,15 @@ internal fun HeavyJavaCodeInsightTestFixtureRule.setUpMavenProject(): PsiClass {
}
""".trimIndent()
)

val projectsManager = MavenProjectsManager.getInstance(project)
projectsManager.addManagedFilesOrUnignore(listOf(pomFile))

runInEdtAndWait {
projectsManager.waitForResolvingCompletion()
projectsManager.performScheduledImportInTests()
projectsManager.importProjects()
}

return lambdaClass
}
5 changes: 5 additions & 0 deletions jetbrains-core/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ If you come across bugs with the toolkit or have feature requests, please raise

<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<!-- All dependencies have to be defined here, you can't define more in an optional config-file,
See PluginManagerCore#mergeOptionalConfigs -->
<depends>com.intellij.modules.lang</depends>
<depends>org.jetbrains.plugins.yaml</depends>

<depends optional="true">org.jetbrains.idea.maven</depends>
<depends optional="true">com.intellij.modules.externalSystem</depends>>
<depends optional="true" config-file="ext-java.xml">com.intellij.modules.java</depends>
<depends optional="true" config-file="ext-python.xml">com.intellij.modules.python</depends>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
package software.aws.toolkits.jetbrains.services.lambda.java

import com.intellij.execution.process.ProcessHandler
import com.intellij.ide.plugins.PluginManager
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.externalSystem.ExternalSystemModulePropertyManager
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import org.jetbrains.idea.maven.project.MavenProjectsManager
import software.amazon.awssdk.services.lambda.model.Runtime
import software.aws.toolkits.jetbrains.services.lambda.BuiltLambda
import software.aws.toolkits.jetbrains.services.lambda.LambdaBuilder
Expand All @@ -27,20 +30,35 @@ class JavaLambdaBuilder : LambdaBuilder() {
samOptions: SamOptions,
onStart: (ProcessHandler) -> Unit
): CompletionStage<BuiltLambda> {
val baseDir = getBaseDirectory(module).path
val baseDir = when {
isGradle(module) -> getGradleProjectLocation(module)
isMaven(module) -> getPomLocation(module)
else -> throw IllegalStateException(message("lambda.build.java.unsupported_build_system", module))
}
val customTemplate = FileUtil.createTempFile("template", ".yaml", true)
val logicalId = "Function"
SamTemplateUtils.writeDummySamTemplate(customTemplate, logicalId, runtime, baseDir, handler, envVars)

return buildLambdaFromTemplate(module, customTemplate.toPath(), logicalId, samOptions, onStart)
}

private fun getBaseDirectory(module: Module): VirtualFile {
val rootManager = ModuleRootManager.getInstance(module)
val contentRoots = rootManager.contentRoots
return when (contentRoots.size) {
1 -> contentRoots[0]
else -> throw IllegalArgumentException(message("lambda.build.too_many_content_roots"))
private fun isGradle(module: Module): Boolean = ExternalSystemModulePropertyManager.getInstance(module)
.getExternalSystemId() == "GRADLE"

private fun getGradleProjectLocation(module: Module): String =
ExternalSystemApiUtil.getExternalProjectPath(module)
?: throw IllegalStateException(message("lambda.build.unable_to_locate_project_root", module))

private fun isMaven(module: Module): Boolean {
if (PluginManager.getPlugin(PluginId.getId("org.jetbrains.idea.maven"))?.isEnabled == true) {
return MavenProjectsManager.getInstance(module.project).isMavenizedModule(module)
}

return false
}

private fun getPomLocation(module: Module): String =
MavenProjectsManager.getInstance(module.project).findProject(module)?.directory ?: throw IllegalStateException(
message("lambda.build.unable_to_locate_project_root", module)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,5 @@ cloudformation.execute_change_set.success=Successfully executed change set again
cloudformation.execute_change_set.success.title=Successfully executed change set
cloudformation.execute_change_set.failed=Failed to execute change set against {0}
cloudformation.toolwindow.label=CloudFormation
lambda.build.too_many_content_roots=Module can only have 1 content root
lambda.build.unable_to_locate_project_root=Unable to locate project diretory for Module ''%s''
lambda.build.java.unsupported_build_system=Module ''%s'' is not managed by Maven or Gradle

0 comments on commit 6ec659c

Please sign in to comment.