Skip to content

Commit

Permalink
Use XDG_RUNTIME_DIR environment variable to choose the path used for …
Browse files Browse the repository at this point in the history
…the creation of sockets (sbt#6887)

The `XDG_RUNTIME_DIR` environment variable will be used to choose the base directory in which the sockets will be created by **sbt**. This can help when issues such as sbt#6777 appear. There are other related issues, such as sbt#6101, [Metals issue sbt#2235](scalameta/metals#2235), [Che issue #18394](eclipse-che/che#18394). Those are closed issues, but there are some cases in which the solution does not work (such as the case in sbt#6777). Furthermore, the solution given seems more like a workaround than an actual fix.

**What causes this issue?**
At least in my case, the **ServerAlreadyBootingException** is thrown after **sbt** tries to create a Unix domain socket and fails. In my specific environment, I was not able to create the sockets in some directories because they were mounted on an NFS. This prevented me from using any automated sbt command on any of those directories (Metals uses sbt under the hood, and it was not able to start because of the ServerAlreadyBootingException), which in turn resulted in me not being able to use Metals on a project that was created on any of those directories. 

**How is the issue solved in this PR?**
If the `XDG_RUNTIME_DIR` environment variable is set, then sockets will be created in a folder with a hashed name, inside the directory `XDG_RUNTIME_DIR/.sbt/`. If this variable is not set, everything works exactly the same as always.

Let's see an example:

1. My environment variable `XDG_RUNTIME_DIR` is set to /home/alonso/.runtime-dir`
2. I create my project in `/home/alonso/workspace/hello-world`
3. I run `sbt compile`
4. The socket is created in `/home/alonso/.runtime-dir/.sbt/sbt-socket102030405060/sbt-load.sock`. The number **102030405060** is a hash that is computed from the base directory of the project (it is actually the same hash that is produced in order to create sockets in Windows) and it will be different depending on the location of the project
5. The sbt command executed correctly, which would not have happened if the socket had been created in the `home/alonso/workspace` directory or any of its subdirectories (in this example, `/home/BlackDiamond/workspace` corresponds to a network file share)

Co-authored-by: Alonso Montero <lumontero@mobilize.net>
  • Loading branch information
2 people authored and eed3si9n committed May 29, 2022
1 parent 359dbed commit 120014b
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions main-command/src/main/java/sbt/internal/BootServerSocket.java
Expand Up @@ -284,10 +284,11 @@ public OutputStream outputStream() {
public BootServerSocket(final AppConfiguration configuration)
throws ServerAlreadyBootingException, IOException {
final Path base = configuration.baseDirectory().toPath().toRealPath();
final Path target = base.resolve("project").resolve("target");
if (!isWindows) {
final String actualSocketLocation = socketLocation(base);
final Path target = Paths.get(actualSocketLocation).getParent();
if (!Files.isDirectory(target)) Files.createDirectories(target);
socketFile = Paths.get(socketLocation(base));
socketFile = Paths.get(actualSocketLocation);
} else {
socketFile = null;
}
Expand All @@ -301,13 +302,20 @@ public BootServerSocket(final AppConfiguration configuration)
}
}

public static String socketLocation(final Path base) throws UnsupportedEncodingException {
public static String socketLocation(final Path base)
throws UnsupportedEncodingException, IOException {
final Path target = base.resolve("project").resolve("target");
long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8"));
if (isWindows) {
long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8"));
return "sbt-load" + hash;
} else {
return base.relativize(target.resolve("sbt-load.sock")).toString();
final String alternativeSocketLocation =
System.getenv().getOrDefault("XDG_RUNTIME_DIR", "/tmp");
final Path alternativeSocketLocationRoot =
Paths.get(alternativeSocketLocation).resolve(".sbt");
final Path locationForSocket = alternativeSocketLocationRoot.resolve("sbt-socket" + hash);
final Path pathForSocket = locationForSocket.resolve("sbt-load.sock");
return pathForSocket.toString();
}
}

Expand Down

0 comments on commit 120014b

Please sign in to comment.