Skip to content

Commit

Permalink
improvement: Remove bazel specific directories when running full clean
Browse files Browse the repository at this point in the history
I also added a small refactor to not use plain strings for the two directories being removed.
  • Loading branch information
tgodzik committed Mar 8, 2024
1 parent f1608f8 commit e4d76b2
Show file tree
Hide file tree
Showing 17 changed files with 119 additions and 65 deletions.
Expand Up @@ -10,6 +10,7 @@ import scala.util.control.NonFatal
import scala.meta.internal.bsp.BspConfigGenerationStatus._
import scala.meta.internal.builds.BuildServerProvider
import scala.meta.internal.builds.ShellRunner
import scala.meta.internal.metals.Directories
import scala.meta.internal.metals.Messages.BspProvider
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.StatusBar
Expand Down Expand Up @@ -45,10 +46,9 @@ final class BspConfigGenerator(
.map {
case Generated if buildTool.projectRoot != workspace =>
try {
val bsp = ".bsp"
workspace.resolve(bsp).createDirectories()
val buildToolBspDir = buildTool.projectRoot.resolve(bsp)
val workspaceBspDir = workspace.resolve(bsp).toNIO
workspace.resolve(Directories.bsp).createDirectories()
val buildToolBspDir = buildTool.projectRoot.resolve(Directories.bsp)
val workspaceBspDir = workspace.resolve(Directories.bsp).toNIO
buildToolBspDir.toFile.listFiles().foreach { file =>
val path = file.toPath()
if (!file.isDirectory() && path.filename.endsWith(".json")) {
Expand Down
Expand Up @@ -14,6 +14,7 @@ import scala.meta.internal.io.FileIO
import scala.meta.internal.metals.BuildServerConnection
import scala.meta.internal.metals.Cancelable
import scala.meta.internal.metals.ClosableOutputStream
import scala.meta.internal.metals.Directories
import scala.meta.internal.metals.JdkSources
import scala.meta.internal.metals.MetalsBuildClient
import scala.meta.internal.metals.MetalsEnrichments._
Expand Down Expand Up @@ -183,8 +184,8 @@ final class BspServers(
buf += p
}
}
visit(mainWorkspace.resolve(".bsp"))
customProjectRoot.map(_.resolve(".bsp")).foreach(visit)
visit(mainWorkspace.resolve(Directories.bsp))
customProjectRoot.map(_.resolve(Directories.bsp)).foreach(visit)
bspGlobalInstallDirectories.foreach(visit)
buf.result()
}
Expand Down
Expand Up @@ -4,6 +4,7 @@ import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption

import scala.meta.internal.metals.Directories
import scala.meta.io.AbsolutePath

trait BuildTool {
Expand Down Expand Up @@ -38,7 +39,7 @@ trait BuildTool {

def isBspGenerated(workspace: AbsolutePath): Boolean =
possibleBuildServerNames
.map(name => workspace.resolve(".bsp").resolve(s"$name.json"))
.map(name => workspace.resolve(Directories.bsp).resolve(s"$name.json"))
.exists(_.isFile)
}

Expand Down
Expand Up @@ -7,6 +7,7 @@ import java.util.concurrent.atomic.AtomicReference
import scala.meta.internal.bsp.ScalaCliBspScope
import scala.meta.internal.io.PathIO
import scala.meta.internal.metals.BloopServers
import scala.meta.internal.metals.Directories
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.UserConfiguration
import scala.meta.internal.metals.scalacli.ScalaCli
Expand Down Expand Up @@ -54,16 +55,18 @@ final class BuildTools(
def bloopProject: Option[AbsolutePath] = searchForBuildTool(isBloop)
def isBloop: Boolean = bloopProject.isDefined
def isBsp: Boolean = {
hasJsonFile(workspace.resolve(".bsp")) ||
customProjectRoot.exists(root => hasJsonFile(root.resolve(".bsp"))) ||
hasJsonFile(workspace.resolve(Directories.bsp)) ||
customProjectRoot.exists(root =>
hasJsonFile(root.resolve(Directories.bsp))
) ||
bspGlobalDirectories.exists(hasJsonFile)
}
private def hasJsonFile(dir: AbsolutePath): Boolean = {
dir.list.exists(_.extension == "json")
}

def isBazelBsp: Boolean = {
workspace.resolve(".bazelbsp").isDirectory &&
workspace.resolve(Directories.bazelBsp).isDirectory &&
BazelBuildTool.existingProjectView(workspace).nonEmpty &&
isBsp
}
Expand Down Expand Up @@ -136,7 +139,7 @@ final class BuildTools(
private def customBsps: List[BspOnly] = {
val bspFolders =
(workspace :: customProjectRoot.toList).distinct
.map(_.resolve(".bsp")) ++ bspGlobalDirectories
.map(_.resolve(Directories.bsp)) ++ bspGlobalDirectories
val root = customProjectRoot.getOrElse(workspace)
for {
bspFolder <- bspFolders
Expand Down
Expand Up @@ -67,7 +67,7 @@ case class SbtBuildTool(
): Option[List[String]] =
Option.when(workspaceSupportsBsp(projectRoot)) {
val bspConfigArgs = List[String]("bspConfig")
val bspDir = workspace.resolve(".bsp").toNIO
val bspDir = workspace.resolve(Directories.bsp).toNIO
composeArgs(bspConfigArgs, projectRoot, bspDir)
}

Expand Down Expand Up @@ -449,7 +449,7 @@ object SbtBuildTool {
workspace: AbsolutePath,
userJavaHome: Option[String],
): Boolean = {
val bspConfigFile = workspace.resolve(".bsp").resolve("sbt.json")
val bspConfigFile = workspace.resolve(Directories.bsp).resolve("sbt.json")
if (bspConfigFile.isFile) {
val matchesSbtJavaHome =
for {
Expand Down
Expand Up @@ -6,6 +6,7 @@ import scala.concurrent.Future

import scala.meta.internal.bsp.BspConfigGenerationStatus._
import scala.meta.internal.metals.BuildInfo
import scala.meta.internal.metals.Directories
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.StatusBar
import scala.meta.internal.metals.UserConfiguration
Expand All @@ -30,7 +31,8 @@ class ScalaCliBuildTool(
): Future[BspConfigGenerationStatus] =
createBspFileArgs(workspace).map(systemProcess).getOrElse {
// fallback to creating `.bsp/scala-cli.json` that starts JVM launcher
val bspConfig = workspace.resolve(".bsp").resolve("scala-cli.json")
val bspConfig =
workspace.resolve(Directories.bsp).resolve("scala-cli.json")
statusBar.addMessage("scala-cli bspConfig")
bspConfig.writeText(
ScalaCli.scalaCliBspJsonContent(projectRoot = projectRoot.toString())
Expand Down Expand Up @@ -70,7 +72,7 @@ object ScalaCliBuildTool {

def pathsToScalaCliBsp(root: AbsolutePath): List[AbsolutePath] =
ScalaCli.names.toList.map(name =>
root.resolve(".bsp").resolve(s"$name.json")
root.resolve(Directories.bsp).resolve(s"$name.json")
)

def apply(
Expand Down
Expand Up @@ -22,6 +22,10 @@ object Directories {
RelativePath(".metals").resolve("workspace-symbol.md")
def stacktrace: RelativePath =
RelativePath(".metals").resolve(stacktraceFilename)
def bazelBsp: RelativePath =
RelativePath(".bazelbsp")
def bsp: RelativePath =
RelativePath(".bsp")

val stacktraceFilename = "stacktrace.scala"
val dependenciesName = "dependencies"
Expand Down
Expand Up @@ -342,6 +342,18 @@ object MetalsEnrichments

implicit class XtensionAbsolutePathBuffers(path: AbsolutePath) {

def isBazelRelatedPath: Boolean = {
val filename = path.toNIO.getFileName.toString
filename == "WORKSPACE" ||
filename == "BUILD" ||
filename == "BUILD.bazel" ||
filename.endsWith(".bzl") ||
filename.endsWith(".bazelproject")
}
def isInBspDirectory(workspace: AbsolutePath): Boolean =
path.toNIO.startsWith(workspace.resolve(Directories.bsp).toNIO)
def isInBazelBspDirectory(workspace: AbsolutePath): Boolean =
path.toNIO.startsWith(workspace.resolve(Directories.bazelBsp).toNIO)
def isScalaProject(): Boolean =
containsProjectFilesSatisfying(_.isScala)
def isMetalsProject(): Boolean =
Expand Down
Expand Up @@ -2834,17 +2834,42 @@ class MetalsLspService(
}
}

private def clearFolders(folders: AbsolutePath*): Unit = {
try {
folders.foreach(_.deleteRecursively())
} catch {
case e: Throwable =>
languageClient.showMessage(Messages.ResetWorkspaceFailed)
scribe.error(
s"Error while deleting directories inside ${folders.mkString(", ")}",
e,
)
}
}

def resetWorkspace(): Future[Unit] =
for {
_ <- disconnectOldBuildServer()
_ = optProjectRoot match {
shouldImport = optProjectRoot match {
case Some(path) if buildTools.isBloop(path) =>
bloopServers.shutdownServer()
clearBloopDir(path)
case _ =>
false
case Some(path) if buildTools.isBazelBsp =>
clearFolders(
path.resolve(Directories.bazelBsp),
path.resolve(Directories.bsp),
)
true
case Some(path) if buildTools.isBsp =>
clearFolders(path.resolve(Directories.bsp))
true
case _ => false
}
_ = tables.cleanAll()
_ <- autoConnectToBuildServer().map(_ => ())
_ <-
if (shouldImport) slowConnectToBuildServer(true)
else autoConnectToBuildServer().map(_ => ())
} yield ()

def getTastyForURI(uri: URI): Future[Either[String, String]] =
Expand Down
Expand Up @@ -345,21 +345,6 @@ trait ScalametaCommonEnrichments extends CommonMtagsEnrichments {
path.toURI.toString
}

def isBazelRelatedPath: Boolean = {
val filename = path.toNIO.getFileName.toString
filename == "WORKSPACE" ||
filename == "BUILD" ||
filename == "BUILD.bazel" ||
filename.endsWith(".bzl") ||
filename.endsWith(".bazelproject")
}

def isInBazelBspDirectory(workspace: AbsolutePath): Boolean =
path.toNIO.startsWith(workspace.resolve(".bazelbsp").toNIO)

def isInBspDirectory(workspace: AbsolutePath): Boolean =
path.toNIO.startsWith(workspace.resolve(".bsp").toNIO)

/*
* This checks if the file has an extension that indicates it's a
* Java or Scala file.
Expand Down
36 changes: 26 additions & 10 deletions tests/slow/src/test/scala/tests/bazel/BazelLspSuite.scala
Expand Up @@ -5,12 +5,14 @@ import scala.concurrent.Promise
import scala.meta.internal.builds.BazelBuildTool
import scala.meta.internal.builds.BazelDigest
import scala.meta.internal.metals.FileDecoderProvider
import scala.meta.internal.metals.Messages
import scala.meta.internal.metals.Messages._
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.ServerCommands
import scala.meta.internal.metals.{BuildInfo => V}
import scala.meta.io.AbsolutePath

import org.eclipse.lsp4j.MessageActionItem
import tests.BaseImportSuite
import tests.BazelBuildLayout
import tests.BazelServerInitializer
Expand Down Expand Up @@ -131,11 +133,21 @@ class BazelLspSuite
}
}

test("import-build") {
test("import-reset-build") {
cleanWorkspace()
writeLayout(
BazelBuildLayout(workspaceLayout, V.bazelScalaVersion, bazelVersion)
)

def getTargetInfo(target: String) = {
server
.executeDecodeFileCommand(
FileDecoderProvider
.createBuildTargetURI(workspace, target)
.toString
)
.map(_.value.linesIterator.take(14).mkString("\n"))
}
for {
_ <- server.initialize()
_ <- server.initialized()
Expand All @@ -153,13 +165,8 @@ class BazelLspSuite
// We need to wait a bit just to ensure the connection is made
_ <- server.server.buildServerPromise.future
targets <- server.listBuildTargets
result <- server.executeDecodeFileCommand(
FileDecoderProvider
.createBuildTargetURI(workspace, targets.head.bazelEscapedDisplayName)
.toString
)
_ = assertNoDiff(
result.value.linesIterator.take(14).mkString("\n"),
result <- getTargetInfo(targets.head.bazelEscapedDisplayName)
expectedTarget =
"""|Target
| @//:hello1
|
Expand All @@ -173,14 +180,23 @@ class BazelLspSuite
| Debug <- NOT SUPPORTED
| Run
| Test <- NOT SUPPORTED
| Compile""".stripMargin,
)
| Compile""".stripMargin
_ = assertNoDiff(result, expectedTarget)
_ = server.server.buildServerPromise = Promise()
_ = client.resetWorkspace =
new MessageActionItem(Messages.ResetWorkspace.resetWorkspace)
_ <- server.executeCommand(ServerCommands.ResetWorkspace)
_ <- server.server.buildServerPromise.future
resultAfter <- getTargetInfo(targets.head.bazelEscapedDisplayName)
_ = assertNoDiff(resultAfter, expectedTarget)
} yield {
assertNoDiff(
client.workspaceMessageRequests,
List(
BazelBuildTool.mainClass,
bazelNavigationMessage,
Messages.ResetWorkspace.message,
BazelBuildTool.mainClass,
).mkString("\n"),
)
assert(bazelBspConfig.exists)
Expand Down
18 changes: 11 additions & 7 deletions tests/unit/src/main/scala/bill/Bill.scala
Expand Up @@ -30,6 +30,7 @@ import scala.util.Try
import scala.util.control.NonFatal

import scala.meta.internal.metals.BuildInfo
import scala.meta.internal.metals.Directories
import scala.meta.internal.metals.Embedded
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.PositionSyntax._
Expand Down Expand Up @@ -476,23 +477,26 @@ object Bill {
* Installed this build tool only for the local workspace
*/
def installWorkspace(
directory: Path,
directory: AbsolutePath,
name: String = "Bill",
): Unit = {
handleInstall(directory.resolve(".bsp"), name)
handleInstall(directory.resolve(Directories.bsp), name)
}

/**
* Installed this build server globally for the machine
*/
def installGlobal(
directory: Path,
directory: AbsolutePath,
name: String = "Bill",
): Unit = {
handleInstall(directory.resolve("bsp"), name)
}

private def handleInstall(directory: Path, name: String = "Bill"): Unit = {
private def handleInstall(
directory: AbsolutePath,
name: String = "Bill",
): Unit = {
val java =
Paths.get(System.getProperty("java.home")).resolve("bin").resolve("java")
val classpath = myClasspath.mkString(File.pathSeparator)
Expand All @@ -511,8 +515,8 @@ object Bill {
)
val json = new GsonBuilder().setPrettyPrinting().create().toJson(details)
val bspJson = directory.resolve(s"${name.toLowerCase()}.json")
Files.createDirectories(directory)
Files.write(bspJson, json.getBytes(StandardCharsets.UTF_8))
directory.createDirectories()
bspJson.writeText(json)
println(s"installed: $bspJson")
}

Expand Down Expand Up @@ -586,7 +590,7 @@ object Bill {
def main(args: Array[String]): Unit = {
args.toList match {
case List("help" | "--help" | "-help" | "-h") => handleHelp()
case List("install") => handleInstall(cwd)
case List("install") => handleInstall(AbsolutePath(cwd))
case List("bsp") => handleBsp()
case List("compile") => handleCompile(cwd)
case List("compile", wd) => handleCompile(Paths.get(wd))
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/src/main/scala/tests/BuildServerInitializer.scala
Expand Up @@ -6,6 +6,7 @@ import scala.util.Properties

import scala.meta.internal.builds.BuildTool
import scala.meta.internal.builds.SbtBuildTool
import scala.meta.internal.metals.Directories
import scala.meta.internal.metals.Messages.ImportBuild
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.ServerCommands
Expand Down Expand Up @@ -137,7 +138,7 @@ object SbtServerInitializer extends BuildServerInitializer {
workspace: AbsolutePath,
sbtVersion: String,
): Unit = {
val bspFolder = workspace.resolve(".bsp")
val bspFolder = workspace.resolve(Directories.bsp)
val sbtJson = bspFolder.resolve("sbt.json")
// don't overwrite existing BSP config
if (!sbtJson.isFile) {
Expand Down

0 comments on commit e4d76b2

Please sign in to comment.