Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ lazy val V =
def scala211 = "2.11.12"
def scala3 = "3.0.1"
def metals = "0.10.6-M1"
def scalameta = "4.4.25"
def scalameta = "4.4.26"
def testcontainers = "0.39.3"
def requests = "0.6.5"
}
Expand Down Expand Up @@ -145,8 +145,12 @@ lazy val cli = project
buildInfoKeys :=
Seq[BuildInfoKey](
version,
sbtVersion,
scalaVersion,
"mtags" -> V.metals,
"sbtSourcegraphVersion" ->
com.sourcegraph.sbtsourcegraph.BuildInfo.version,
"semanticdbVersion" -> V.scalameta,
"mtagsVersion" -> V.metals,
"scala211" -> V.scala211,
"scala212" -> V.scala212,
"scala213" -> V.scala213,
Expand Down Expand Up @@ -268,6 +272,7 @@ lazy val minimizedSettings = List[Def.Setting[_]](
s"-Arandomtimestamp=${System.nanoTime()}",
List(
s"-Xplugin:semanticdb",
s"-build-tool:sbt",
s"-text:on",
s"-verbose",
s"-sourceroot:${(ThisBuild / baseDirectory).value}",
Expand All @@ -290,7 +295,11 @@ lazy val minimized8 = project

lazy val minimized15 = project
.in(file("tests/minimized/.j15"))
.settings(minimizedSettings, javaToolchainVersion := "15")
.settings(
minimizedSettings,
javaToolchainVersion := "15",
Compile / javaHome := None
)
.dependsOn(agent, plugin)
.disablePlugins(JavaFormatterPlugin)

Expand Down
45 changes: 45 additions & 0 deletions lsif-java/src/main/scala/com/sourcegraph/io/AutoDeletedFile.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.sourcegraph.io

import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption

import scala.util.Using.Releasable

class AutoDeletedFile private (
val path: Path,
val oldContent: Option[Array[Byte]]
)

object AutoDeletedFile {
def fromPath(path: Path, newContent: String): AutoDeletedFile = {
val oldContent =
if (Files.isRegularFile(path))
Some(Files.readAllBytes(path))
else
None
Files.createDirectories(path.getParent)
Files.write(
path,
newContent.getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
)
new AutoDeletedFile(path, oldContent)
}
implicit val releasableAutoDeletedFile: Releasable[AutoDeletedFile] = {
file =>
file.oldContent match {
case Some(oldBytes) =>
Files.write(
file.path,
oldBytes,
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING
)
case None =>
Files.deleteIfExists(file.path)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,53 @@
package com.sourcegraph.lsif_java.buildtools

import java.nio.file.Files
import java.nio.file.Path

import com.sourcegraph.io.AbsolutePath
import com.sourcegraph.lsif_java.commands.IndexCommand
import com.sourcegraph.lsif_java.commands.IndexSemanticdbCommand
import os.CommandResult

/**
* A build tool such as Gradle, Maven or Bazel.
*/
abstract class BuildTool(val name: String, index: IndexCommand) {

protected def defaultTargetroot: Path

def isHidden: Boolean = false
def buildKind: String = ""

final def sourceroot: Path = index.workingDirectory
final def targetroot: Path =
AbsolutePath
.of(index.targetroot.getOrElse(defaultTargetroot), index.workingDirectory)

def usedInCurrentDirectory(): Boolean

def generateSemanticdb(): os.CommandResult

def generateLsif(): Int
}

object BuildTool {
def all(index: IndexCommand): List[BuildTool] =
List(
new GradleBuildTool(index),
new MavenBuildTool(index),
new LsifBuildTool(index)
new LsifBuildTool(index),
new SbtBuildTool(index)
)
def allNames: String =
all(IndexCommand()).filterNot(_.isHidden).map(_.name).mkString(", ")

def generateLsifFromTargetroot(
generateSemanticdbResult: CommandResult,
targetroot: Path,
index: IndexCommand,
buildKind: String = ""
): Int = {
if (!Files.isDirectory(targetroot)) {
generateSemanticdbResult.exitCode
} else if (index.app.reporter.hasErrors()) {
index.app.reporter.exitCode()
} else if (generateSemanticdbResult.exitCode != 0) {
generateSemanticdbResult.exitCode
} else {
IndexSemanticdbCommand(
output = index.finalOutput,
targetroot = List(targetroot),
packagehub = index.packagehub,
buildKind = buildKind,
app = index.app
).run()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,23 @@ import os.CommandResult

class GradleBuildTool(index: IndexCommand) extends BuildTool("Gradle", index) {

override def defaultTargetroot: Path =
Paths.get("build", "semanticdb-targetroot")

override def usedInCurrentDirectory(): Boolean = {
Files.isRegularFile(index.workingDirectory.resolve("settings.gradle")) ||
Files.isRegularFile(index.workingDirectory.resolve("gradlew")) ||
Files.isRegularFile(index.workingDirectory.resolve("build.gradle")) ||
Files.isRegularFile(index.workingDirectory.resolve("build.gradle.kts"))
}

override def generateSemanticdb(): CommandResult = {
override def generateLsif(): Int = {
BuildTool
.generateLsifFromTargetroot(generateSemanticdb(), targetroot, index)
}

def targetroot: Path = index.finalTargetroot(defaultTargetroot)

private def defaultTargetroot: Path =
Paths.get("build", "semanticdb-targetroot")
private def generateSemanticdb(): CommandResult = {
val gradleWrapper: Path = index
.workingDirectory
.resolve(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,25 @@ class LsifBuildTool(index: IndexCommand) extends BuildTool("LSIF", index) {
.getDefault
.getPathMatcher("glob:**.{java,scala}")
private val moduleInfo = Paths.get("module-info.java")
protected def defaultTargetroot: Path = Paths.get("target")

override def usedInCurrentDirectory(): Boolean =
Files.isRegularFile(configFile)
override def isHidden: Boolean = true
override def generateLsif(): Int = {
BuildTool.generateLsifFromTargetroot(
generateSemanticdb(),
index.finalTargetroot(defaultTargetroot),
index,
buildKind
)
}

private def targetroot: Path = index.finalTargetroot(defaultTargetroot)
private def defaultTargetroot: Path = Paths.get("target")
private def configFile =
index.workingDirectory.resolve(LsifBuildTool.ConfigFileName)
def usedInCurrentDirectory(): Boolean = Files.isRegularFile(configFile)
override def isHidden: Boolean = true
override def buildKind: String =
parsedConfig.fold(_.kind, _ => super.buildKind)
def generateSemanticdb(): CommandResult = {
private def buildKind: String = parsedConfig.fold(_.kind, _ => "")
private def generateSemanticdb(): CommandResult = {
parsedConfig match {
case ValueResult(value) =>
clean()
Expand Down Expand Up @@ -224,7 +235,7 @@ class LsifBuildTool(index: IndexCommand) extends BuildTool("LSIF", index) {
)
}
val mtags = Dependencies.resolveDependencies(
List(s"org.scalameta:mtags_${scalaVersion}:${BuildInfo.mtags}")
List(s"org.scalameta:mtags_${scalaVersion}:${BuildInfo.mtagsVersion}")
)
val scalaLibrary = mtags
.classpath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,22 @@ import com.sourcegraph.lsif_java.commands.IndexCommand
import os.CommandResult

class MavenBuildTool(index: IndexCommand) extends BuildTool("Maven", index) {
override def defaultTargetroot: Path =
Paths.get("target", "semanticdb-targetroot")

override def usedInCurrentDirectory(): Boolean =
Files.isRegularFile(index.workingDirectory.resolve("pom.xml"))

override def generateSemanticdb(): CommandResult = {
override def generateLsif(): Int = {
BuildTool.generateLsifFromTargetroot(
generateSemanticdb(),
index.finalTargetroot(defaultTargetroot),
index
)
}

private def defaultTargetroot: Path =
Paths.get("target", "semanticdb-targetroot")

private def generateSemanticdb(): CommandResult = {
TemporaryFiles.withDirectory(index) { tmp =>
val mvnw = index.workingDirectory.resolve("mvnw")
val mavenScript =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.sourcegraph.lsif_java.buildtools

import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.Properties

import scala.util.Using

import com.sourcegraph.io.AutoDeletedFile
import com.sourcegraph.lsif_java.BuildInfo
import com.sourcegraph.lsif_java.commands.IndexCommand

class SbtBuildTool(index: IndexCommand) extends BuildTool("sbt", index) {
override def usedInCurrentDirectory(): Boolean = {
Files.isRegularFile(index.workingDirectory.resolve("build.sbt")) ||
sbtVersion().isDefined
}

override def generateLsif(): Int = {
sbtVersion() match {
case Some(version) =>
if (isSupportedSbtVersion(version)) {
unconditionallyGenerateLsif()
} else {
failFast(
s"Unsupported sbt version '$version'. " +
s"To fix this problem, upgrade to sbt ${BuildInfo.sbtVersion} and try again."
)
}
case None =>
failFast(
s"No sbt version detected. " +
s"To fix this problem, run the following command and try again: " +
s"echo 'sbt.version=${BuildInfo.sbtVersion}' >> project/build.properties"
)
}
}

private def failFast(message: String): Int = {
index.app.error(message)
1
}

private def unconditionallyGenerateLsif(): Int =
Using.resource(sourcegraphSbtPluginFile()) { _ =>
val sourcegraphLsif = index
.process(List("sbt", "sourcegraphEnable", "sourcegraphLsif"))
val inputDump = index
.workingDirectory
.resolve("target")
.resolve("sbt-sourcegraph")
.resolve("dump.lsif")
if (sourcegraphLsif.exitCode == 0 && Files.isRegularFile(inputDump)) {
val outputDump = index.workingDirectory.resolve("dump.lsif")
Files.copy(inputDump, outputDump, StandardCopyOption.REPLACE_EXISTING)
index.app.info(outputDump.toString)
}
sourcegraphLsif.exitCode
}

private def isSupportedSbtVersion(version: String): Boolean = {
(!version.startsWith("0.13") || version.startsWith("0.13.17")) &&
!version.startsWith("1.0") && !version.startsWith("1.1")
}

private def sbtVersion(): Option[String] = {
val buildProperties = index
.workingDirectory
.resolve("project")
.resolve("build.properties")
if (Files.isRegularFile(buildProperties)) {
val props = new Properties()
val in = Files.newInputStream(buildProperties)
try props.load(in)
finally in.close()
Option(props.getProperty("sbt.version"))
} else {
None
}
}

private def sourcegraphSbtPluginFile(): AutoDeletedFile = {
val addSbtPluginFile = index
.workingDirectory
.resolve("project")
.resolve("sourcegraph_generated.sbt")
val version = BuildInfo.sbtSourcegraphVersion
AutoDeletedFile.fromPath(
addSbtPluginFile,
s"""addSbtPlugin("com.sourcegraph" % "sbt-sourcegraph" % "$version")
|""".stripMargin
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,16 @@ case class IndexCommand(
shellable: Shellable,
env: Map[String, String] = Map.empty
): CommandResult = {
app.out.println(Color.DarkGray(shellable.value.mkString("$ ", " ", "")))
val commandSyntax = shellable
.value
.map { line =>
if (line.contains(" "))
s"""'$line'"""
else
line
}
.mkString("$ ", " ", "")
app.out.println(Color.DarkGray(commandSyntax))
app
.process(shellable)
.call(
Expand Down Expand Up @@ -149,22 +158,7 @@ case class IndexCommand(
}
1
case tool :: Nil =>
val generateSemanticdbResult = tool.generateSemanticdb()
if (!Files.isDirectory(tool.targetroot)) {
generateSemanticdbResult.exitCode
} else if (app.reporter.hasErrors()) {
app.reporter.exitCode()
} else if (generateSemanticdbResult.exitCode != 0) {
generateSemanticdbResult.exitCode
} else {
IndexSemanticdbCommand(
output = finalOutput,
targetroot = List(tool.targetroot),
packagehub = packagehub,
buildKind = tool.buildKind,
app = app
).run()
}
tool.generateLsif()
case many =>
val names = many.map(_.name).mkString(", ")
app.error(
Expand Down
Loading