Skip to content

Commit 31a9f2a

Browse files
authored
Merge pull request #460 from fwcd/improve-shell-resolver
Improve shell classpath and stdlib resolution
2 parents 80ad2d8 + b8c9328 commit 31a9f2a

File tree

7 files changed

+35
-258
lines changed

7 files changed

+35
-258
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ The project uses the internal APIs of the [Kotlin compiler](https://github.com/J
3737

3838
### Figuring out the dependencies
3939

40-
Dependencies are determined by the [DefaultClassPathResolver.kt](shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt), which invokes Maven or Gradle to get a list of classpath JARs. Alternatively, projects can also 'manually' provide a list of dependencies through a shell script, located either at `[project root]/kotlinLspClasspath.{sh,bat,cmd}` or `[config root]/KotlinLanguageServer/classpath.{sh,bat,cmd}`, which outputs a list of JARs.
40+
Dependencies are determined by the [DefaultClassPathResolver.kt](shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt), which invokes Maven or Gradle to get a list of classpath JARs. Alternatively, projects can also 'manually' provide a list of dependencies through a shell script, located either at `[project root]/kls-classpath` or `[config root]/kotlin-language-server/classpath`, which outputs a list of JARs. Depending on your platform, the scripts also can be suffixed with `.{sh,bat,cmd}`.
4141

42-
* Example of the `~/.config/KotlinLanguageServer/classpath.sh` on Linux:
42+
* Example of the `~/.config/kotlin-language-server/classpath` on Linux:
4343
```bash
4444
#!/bin/bash
4545
echo /my/path/kotlin-compiler-1.4.10/lib/kotlin-stdlib.jar:/my/path/my-lib.jar
4646
```
4747

48-
* Example of the `%HOMEPATH%\.config\KotlinLanguageServer\classpath.bat` on Windows:
48+
* Example of the `%HOMEPATH%\.config\kotlin-language-server\classpath.bat` on Windows:
4949
```cmd
5050
@echo off
5151
echo C:\my\path\kotlin-compiler-1.4.10\lib\kotlin-stdlib.jar;C:\my\path\my-lib.jar

detekt.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ exceptions:
1010
- NumberFormatException
1111
- ParseException
1212
- MissingPropertyException
13+
14+
style:
15+
MaxLineLength:
16+
active: false

detekt_baseline.xml

Lines changed: 0 additions & 239 deletions
Large diffs are not rendered by default.

shared/src/main/kotlin/org/javacs/kt/classpath/BackupClassPathResolver.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import java.nio.file.attribute.BasicFileAttributes
77
import java.util.function.BiPredicate
88
import org.javacs.kt.util.tryResolving
99
import org.javacs.kt.util.findCommandOnPath
10+
import org.javacs.kt.LOG
1011
import java.nio.file.Paths
1112

1213
/** Backup classpath that find Kotlin in the user's Maven/Gradle home or kotlinc's libraries folder. */
@@ -16,8 +17,8 @@ object BackupClassPathResolver : ClassPathResolver {
1617
}
1718

1819
fun findKotlinStdlib(): Path? =
19-
findLocalArtifact("org.jetbrains.kotlin", "kotlin-stdlib")
20-
?: findKotlinCliCompilerLibrary("kotlin-stdlib")
20+
findKotlinCliCompilerLibrary("kotlin-stdlib")
21+
?: findLocalArtifact("org.jetbrains.kotlin", "kotlin-stdlib")
2122
?: findAlternativeLibraryLocation("kotlin-stdlib")
2223

2324
private fun findLocalArtifact(group: String, artifact: String) =
@@ -33,7 +34,7 @@ private fun tryFindingLocalArtifactUsing(@Suppress("UNUSED_PARAMETER") group: St
3334
val expected = "${artifact}-${version}.jar"
3435
name == expected
3536
}
36-
else -> name.startsWith(artifact) && name.endsWith(".jar")
37+
else -> name.startsWith(artifact) && ("-sources" !in name) && name.endsWith(".jar")
3738
}
3839
}
3940
return Files.list(artifactDirResolution.artifactDir)
@@ -69,6 +70,9 @@ private fun findKotlinCliCompilerLibrary(name: String): Path? =
6970
?.filter { it.fileName.toString() == "$name.jar" }
7071
?.findFirst()
7172
?.orElse(null)
73+
?.also {
74+
LOG.info("Found Kotlin CLI compiler library $name at $it")
75+
}
7276

7377

7478
// alternative library locations like for snap

shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import java.nio.file.Files
55
import java.nio.file.Path
66
import java.nio.file.Paths
77
import org.javacs.kt.util.userHome
8+
import org.javacs.kt.util.isOSWindows
89
import org.javacs.kt.LOG
910

1011
/** Executes a shell script to determine the classpath */
@@ -29,11 +30,20 @@ internal class ShellClassPathResolver(
2930
}
3031

3132
companion object {
32-
private val scriptExtensions = listOf("sh", "bat", "cmd")
33+
private val configDirNames = listOf("kotlin-language-server", "KotlinLanguageServer")
34+
private val scriptNames = listOf("kls-classpath", "kotlinLspClasspath")
35+
private val scriptExtensions = if (isOSWindows()) listOf(".bat", ".cmd", ".ps1") else listOf("", ".sh", ".bash")
3336

3437
/** Create a shell resolver if a file is a pom. */
3538
fun maybeCreate(file: Path): ShellClassPathResolver? =
36-
file.takeIf { scriptExtensions.any { file.endsWith("kotlinLspClasspath.$it") } }
39+
file.takeIf { scriptNames.any { name -> scriptExtensions.any { file.endsWith("$name$it") } } }
40+
?.takeIf {
41+
val isExecutable = Files.isExecutable(it)
42+
if (!isExecutable) {
43+
LOG.warn("Found classpath script $it that is NOT executable and therefore cannot be used. Perhaps you'd want to chmod +x it?")
44+
}
45+
isExecutable
46+
}
3747
?.let { ShellClassPathResolver(it) }
3848

3949
/** The root directory for config files. */
@@ -42,12 +52,10 @@ internal class ShellClassPathResolver(
4252

4353
/** Returns the ShellClassPathResolver for the global home directory shell script. */
4454
fun global(workingDir: Path?): ClassPathResolver =
45-
globalConfigRoot.resolve("KotlinLanguageServer")
46-
?.let { root ->
47-
scriptExtensions
48-
.map { root.resolve("classpath.$it") }
49-
.firstOrNull { Files.exists(it) }
50-
}
55+
configDirNames
56+
.map(globalConfigRoot::resolve)
57+
.flatMap { root -> scriptExtensions.map { root.resolve("classpath$it") } }
58+
.firstOrNull(Files::exists)
5159
?.let { ShellClassPathResolver(it, workingDir) }
5260
?: ClassPathResolver.empty
5361
}

shared/src/main/kotlin/org/javacs/kt/classpath/WithStdlibResolver.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ private fun wrapWithStdlib(paths: Set<Path>): Set<Path> {
4545
}
4646

4747
private data class StdLibItem(
48-
val key : String,
49-
val major : Int,
48+
val key: String,
49+
val major: Int,
5050
val minor: Int,
51-
val patch : Int,
51+
val patch: Int,
5252
val path: Path
5353
) {
5454
companion object {
5555
// Matches names like: "kotlin-stdlib-jdk7-1.2.51.jar"
56-
val parser = Regex("""(kotlin-stdlib(-[^-]+)?)-(\d+)\.(\d+)\.(\d+)\.jar""")
56+
val parser = Regex("""(kotlin-stdlib(-[^-]+)?)(?:-(\d+)\.(\d+)\.(\d+))?\.jar""")
5757

5858
fun from(path: Path) : StdLibItem? {
5959
return parser.matchEntire(path.fileName.toString())?.let { match ->

shared/src/main/kotlin/org/javacs/kt/util/Utils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ inline fun <T> tryResolving(what: String, resolver: () -> T?): T? {
9090
try {
9191
val resolved = resolver()
9292
if (resolved != null) {
93-
LOG.info("Successfully resolved {}", what)
93+
LOG.info("Successfully resolved {} to {}", what, resolved)
9494
return resolved
9595
} else {
9696
LOG.info("Could not resolve {} as it is null", what)

0 commit comments

Comments
 (0)