Skip to content

Commit

Permalink
Remove the BaseState system from run configs (#1073)
Browse files Browse the repository at this point in the history
* It kept having aliasing issues related to editing a cloned run config
* It kept us from 192 due to NoSuchMethod error
  • Loading branch information
abrooksv authored and Zhaoxi Zhang committed Aug 1, 2019
1 parent 344b90f commit 81b36d7
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type" : "bugfix",
"description" : "Fix issue where modifying a cloned run config results in mutation of the original"
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ abstract class LambdaRunConfigurationBase<T : BaseLambdaOptions>(
RunConfigurationWithSuppressedDefaultRunAction,
RunConfigurationWithSuppressedDefaultDebugAction {

protected abstract val lambdaOptions: BaseLambdaOptions
protected abstract val state: BaseLambdaOptions

final override fun readExternal(element: Element) {
super.readExternal(element)
XmlSerializer.deserializeInto(lambdaOptions, element)
XmlSerializer.deserializeInto(state, element)
}

final override fun writeExternal(element: Element) {
super.writeExternal(element)
XmlSerializer.serializeInto(lambdaOptions, element)
XmlSerializer.serializeInto(state, element)
}

@Suppress("UNCHECKED_CAST")
Expand All @@ -55,20 +55,20 @@ abstract class LambdaRunConfigurationBase<T : BaseLambdaOptions>(
}

fun useInputFile(inputFile: String?) {
val inputOptions = lambdaOptions.inputOptions
val inputOptions = state.inputOptions
inputOptions.inputIsFile = true
inputOptions.input = inputFile
}

fun useInputText(input: String?) {
val inputOptions = lambdaOptions.inputOptions
val inputOptions = state.inputOptions
inputOptions.inputIsFile = false
inputOptions.input = input
}

fun isUsingInputFile() = lambdaOptions.inputOptions.inputIsFile
fun isUsingInputFile() = state.inputOptions.inputIsFile

fun inputSource() = lambdaOptions.inputOptions.input
fun inputSource() = state.inputOptions.input

protected fun checkInput() {
inputSource()?.let {
Expand Down Expand Up @@ -100,10 +100,10 @@ abstract class LambdaRunConfigurationBase<T : BaseLambdaOptions>(
}
} ?: throw RuntimeConfigurationError(message("lambda.run_configuration.no_input_specified"))

fun credentialProviderId() = lambdaOptions.accountOptions.credentialProviderId
fun credentialProviderId() = state.accountOptions.credentialProviderId

fun credentialProviderId(credentialsProviderId: String?) {
lambdaOptions.accountOptions.credentialProviderId = credentialsProviderId
state.accountOptions.credentialProviderId = credentialsProviderId
}

protected fun resolveCredentials() = credentialProviderId()?.let {
Expand All @@ -121,10 +121,10 @@ abstract class LambdaRunConfigurationBase<T : BaseLambdaOptions>(
}
} ?: throw RuntimeConfigurationError(message("lambda.run_configuration.no_credentials_specified"))

fun regionId() = lambdaOptions.accountOptions.regionId
fun regionId() = state.accountOptions.regionId

fun regionId(regionId: String?) {
lambdaOptions.accountOptions.regionId = regionId
state.accountOptions.regionId = regionId
}

protected fun resolveRegion() = regionId()?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,9 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.listeners.RefactoringElementAdapter
import com.intellij.refactoring.listeners.RefactoringElementListener
import com.intellij.util.ExceptionUtil
import org.jetbrains.concurrency.isPending
import software.amazon.awssdk.services.lambda.model.Runtime
import software.aws.toolkits.core.credentials.ToolkitCredentialsProvider
import software.aws.toolkits.core.region.AwsRegion
import software.aws.toolkits.core.utils.getLogger
import software.aws.toolkits.core.utils.info
import software.aws.toolkits.core.utils.tryOrNull
import software.aws.toolkits.jetbrains.services.lambda.Lambda.findPsiElementsForHandler
import software.aws.toolkits.jetbrains.services.lambda.LambdaHandlerResolver
Expand All @@ -38,10 +34,8 @@ import software.aws.toolkits.jetbrains.services.lambda.runtimeGroup
import software.aws.toolkits.jetbrains.services.lambda.sam.SamCommon
import software.aws.toolkits.jetbrains.services.lambda.sam.SamOptions
import software.aws.toolkits.jetbrains.services.lambda.sam.SamTemplateUtils.findFunctionsFromTemplate
import software.aws.toolkits.jetbrains.services.lambda.sam.SamVersionCache
import software.aws.toolkits.jetbrains.services.lambda.validOrNull
import software.aws.toolkits.jetbrains.settings.AwsSettingsConfigurable
import software.aws.toolkits.jetbrains.settings.SamSettings
import software.aws.toolkits.resources.message
import java.nio.file.Path

Expand All @@ -54,11 +48,7 @@ class LocalLambdaRunConfigurationFactory(configuration: LambdaRunConfiguration)
class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactory) :
LambdaRunConfigurationBase<LocalLambdaOptions>(project, factory, "SAM CLI"),
RefactoringListenerProvider {
companion object {
private val logger = getLogger<LocalLambdaRunConfiguration>()
}

override val lambdaOptions = LocalLambdaOptions()
override val state = LocalLambdaOptions()

override fun getConfigurationEditor(): SettingsEditor<LocalLambdaRunConfiguration> {
val group = SettingsEditorGroup<LocalLambdaRunConfiguration>()
Expand All @@ -68,24 +58,7 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
}

override fun checkConfiguration() {
val executablePath = SamSettings.getInstance().executablePath
?: throw RuntimeConfigurationError(message("sam.cli_not_configured"))

val promise = SamVersionCache.evaluate(executablePath)

if (promise.isPending) {
logger.info { "Validation will proceed asynchronously for SAM CLI version" }
throw RuntimeConfigurationError(message("lambda.run_configuration.sam.validation.in_progress"))
}

val errorMessage = try {
val semVer = promise.blockingGet(0)!!
SamCommon.getInvalidVersionMessage(semVer)
} catch (e: Exception) {
ExceptionUtil.getRootCause(e).message ?: message("general.unknown_error")
}

errorMessage?.let {
SamCommon.validate()?.let {
throw RuntimeConfigurationError(message("lambda.run_configuration.sam.invalid_executable", it)) {
ShowSettingsUtil.getInstance().showSettingsDialog(project, AwsSettingsConfigurable::class.java)
}
Expand All @@ -105,7 +78,7 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
val psiElement = handlerPsiElement(handler, runtime)
?: throw RuntimeConfigurationError(message("lambda.run_configuration.handler_not_found", handler))

val samRunSettings = LocalLambdaRunSettings(
val samRunSettings = LocalLambdaSettings(
runtime,
handler,
resolveInput(),
Expand All @@ -114,7 +87,7 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
resolveRegion(),
psiElement,
templateDetails,
lambdaOptions.samOptions.copy()
state.samOptions.copy()
)

return SamRunningState(environment, samRunSettings)
Expand All @@ -133,16 +106,16 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor

if (PsiTreeUtil.isAncestor(element, handlerPsi, false)) {
return object : RefactoringElementAdapter() {
private val originalHandler = lambdaOptions.functionOptions.handler
private val originalHandler = state.functionOptions.handler

override fun elementRenamedOrMoved(newElement: PsiElement) {
handlerResolver.determineHandler(handlerPsi)?.let { newHandler ->
lambdaOptions.functionOptions.handler = newHandler
state.functionOptions.handler = newHandler
}
}

override fun undoElementMovedOrRenamed(newElement: PsiElement, oldQualifiedName: String) {
lambdaOptions.functionOptions.handler = originalHandler
state.functionOptions.handler = originalHandler
}
}
}
Expand All @@ -151,7 +124,7 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
}

fun useTemplate(templateLocation: String?, logicalId: String?) {
val functionOptions = lambdaOptions.functionOptions
val functionOptions = state.functionOptions
functionOptions.useTemplate = true

functionOptions.templateFile = templateLocation
Expand All @@ -162,7 +135,7 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
}

fun useHandler(runtime: Runtime?, handler: String?) {
val functionOptions = lambdaOptions.functionOptions
val functionOptions = state.functionOptions
functionOptions.useTemplate = false

functionOptions.templateFile = null
Expand All @@ -172,47 +145,47 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
functionOptions.runtime = runtime.toString()
}

fun isUsingTemplate() = lambdaOptions.functionOptions.useTemplate
fun isUsingTemplate() = state.functionOptions.useTemplate

fun templateFile() = lambdaOptions.functionOptions.templateFile
fun templateFile() = state.functionOptions.templateFile

fun logicalId() = lambdaOptions.functionOptions.logicalId
fun logicalId() = state.functionOptions.logicalId

fun handler() = lambdaOptions.functionOptions.handler
fun handler() = state.functionOptions.handler

fun runtime(): Runtime? = Runtime.fromValue(lambdaOptions.functionOptions.runtime)?.validOrNull
fun runtime(): Runtime? = Runtime.fromValue(state.functionOptions.runtime)?.validOrNull

fun environmentVariables() = lambdaOptions.functionOptions.environmentVariables
fun environmentVariables() = state.functionOptions.environmentVariables

fun environmentVariables(envVars: Map<String, String>) {
lambdaOptions.functionOptions.environmentVariables = envVars
state.functionOptions.environmentVariables = envVars
}

fun dockerNetwork(): String? = lambdaOptions.samOptions.dockerNetwork
fun dockerNetwork(): String? = state.samOptions.dockerNetwork

fun dockerNetwork(network: String?) {
lambdaOptions.samOptions.dockerNetwork = network
state.samOptions.dockerNetwork = network
}

fun skipPullImage(): Boolean = lambdaOptions.samOptions.skipImagePull
fun skipPullImage(): Boolean = state.samOptions.skipImagePull

fun skipPullImage(skip: Boolean) {
lambdaOptions.samOptions.skipImagePull = skip
state.samOptions.skipImagePull = skip
}

fun buildInContainer(): Boolean = lambdaOptions.samOptions.buildInContainer
fun buildInContainer(): Boolean = state.samOptions.buildInContainer

fun buildInContainer(useContainer: Boolean) {
lambdaOptions.samOptions.buildInContainer = useContainer
state.samOptions.buildInContainer = useContainer
}

override fun suggestedName(): String? {
val subName = lambdaOptions.functionOptions.logicalId ?: handlerDisplayName()
val subName = state.functionOptions.logicalId ?: handlerDisplayName()
return "[${message("lambda.run_configuration.local")}] $subName"
}

private fun handlerDisplayName(): String? {
val handler = lambdaOptions.functionOptions.handler ?: return null
val handler = state.functionOptions.handler ?: return null
return runtime()
?.runtimeGroup
?.let { LambdaHandlerResolver.getInstance(it) }
Expand Down Expand Up @@ -269,7 +242,7 @@ class LocalLambdaRunConfiguration(project: Project, factory: ConfigurationFactor
}
}

data class LocalLambdaRunSettings(
class LocalLambdaSettings(
val runtime: Runtime,
val handler: String,
val input: String,
Expand Down
Loading

0 comments on commit 81b36d7

Please sign in to comment.