Skip to content

Commit

Permalink
Merge pull request #460 from fwcd/improve-shell-resolver
Browse files Browse the repository at this point in the history
Improve shell classpath and stdlib resolution
  • Loading branch information
fwcd committed Apr 14, 2023
2 parents 80ad2d8 + b8c9328 commit 31a9f2a
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 258 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ The project uses the internal APIs of the [Kotlin compiler](https://github.com/J

### Figuring out the dependencies

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.
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}`.

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

* Example of the `%HOMEPATH%\.config\KotlinLanguageServer\classpath.bat` on Windows:
* Example of the `%HOMEPATH%\.config\kotlin-language-server\classpath.bat` on Windows:
```cmd
@echo off
echo C:\my\path\kotlin-compiler-1.4.10\lib\kotlin-stdlib.jar;C:\my\path\my-lib.jar
Expand Down
4 changes: 4 additions & 0 deletions detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ exceptions:
- NumberFormatException
- ParseException
- MissingPropertyException

style:
MaxLineLength:
active: false
239 changes: 0 additions & 239 deletions detekt_baseline.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import java.nio.file.attribute.BasicFileAttributes
import java.util.function.BiPredicate
import org.javacs.kt.util.tryResolving
import org.javacs.kt.util.findCommandOnPath
import org.javacs.kt.LOG
import java.nio.file.Paths

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

fun findKotlinStdlib(): Path? =
findLocalArtifact("org.jetbrains.kotlin", "kotlin-stdlib")
?: findKotlinCliCompilerLibrary("kotlin-stdlib")
findKotlinCliCompilerLibrary("kotlin-stdlib")
?: findLocalArtifact("org.jetbrains.kotlin", "kotlin-stdlib")
?: findAlternativeLibraryLocation("kotlin-stdlib")

private fun findLocalArtifact(group: String, artifact: String) =
Expand All @@ -33,7 +34,7 @@ private fun tryFindingLocalArtifactUsing(@Suppress("UNUSED_PARAMETER") group: St
val expected = "${artifact}-${version}.jar"
name == expected
}
else -> name.startsWith(artifact) && name.endsWith(".jar")
else -> name.startsWith(artifact) && ("-sources" !in name) && name.endsWith(".jar")
}
}
return Files.list(artifactDirResolution.artifactDir)
Expand Down Expand Up @@ -69,6 +70,9 @@ private fun findKotlinCliCompilerLibrary(name: String): Path? =
?.filter { it.fileName.toString() == "$name.jar" }
?.findFirst()
?.orElse(null)
?.also {
LOG.info("Found Kotlin CLI compiler library $name at $it")
}


// alternative library locations like for snap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import org.javacs.kt.util.userHome
import org.javacs.kt.util.isOSWindows
import org.javacs.kt.LOG

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

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

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

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

/** Returns the ShellClassPathResolver for the global home directory shell script. */
fun global(workingDir: Path?): ClassPathResolver =
globalConfigRoot.resolve("KotlinLanguageServer")
?.let { root ->
scriptExtensions
.map { root.resolve("classpath.$it") }
.firstOrNull { Files.exists(it) }
}
configDirNames
.map(globalConfigRoot::resolve)
.flatMap { root -> scriptExtensions.map { root.resolve("classpath$it") } }
.firstOrNull(Files::exists)
?.let { ShellClassPathResolver(it, workingDir) }
?: ClassPathResolver.empty
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ private fun wrapWithStdlib(paths: Set<Path>): Set<Path> {
}

private data class StdLibItem(
val key : String,
val major : Int,
val key: String,
val major: Int,
val minor: Int,
val patch : Int,
val patch: Int,
val path: Path
) {
companion object {
// Matches names like: "kotlin-stdlib-jdk7-1.2.51.jar"
val parser = Regex("""(kotlin-stdlib(-[^-]+)?)-(\d+)\.(\d+)\.(\d+)\.jar""")
val parser = Regex("""(kotlin-stdlib(-[^-]+)?)(?:-(\d+)\.(\d+)\.(\d+))?\.jar""")

fun from(path: Path) : StdLibItem? {
return parser.matchEntire(path.fileName.toString())?.let { match ->
Expand Down
2 changes: 1 addition & 1 deletion shared/src/main/kotlin/org/javacs/kt/util/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ inline fun <T> tryResolving(what: String, resolver: () -> T?): T? {
try {
val resolved = resolver()
if (resolved != null) {
LOG.info("Successfully resolved {}", what)
LOG.info("Successfully resolved {} to {}", what, resolved)
return resolved
} else {
LOG.info("Could not resolve {} as it is null", what)
Expand Down

0 comments on commit 31a9f2a

Please sign in to comment.