From 8e7dfb4b203e6d14924db0604e81429ca990f3b5 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 8 Feb 2018 09:08:13 +0000 Subject: [PATCH 1/2] Handle very long socket file paths on UNIX Fixes #3930 --- .../scala/sbt/internal/CommandExchange.scala | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index 69cb89477..cfc48c69a 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -9,6 +9,7 @@ package sbt package internal import java.io.IOException +import java.nio.file.Files import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic._ import scala.collection.mutable.ListBuffer @@ -23,6 +24,7 @@ import BasicKeys.{ logLevel } import java.net.Socket +import org.scalasbt.ipcsocket.UnixDomainSocketLibrary import sjsonnew.JsonFormat import sjsonnew.shaded.scalajson.ast.unsafe._ import scala.concurrent.Await @@ -32,7 +34,7 @@ import sbt.io.syntax._ import sbt.io.{ Hash, IO } import sbt.internal.server._ import sbt.internal.langserver.{ LogMessageParams, MessageType } -import sbt.internal.util.{ StringEvent, ObjectEvent, MainAppender } +import sbt.internal.util.{ StringEvent, ObjectEvent, MainAppender, Util } import sbt.internal.util.codec.JValueFormats import sbt.protocol.{ EventMessage, ExecStatusEvent } import sbt.util.{ Level, Logger, LogExchange } @@ -140,7 +142,18 @@ private[sbt] final class CommandExchange { val portfile = s.baseDir / "project" / "target" / "active.json" val h = Hash.halfHashString(IO.toURI(portfile).toString) val tokenfile = BuildPaths.getGlobalBase(s) / "server" / h / "token.json" - val socketfile = BuildPaths.getGlobalBase(s) / "server" / h / "sock" + val socketfile = { + val socketfile = BuildPaths.getGlobalBase(s) / "server" / h / "sock" + connectionType match { + case ConnectionType.Local if !Util.isWindows => + val maxSocketLength = new UnixDomainSocketLibrary.SockaddrUn().sunPath.length - 1 + if (socketfile.absolutePath.length > maxSocketLength) + Files.createTempFile("sbt-server", ".sock").toFile // assuming this is short enough.. + else + socketfile + case _ => socketfile + } + } val pipeName = "sbt-server-" + h val connection = ServerConnection( connectionType, From 4e038c91ce93196efff6490e1c1182ba5e8ee9fe Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 12 Feb 2018 17:56:53 +0000 Subject: [PATCH 2/2] Introduce SBT_GLOBAL_SERVER_DIR env var to override too long paths --- .../scala/sbt/internal/server/Server.scala | 11 ++++++++-- .../scala/sbt/internal/CommandExchange.scala | 21 +++++-------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/main-command/src/main/scala/sbt/internal/server/Server.scala b/main-command/src/main/scala/sbt/internal/server/Server.scala index f45019fb5..05b86c48a 100644 --- a/main-command/src/main/scala/sbt/internal/server/Server.scala +++ b/main-command/src/main/scala/sbt/internal/server/Server.scala @@ -60,9 +60,16 @@ private[sbt] object Server { // Named pipe already has an exclusive lock. addServerError(new Win32NamedPipeServerSocket(pipeName)) case ConnectionType.Local => - tryClient(new UnixDomainSocket(socketfile.getAbsolutePath)) + val maxSocketLength = new UnixDomainSocketLibrary.SockaddrUn().sunPath.length - 1 + val path = socketfile.getAbsolutePath + if (path.length > maxSocketLength) + sys.error("socket file absolute path too long; " + + "either switch to another connection type " + + "or define a short \"SBT_GLOBAL_SERVER_DIR\" value. " + + s"Current path: ${path}") + tryClient(new UnixDomainSocket(path)) prepareSocketfile() - addServerError(new UnixDomainServerSocket(socketfile.getAbsolutePath)) + addServerError(new UnixDomainServerSocket(path)) case ConnectionType.Tcp => tryClient(new Socket(InetAddress.getByName(host), port)) addServerError(new ServerSocket(port, 50, InetAddress.getByName(host))) diff --git a/main/src/main/scala/sbt/internal/CommandExchange.scala b/main/src/main/scala/sbt/internal/CommandExchange.scala index cfc48c69a..873946340 100644 --- a/main/src/main/scala/sbt/internal/CommandExchange.scala +++ b/main/src/main/scala/sbt/internal/CommandExchange.scala @@ -9,7 +9,6 @@ package sbt package internal import java.io.IOException -import java.nio.file.Files import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.atomic._ import scala.collection.mutable.ListBuffer @@ -24,7 +23,6 @@ import BasicKeys.{ logLevel } import java.net.Socket -import org.scalasbt.ipcsocket.UnixDomainSocketLibrary import sjsonnew.JsonFormat import sjsonnew.shaded.scalajson.ast.unsafe._ import scala.concurrent.Await @@ -34,7 +32,7 @@ import sbt.io.syntax._ import sbt.io.{ Hash, IO } import sbt.internal.server._ import sbt.internal.langserver.{ LogMessageParams, MessageType } -import sbt.internal.util.{ StringEvent, ObjectEvent, MainAppender, Util } +import sbt.internal.util.{ StringEvent, ObjectEvent, MainAppender } import sbt.internal.util.codec.JValueFormats import sbt.protocol.{ EventMessage, ExecStatusEvent } import sbt.util.{ Level, Logger, LogExchange } @@ -141,19 +139,10 @@ private[sbt] final class CommandExchange { if (server.isEmpty && firstInstance.get) { val portfile = s.baseDir / "project" / "target" / "active.json" val h = Hash.halfHashString(IO.toURI(portfile).toString) - val tokenfile = BuildPaths.getGlobalBase(s) / "server" / h / "token.json" - val socketfile = { - val socketfile = BuildPaths.getGlobalBase(s) / "server" / h / "sock" - connectionType match { - case ConnectionType.Local if !Util.isWindows => - val maxSocketLength = new UnixDomainSocketLibrary.SockaddrUn().sunPath.length - 1 - if (socketfile.absolutePath.length > maxSocketLength) - Files.createTempFile("sbt-server", ".sock").toFile // assuming this is short enough.. - else - socketfile - case _ => socketfile - } - } + val serverDir = + sys.env get "SBT_GLOBAL_SERVER_DIR" map file getOrElse BuildPaths.getGlobalBase(s) / "server" + val tokenfile = serverDir / h / "token.json" + val socketfile = serverDir / h / "sock" val pipeName = "sbt-server-" + h val connection = ServerConnection( connectionType,