Skip to content

Commit

Permalink
Move Mill process working directory to sandbox (#3367)
Browse files Browse the repository at this point in the history
This makes `os.pwd` an empty directory: `out/mill-worker-*/sandbox/` for
Mill's server mode, `out/mill-no-server/sandbox/` otherwise

In general, code outside of tasks should use `millSourcePath`, while
code inside of tasks should use `T.dest` or the `PathRef`s given to it
by upstream tasks. Accessing project files via `os.pwd` can result in
tasks not invalidating when files changed.

Like #3347, this does not
prevent people intentionally walking the filesystem to work mischieve,
but it does help mitigate "accidental" usage of `os.pwd` to access
project files. The original `os.pwd` is still made available as
`mill.api.WorkspaceRoot.workspaceRoot` outside of tasks, or
`T.workspace` inside of tasks, for the occasional scenarios that need
it. But at least this adds some partial guardrails against accidentally
using `os.pwd` in a way that subverts Mill's expectations, and the APIs
that expose the workspace root can be appropriately documented to warn
people against doing the wrong thing
  • Loading branch information
lihaoyi authored Aug 16, 2024
1 parent 1722258 commit b3b2999
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 9 deletions.
6 changes: 5 additions & 1 deletion contrib/bloop/src/mill/contrib/bloop/Bloop.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package mill.contrib.bloop

import mill.eval.Evaluator
import mill.api.WorkspaceRoot

/**
* Usage : `mill mill.contrib.bloop.Bloop/install`
*/
object Bloop extends BloopImpl(() => Evaluator.allBootstrapEvaluators.value.value, os.pwd)
object Bloop extends BloopImpl(
() => Evaluator.allBootstrapEvaluators.value.value,
WorkspaceRoot.workspaceRoot
)
9 changes: 9 additions & 0 deletions example/thirdparty/acyclic/build.sc
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import mill._, scalalib._, publish._

// acyclic test suite assumes files are on disk at specific paths relative to `os.pwd`.
// To avoid changing the test code, we instead copy the necessary files into the `os.pwd`
// when preparing the resources for test suite execution
os.copy.over(
interp.watch(mill.api.WorkspaceRoot.workspaceRoot / "acyclic"),
os.pwd / "acyclic",
createFolders = true
)

object Deps {
def acyclic = ivy"com.lihaoyi:::acyclic:0.3.6"
def scalaCompiler(scalaVersion: String) = ivy"org.scala-lang:scala-compiler:$scalaVersion"
Expand Down
4 changes: 2 additions & 2 deletions example/thirdparty/netty/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ object common extends NettyModule{
val shell = new groovy.lang.GroovyShell()

val context = new java.util.HashMap[String, Object]
context.put("collection.template.dir", "common/src/main/templates")
context.put("collection.template.test.dir", "common/src/test/templates")
context.put("collection.template.dir", T.workspace + "/common/src/main/templates")
context.put("collection.template.test.dir", T.workspace + "/common/src/test/templates")
context.put("collection.src.dir", (T.dest / "src").toString)
context.put("collection.testsrc.dir", (T.dest / "testsrc").toString)
shell.setProperty("properties", context)
Expand Down
2 changes: 1 addition & 1 deletion integration/invalidation/watch-source-input/repo/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def lol = T{
def writeCompletionMarker(name: String) = {

Range(0, 10)
.map(i => os.pwd / "out" / s"$name$i")
.map(i => mill.api.WorkspaceRoot.workspaceRoot / "out" / s"$name$i")
.find(!os.exists(_))
.foreach(os.write(_, ""))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ abstract class IntegrationTestSuite extends TestSuite {

override def utestAfterEach(path: Seq[String]): Unit = {
runnerState = RunnerState.empty
if (integrationTestMode == "server") {
if (integrationTestMode == "server" || integrationTestMode == "local") {
// try to stop the server
try {
os.proc(millReleaseFileOpt.get, "shutdown").call(
Expand Down
12 changes: 8 additions & 4 deletions runner/client/src/mill/runner/client/MillProcessLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static Process configureRunMillProcess(ProcessBuilder builder,
builder.environment().put("MILL_WORKSPACE_ROOT", new File("").getCanonicalPath());
File sandbox = new java.io.File(serverDir + "/" + ServerFiles.sandbox);
sandbox.mkdirs();
// builder.directory(sandbox);
builder.directory(sandbox);
return builder.start();
}

Expand Down Expand Up @@ -88,7 +88,7 @@ static String javaExe() {
return "java";
}

static String[] millClasspath() {
static String[] millClasspath() throws Exception {
String selfJars = "";
List<String> vmOptions = new LinkedList<>();
String millOptionsPath = System.getProperty("MILL_OPTIONS_PATH");
Expand Down Expand Up @@ -121,10 +121,14 @@ static String[] millClasspath() {
if (selfJars == null || selfJars.trim().isEmpty()) {
throw new RuntimeException("MILL_CLASSPATH is empty!");
}
return selfJars.split("[,]");
String[] selfJarsArray = selfJars.split("[,]");
for(int i = 0; i < selfJarsArray.length; i++){
selfJarsArray[i] = new java.io.File(selfJarsArray[i]).getCanonicalPath();
}
return selfJarsArray;
}

static List<String> millLaunchJvmCommand(boolean setJnaNoSys) {
static List<String> millLaunchJvmCommand(boolean setJnaNoSys) throws Exception {
final List<String> vmOptions = new ArrayList<>();

// Java executable
Expand Down

0 comments on commit b3b2999

Please sign in to comment.