@@ -21,10 +21,22 @@ import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceTyp
21
21
import com.intellij.openapi.externalSystem.model.project.ModuleData
22
22
import com.intellij.openapi.externalSystem.model.project.ProjectData
23
23
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId
24
+ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationEvent
24
25
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener
25
26
import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver
26
27
import dev.elide.intellij.Constants
28
+ import dev.elide.intellij.manifests.ElideManifestService
27
29
import dev.elide.intellij.settings.ElideExecutionSettings
30
+ import java.nio.file.Path
31
+ import kotlinx.coroutines.runBlocking
32
+ import kotlin.io.path.Path
33
+ import kotlin.io.path.notExists
34
+ import elide.tooling.lockfile.LockfileLoader
35
+ import elide.tooling.lockfile.loadLockfileSafe
36
+ import elide.tooling.project.ElideConfiguredProject
37
+ import elide.tooling.project.ElideProjectInfo
38
+ import elide.tooling.project.ElideProjectLoader
39
+ import elide.tooling.project.SourceSetFactory
28
40
29
41
/* *
30
42
* A service capable of using the Elide manifest and lockfile to build a project model that can be understood by the
@@ -35,33 +47,81 @@ import dev.elide.intellij.settings.ElideExecutionSettings
35
47
* tracker.
36
48
*/
37
49
class ElideProjectResolver : ExternalSystemProjectResolver <ElideExecutionSettings > {
38
- override fun cancelTask (id : ExternalSystemTaskId , listener : ExternalSystemTaskNotificationListener ): Boolean = true
50
+ /* * Shortcut to emit a status change event with the given description [text]. */
51
+ private fun ExternalSystemTaskNotificationListener.onStep (taskId : ExternalSystemTaskId , text : String ) {
52
+ val event = ExternalSystemTaskNotificationEvent (taskId, text)
53
+ onStatusChange(event)
54
+ }
55
+
56
+ override fun cancelTask (id : ExternalSystemTaskId , listener : ExternalSystemTaskNotificationListener ): Boolean {
57
+ return true
58
+ }
39
59
40
60
override fun resolveProjectInfo (
41
61
id : ExternalSystemTaskId ,
42
62
projectPath : String ,
43
63
isPreviewMode : Boolean ,
44
64
settings : ElideExecutionSettings ? ,
45
65
listener : ExternalSystemTaskNotificationListener
46
- ): DataNode <ProjectData ? >? {
66
+ ): DataNode <ProjectData >? {
47
67
LOG .debug(" Resolving project at '$projectPath '" )
68
+ listener.onStart(projectPath, id)
69
+ val projectModel = runCatching {
70
+ // find a manifest in the project directory
71
+ listener.onStep(id, Constants .Strings [" resolve.steps.discovery" ])
72
+ val projectRoot = Path (projectPath)
73
+ val manifestPath = projectRoot.resolve(Constants .MANIFEST_NAME )
74
+
75
+ if (manifestPath.notExists()) {
76
+ LOG .debug(" No Elide manifest found under $projectPath " )
77
+ return @runCatching null
78
+ }
79
+
80
+ // parse the manifest
81
+ listener.onStep(id, Constants .Strings [" resolve.steps.parse" ])
82
+ val manifest = ElideManifestService ().parse(manifestPath)
48
83
84
+ // call the CLI in case the lockfile is outdated
85
+ // listener.onStep(id, Constants.Strings["resolve.steps.sync"])
86
+ // TODO: launch sync task in the background and wait for it here
87
+
88
+ // configure the project
89
+ listener.onStep(id, Constants .Strings [" resolve.steps.configure" ])
90
+ val loader = buildProjectLoader(projectRoot, settings)
91
+ val project = runBlocking { ElideProjectInfo (projectRoot, manifest, null ).load(loader) }
92
+
93
+ // build the project model from the manifest and lockfile
94
+ listener.onStep(id, Constants .Strings [" resolve.steps.buildModel" ])
95
+ buildProjectModel(projectPath, project)
96
+ }.onSuccess {
97
+ listener.onSuccess(projectPath, id)
98
+ }.onFailure { cause ->
99
+ listener.onTaskOutput(id, " Failed to sync project: $cause " , false )
100
+ listener.onFailure(projectPath, id, RuntimeException (cause))
101
+ }
102
+
103
+ listener.onEnd(projectPath, id)
104
+ return projectModel.getOrThrow()
105
+ }
106
+
107
+ /* * Build the project model given a configured Elide [project]. */
108
+ private fun buildProjectModel (projectPath : String , project : ElideConfiguredProject ): DataNode <ProjectData > {
49
109
// stubbed project model
50
110
val projectData = ProjectData (
51
- Constants .SYSTEM_ID ,
52
- " Elide Project " ,
53
- projectPath,
54
- projectPath,
111
+ /* owner = */ Constants .SYSTEM_ID ,
112
+ /* externalName = */ project.manifest.name ? : Constants . Strings [ " project.defaults.name " ] ,
113
+ /* ideProjectFileDirectoryPath = */ projectPath,
114
+ /* linkedExternalProjectPath = */ projectPath,
55
115
)
56
116
57
- // stubbed sample module
117
+ // main project module
58
118
val module = ModuleData (
59
- " sample " ,
60
- Constants .SYSTEM_ID ,
61
- " JAVA_MODULE" ,
62
- " Sample " ,
63
- " $projectPath /src/main" ,
64
- " $projectPath /src/main" ,
119
+ /* id = */ " main " ,
120
+ /* owner = */ Constants .SYSTEM_ID ,
121
+ /* moduleTypeId = */ " JAVA_MODULE" ,
122
+ /* externalName = */ " main " ,
123
+ /* moduleFileDirectoryPath = */ " $projectPath /src/main" ,
124
+ /* externalConfigPath = */ " $projectPath /src/main" ,
65
125
)
66
126
67
127
val projectNode = DataNode (ProjectKeys .PROJECT , projectData, null )
@@ -79,6 +139,20 @@ class ElideProjectResolver : ExternalSystemProjectResolver<ElideExecutionSetting
79
139
return projectNode
80
140
}
81
141
142
+ /* *
143
+ * Construct a new [ElideProjectLoader] that uses the resources from the Elide distribution set in the execution
144
+ * [settings].
145
+ */
146
+ private fun buildProjectLoader (projectPath : Path , settings : ElideExecutionSettings ? ): ElideProjectLoader {
147
+ return object : ElideProjectLoader {
148
+ override val lockfileLoader: LockfileLoader = LockfileLoader { loadLockfileSafe(projectPath) }
149
+ override val sourceSetFactory: SourceSetFactory = SourceSetFactory .Default
150
+
151
+ // TODO(@darvld): resolve from execution settings
152
+ override val resourcesPath: Path get() = projectPath.resolve(" .elide" )
153
+ }
154
+ }
155
+
82
156
private companion object {
83
157
@JvmStatic private val LOG = Logger .getInstance(ElideProjectResolver ::class .java)
84
158
}
0 commit comments