@@ -2,6 +2,7 @@ import sbt.Keys._
22import sbt ._
33import java .io .{ RandomAccessFile , File }
44import java .nio .channels .FileLock
5+ import scala .reflect .io .Path
56
67object DottyBuild extends Build {
78
@@ -16,8 +17,6 @@ object DottyBuild extends Build {
1617 // "-XX:+HeapDumpOnOutOfMemoryError", "-Xmx1g", "-Xss2m"
1718 )
1819
19- var partestLock : FileLock = null
20-
2120 val defaults = Defaults .defaultSettings ++ Seq (
2221 scalaVersion in Global := " 2.11.5" ,
2322 version in Global := " 0.1-SNAPSHOT" ,
@@ -42,16 +41,16 @@ object DottyBuild extends Build {
4241 // to get Scala 2.11
4342 resolvers += Resolver .sonatypeRepo(" releases" ),
4443
45- // get reflect and xml onboard
46- libraryDependencies ++= Seq (" org.scala-lang" % " scala-reflect" % scalaVersion.value,
47- " org.scala-lang.modules" %% " scala-xml" % " 1.0.1" ,
48- " me.d-d" % " scala-compiler" % " 2.11.5-20150506-175515-8fc7635b56" ,
44+ // get libraries onboard
45+ partestDeps := Seq (" me.d-d" % " scala-compiler" % " 2.11.5-20150506-175515-8fc7635b56" ,
46+ " org.scala-lang" % " scala-reflect" % scalaVersion.value,
47+ " org.scala-lang" % " scala-library" % scalaVersion.value % " test" ),
48+ libraryDependencies ++= partestDeps.value,
49+ libraryDependencies ++= Seq (" org.scala-lang.modules" %% " scala-xml" % " 1.0.1" ,
4950 " org.scala-lang.modules" %% " scala-partest" % " 1.0.5" % " test" ,
51+ " com.novocode" % " junit-interface" % " 0.11" % " test" ,
5052 " jline" % " jline" % " 2.12" ),
5153
52- // get junit onboard
53- libraryDependencies += " com.novocode" % " junit-interface" % " 0.11" % " test" ,
54-
5554 // scalac options
5655 scalacOptions in Global ++= Seq (" -feature" , " -deprecation" , " -language:_" ),
5756
@@ -62,14 +61,26 @@ object DottyBuild extends Build {
6261
6362 // enable verbose exception messages for JUnit
6463 testOptions in Test += Tests .Argument (TestFrameworks .JUnit , " -a" , " -v" , " --run-listener=test.ContextEscapeDetector" ),
65- testOptions in Test += Tests .Cleanup ({ () => if (partestLock != null ) partestLock.release }),
66- // when this file is locked, running test generates the files for partest
67- // otherwise it just executes the tests directly
64+ testOptions in Test += Tests .Cleanup ({ () => partestLockFile.delete }),
65+
6866 lockPartestFile := {
69- val partestLockFile = " ." + File .separator + " tests" + File .separator + " partest.lock"
70- partestLock = new RandomAccessFile (partestLockFile, " rw" ).getChannel.tryLock
67+ // When this file is present, running `test` generates the files for
68+ // partest. Otherwise it just executes the tests directly.
69+ val lockDir = partestLockFile.getParentFile
70+ lockDir.mkdirs
71+ // Cannot have concurrent partests as they write to the same directory.
72+ if (lockDir.list.size > 0 )
73+ throw new RuntimeException (" ERROR: sbt partest: another partest is already running, pid in lock file: " + lockDir.list.toList.mkString(" " ))
74+ partestLockFile.createNewFile
75+ partestLockFile.deleteOnExit
76+ },
77+ runPartestRunner <<= Def .taskDyn {
78+ val jars = Seq ((packageBin in Compile ).value.getAbsolutePath) ++
79+ getJarPaths(partestDeps.value, ivyPaths.value.ivyHome)
80+ val dottyJars = " -dottyJars " + jars.length + " " + jars.mkString(" " )
81+ // Provide the jars required on the classpath of run tests
82+ runTask(Test , " dotty.partest.DPConsoleRunner" , dottyJars)
7183 },
72- runPartestRunner <<= runTask(Test , " dotty.partest.DPConsoleRunner" , " " ) dependsOn (test in Test ),
7384
7485 // Adjust classpath for running dotty
7586 mainClass in (Compile , run) := Some (" dotty.tools.dotc.Main" ),
@@ -79,31 +90,31 @@ object DottyBuild extends Build {
7990
8091 // http://grokbase.com/t/gg/simple-build-tool/135ke5y90p/sbt-setting-jvm-boot-paramaters-for-scala
8192 javaOptions <++= (managedClasspath in Runtime , packageBin in Compile ) map { (attList, bin) =>
82- // put the Scala {library, reflect} in the classpath
83- val path = for {
84- file <- attList.map(_.data)
85- path = file.getAbsolutePath
86- } yield " -Xbootclasspath/p:" + path
87- // dotty itself needs to be in the bootclasspath
88- val fullpath = (" -Xbootclasspath/a:" + bin) :: path.toList
89- // System.err.println("BOOTPATH: " + fullpath)
90-
91- val travis_build = // propagate if this is a travis build
92- if (sys.props.isDefinedAt(TRAVIS_BUILD ))
93- List (s " -D $TRAVIS_BUILD= ${sys.props(TRAVIS_BUILD )}" ) ::: travisMemLimit
94- else
95- List ()
96-
97- val tuning =
98- if (sys.props.isDefinedAt(" Oshort" ))
99- // Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
100- List (" -XX:+TieredCompilation" , " -XX:TieredStopAtLevel=1" )
93+ // put the Scala {library, reflect} in the classpath
94+ val path = for {
95+ file <- attList.map(_.data)
96+ path = file.getAbsolutePath
97+ } yield " -Xbootclasspath/p:" + path
98+ // dotty itself needs to be in the bootclasspath
99+ val fullpath = (" -Xbootclasspath/a:" + bin) :: path.toList
100+ // System.err.println("BOOTPATH: " + fullpath)
101+
102+ val travis_build = // propagate if this is a travis build
103+ if (sys.props.isDefinedAt(TRAVIS_BUILD ))
104+ List (s " -D $TRAVIS_BUILD= ${sys.props(TRAVIS_BUILD )}" ) ::: travisMemLimit
101105 else
102106 List ()
103107
104- tuning ::: agentOptions ::: travis_build ::: fullpath
108+ val tuning =
109+ if (sys.props.isDefinedAt(" Oshort" ))
110+ // Optimize for short-running applications, see https://github.com/lampepfl/dotty/issues/222
111+ List (" -XX:+TieredCompilation" , " -XX:TieredStopAtLevel=1" )
112+ else
113+ List ()
114+
115+ (" -DpartestParentID=" + pid) :: tuning ::: agentOptions ::: travis_build ::: fullpath
105116 }
106- ) ++ addCommandAlias(" partest" , " ;lockPartestFile;runPartestRunner" )
117+ ) ++ addCommandAlias(" partest" , " ;test:compile; lockPartestFile;test:test ;runPartestRunner" )
107118
108119 lazy val dotty = Project (id = " dotty" , base = file(" ." ), settings = defaults)
109120
@@ -154,7 +165,23 @@ object DottyBuild extends Build {
154165 lazy val benchmarks = Project (id = " dotty-bench" , settings = benchmarkSettings,
155166 base = file(" bench" )) dependsOn(dotty % " compile->test" )
156167
157- lazy val lockPartestFile = TaskKey [Unit ](" lockPartestFile" , " Creates the file lock on ./tests/partest.lock" )
158- lazy val runPartestRunner = TaskKey [Unit ](" runPartestRunner" , " Runs partests" )
159-
168+ // Partest tasks
169+ lazy val lockPartestFile = TaskKey [Unit ](" lockPartestFile" , " Creates the lock file at ./tests/locks/partest-<pid>.lock" )
170+ lazy val partestLockFile = new File (" ." + File .separator + " tests" + File .separator + " locks" + File .separator + s " partest- $pid.lock " )
171+ def pid = java.lang.Long .parseLong(java.lang.management.ManagementFactory .getRuntimeMXBean().getName().split(" @" )(0 ))
172+
173+ lazy val runPartestRunner = TaskKey [Unit ](" runPartestRunner" , " Runs partest" )
174+
175+ lazy val partestDeps = SettingKey [Seq [ModuleID ]](" partestDeps" , " Finds jars for partest dependencies" )
176+ def getJarPaths (modules : Seq [ModuleID ], ivyHome : Option [File ]): Seq [String ] = ivyHome match {
177+ case Some (home) =>
178+ modules.map({ module =>
179+ val file = Path (home) / Path (" cache" ) /
180+ Path (module.organization) / Path (module.name) / Path (" jars" ) /
181+ Path (module.name + " -" + module.revision + " .jar" )
182+ if (! file.isFile) throw new RuntimeException (" ERROR: sbt getJarPaths: dependency jar not found: " + file)
183+ else file.jfile.getAbsolutePath
184+ })
185+ case None => throw new RuntimeException (" ERROR: sbt getJarPaths: ivyHome not defined" )
186+ }
160187}
0 commit comments