Skip to content

Commit b45b47f

Browse files
committed
Refactor MIX_HOME handling to improve readability
1 parent 4edbfde commit b45b47f

File tree

2 files changed

+84
-27
lines changed

2 files changed

+84
-27
lines changed

jps-shared/src/org/elixir_lang/jps/shared/sdk/SdkPaths.kt

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ object SdkPaths {
2323
System.getProperty("os.name").lowercase(Locale.ROOT).contains("windows")
2424
const val MISE_POSIX_PATH_FROM_HOME = ".local/share/mise/installs"
2525
const val MISE_WINDOWS_PATH_FROM_HOME = "appdata/local/mise/installs"
26+
private const val ASDF_INSTALLS_PREFIX = "/.asdf/installs/"
27+
private const val ELIXIR_INSTALL_INSTALLS_PREFIX = "/.elixir-install/installs/"
28+
private const val ELIXIR_INSTALL_PATH_SEGMENT = "/.elixir-install/"
2629

2730
fun detectSource(homePath: String): String? {
2831
val posixPath = FileUtil.toSystemIndependentName(homePath)
@@ -31,10 +34,10 @@ object SdkPaths {
3134
if (matchPath.contains(MISE_POSIX_PATH_FROM_HOME) || matchPath.contains(MISE_WINDOWS_PATH_FROM_HOME)) {
3235
return SOURCE_NAME_MISE
3336
}
34-
if (matchPath.contains("/.asdf/installs/")) {
37+
if (matchPath.contains(ASDF_INSTALLS_PREFIX)) {
3538
return SOURCE_NAME_ASDF
3639
}
37-
if (matchPath.contains("/.elixir-install/")) {
40+
if (matchPath.contains(ELIXIR_INSTALL_PATH_SEGMENT)) {
3841
return SOURCE_NAME_ELIXIR_INSTALL
3942
}
4043
if (matchPath.contains("/usr/local/cellar/") || matchPath.contains("/opt/homebrew/cellar/")) {
@@ -66,50 +69,65 @@ object SdkPaths {
6669
return File(parentDir, ".mix")
6770
}
6871

69-
fun mixHomeReplacePrefix(source: String?, homePath: String?): String? {
70-
if (SOURCE_NAME_MISE == source) {
71-
if (homePath != null) {
72-
val posixPath = FileUtil.toSystemIndependentName(homePath)
73-
val matchPath = posixPath.lowercase(Locale.ROOT)
74-
if (matchPath.contains(MISE_WINDOWS_PATH_FROM_HOME)) {
75-
return MISE_WINDOWS_PATH_FROM_HOME
76-
}
77-
}
72+
private fun expectedMixHomePrefix(source: String?, homePath: String?): String? = when (source) {
73+
SOURCE_NAME_MISE -> expectedMisePrefix(homePath)
74+
SOURCE_NAME_ASDF -> ASDF_INSTALLS_PREFIX
75+
SOURCE_NAME_ELIXIR_INSTALL -> ELIXIR_INSTALL_INSTALLS_PREFIX
76+
else -> null
77+
}
78+
79+
private fun expectedMisePrefix(homePath: String?): String {
80+
if (homePath == null) {
7881
return MISE_POSIX_PATH_FROM_HOME
7982
}
80-
if (SOURCE_NAME_ASDF == source) {
81-
return "/.asdf/installs/"
82-
}
83-
if (SOURCE_NAME_ELIXIR_INSTALL == source) {
84-
return "/.elixir-install/installs/"
83+
84+
val posixPath = FileUtil.toSystemIndependentName(homePath)
85+
return if (containsIgnoreCase(posixPath, MISE_WINDOWS_PATH_FROM_HOME)) {
86+
MISE_WINDOWS_PATH_FROM_HOME
87+
} else {
88+
MISE_POSIX_PATH_FROM_HOME
8589
}
86-
return null
8790
}
8891

89-
fun shouldReplaceMixHome(existingMixHome: String?, replacePrefix: String?): Boolean {
92+
/**
93+
* Only replace MIX_HOME when it is missing or still under the current manager's default prefix.
94+
* If the user configured a custom MIX_HOME elsewhere, keep it.
95+
*/
96+
private fun shouldReplaceMixHomeIfExpectedPrefixMatches(existingMixHome: String?, expectedPrefix: String?): Boolean {
9097
if (existingMixHome == null) {
9198
return true
9299
}
93-
if (replacePrefix == null) {
100+
if (expectedPrefix == null) {
94101
return false
95102
}
96103

97-
val posixPath = FileUtil.toSystemIndependentName(existingMixHome)
98-
if (IS_WINDOWS) {
99-
val matchPath = posixPath.lowercase(Locale.ROOT)
100-
val matchPrefix = replacePrefix.lowercase(Locale.ROOT)
101-
return matchPath.contains(matchPrefix)
104+
return pathContains(existingMixHome, expectedPrefix)
105+
}
106+
107+
private fun pathContains(path: String, expectedPrefix: String): Boolean {
108+
val posixPath = FileUtil.toSystemIndependentName(path)
109+
return if (IS_WINDOWS) {
110+
containsIgnoreCase(posixPath, expectedPrefix)
111+
} else {
112+
posixPath.contains(expectedPrefix)
102113
}
103-
return posixPath.contains(replacePrefix)
104114
}
105115

116+
private fun containsIgnoreCase(text: String, fragment: String): Boolean =
117+
text.lowercase(Locale.ROOT).contains(fragment.lowercase(Locale.ROOT))
118+
119+
/**
120+
* Updates MIX_HOME and MIX_ARCHIVES when the existing values are missing or still under the
121+
* current version manager's default install prefix. If the user configured custom values
122+
* elsewhere, keep them intact.
123+
*/
106124
@JvmStatic
107125
fun maybeUpdateMixHome(environment: MutableMap<String, String>, homePath: String?) {
108126
val mixHome = mixHome(homePath) ?: return
109127
val source = detectSource(homePath ?: return)
110-
val replacePrefix = mixHomeReplacePrefix(source, homePath)
128+
val expected = expectedMixHomePrefix(source, homePath)
111129
val existingMixHome = environment["MIX_HOME"]
112-
if (shouldReplaceMixHome(existingMixHome, replacePrefix)) {
130+
if (shouldReplaceMixHomeIfExpectedPrefixMatches(existingMixHome, expected)) {
113131
environment["MIX_HOME"] = mixHome.absolutePath
114132
environment["MIX_ARCHIVES"] = mixHome.resolve("archives").absolutePath
115133
logger.info("Updated mix environment variables (MIX_HOME=${environment["MIX_HOME"]}, MIX_ARCHIVES=${environment["MIX_ARCHIVES"]})")

tests/org/elixir_lang/jps/shared/sdk/SdkPathsTest.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package org.elixir_lang.jps.shared.sdk
22

33
import org.elixir_lang.PlatformTestCase
4+
import java.io.File
45

56
/**
67
* Tests for SdkPaths utility methods.
78
*/
89
class SdkPathsTest : PlatformTestCase() {
10+
private val asdfElixir117 = "/home/user/.asdf/installs/elixir/1.17.0"
11+
private val asdfElixir116 = "/home/user/.asdf/installs/elixir/1.16.0"
12+
private val customMixHome = "/custom/mix/home"
913

1014
fun testDetectSource_mise() {
1115
assertEquals("mise", SdkPaths.detectSource("/Users/josh/.local/share/mise/installs/elixir/1.15.0"))
@@ -46,4 +50,39 @@ class SdkPathsTest : PlatformTestCase() {
4650
assertNull(SdkPaths.detectSource(""))
4751
assertNull(SdkPaths.detectSource("/"))
4852
}
53+
54+
fun testMaybeUpdateMixHome_setsWhenMissing() {
55+
val environment = mutableMapOf<String, String>()
56+
57+
SdkPaths.maybeUpdateMixHome(environment, asdfElixir117)
58+
59+
val expectedMixHome = mixHomePath(asdfElixir117)
60+
assertEquals(expectedMixHome, environment["MIX_HOME"])
61+
assertEquals(File(expectedMixHome, "archives").absolutePath, environment["MIX_ARCHIVES"])
62+
}
63+
64+
fun testMaybeUpdateMixHome_replacesWhenUnderManagerPrefix() {
65+
val environment = mutableMapOf<String, String>()
66+
environment["MIX_HOME"] = mixHomePath(asdfElixir116)
67+
environment["MIX_ARCHIVES"] = File(environment["MIX_HOME"]!!, "archives").absolutePath
68+
69+
SdkPaths.maybeUpdateMixHome(environment, asdfElixir117)
70+
71+
val expectedMixHome = mixHomePath(asdfElixir117)
72+
assertEquals(expectedMixHome, environment["MIX_HOME"])
73+
assertEquals(File(expectedMixHome, "archives").absolutePath, environment["MIX_ARCHIVES"])
74+
}
75+
76+
fun testMaybeUpdateMixHome_preservesCustomMixHome() {
77+
val environment = mutableMapOf<String, String>()
78+
environment["MIX_HOME"] = customMixHome
79+
environment["MIX_ARCHIVES"] = "$customMixHome/archives"
80+
81+
SdkPaths.maybeUpdateMixHome(environment, asdfElixir117)
82+
83+
assertEquals(customMixHome, environment["MIX_HOME"])
84+
assertEquals("$customMixHome/archives", environment["MIX_ARCHIVES"])
85+
}
86+
87+
private fun mixHomePath(homePath: String): String = File(homePath, ".mix").absolutePath
4988
}

0 commit comments

Comments
 (0)