Skip to content

Commit eb243de

Browse files
ArtManyakrli
andauthored
Moved to the new customization API of new solution dialog. (#4153)
Rewrite integration with the New Solution dialog in Rider to use the new API. Without this, in 2024.1 the plugin won't provide any extension for the New Solution dialog. Co-authored-by: Richard Li <[email protected]>
1 parent 83ead2f commit eb243de

File tree

11 files changed

+248
-2
lines changed

11 files changed

+248
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Rewrite integration with the New Solution dialog in Rider to use the new API."
4+
}

plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,7 @@ sam.init.execution_error=Could not execute `sam init`!
16171617
sam.init.generating.schema=Generating Schema
16181618
sam.init.generating.template=Generating SAM template
16191619
sam.init.go.sdk=Go SDK:
1620+
sam.init.group.name=Other
16201621
sam.init.name=AWS Serverless Application
16211622
sam.init.node_interpreter.label=Node interpreter:
16221623
sam.init.packaging=Package Type:
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
2+
<!-- SPDX-License-Identifier: Apache-2.0 -->
3+
4+
<idea-plugin>
5+
<extensions defaultExtensionNs="com.intellij">
6+
<projectTemplateProvider implementation="software.aws.toolkits.jetbrains.services.lambda.dotnet.DotNetSamProjectProvider" order="last"/>
7+
</extensions>
8+
</idea-plugin>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
2+
<!-- SPDX-License-Identifier: Apache-2.0 -->
3+
4+
<idea-plugin>
5+
<extensions defaultExtensionNs="com.intellij">
6+
<projectTemplateProviderNew implementation="software.aws.toolkits.jetbrains.services.lambda.dotnet.DotNetSamProjectProvider" order="last"/>
7+
</extensions>
8+
</idea-plugin>

plugins/toolkit/jetbrains-rider/resources/META-INF/ext-rider.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<!-- Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
22
<!-- SPDX-License-Identifier: Apache-2.0 -->
33

4-
<idea-plugin>
4+
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
5+
<xi:include href="/META-INF/ext-rider-wizard.xml">
6+
<xi:fallback/>
7+
</xi:include>
58

69
<project-components>
710
<component>
@@ -18,7 +21,6 @@
1821
</projectListeners>
1922

2023
<extensions defaultExtensionNs="com.intellij">
21-
<projectTemplateProvider implementation="software.aws.toolkits.jetbrains.services.lambda.dotnet.DotNetSamProjectProvider" order="last"/>
2224
<postStartupActivity implementation="software.aws.toolkits.jetbrains.icons.RiderAwsIconsPatcherRegistrar"/>
2325
<postStartupActivity implementation="software.aws.toolkits.jetbrains.settings.RiderSyncSettings"/>
2426
</extensions>
File renamed without changes.
File renamed without changes.
File renamed without changes.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.lambda.dotnet
5+
6+
import com.intellij.openapi.module.ModuleManager
7+
import com.intellij.openapi.progress.DumbProgressIndicator
8+
import com.intellij.openapi.progress.blockingContext
9+
import com.intellij.openapi.project.rootManager
10+
import com.intellij.openapi.util.io.FileUtil
11+
import com.intellij.openapi.vfs.LocalFileSystem
12+
import com.jetbrains.rd.util.lifetime.Lifetime
13+
import com.jetbrains.rider.ideaInterop.fileTypes.msbuild.CsprojFileType
14+
import com.jetbrains.rider.projectView.SolutionManager
15+
import com.jetbrains.rider.projectView.projectTemplates.NewProjectDialogContext
16+
import com.jetbrains.rider.projectView.projectTemplates.ProjectTemplatesSharedModel
17+
import com.jetbrains.rider.projectView.projectTemplates.utils.ProjectTemplatesExpanderUtils
18+
import kotlinx.coroutines.launch
19+
import software.aws.toolkits.jetbrains.core.coroutines.applicationCoroutineScope
20+
import software.aws.toolkits.resources.message
21+
import java.io.File
22+
23+
class DotNetSamProjectGenerator(
24+
lifetime: Lifetime,
25+
private val context: NewProjectDialogContext,
26+
sharedModel: ProjectTemplatesSharedModel
27+
) : DotNetSamProjectGeneratorRoot(lifetime, context, sharedModel) {
28+
override suspend fun expandTemplate(): suspend () -> Unit = {
29+
val samPanel = getSamPanel()
30+
val generator = getSamGenerator()
31+
val samSettings = samPanel.getNewProjectSettings()
32+
33+
val solutionDirectory = getSolutionDirectory()
34+
?: throw Exception(message("sam.init.error.no.solution.basepath"))
35+
36+
val fileSystem = LocalFileSystem.getInstance()
37+
if (!solutionDirectory.exists()) {
38+
FileUtil.createDirectory(solutionDirectory)
39+
}
40+
41+
val outDirVf = blockingContext {
42+
fileSystem.refreshAndFindFileByIoFile(solutionDirectory)
43+
?: throw Exception(message("sam.init.error.no.virtual.file"))
44+
}
45+
46+
val samProjectBuilder = generator.createModuleBuilder()
47+
samProjectBuilder.runSamInit(
48+
context.project,
49+
projectNameProperty.get(),
50+
samSettings,
51+
null,
52+
outDirVf
53+
)
54+
55+
// Create solution file
56+
val projectFiles =
57+
File(solutionDirectory, "src").walk().filter { it.extension == CsprojFileType.defaultExtension } +
58+
File(solutionDirectory, "test").walk().filter { it.extension == CsprojFileType.defaultExtension }
59+
60+
// Get the rest of generated files and copy to "SolutionItems" default folder in project structure
61+
val solutionFiles = solutionDirectory.listFiles()?.filter { it.isFile }?.toList() ?: emptyList()
62+
63+
val solutionFile = ProjectTemplatesExpanderUtils.expandSolution(
64+
name = solutionNameProperty.get(),
65+
directory = solutionDirectory,
66+
projectFiles = projectFiles.toList(),
67+
protocolHost = context.protocolHost,
68+
solutionFiles = solutionFiles
69+
) ?: throw Exception(message("sam.init.error.solution.create.fail"))
70+
71+
applicationCoroutineScope().launch {
72+
val project =
73+
SolutionManager.openExistingSolution(
74+
projectToClose = null,
75+
forceOpenInNewFrame = false,
76+
solutionFile = solutionFile,
77+
forceConsiderTrusted = true
78+
) ?: return@launch
79+
if (createGitRepositoryProperty.get() && repositoryInitializer.canInit()) {
80+
repositoryInitializer.execute(project)
81+
}
82+
83+
val modifiableModel = ModuleManager.getInstance(project).modules.firstOrNull()?.rootManager?.modifiableModel ?: return@launch
84+
try {
85+
val progressIndicator = DumbProgressIndicator()
86+
87+
samProjectBuilder.runPostSamInit(project, modifiableModel, progressIndicator, samSettings, outDirVf)
88+
} finally {
89+
modifiableModel.dispose()
90+
}
91+
}
92+
}
93+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.lambda.dotnet
5+
6+
import com.intellij.openapi.ui.DialogPanel
7+
import com.intellij.openapi.ui.ValidationInfo
8+
import com.intellij.ui.dsl.builder.Align
9+
import com.intellij.ui.dsl.builder.panel
10+
import com.jetbrains.rd.util.lifetime.Lifetime
11+
import com.jetbrains.rider.model.RdProjectTemplate2
12+
import com.jetbrains.rider.projectView.projectTemplates.NewProjectDialogContext
13+
import com.jetbrains.rider.projectView.projectTemplates.ProjectTemplatesSharedModel
14+
import com.jetbrains.rider.projectView.projectTemplates.StatusMessageType
15+
import com.jetbrains.rider.projectView.projectTemplates.StatusMessages
16+
import com.jetbrains.rider.projectView.projectTemplates.generators.ProjectTemplateGeneratorBase
17+
import software.aws.toolkits.jetbrains.services.lambda.BuiltInRuntimeGroups
18+
import software.aws.toolkits.jetbrains.services.lambda.RuntimeGroup
19+
import software.aws.toolkits.jetbrains.services.lambda.wizard.SamInitSelectionPanel
20+
import software.aws.toolkits.jetbrains.services.lambda.wizard.SamProjectGenerator
21+
import software.aws.toolkits.jetbrains.utils.DotNetRuntimeUtils
22+
import javax.swing.JComponent
23+
24+
abstract class DotNetSamProjectGeneratorRoot(
25+
lifetime: Lifetime,
26+
private val context: NewProjectDialogContext,
27+
sharedModel: ProjectTemplatesSharedModel
28+
) : ProjectTemplateGeneratorBase(
29+
lifetime,
30+
context,
31+
sharedModel,
32+
createProject = true
33+
) {
34+
companion object {
35+
private const val SAM_HELLO_WORLD_PROJECT_NAME = "HelloWorld"
36+
}
37+
38+
override val defaultName = SAM_HELLO_WORLD_PROJECT_NAME
39+
40+
// TODO: Decouple SamProjectGenerator from the framework wizards so we can re-use its panels
41+
private val generator = SamProjectGenerator()
42+
private val samPanel = SamInitSelectionPanel(
43+
generator.wizardFragments,
44+
// Only show templates for DotNet in Rider
45+
runtimeFilter = { RuntimeGroup.getById(BuiltInRuntimeGroups.Dotnet).supportedRuntimes.contains(it) },
46+
// needed to rerun the validation when the wizard is changed
47+
wizardUpdateCallback = { validateData() }
48+
)
49+
50+
fun getSamPanel() = samPanel
51+
52+
fun getSamGenerator() = generator
53+
54+
init {
55+
/**
56+
* The project name is generated inside SAM CLI generator and cannot be re-defined via parameters.
57+
* Hardcode the project name to the generated one - "HelloWorld".
58+
*/
59+
projectNameProperty.set(SAM_HELLO_WORLD_PROJECT_NAME)
60+
sameDirectoryProperty.set(false)
61+
62+
initSamPanel()
63+
}
64+
65+
override fun getComponent(): JComponent {
66+
val component = super.getComponent()
67+
projectNameTextField?.component?.isEnabled = false
68+
sameDirectoryCheckbox?.component?.isEnabled = false
69+
return component
70+
}
71+
72+
override fun createTemplateSpecificPanel(): DialogPanel {
73+
val panel = panel { row { cell(samPanel.mainPanel).align(Align.FILL).resizableColumn() }.resizableRow() }
74+
validateData()
75+
return panel
76+
}
77+
78+
override fun checkIsAbleToExpand(template: RdProjectTemplate2?, validations: Map<JComponent, ValidationInfo>) {
79+
// we don't care about template here.
80+
canExpand.set(validations.isEmpty())
81+
}
82+
83+
private fun validateData() {
84+
// first validateData comes from SamInitSelectionPanel constructor...
85+
samPanel.validate()?.let {
86+
context.statusMessages.add(StatusMessages.Error(it.message))
87+
return
88+
}
89+
context.statusMessages.removeIf { it.type == StatusMessageType.Error }
90+
}
91+
92+
private fun initSamPanel() {
93+
samPanel.setRuntime(DotNetRuntimeUtils.getCurrentDotNetCoreRuntime())
94+
}
95+
}

0 commit comments

Comments
 (0)