Skip to content

Commit 3b86cf9

Browse files
committed
Refactor SDK creation and dependency wiring
Hopefully resolve some of the issues with this.
1 parent 2a18825 commit 3b86cf9

File tree

9 files changed

+427
-223
lines changed

9 files changed

+427
-223
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.elixir_lang.jps.shared;
2+
3+
public final class ErlangSdkTypeId {
4+
private ErlangSdkTypeId() {
5+
}
6+
7+
public static final String ERLANG_SDK_TYPE_ID = "Erlang SDK";
8+
}

src/org/elixir_lang/action/AddDevelopmentSdksAction.kt

Lines changed: 14 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,9 @@ package org.elixir_lang.action
22

33
import com.intellij.openapi.actionSystem.AnAction
44
import com.intellij.openapi.actionSystem.AnActionEvent
5-
import com.intellij.openapi.application.ApplicationManager
6-
import com.intellij.openapi.application.edtWriteAction
7-
import com.intellij.openapi.progress.runBlockingCancellable
8-
import com.intellij.openapi.projectRoots.ProjectJdkTable
9-
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl
105
import org.elixir_lang.notification.setup_sdk.Notifier
11-
import org.elixir_lang.sdk.elixir.Type as ElixirSdkType
6+
import org.elixir_lang.sdk.SdkRegistrar
127
import org.elixir_lang.sdk.erlang.Type as ErlangSdkType
13-
import org.elixir_lang.sdk.erlang_dependent.SdkAdditionalData
148
import java.io.File
159

1610
/**
@@ -56,7 +50,7 @@ class AddDevelopmentSdksAction : AnAction() {
5650

5751
// Create Elixir SDK
5852
if (!elixirPath.isNullOrBlank()) {
59-
val createdElixirSdk = createElixirSdk(elixirPath, erlangSdk)
53+
val createdElixirSdk = createElixirSdk(elixirPath, erlangSdk, project)
6054
elixirSdkCreated = createdElixirSdk != null
6155
if (elixirSdkCreated) {
6256
Notifier.sdkRefreshSuccess(project, 1, 1, 0, 0)
@@ -76,91 +70,30 @@ class AddDevelopmentSdksAction : AnAction() {
7670
return null
7771
}
7872

79-
val projectJdkTable = ProjectJdkTable.getInstance()
80-
val erlangSdkType = ErlangSdkType()
81-
82-
// Check if SDK with this home path already exists
83-
val existingSdk = projectJdkTable.allJdks.find {
84-
it.sdkType is ErlangSdkType && it.homePath == homePath
85-
}
86-
if (existingSdk != null) {
87-
return existingSdk
88-
}
89-
90-
val sdkName = erlangSdkType.suggestSdkName("Erlang (Dev)", homePath)
91-
val sdk = ProjectJdkImpl(sdkName, erlangSdkType)
92-
93-
val modificator = sdk.sdkModificator
94-
modificator.homePath = homePath
95-
96-
if (sdk.versionString == null) {
97-
return null
98-
}
99-
100-
modificator.commitChanges()
101-
102-
runBlockingCancellable {
103-
edtWriteAction {
104-
projectJdkTable.addJdk(sdk)
105-
erlangSdkType.setupSdkPaths(sdk)
106-
}
107-
}
108-
109-
return sdk
73+
return SdkRegistrar.registerOrUpdateErlangSdk(homePath)
11074
}
11175

11276
private fun createElixirSdk(
11377
homePath: String,
114-
erlangSdk: com.intellij.openapi.projectRoots.Sdk?
78+
erlangSdk: com.intellij.openapi.projectRoots.Sdk?,
79+
project: com.intellij.openapi.project.Project
11580
): com.intellij.openapi.projectRoots.Sdk? {
11681
if (!File(homePath).exists()) {
11782
return null
11883
}
11984

120-
val projectJdkTable = ProjectJdkTable.getInstance()
121-
val elixirSdkType = ElixirSdkType.instance
122-
123-
// Check if SDK with this home path already exists
124-
val existingSdk = projectJdkTable.allJdks.find {
125-
it.sdkType is ElixirSdkType && it.homePath == homePath
126-
}
127-
if (existingSdk != null) {
128-
return existingSdk
129-
}
130-
131-
val sdkName = elixirSdkType.suggestSdkName("Elixir (Dev)", homePath)
132-
val sdk = ProjectJdkImpl(sdkName, elixirSdkType)
133-
134-
val modificator = sdk.sdkModificator
135-
modificator.homePath = homePath
136-
137-
if (sdk.versionString == null) {
138-
return null
139-
}
140-
141-
// Set the Erlang SDK as internal dependency if available
14285
val actualErlangSdk = erlangSdk ?: findExistingErlangSdk()
143-
if (actualErlangSdk != null) {
144-
modificator.sdkAdditionalData = SdkAdditionalData(actualErlangSdk, sdk)
145-
}
146-
147-
modificator.commitChanges()
148-
149-
runBlockingCancellable {
150-
edtWriteAction {
151-
projectJdkTable.addJdk(sdk)
152-
elixirSdkType.setupSdkPaths(sdk)
153-
}
154-
}
155-
156-
return sdk
86+
return SdkRegistrar.registerOrUpdateElixirSdk(
87+
homePath = homePath,
88+
erlangSdk = actualErlangSdk,
89+
project = project,
90+
)
15791
}
15892

159-
private fun findExistingErlangSdk(): com.intellij.openapi.projectRoots.Sdk? {
160-
return ProjectJdkTable.getInstance().allJdks.find {
161-
it.sdkType is ErlangSdkType
162-
}
163-
}
93+
private fun findExistingErlangSdk(): com.intellij.openapi.projectRoots.Sdk? =
94+
com.intellij.openapi.projectRoots.ProjectJdkTable.getInstance()
95+
.getSdksOfType(ErlangSdkType.instance)
96+
.firstOrNull()
16497

16598
override fun update(e: AnActionEvent) {
16699
// Only enable if we have SDK paths configured

src/org/elixir_lang/module/ElixirModuleType.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ public static ElixirModuleType getInstance(){
2626
return (ElixirModuleType) ModuleTypeManager.getInstance().findByID(MODULE_TYPE_ID);
2727
}
2828

29+
public static Boolean isElixirModule(com.intellij.openapi.module.Module mod) {
30+
return ModuleType.is(mod, getInstance());
31+
}
32+
2933
@NotNull
3034
@Override
3135
public ElixirModuleBuilder createModuleBuilder() {
@@ -50,7 +54,7 @@ public Icon getBigIcon() {
5054
}
5155

5256
@Override
53-
public Icon getNodeIcon(@Deprecated boolean isOpened) {
57+
public @NotNull Icon getNodeIcon(@Deprecated boolean isOpened) {
5458
return Icons.MODULE;
5559
}
5660

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package org.elixir_lang.sdk
2+
3+
import com.intellij.openapi.application.ApplicationManager
4+
import com.intellij.openapi.application.WriteAction
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.openapi.projectRoots.ProjectJdkTable
7+
import com.intellij.openapi.projectRoots.Sdk
8+
import com.intellij.openapi.projectRoots.SdkType
9+
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl
10+
import org.elixir_lang.notification.setup_sdk.Notifier
11+
import org.elixir_lang.sdk.elixir.Type as ElixirSdkType
12+
import org.elixir_lang.sdk.erlang.Type as ErlangSdkType
13+
import org.elixir_lang.sdk.erlang_dependent.Type as ErlangDependentType
14+
import org.elixir_lang.sdk.wsl.wslCompat
15+
16+
object SdkRegistrar {
17+
fun registerOrUpdateErlangSdk(
18+
homePath: String,
19+
resolvedVersion: String? = null,
20+
): Sdk? {
21+
val canonicalHomePath = canonicalHomePath(homePath) ?: return null
22+
val sdkType = ErlangSdkType.instance
23+
val versionString = ErlangSdkType.versionStringForHome(canonicalHomePath, resolvedVersion) ?: return null
24+
val existing = findSdkByHomePath(sdkType, canonicalHomePath)
25+
val sdkName = ErlangSdkType.suggestSdkNameForHome(canonicalHomePath, resolvedVersion)
26+
27+
val updatedSdk = ProjectJdkImpl(sdkName, sdkType, canonicalHomePath, versionString)
28+
val registeredSdk = registerOrUpdate(existing, updatedSdk)
29+
30+
sdkType.setupSdkPaths(registeredSdk)
31+
return registeredSdk
32+
}
33+
34+
fun registerOrUpdateElixirSdk(
35+
homePath: String,
36+
erlangSdk: Sdk?,
37+
resolvedVersion: String? = null,
38+
project: Project? = null,
39+
): Sdk? {
40+
val canonicalHomePath = canonicalHomePath(homePath) ?: return null
41+
val sdkType = ElixirSdkType.instance
42+
val versionString = ElixirSdkType.versionStringForHome(canonicalHomePath, resolvedVersion) ?: return null
43+
val existing = findSdkByHomePath(sdkType, canonicalHomePath)
44+
val sdkName = ElixirSdkType.suggestSdkNameForHome(canonicalHomePath, resolvedVersion)
45+
46+
val updatedSdk = ProjectJdkImpl(sdkName, sdkType, canonicalHomePath, versionString)
47+
val registeredSdk = registerOrUpdate(existing, updatedSdk)
48+
49+
ErlangDependentType.attachErlangDependency(registeredSdk, erlangSdk)
50+
51+
if (erlangSdk == null && project != null) {
52+
Notifier.elixirSdkMissingErlangDependency(project, registeredSdk.name)
53+
}
54+
55+
sdkType.setupSdkPaths(registeredSdk)
56+
return registeredSdk
57+
}
58+
59+
private fun canonicalHomePath(homePath: String?): String? =
60+
wslCompat.canonicalizePathNullable(homePath)
61+
62+
private fun findSdkByHomePath(sdkType: SdkType, homePath: String): Sdk? {
63+
val projectJdkTable = ProjectJdkTable.getInstance()
64+
return projectJdkTable.allJdks.firstOrNull { sdk ->
65+
sdk.sdkType == sdkType && wslCompat.pathsEqualWslAware(sdk.homePath, homePath)
66+
}
67+
}
68+
69+
private fun registerOrUpdate(existing: Sdk?, updatedSdk: Sdk): Sdk {
70+
return writeAction {
71+
val table = ProjectJdkTable.getInstance()
72+
if (existing == null) {
73+
table.addJdk(updatedSdk)
74+
updatedSdk
75+
} else {
76+
table.updateJdk(existing, updatedSdk)
77+
existing
78+
}
79+
}
80+
}
81+
82+
private fun <T> writeAction(block: () -> T): T {
83+
val app = ApplicationManager.getApplication()
84+
if (app.isWriteAccessAllowed) {
85+
return block()
86+
}
87+
88+
var result: T? = null
89+
var resultSet = false
90+
val runnable = Runnable {
91+
result = WriteAction.compute<T, Throwable> { block() }
92+
resultSet = true
93+
}
94+
95+
if (app.isDispatchThread) {
96+
runnable.run()
97+
} else {
98+
app.invokeAndWait(runnable)
99+
}
100+
101+
if (!resultSet) {
102+
throw IllegalStateException("Write action did not execute")
103+
}
104+
@Suppress("UNCHECKED_CAST")
105+
return result as T
106+
}
107+
}

0 commit comments

Comments
 (0)