Skip to content

Commit e75a04c

Browse files
authored
Remove coursier bootstrap and respect COURSIER_JVM_INDEX (#631)
1 parent 30378f1 commit e75a04c

File tree

6 files changed

+173
-85
lines changed

6 files changed

+173
-85
lines changed

build.sbt

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ lazy val cli = project
250250
libraryDependencies ++=
251251
List(
252252
"io.get-coursier" %% "coursier" % V.coursier,
253+
"io.get-coursier" %% "coursier-jvm" % V.coursier,
253254
"org.scalameta" % "mtags-interfaces" % V.metals,
254255
"org.scala-lang.modules" %% "scala-xml" % V.scalaXml,
255256
"com.lihaoyi" %% "requests" % V.requests,
-125 KB
Binary file not shown.

scip-java/src/main/scala/com/sourcegraph/scip_java/Embedded.scala

-5
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ object Embedded {
1818
copyFile(tmpDir, "gradle-plugin.jar")
1919

2020
def agentJar(tmpDir: Path): Path = copyFile(tmpDir, "semanticdb-agent.jar")
21-
def coursier(tmpDir: Path): Path = {
22-
val result = copyFile(tmpDir, "scip-java/coursier")
23-
result.toFile().setExecutable(true)
24-
result
25-
}
2621

2722
private def javacErrorpath(tmp: Path) = tmp.resolve("errorpath.txt")
2823

scip-java/src/main/scala/com/sourcegraph/scip_java/buildtools/ScipBuildTool.scala

+53-17
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import java.util.jar.JarFile
2222

2323
import scala.collection.mutable.ArrayBuffer
2424
import scala.collection.mutable.ListBuffer
25+
import scala.concurrent.Await
26+
import scala.concurrent.ExecutionContext
27+
import scala.concurrent.duration.Duration
2528
import scala.jdk.CollectionConverters._
2629
import scala.language.postfixOps
2730
import scala.util.Failure
@@ -40,6 +43,7 @@ import com.sourcegraph.scip_java.Embedded
4043
import com.sourcegraph.scip_java.commands.IndexCommand
4144
import com.sourcegraph.semanticdb_javac.Semanticdb.TextDocument
4245
import com.sourcegraph.semanticdb_javac.Semanticdb.TextDocuments
46+
import coursier.jvm.JvmIndex
4347
import moped.json.DecodingContext
4448
import moped.json.ErrorResult
4549
import moped.json.JsonCodec
@@ -606,30 +610,62 @@ class ScipBuildTool(index: IndexCommand) extends BuildTool("SCIP", index) {
606610
}
607611

608612
private def javacPathViaCoursier(jvmVersion: String, tmp: Path): Path = {
609-
val coursier = Embedded.coursier(tmp)
610-
Paths.get(
611-
os.proc(
612-
coursier.toString,
613-
"java-home",
614-
"--jvm",
615-
jvmVersion,
616-
"--architecture",
617-
jvmArchitecture
613+
import _root_.coursier.jvm._
614+
615+
val jvmChannel = index
616+
.app
617+
.env
618+
.environmentVariables
619+
.get("COURSIER_JVM_INDEX")
620+
.map { idx =>
621+
JvmChannel
622+
.parse(idx)
623+
.fold(
624+
msg =>
625+
throw new RuntimeException(
626+
s"Malformed COURSIER_JVM_INDEX environment variable variable: $msg"
627+
),
628+
identity
629+
)
630+
}
631+
632+
val home = JavaHome().withCache(
633+
JvmCache()
634+
.withIndexChannel(
635+
repositories = Seq.empty,
636+
indexChannel = jvmChannel
637+
.getOrElse(JvmChannel.url(JvmIndex.defaultIndexUrl))
618638
)
619-
.call()
620-
.out
621-
.trim(),
622-
"bin",
623-
"javac"
639+
.withArchitecture(jvmArchitecture(jvmVersion))
624640
)
625641

642+
val javaExecutable = Await.result(
643+
home.javaBin(jvmVersion).value(ExecutionContext.global),
644+
Duration.Inf
645+
)
646+
647+
javaExecutable
648+
.getParent()
649+
.resolve {
650+
if (scala.util.Properties.isWin)
651+
"javac.exe"
652+
else
653+
"javac"
654+
}
655+
626656
}
627657

628-
private def jvmArchitecture: String =
629-
if (scala.util.Properties.isMac && sys.props("os.arch") == "aarch64")
658+
private def jvmArchitecture(jvm: String): String =
659+
if (
660+
// Hack only for local development on ARM64 Mac OS X
661+
// won't affect any other system
662+
scala.util.Properties.isMac && sys.props("os.arch") == "aarch64" &&
663+
(jvm.startsWith("8") || jvm.startsWith("1.8"))
664+
)
630665
"amd64"
631666
else
632-
defaultCoursierJVMArchitecture
667+
JvmIndex.defaultArchitecture()
668+
633669
def defaultCoursierJVMArchitecture: String =
634670
sys.props("os.arch") match {
635671
case "x86_64" =>

tests/buildTools/src/test/scala/tests/ScipBuildToolSuite.scala

+61-20
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,76 @@
11
package tests
22

33
import com.sourcegraph.scip_java.{BuildInfo => V}
4+
import moped.testkit.FileLayout
45

56
class ScipBuildToolSuite extends BaseBuildToolSuite {
67
override def tags = List(SkipWindows)
78

8-
test("COURSIER_CREDENTIALS and COURSIER_REPOSITORIES are respected") {
9+
test("respect-coursier-jvm-index") {
910

10-
val cli = sys.env.getOrElse("SCIP_JAVA_CLI", fail("wwaaaa"))
11+
val (requests, _) = TracingServer.run { run =>
12+
val env = Map(
13+
"COURSIER_JVM_INDEX" -> s"${run.address.toString}/index.json"
14+
)
15+
16+
val tmp = FileLayout
17+
.fromString("""
18+
|/lsif-java.json
19+
|{"dependencies": ["junit:junit:4.13.1"],"jvm": "17"}
20+
|/src/main/java/Example.java
21+
|package foo;\npublic class Example{}
22+
""".stripMargin)
23+
24+
val result = os
25+
.proc(scipJavaCli(), "index", "--build-tool=scip")
26+
.call(cwd = os.Path(tmp), env = env, check = false)
27+
28+
assertNotEquals(result.exitCode, 0)
29+
}
30+
31+
assert(
32+
requests.nonEmpty,
33+
"No requests were sent to the local server - suggesting that COURSIER_JVM_INDEX is not respected by ScipBuildTool"
34+
)
35+
36+
assert(
37+
clue(requests)
38+
.collectFirst {
39+
case req if req.url.getPath() == "/index.json" =>
40+
req
41+
}
42+
.nonEmpty,
43+
"No requests were sent to the local server - suggesting that COURSIER_JVM_INDEX is not respected by ScipBuildTool"
44+
)
45+
}
46+
47+
test("respect-coursier-credentials-and-repositories") {
1148

1249
val Username = "hello"
1350
val Password = "world"
1451

15-
val (requests, _) = PasswordProtectedServer(Username, Password).runWith {
16-
run =>
52+
val (requests, _) =
53+
TracingServer.runWithAuth(Username, Password) { run =>
1754
val env = Map(
1855
"COURSIER_REPOSITORIES" -> run.address.toString(),
1956
"COURSIER_CREDENTIALS" -> s"localhost $Username:$Password"
2057
)
2158

22-
val tmp = os.temp.dir(prefix = "scip-java")
23-
os.write(
24-
tmp / "lsif-java.json",
25-
// We use non-existent library to make sure caches are never used
26-
s""" {"dependencies": ["bla.bla.nonexistent-library:junit:4.13.1"]} """
27-
.trim
28-
)
29-
os.write(
30-
tmp / "foo" / "Example.java",
31-
"package foo;\npublic class Example{}",
32-
createFolders = true
59+
val tmp = FileLayout.fromString(
60+
"""
61+
|/lsif-java.json
62+
|{"dependencies": ["bla.bla.nonexistent-library:junit:4.13.1"]}
63+
|/src/main/java/Example.java
64+
|package foo;\npublic class Example{}
65+
""".stripMargin
3366
)
3467

3568
val result = os
36-
.proc(cli, "index", "--build-tool=scip")
37-
.call(cwd = tmp, env = env, check = false)
38-
39-
os.remove.all(tmp)
69+
.proc(scipJavaCli(), "index", "--build-tool=scip")
70+
.call(cwd = os.Path(tmp), env = env, check = false)
4071

4172
assertNotEquals(result.exitCode, 0)
42-
}
73+
}
4374

4475
assert(
4576
requests.nonEmpty,
@@ -69,6 +100,16 @@ class ScipBuildToolSuite extends BaseBuildToolSuite {
69100
private def base64(str: String) =
70101
new String(java.util.Base64.getEncoder().encode(str.getBytes))
71102

103+
private def scipJavaCli() =
104+
sys
105+
.env
106+
.getOrElse(
107+
"SCIP_JAVA_CLI",
108+
fail(
109+
"SCIP_JAVA_CLI env variable is not set, perhaps the build is misconfigured"
110+
)
111+
)
112+
72113
checkBuild(
73114
"basic",
74115
"""|/lsif-java.json

tests/buildTools/src/test/scala/tests/PasswordProtectedServer.scala renamed to tests/buildTools/src/test/scala/tests/TracingServer.scala

+58-43
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,17 @@ import scala.jdk.CollectionConverters._
77

88
import com.sun.net.httpserver._
99

10-
case class PasswordProtectedServer(user: String, pwd: String) {
11-
import PasswordProtectedServer._
12-
private class MyHandler(storage: ListBuffer[SimpleHttpRequest])
13-
extends HttpHandler {
14-
val auth =
15-
new BasicAuthenticator("") {
16-
override def checkCredentials(
17-
username: String,
18-
password: String
19-
): Boolean = username == user && password == pwd
20-
}
21-
override def handle(t: HttpExchange): Unit = {
22-
val headers = t
23-
.getRequestHeaders()
24-
.asScala
25-
.toMap
26-
.flatMap { case (k, v) =>
27-
v.asScala.headOption.map(k -> _)
28-
}
29-
30-
val url = t.getRequestURI()
31-
storage.synchronized {
32-
storage.addOne(SimpleHttpRequest(url, headers))
33-
}
10+
object TracingServer {
11+
case class SimpleHttpRequest(url: URI, simpleHeaders: Map[String, String])
3412

35-
auth.authenticate(t) match {
36-
case f: Authenticator.Failure =>
37-
t.sendResponseHeaders(f.getResponseCode(), 0L)
38-
case r: Authenticator.Retry =>
39-
t.sendResponseHeaders(r.getResponseCode(), 0L)
40-
case r: Authenticator.Success =>
41-
t.sendResponseHeaders(404, 0L)
42-
}
13+
case class RunningServer(address: URI, shutdown: () => Unit)
4314

44-
t.close()
45-
}
46-
}
47-
def runWith[A](f: RunningServer => A): (List[SimpleHttpRequest], A) = {
48-
val storage = ListBuffer.empty[SimpleHttpRequest]
15+
private def runImpl[A](handler: MyHandler)(f: RunningServer => A) = {
4916
val server = HttpServer
5017
.create(new java.net.InetSocketAddress("localhost", 0), 0);
5118
val result =
5219
try {
53-
server.createContext("/", new MyHandler(storage))
20+
server.createContext("/", handler)
5421
server.setExecutor(null) // creates a default executor
5522
server.start()
5623
f(
@@ -65,12 +32,60 @@ case class PasswordProtectedServer(user: String, pwd: String) {
6532
server.stop(0)
6633
}
6734

68-
storage.toList -> result
35+
handler.tracedRequests -> result
6936
}
70-
}
7137

72-
object PasswordProtectedServer {
73-
case class SimpleHttpRequest(url: URI, simpleHeaders: Map[String, String])
38+
def run[A](f: RunningServer => A): (List[SimpleHttpRequest], A) = {
39+
runImpl(new MyHandler(auth = None))(f)
40+
}
41+
def runWithAuth[A](username: String, password: String)(
42+
f: RunningServer => A
43+
): (List[SimpleHttpRequest], A) = {
44+
val authenticator =
45+
new BasicAuthenticator("") {
46+
override def checkCredentials(
47+
_username: String,
48+
_password: String
49+
): Boolean = username == _username && _password == password
50+
}
7451

75-
case class RunningServer(address: URI, shutdown: () => Unit)
52+
runImpl(new MyHandler(auth = Some(authenticator)))(f)
53+
}
54+
55+
private class MyHandler(auth: Option[Authenticator] = None)
56+
extends HttpHandler {
57+
58+
val storage: ListBuffer[SimpleHttpRequest] = ListBuffer.empty
59+
60+
override def handle(t: HttpExchange): Unit = {
61+
val headers = t
62+
.getRequestHeaders()
63+
.asScala
64+
.toMap
65+
.flatMap { case (k, v) =>
66+
v.asScala.headOption.map(k -> _)
67+
}
68+
69+
val url = t.getRequestURI()
70+
storage.synchronized {
71+
storage.addOne(SimpleHttpRequest(url, headers))
72+
}
73+
74+
auth.foreach {
75+
_.authenticate(t) match {
76+
case f: Authenticator.Failure =>
77+
t.sendResponseHeaders(f.getResponseCode(), 0L)
78+
case r: Authenticator.Retry =>
79+
t.sendResponseHeaders(r.getResponseCode(), 0L)
80+
case r: Authenticator.Success =>
81+
t.sendResponseHeaders(404, 0L)
82+
}
83+
}
84+
85+
t.close()
86+
}
87+
88+
def tracedRequests = storage.result
89+
90+
}
7691
}

0 commit comments

Comments
 (0)