cvogt / cbt

CBT - fun, fast, intuitive, compositional, statically checked builds written in Scala
Other
488 stars 60 forks source link

Wrong path in running cbt instance #153

Open rockjam opened 8 years ago

rockjam commented 8 years ago

I found one nasty issue in cbt, when you get wrong current directory. I got two cbt projects.

First:

➜  cbt-uber-jar pwd
/Users/rockjam/projects/cbt-uber-jar
➜  cbt-uber-jar tree -L 2
.
├── build
│   └── build.scala
└── src
    └── Main.scala

Second:

➜  cbt-another pwd
/Users/rockjam/projects/cbt-another
➜  cbt-another tree -L 2
.
├── Main.scala
└── build
    └── build.scala

Build files are identical:

import cbt._
import java.nio.file.Paths

class Build(val context: Context) extends BaseBuild{
  def currentPath: Unit = {
    println(s"current path is: ${Paths.get("").toAbsolutePath}")
  }
}

I don't have running cbt process. In first project(/Users/rockjam/projects/cbt-uber-jar) I call cbt currentPath:

➜  cbt-uber-jar cbt currentPath
current path is: /Users/rockjam/projects/cbt-uber-jar

In second project(/Users/rockjam/projects/cbt-another) I call cbt currentPath:

➜  cbt-another cbt currentPath
current path is: /Users/rockjam/projects/cbt-uber-jar

!!!Absolute path comes back to normal only when I kill nailgun process.
➜  cbt-another ps aux | grep java | grep nailgun
rockjam         78352   0.1  2.2  8287252 367608 s000  S     1:50AM   0:25.50 /usr/bin/java -server -jar /usr/local/Cellar/nailgun/0.9.1/libexec/nailgun-server-0.9.1.jar 127.0.0.1:4444
➜  cbt-another kill 78352
➜  cbt-another cbt currentPath
current path is: /Users/rockjam/projects/cbt-another
benjaminfrank commented 8 years ago

I believe this is an artifact of using nailgun. The current working directory (from JVM point of view) is the working directory where the JVM was started. In our case that is the nailgun-server which is started by the cbt script. And the cbt script has as working directory the directory you call it from. So the CWD of nailgun will be the CWD you call CBT from when it starts nailgun. As a result anything run via nailgun has the current working directory of the JVM/nailgun, see the following example. It will run the following code:

import java.nio.file.Paths
object Main {
  def main(args: Array[String]): Unit = {
    println(s"current path is: ${Paths.get("").toAbsolutePath}")
  }
}

Result:

XXPM00355799A:~ d061778$  ~/repos/other/cbt/cbt kill
Stopping nailgun
XXPM00355799A:~ d061778$  ~/repos/other/cbt/cbt nonexistingCommand #starts nailgun
Method not found: nonexistingCommand

Methods provided by CBT (but possibly overwritten)

  _context  apiTarget  c  classLoaderCache  classpath  compile  compileClasspath 
 compileDependencies  compileStatusFile  compileTarget  context  
crossScalaVersions crossScalaVersionsArray  defaultScalaVersion  dependencies
  dependenciesArray  dependencyClasspath  dependencyClasspathArray  
dependencyTree  enableConcurrency  exportedClasspath  exportedClasspathArray
  finalBuild  jarTarget  lib  localJars  logEmptySourceDirectories  logger  
needsUpdate  needsUpdateCompat  projectDirectory  projectName  r  recursive
  rt  run  runClass  scalaMajorVersion  scalaTarget  scalaVersion  scalacOptions
  show  sourceFiles  sources  t  target  targetClasspath  test  
transitiveDependencies  triggerLoopFiles  triggerLoopFilesArray  usage  
zincVersion

XXPM00355799A:~ d061778$ cd tmp/prt/
XXPM00355799A:prt d061778$  ~/repos/other/cbt/cbt run
current path is: /Users/d061778
XXPM00355799A:prt d061778$

See how my code in ~/tmp/prt/has ~ as CWD because that is where CBT started the nailgun process. I am not sure how this can be properly resolves. Even if you could change the CWD of a running JVM, this would probably break concurrent compiles/runs even more than now (imaging you change CWD during execution...). Maybe a forked JVM to run stuff might be an option. Or cbt run simply has this caveat. I guess it isn't really intended to start your program anyway, and more for checking what your programm does during development.

cvogt commented 8 years ago

So cbt does not use java's cwd but tracks it's own w which is passed from the client to the nailgun server. So cbt should be OK with switching cwds if that's possible. It's still hacky and error prone to other code.

We have the same problem. For environment vars and system properties. The are all global to the jvm which makes running multiple apps on the same jvm tricky. Maybe we should write a little library that provides scoped alternatives to these globals which Java / Scala code can use instead of the original globals and which default the the normal globals but persistent runtimes such as nailgun or cbt on top of nailgun can use to scope things. Doesn't help existing Java / Scala code but could at least help us to do better in new projects.

cvogt commented 8 years ago

A forked jvm would be another way to solve this, but means no caching of class loaders in between which can mean multiple seconds overhead for switching. cbt direct <task> does that. It should work as expected.