From b8e3edf032c60e8c9ae4f28d5c3ac2e2720308cc Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 13 Feb 2017 22:54:12 -0500 Subject: easier setting of projectDirectory in sub-builds by replacing context.projectDirectory by workingDirectory and using it as the default but allowing it to being overridden --- compatibility/Context.java | 6 +++++- examples/multi-combined-example/build/build.scala | 8 ++++---- libraries/eval/build/build.scala | 2 +- stage1/ContextImplementation.scala | 4 +++- stage1/cbt.scala | 4 ++-- stage2/BasicBuild.scala | 4 ++-- stage2/BuildBuild.scala | 2 +- stage2/BuildDependency.scala | 4 ++-- stage2/GitDependency.scala | 4 ++-- stage2/Lib.scala | 8 ++++---- 10 files changed, 26 insertions(+), 20 deletions(-) diff --git a/compatibility/Context.java b/compatibility/Context.java index afd0b15..389d401 100644 --- a/compatibility/Context.java +++ b/compatibility/Context.java @@ -18,9 +18,11 @@ public interface Context{ public default long start(){ throw new IncompatibleCbtVersionException("You need to define method start."); }; + public default File workingDirectory(){ + return projectDirectory(); + }; // methods that exist for longer which every CBT version in use should have by now, no default values needed - public abstract File projectDirectory(); public abstract File cwd(); // REPLACE by something that allows to run cbt on some other directly public abstract String[] argsArray(); // replace this by https://github.com/cvogt/cbt/issues/172 ? public abstract String[] enabledLoggersArray(); @@ -40,4 +42,6 @@ public interface Context{ public abstract ConcurrentHashMap permanentKeys(); @java.lang.Deprecated public abstract ConcurrentHashMap permanentClassLoaders(); + @java.lang.Deprecated + public abstract File projectDirectory(); } diff --git a/examples/multi-combined-example/build/build.scala b/examples/multi-combined-example/build/build.scala index 41c03d6..7d1ff9f 100644 --- a/examples/multi-combined-example/build/build.scala +++ b/examples/multi-combined-example/build/build.scala @@ -10,7 +10,7 @@ class Shared(val context: Context) extends SharedCbtBuild class Sub(val context:Context) extends SharedCbtBuild{ override def dependencies = Seq(new Shared( context.copy( - projectDirectory = projectDirectory ++ "/../shared" + workingDirectory = projectDirectory ++ "/../shared" ) )) } @@ -24,19 +24,19 @@ class Build(val context: Context) extends BaseBuild{ */ def sub1 = new Sub( context.copy( - projectDirectory = projectDirectory ++ "/sub1" + workingDirectory = projectDirectory ++ "/sub1" ) ) def sub2 = new Sub( context.copy( - projectDirectory = projectDirectory ++ "/sub2" + workingDirectory = projectDirectory ++ "/sub2" ) ) def sub3 = // DON'T DO THIS, anonymous classes are currently not supported here. new SharedCbtBuild{ def context = Build.this.context.copy( - projectDirectory = Build.this.projectDirectory ++ "/sub3" + workingDirectory = Build.this.projectDirectory ++ "/sub3" ) } diff --git a/libraries/eval/build/build.scala b/libraries/eval/build/build.scala index 7135d3f..a869ace 100644 --- a/libraries/eval/build/build.scala +++ b/libraries/eval/build/build.scala @@ -5,7 +5,7 @@ class Build(val context: Context) extends BaseBuild{ new ScalaCompilerDependency( context.cbtLastModified, context.paths.mavenCache, scalaVersion ) override def test: Option[ExitCode] = Some{ - new BasicBuild(context.copy(projectDirectory = projectDirectory ++ "/test")) with ScalaTest{ + new BasicBuild(context.copy(workingDirectory = projectDirectory ++ "/test")) with ScalaTest{ override def dependencies = super.dependencies ++ Seq( DirectoryDependency(projectDirectory++"/..") ) diff --git a/stage1/ContextImplementation.scala b/stage1/ContextImplementation.scala index 69094b0..b263ef4 100644 --- a/stage1/ContextImplementation.scala +++ b/stage1/ContextImplementation.scala @@ -2,7 +2,7 @@ package cbt import java.io._ class ContextImplementation( - override val projectDirectory: File, + override val workingDirectory: File, override val cwd: File, override val argsArray: Array[String], override val enabledLoggersArray: Array[String], @@ -17,6 +17,8 @@ class ContextImplementation( override val compatibilityTarget: File, override val parentBuildOrNull: BuildInterface ) extends Context{ + @deprecated("this method is replaced by workingDirectory","") + def projectDirectory = workingDirectory @deprecated("this method is replaced by cbtLastModified","") def cbtHasChangedCompat = true @deprecated("this method is replaced by start","") diff --git a/stage1/cbt.scala b/stage1/cbt.scala index a1776b1..54f3159 100644 --- a/stage1/cbt.scala +++ b/stage1/cbt.scala @@ -77,7 +77,7 @@ object `package`{ def cbtLastModified: scala.Long = subject.cbtLastModified def copy( - projectDirectory: File = projectDirectory, + workingDirectory: File = workingDirectory, args: Seq[String] = args, //enabledLoggers: Set[String] = enabledLoggers, cbtLastModified: Long = cbtLastModified, @@ -85,7 +85,7 @@ object `package`{ cbtHome: File = cbtHome, parentBuild: Option[BuildInterface] = None ): Context = new ContextImplementation( - projectDirectory, + workingDirectory, cwd, args.to, enabledLoggers.to, diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index b7b0854..a2c7238 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -21,7 +21,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge // ========== general stuff ========== def enableConcurrency = false - final def projectDirectory: File = lib.realpath(context.projectDirectory) + def projectDirectory: File = lib.realpath(context.workingDirectory) assert( projectDirectory.exists, "projectDirectory does not exist: " ++ projectDirectory.string ) assert( projectDirectory.getName =!= "build" || @@ -107,7 +107,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge ) = lib.ScalaDependency( groupId, artifactId, version, classifier, scalaVersion ) final def DirectoryDependency(path: File) = cbt.DirectoryDependency( - context.copy( projectDirectory = path, args = Seq() ) + context.copy( workingDirectory = path, args = Seq() ) ) def triggerLoopFiles: Seq[File] = sources ++ transitiveDependencies.collect{ case b: TriggerLoop => b.triggerLoopFiles }.flatten diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index 1b05214..994ac2e 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -12,7 +12,7 @@ trait BuildBuildWithoutEssentials extends BaseBuild{ ) protected final val managedContext = context.copy( - projectDirectory = managedBuildDirectory, + workingDirectory = managedBuildDirectory, parentBuild=Some(this) ) diff --git a/stage2/BuildDependency.scala b/stage2/BuildDependency.scala index 236f958..ed6c2bd 100644 --- a/stage2/BuildDependency.scala +++ b/stage2/BuildDependency.scala @@ -17,8 +17,8 @@ trait TriggerLoop extends DependencyImplementation{ /** You likely want to use the factory method in the BasicBuild class instead of this. */ final case class DirectoryDependency(context: Context) extends TriggerLoop{ override def toString = show - override def show = this.getClass.getSimpleName ++ "(" ++ context.projectDirectory.string ++ ")" - def moduleKey = this.getClass.getName ++ "("+context.projectDirectory.string+")" + override def show = this.getClass.getSimpleName ++ "(" ++ context.workingDirectory.string ++ ")" + def moduleKey = this.getClass.getName ++ "("+context.workingDirectory.string+")" lazy val logger = context.logger override lazy val lib: Lib = new Lib(logger) def transientCache = context.transientCache diff --git a/stage2/GitDependency.scala b/stage2/GitDependency.scala index 059d650..754e41a 100644 --- a/stage2/GitDependency.scala +++ b/stage2/GitDependency.scala @@ -21,7 +21,7 @@ case class GitDependency( // See http://www.codeaffine.com/2014/12/09/jgit-authentication/ private val GitUrl( _, domain, path ) = url - private val credentialsFile = context.projectDirectory ++ "/git.login" + private val credentialsFile = context.workingDirectory ++ "/git.login" private def authenticate(_git: CloneCommand) = if(!credentialsFile.exists){ @@ -67,7 +67,7 @@ case class GitDependency( def dependency = taskCache[GitDependency]("dependency").memoize{ DirectoryDependency( context.copy( - projectDirectory = checkout ++ subDirectory.map("/" ++ _).getOrElse("") + workingDirectory = checkout ++ subDirectory.map("/" ++ _).getOrElse("") ) ) } diff --git a/stage2/Lib.scala b/stage2/Lib.scala index fcf2642..d5119a7 100644 --- a/stage2/Lib.scala +++ b/stage2/Lib.scala @@ -31,7 +31,7 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{ if(buildDir.exists) findStartDir(buildDir) else directory } - val directory = context.projectDirectory + val directory = context.workingDirectory context.logger.composition( context.logger.showInvocation("Build.loadRoot",directory) ) @@ -41,7 +41,7 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{ try{ if(useBasicBuild) { - new BasicBuild( context.copy( projectDirectory = directory) ) + new BasicBuild( context.copy( workingDirectory = directory ) ) } else if( // essentials depends on eval, which has a build that depends on scalatest // this means in these we can't depend on essentials @@ -50,9 +50,9 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{ || directory == (context.cbtHome ++ "/libraries/eval") || directory == (context.cbtHome ++ "/plugins/scalatest") ) - new cbt.BasicBuild( context.copy( projectDirectory = start ) ) with BuildBuildWithoutEssentials + new cbt.BasicBuild( context.copy( workingDirectory = start ) ) with BuildBuildWithoutEssentials else - new cbt.BasicBuild( context.copy( projectDirectory = start ) ) with BuildBuild + new cbt.BasicBuild( context.copy( workingDirectory = start ) ) with BuildBuild } catch { case e:ClassNotFoundException if e.getMessage == "Build" => throw new Exception(s"no class Build found in " ++ start.string) -- cgit v1.2.3 From 0442721647d186faab7d3055a6ca1dc45234d84d Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 13 Feb 2017 23:01:48 -0500 Subject: fix dotty runtime dependency and expose some more config statically --- stage2/plugins/Dotty.scala | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/stage2/plugins/Dotty.scala b/stage2/plugins/Dotty.scala index 8a49257..8b1726e 100644 --- a/stage2/plugins/Dotty.scala +++ b/stage2/plugins/Dotty.scala @@ -9,15 +9,15 @@ trait Dotty extends BaseBuild{ def dottyOptions: Seq[String] = Seq() override def scalaTarget: File = target ++ s"/dotty-$dottyVersion" - def dottyDependency: DependencyImplementation = - Resolver(mavenCentral).bindOne( - MavenDependency(Dotty.groupId,Dotty.artifactId,Dotty.version) - ) + def dottyCompiler: DependencyImplementation = Resolver(mavenCentral).bindOne( Dotty.compilerOnMaven( dottyVersion ) ) + def dottyLibrary: DependencyImplementation = Resolver(mavenCentral).bindOne( Dotty.libraryOnMaven( dottyVersion ) ) + // this seems needed for cbt run of dotty produced artifacts + override def dependencies: Seq[Dependency] = Seq( dottyLibrary ) private lazy val dottyLib = new DottyLib( logger, context.cbtLastModified, context.paths.mavenCache, - context.classLoaderCache, dottyDependency + context.classLoaderCache, dottyCompiler ) override def compile: Option[Long] = taskCache[Dotty]("compile").memoize{ @@ -32,15 +32,16 @@ trait Dotty extends BaseBuild{ ) override def repl = dottyLib.repl(context.args, classpath) - - // this seems needed for cbt run of dotty produced artifacts - override def dependencies: Seq[Dependency] = Seq( dottyDependency ) } object Dotty{ - val version: String = "0.1.1-20170203-da7d723-NIGHTLY" val groupId = "ch.epfl.lamp" - val artifactId = "dotty_2.11" + val version: String = "0.1.1-20170203-da7d723-NIGHTLY" + val libraryArtifactId = "dotty-library_2.11" + val compilerArtifactId = "dotty-compiler_2.11" + val interfacesArtifactId = "dotty-interfaces" + def compilerOnMaven(version: String) = MavenDependency(groupId,compilerArtifactId,version) + def libraryOnMaven(version: String) = MavenDependency(groupId,libraryArtifactId,version) } class DottyLib( -- cgit v1.2.3 From 5c5aebe269f4add3bceb669aab6b5c9ea565d8f8 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 13 Feb 2017 23:03:19 -0500 Subject: add support for compiling .java files to Dotty plugin --- stage2/plugins/Dotty.scala | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/stage2/plugins/Dotty.scala b/stage2/plugins/Dotty.scala index 8b1726e..5481fa6 100644 --- a/stage2/plugins/Dotty.scala +++ b/stage2/plugins/Dotty.scala @@ -20,10 +20,35 @@ trait Dotty extends BaseBuild{ context.classLoaderCache, dottyCompiler ) + def compileJavaFirst: Boolean = false + + // this makes sure the scala or java classes compiled first are available on subsequent compile + override def compileDependencies: Seq[Dependency] + = super.compileDependencies ++ Seq( compileTarget ).filter(_.exists).map( t => BinaryDependency( Seq(t), Nil ) ) + override def compile: Option[Long] = taskCache[Dotty]("compile").memoize{ - dottyLib.compile( - sourceFiles, compileTarget, compileStatusFile, compileDependencies, dottyOptions - ) + def compileDotty = + dottyLib.compile( + sourceFiles.filter(_.string.endsWith(".scala")), + compileTarget, compileStatusFile, compileDependencies, dottyOptions + ) + def compileJava = + lib.compile( + context.cbtLastModified, + sourceFiles.filter(_.string.endsWith(".java")), + compileTarget, compileStatusFile, compileDependencies, context.paths.mavenCache, + scalacOptions, zincVersion = zincVersion, classLoaderCache = classLoaderCache, scalaVersion = scalaVersion + ) + + def set(time: Long) = if(compileStatusFile.exists) Files.setLastModifiedTime(compileStatusFile.toPath, FileTime.fromMillis(time) ) + + val before = compileStatusFile.lastModified + val firstLastModified = if(compileJavaFirst) compileJava else compileDotty + set( before ) + val secondLastModified = if(!compileJavaFirst) compileJava else compileDotty + val min = (firstLastModified ++ secondLastModified).reduceOption(_ min _).getOrElse(0l) + set( min ) + Some(min) } def doc: ExitCode = -- cgit v1.2.3 From dfde369b30bcde1c60add172e0e91caeb51e541b Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Mon, 13 Feb 2017 23:45:39 -0500 Subject: use target directory rather than projectDirectory as caching key makes more sense as multiple projects with the same projectDirectory but different sources and targets can make sense e.g. for sbt directory structure, etc --- stage2/BasicBuild.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index a2c7238..9ed6787 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -9,7 +9,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge // will create new instances given the context, which means operations in the // overrides will happen multiple times and if they are not idempotent stuff likely breaks def context: Context - def moduleKey: String = "BaseBuild("+projectDirectory.string+")" + def moduleKey: String = "BaseBuild("+target.string+")" implicit def transientCache: java.util.Map[AnyRef,AnyRef] = context.transientCache // library available to builds -- cgit v1.2.3 From 92b26f394460aa609f9d073ea044776e7d8c46fb Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:07:57 -0500 Subject: implicitly pass classloader, might make code easier and prepares for allowing `run` and `runFlat` at Dependency instead of Build level --- plugins/scalajs/ScalaJsBuild.scala | 6 +--- plugins/scalajs/ScalaJsLib.scala | 7 ++--- plugins/scalatest/ScalaTest.scala | 5 ++-- stage1/MavenRepository.scala | 2 +- stage1/Stage1.scala | 45 ++++++++++++++---------------- stage1/Stage1Lib.scala | 11 ++++---- stage1/cbt.scala | 6 ++-- stage1/resolver.scala | 57 +++++++++++++++++++++----------------- stage2/BasicBuild.scala | 11 ++++---- stage2/BuildBuild.scala | 4 +-- stage2/BuildDependency.scala | 1 + stage2/GitDependency.scala | 1 + stage2/Lib.scala | 5 ++-- stage2/PackageJars.scala | 2 +- stage2/ToolsStage2.scala | 2 +- stage2/ToolsTasks.scala | 9 +++--- stage2/plugins/Dotty.scala | 27 +++++++++--------- stage2/plugins/Frege.scala | 9 +++--- test/test.scala | 1 + 19 files changed, 103 insertions(+), 108 deletions(-) diff --git a/plugins/scalajs/ScalaJsBuild.scala b/plugins/scalajs/ScalaJsBuild.scala index 99f8616..1694aea 100644 --- a/plugins/scalajs/ScalaJsBuild.scala +++ b/plugins/scalajs/ScalaJsBuild.scala @@ -4,11 +4,7 @@ import java.net.URL trait ScalaJsBuild extends BaseBuild { final protected val scalaJsLib = ScalaJsLib( - scalaJsVersion, - scalaVersion, - context.cbtLastModified, - context.classLoaderCache, - context.paths.mavenCache + scalaJsVersion, scalaVersion, context.cbtLastModified, context.paths.mavenCache ) import scalaJsLib.{link => _,_} diff --git a/plugins/scalajs/ScalaJsLib.scala b/plugins/scalajs/ScalaJsLib.scala index f500039..393ebfe 100644 --- a/plugins/scalajs/ScalaJsLib.scala +++ b/plugins/scalajs/ScalaJsLib.scala @@ -2,9 +2,8 @@ package cbt import java.io.File case class ScalaJsLib( - scalaJsVersion: String, scalaVersion: String, - cbtLastModified: Long, classLoaderCache: ClassLoaderCache, mavenCache: File -)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]){ + scalaJsVersion: String, scalaVersion: String, cbtLastModified: Long, mavenCache: File +)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache){ sealed trait ScalaJsOutputMode { def option: String def fileSuffix: String @@ -36,7 +35,7 @@ case class ScalaJsLib( "--stdlib", s"${scalaJsLibraryDependency.jar.getAbsolutePath}", "--output", outputPath.string ) ++ scalaJsOptions ++ entriesToLink.map(_.getAbsolutePath), - scalaJsCliDep.classLoader(classLoaderCache) + scalaJsCliDep.classLoader ) } diff --git a/plugins/scalatest/ScalaTest.scala b/plugins/scalatest/ScalaTest.scala index 56405aa..21f656b 100644 --- a/plugins/scalatest/ScalaTest.scala +++ b/plugins/scalatest/ScalaTest.scala @@ -5,9 +5,8 @@ import org.scalatest._ trait ScalaTest extends BaseBuild{ override def run: ExitCode = { import ScalaTestLib._ - val _classLoader = classLoader(context.classLoaderCache) - val suiteNames = exportedClasspath.files.map( d => discoverSuites(d, _classLoader) ).flatten - runSuites( suiteNames.map( loadSuite( _, _classLoader ) ) ) + val suiteNames = exportedClasspath.files.map( d => discoverSuites(d, classLoader) ).flatten + runSuites( suiteNames.map( loadSuite( _, classLoader ) ) ) ExitCode.Success } override def dependencies = super.dependencies ++ Resolver( mavenCentral ).bind( ScalaDependency("org.scalatest","scalatest","2.2.4") ) diff --git a/stage1/MavenRepository.scala b/stage1/MavenRepository.scala index a8c9b51..6be537b 100644 --- a/stage1/MavenRepository.scala +++ b/stage1/MavenRepository.scala @@ -4,7 +4,7 @@ import java.net._ case class MavenResolver( cbtLastModified: Long, mavenCache: File, urls: URL* )( - implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef] + implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache ){ def bind( dependencies: MavenDependency* ): Seq[BoundMavenDependency] = dependencies.map( BoundMavenDependency(cbtLastModified,mavenCache,_,urls.to) ).to diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index bf6a3d4..60f0ad9 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -36,17 +36,16 @@ abstract class Stage2Base{ def run( context: Stage2Args ): ExitCode } -case class Stage2Args( - cwd: File, - args: Seq[String], - stage2LastModified: Long, - logger: Logger, - classLoaderCache: ClassLoaderCache, - cache: File, - cbtHome: File, - compatibilityTarget: File +class Stage2Args( + val cwd: File, + val args: Seq[String], + val stage2LastModified: Long, + val logger: Logger, + val cache: File, + val cbtHome: File, + val compatibilityTarget: File )( - implicit val transientCache: java.util.Map[AnyRef,AnyRef] + implicit val transientCache: java.util.Map[AnyRef,AnyRef], val classLoaderCache: ClassLoaderCache ){ val persistentCache = classLoaderCache.hashMap } @@ -61,11 +60,10 @@ object Stage1{ val logger = new Logger( context.enabledLoggers, buildStage1.start ) val (cbtLastModified, classLoader) = buildStage2( buildStage1, - new ClassLoaderCache( context.persistentCache ), context.cbtHome, context.cache, logger - )(context.transientCache) + )(context.transientCache, new ClassLoaderCache( context.persistentCache )) classLoader .loadClass("cbt.Stage2") @@ -79,8 +77,8 @@ object Stage1{ } def buildStage2( - buildStage1: BuildStage1Result, classLoaderCache: ClassLoaderCache, cbtHome: File, cache: File, logger: Logger - )(implicit transientCache: java.util.Map[AnyRef,AnyRef]): (Long, ClassLoader) = { + buildStage1: BuildStage1Result, cbtHome: File, cache: File, logger: Logger + )(implicit transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache): (Long, ClassLoader) = { import buildStage1._ @@ -106,9 +104,9 @@ object Stage1{ stage2sourceFiles, stage2Target, stage2StatusFile, cbtDependencies.stage2Dependency.dependencies, mavenCache, - Seq("-deprecation","-feature","-unchecked"), classLoaderCache, + Seq("-deprecation","-feature","-unchecked"), zincVersion = constants.zincVersion, scalaVersion = constants.scalaVersion - )(transientCache) + ) logger.stage1(s"calling CbtDependency.classLoader") @@ -129,19 +127,19 @@ object Stage1{ "cbt unchanged, expected stage1 classloader to be cached" ) - val stage2ClassLoader = cbtDependencies.stage2Dependency.classLoader(classLoaderCache) + val stage2ClassLoader = cbtDependencies.stage2Dependency.classLoader { // a few classloader sanity checks val compatibilityClassLoader = - cbtDependencies.compatibilityDependency.classLoader(classLoaderCache) + cbtDependencies.compatibilityDependency.classLoader assert( classOf[BuildInterface].getClassLoader == compatibilityClassLoader, classOf[BuildInterface].getClassLoader.toString ++ "\n\nis not the same as\n\n" ++ compatibilityClassLoader.toString ) //------------- val stage1ClassLoader = - cbtDependencies.stage1Dependency.classLoader(classLoaderCache) + cbtDependencies.stage1Dependency.classLoader assert( classOf[Stage1ArgsParser].getClassLoader == stage1ClassLoader, classOf[Stage1ArgsParser].getClassLoader.toString ++ "\n\nis not the same as\n\n" ++ stage1ClassLoader.toString @@ -165,20 +163,19 @@ object Stage1{ ): Int = { val args = Stage1ArgsParser(_args.toVector) val logger = new Logger(args.enabledLoggers, buildStage1.start) - implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap logger.stage1(s"Stage1 start") - val classLoaderCache = new ClassLoaderCache( persistentCache ) + implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap + implicit val classLoaderCache = new ClassLoaderCache( persistentCache ) - val (stage2LastModified, classLoader) = buildStage2( buildStage1, classLoaderCache, cbtHome, cache, logger ) + val (stage2LastModified, classLoader) = buildStage2( buildStage1, cbtHome, cache, logger ) - val stage2Args = Stage2Args( + val stage2Args = new Stage2Args( new File( args.args(0) ), args.args.drop(1).dropWhile(_ == "direct").toVector, // launcher changes cause entire nailgun restart, so no need for them here stage2LastModified = stage2LastModified, logger = logger, - classLoaderCache = classLoaderCache, cache, cbtHome, new File(buildStage1.compatibilityClasspath) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 5a2f05d..67c1f4e 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -192,11 +192,10 @@ class Stage1Lib( logger: Logger ) extends BaseLib{ dependencies: Seq[Dependency], mavenCache: File, scalacOptions: Seq[String] = Seq(), - classLoaderCache: ClassLoaderCache, zincVersion: String, scalaVersion: String )( - implicit transientCache: java.util.Map[AnyRef, AnyRef] + implicit transientCache: java.util.Map[AnyRef, AnyRef], classLoaderCache: ClassLoaderCache ): Option[Long] = { val d = Dependencies(dependencies) val classpath = d.classpath @@ -259,7 +258,7 @@ class Stage1Lib( logger: Logger ) extends BaseLib{ dualArgs ++ singleArgs ++ ( if(cp.isEmpty) Nil else Seq("-cp", cp) ) ++ sourceFiles.map(_.toString), - zinc.classLoader(classLoaderCache) + zinc.classLoader ) } catch { case scala.util.control.NonFatal(e) => @@ -413,20 +412,20 @@ ${sourceFiles.sorted.mkString(" \\\n")} case d => d } - def classLoaderRecursion( dependency: Dependency, latest: Map[(String,String),Dependency], cache: ClassLoaderCache)(implicit transientCache: java.util.Map[AnyRef,AnyRef] ): ClassLoader = { + def classLoaderRecursion( dependency: Dependency, latest: Map[(String,String),Dependency])(implicit transientCache: java.util.Map[AnyRef,AnyRef], cache: ClassLoaderCache): ClassLoader = { // FIXME: shouldn't we be using KeyLockedLazyCache instead of hashmap directly here? val dependencies = dependency.dependencies val dependencyClassLoader: ClassLoader = { if( dependency.dependencies.isEmpty ){ NailgunLauncher.jdkClassLoader } else if( dependencies.size == 1 ){ - classLoaderRecursion( dependencies.head, latest, cache ) + classLoaderRecursion( dependencies.head, latest ) } else{ val lastModified = dependencies.map( _.lastModified ).max val cp = dependency.dependencyClasspath.string val cl = new MultiClassLoader( - dependencies.map( classLoaderRecursion(_, latest, cache) ) + dependencies.map( classLoaderRecursion(_, latest) ) ) if(dependency.isInstanceOf[BuildInterface]) cl // Don't cache builds right now. We need to fix invalidation first. diff --git a/stage1/cbt.scala b/stage1/cbt.scala index 54f3159..f88ef16 100644 --- a/stage1/cbt.scala +++ b/stage1/cbt.scala @@ -52,10 +52,10 @@ object `package`{ } implicit class DependencyExtensions(subject: Dependency){ import subject._ - def dependencyClasspath(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]): ClassPath + def dependencyClasspath(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache): ClassPath = Dependencies(dependenciesArray.to).classpath def exportedClasspath: ClassPath = ClassPath(exportedClasspathArray.to) - def classpath(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) = exportedClasspath ++ dependencyClasspath + def classpath(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache) = exportedClasspath ++ dependencyClasspath def dependencies: Seq[Dependency] = dependenciesArray.to } implicit class ContextExtensions(subject: Context){ @@ -66,7 +66,7 @@ object `package`{ def classLoaderCache: ClassLoaderCache = new ClassLoaderCache( persistentCache ) def cbtDependencies = { import paths._ - new CbtDependencies(mavenCache, nailgunTarget, stage1Target, stage2Target, compatibilityTarget)(logger, transientCache) + new CbtDependencies(mavenCache, nailgunTarget, stage1Target, stage2Target, compatibilityTarget)(logger, transientCache, classLoaderCache) } val cbtDependency = cbtDependencies.stage2Dependency diff --git a/stage1/resolver.scala b/stage1/resolver.scala index 97cd36a..4731b0c 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -9,6 +9,7 @@ trait DependencyImplementation extends Dependency{ implicit protected def logger: Logger protected def lib = new Stage1Lib(logger) implicit protected def transientCache: java.util.Map[AnyRef,AnyRef] + implicit protected def classLoaderCache: ClassLoaderCache /** key used by taskCache to identify different objects that represent the same logical module */ protected def moduleKey: String @@ -78,23 +79,29 @@ trait DependencyImplementation extends Dependency{ } */ - def classLoader( cache: ClassLoaderCache ): ClassLoader = { - /* - if( concurrencyEnabled ){ - // trigger concurrent building / downloading dependencies - exportClasspathConcurrently + def flatClassLoader: Boolean = false + + def classLoader: ClassLoader = { + if( flatClassLoader ){ + new java.net.URLClassLoader(classpath.strings.map(f => new URL("file://" ++ f)).toArray) + } else { + /* + if( concurrencyEnabled ){ + // trigger concurrent building / downloading dependencies + exportClasspathConcurrently + } + */ + lib.classLoaderRecursion( + this, + (this +: transitiveDependencies).collect{ + case d: ArtifactInfo => d + }.groupBy( + d => (d.groupId,d.artifactId) + ).mapValues(_.head) + ) } - */ - lib.classLoaderRecursion( - this, - (this +: transitiveDependencies).collect{ - case d: ArtifactInfo => d - }.groupBy( - d => (d.groupId,d.artifactId) - ).mapValues(_.head), - cache // FIXME - ) } + // FIXME: these probably need to update outdated as well def classpath : ClassPath = exportedClasspath ++ dependencyClasspath def dependencyClasspath : ClassPath = ClassPath( @@ -116,11 +123,11 @@ trait DependencyImplementation extends Dependency{ } // TODO: all this hard codes the scala version, needs more flexibility -class ScalaCompilerDependency(cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BoundMavenDependency(cbtLastModified, mavenCache, MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(mavenCentral)) -class ScalaLibraryDependency (cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BoundMavenDependency(cbtLastModified, mavenCache, MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(mavenCentral)) -class ScalaReflectDependency (cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends BoundMavenDependency(cbtLastModified, mavenCache, MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(mavenCentral)) +class ScalaCompilerDependency(cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache) extends BoundMavenDependency(cbtLastModified, mavenCache, MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(mavenCentral)) +class ScalaLibraryDependency (cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache) extends BoundMavenDependency(cbtLastModified, mavenCache, MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(mavenCentral)) +class ScalaReflectDependency (cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache) extends BoundMavenDependency(cbtLastModified, mavenCache, MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(mavenCentral)) -class ScalaDependencies(cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef]) extends Dependencies( +class ScalaDependencies(cbtLastModified: Long, mavenCache: File, version: String)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache) extends Dependencies( Seq( new ScalaCompilerDependency(cbtLastModified, mavenCache, version), new ScalaLibraryDependency(cbtLastModified, mavenCache, version), @@ -128,7 +135,7 @@ class ScalaDependencies(cbtLastModified: Long, mavenCache: File, version: String ) ) -case class BinaryDependency( paths: Seq[File], dependencies: Seq[Dependency] )(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef]) extends DependencyImplementation{ +case class BinaryDependency( paths: Seq[File], dependencies: Seq[Dependency] )(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef], val classLoaderCache: ClassLoaderCache) extends DependencyImplementation{ assert(paths.nonEmpty) def exportedClasspath = ClassPath(paths) override def lastModified = paths.map(_.lastModified).maxOption.getOrElse(0) // FIXME: cache this @@ -137,7 +144,7 @@ case class BinaryDependency( paths: Seq[File], dependencies: Seq[Dependency] )(i } /** Allows to easily assemble a bunch of dependencies */ -case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef]) extends DependencyImplementation{ +case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef], val classLoaderCache: ClassLoaderCache) extends DependencyImplementation{ override def lastModified = dependencies.map(_.lastModified).maxOption.getOrElse(0) def moduleKey = this.getClass.getName ++ "(" ++ dependencies.map(_.moduleKey).mkString(", ") ++ ")" def targetClasspath = ClassPath() @@ -145,14 +152,14 @@ case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Lo override def show: String = this.getClass.getSimpleName + "( " + dependencies.map(_.show).mkString(", ") + " )" } -case class PostBuildDependency(target: File, _dependencies: Seq[DependencyImplementation])(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef]) extends DependencyImplementation{ +case class PostBuildDependency(target: File, _dependencies: Seq[DependencyImplementation])(implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef], val classLoaderCache: ClassLoaderCache) extends DependencyImplementation{ override final lazy val lastModified = (target++".last-success").lastModified def moduleKey = target.string override def targetClasspath = exportedClasspath override def exportedClasspath = ClassPath( Seq(target) ) override def dependencies = _dependencies } -case class CbtDependencies(mavenCache: File, nailgunTarget: File, stage1Target: File, stage2Target: File, compatibilityTarget: File)(implicit logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef]){ +case class CbtDependencies(mavenCache: File, nailgunTarget: File, stage1Target: File, stage2Target: File, compatibilityTarget: File)(implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache){ val compatibilityDependency = PostBuildDependency(compatibilityTarget, Nil) val cbtLastModified = (stage2Target++".last-success").lastModified val stage1Dependency = PostBuildDependency( @@ -188,7 +195,7 @@ abstract class DependenciesProxy{ class BoundMavenDependencies( cbtLastModified: Long, mavenCache: File, urls: Seq[URL], mavenDependencies: Seq[MavenDependency] )( - implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef] + implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache ) extends Dependencies( mavenDependencies.map( BoundMavenDependency(cbtLastModified,mavenCache,_,urls) ) ) @@ -206,7 +213,7 @@ object MavenDependency{ case class BoundMavenDependency( cbtLastModified: Long, mavenCache: File, mavenDependency: MavenDependency, repositories: Seq[URL] )( - implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef] + implicit val logger: Logger, val transientCache: java.util.Map[AnyRef,AnyRef], val classLoaderCache: ClassLoaderCache ) extends ArtifactInfo with DependencyImplementation{ def moduleKey = this.getClass.getName ++ "(" ++ mavenDependency.serialize ++ ")" val MavenDependency( groupId, artifactId, version, classifier ) = mavenDependency diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 9ed6787..5f73568 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -147,16 +147,16 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge lib.compile( context.cbtLastModified, sourceFiles, compileTarget, compileStatusFile, compileDependencies, - context.paths.mavenCache, scalacOptions, context.classLoaderCache, + context.paths.mavenCache, scalacOptions, zincVersion = zincVersion, scalaVersion = scalaVersion ) } - def mainClasses: Seq[Class[_]] = exportedClasspath.files.flatMap( lib.mainClasses( _, classLoader(classLoaderCache) ) ) + def mainClasses: Seq[Class[_]] = exportedClasspath.files.flatMap( lib.mainClasses( _, classLoader ) ) def runClass: Option[String] = lib.runClass( mainClasses ).map( _.getName ) - def runMain( className: String, args: String* ) = lib.runMain( className, args, classLoader(context.classLoaderCache) ) + def runMain( className: String, args: String* ) = lib.runMain( className, args, classLoader ) def flatClassLoader: Boolean = false @@ -200,15 +200,14 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge } val scalac = new ScalaCompilerDependency(context.cbtLastModified, context.paths.mavenCache, scalaVersion) - lib.runMain( + runMain( "scala.tools.nsc.MainGenericRunner", Seq( "-bootclasspath", scalac.classpath.string, "-classpath", classpath.string - ) ++ context.args, - scalac.classLoader(classLoaderCache) + ) ++ context.args : _* ) } diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index 994ac2e..474599a 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -57,14 +57,14 @@ trait BuildBuildWithoutEssentials extends BaseBuild{ // Launcher in the checkout with itself and then run it via reflection. val dep = new GitDependency(base, hash, Some("nailgun_launcher")) val ctx = managedContext.copy( cbtHome = dep.checkout ) - dep.classLoader(classLoaderCache) + dep.classLoader .loadClass( "cbt.NailgunLauncher" ) .getMethod( "getBuild", classOf[AnyRef] ) .invoke( null, ctx ) } }.getOrElse{ try{ - classLoader(context.classLoaderCache) + classLoader .loadClass(lib.buildClassName) .getConstructors.head .newInstance(managedContext) diff --git a/stage2/BuildDependency.scala b/stage2/BuildDependency.scala index ed6c2bd..56069c3 100644 --- a/stage2/BuildDependency.scala +++ b/stage2/BuildDependency.scala @@ -16,6 +16,7 @@ trait TriggerLoop extends DependencyImplementation{ } /** You likely want to use the factory method in the BasicBuild class instead of this. */ final case class DirectoryDependency(context: Context) extends TriggerLoop{ + def classLoaderCache = context.classLoaderCache override def toString = show override def show = this.getClass.getSimpleName ++ "(" ++ context.workingDirectory.string ++ ")" def moduleKey = this.getClass.getName ++ "("+context.workingDirectory.string+")" diff --git a/stage2/GitDependency.scala b/stage2/GitDependency.scala index 754e41a..ecd0ee1 100644 --- a/stage2/GitDependency.scala +++ b/stage2/GitDependency.scala @@ -15,6 +15,7 @@ case class GitDependency( )(implicit val logger: Logger, classLoaderCache: ClassLoaderCache, context: Context ) extends DependencyImplementation{ import GitDependency._ override def lib = new Lib(logger) + def classLoaderCache = context.classLoaderCache def moduleKey = this.getClass.getName ++ "(" ++ url ++ subDirectory.map("/" ++ _).getOrElse("") ++ "#" ++ ref ++ ")" def transientCache = context.transientCache // TODO: add support for authentication via ssh and/or https diff --git a/stage2/Lib.scala b/stage2/Lib.scala index d5119a7..2642ec9 100644 --- a/stage2/Lib.scala +++ b/stage2/Lib.scala @@ -84,9 +84,8 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{ scalaMajorVersion: String, version: String, compileArgs: Seq[String], - classLoaderCache: ClassLoaderCache, mavenCache: File - )(implicit transientCache: java.util.Map[AnyRef,AnyRef]): Option[File] = { + )(implicit transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache): Option[File] = { if(sourceFiles.isEmpty){ None } else { @@ -101,7 +100,7 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{ runMain( "scala.tools.nsc.ScalaDoc", args, - new ScalaDependencies(cbtLastModified,mavenCache,scalaVersion).classLoader(classLoaderCache) + new ScalaDependencies(cbtLastModified,mavenCache,scalaVersion).classLoader ) } lib.jarFile( diff --git a/stage2/PackageJars.scala b/stage2/PackageJars.scala index fddbfc6..8ba1798 100644 --- a/stage2/PackageJars.scala +++ b/stage2/PackageJars.scala @@ -23,7 +23,7 @@ trait PackageJars extends BaseBuild with ArtifactInfo{ context.cbtLastModified, scalaVersion, sourceFiles, compileClasspath, docTarget, jarTarget, artifactId, scalaMajorVersion, version, - scalacOptions, context.classLoaderCache, context.paths.mavenCache + scalacOptions, context.paths.mavenCache ) } } diff --git a/stage2/ToolsStage2.scala b/stage2/ToolsStage2.scala index 2899173..e1c4a8e 100644 --- a/stage2/ToolsStage2.scala +++ b/stage2/ToolsStage2.scala @@ -4,7 +4,7 @@ object ToolsStage2 extends Stage2Base{ def run( _args: Stage2Args ): ExitCode = { val args = _args.args.dropWhile(Seq("tools","direct") contains _) val lib = new Lib(_args.logger) - val toolsTasks = new ToolsTasks(lib, args, _args.cwd, _args.classLoaderCache, _args.cache, _args.cbtHome, _args.stage2LastModified) + val toolsTasks = new ToolsTasks(lib, args, _args.cwd, _args.cache, _args.cbtHome, _args.stage2LastModified)(_args.classLoaderCache) new lib.ReflectObject(toolsTasks){ def usage: String = "Available methods: " ++ lib.taskNames(toolsTasks.getClass).mkString(" ") }.callNullary(args.lift(0)) diff --git a/stage2/ToolsTasks.scala b/stage2/ToolsTasks.scala index 6acf72c..25156fb 100644 --- a/stage2/ToolsTasks.scala +++ b/stage2/ToolsTasks.scala @@ -6,16 +6,15 @@ class ToolsTasks( lib: Lib, args: Seq[String], cwd: File, - classLoaderCache: ClassLoaderCache, cache: File, cbtHome: File, cbtLastModified: Long -){ +)(implicit classLoaderCache: ClassLoaderCache){ private val paths = CbtPaths(cbtHome, cache) import paths._ - private def Resolver( urls: URL* ) = MavenResolver(cbtLastModified,mavenCache,urls: _*) implicit val logger: Logger = lib.logger implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap + private def Resolver( urls: URL* ) = MavenResolver(cbtLastModified,mavenCache,urls: _*) def createMain: Unit = lib.createMain( cwd ) def createBuild: Unit = lib.createBuild( cwd ) def gui = NailgunLauncher.main(Array( @@ -48,7 +47,7 @@ class ToolsTasks( MavenDependency( "com.lihaoyi","ammonite-repl_2.11.8",args.lift(1).getOrElse("0.5.8") ) - ).classLoader(classLoaderCache) + ).classLoader // FIXME: this does not work quite yet, throws NoSuchFileException: /ammonite/repl/frontend/ReplBridge$.class lib.runMain( "ammonite.repl.Main", args.drop(2), classLoader @@ -59,7 +58,7 @@ class ToolsTasks( val scalac = new ScalaCompilerDependency( cbtLastModified, mavenCache, version ) val _args = Seq("-cp", scalac.classpath.string) ++ args.drop(2) lib.runMain( - "scala.tools.nsc.MainGenericRunner", _args, scalac.classLoader(classLoaderCache) + "scala.tools.nsc.MainGenericRunner", _args, scalac.classLoader ) } def cbtEarlyDependencies = { diff --git a/stage2/plugins/Dotty.scala b/stage2/plugins/Dotty.scala index 5481fa6..9de2218 100644 --- a/stage2/plugins/Dotty.scala +++ b/stage2/plugins/Dotty.scala @@ -16,8 +16,7 @@ trait Dotty extends BaseBuild{ override def dependencies: Seq[Dependency] = Seq( dottyLibrary ) private lazy val dottyLib = new DottyLib( - logger, context.cbtLastModified, context.paths.mavenCache, - context.classLoaderCache, dottyCompiler + logger, context.cbtLastModified, context.paths.mavenCache, dottyCompiler ) def compileJavaFirst: Boolean = false @@ -37,7 +36,7 @@ trait Dotty extends BaseBuild{ context.cbtLastModified, sourceFiles.filter(_.string.endsWith(".java")), compileTarget, compileStatusFile, compileDependencies, context.paths.mavenCache, - scalacOptions, zincVersion = zincVersion, classLoaderCache = classLoaderCache, scalaVersion = scalaVersion + scalacOptions, zincVersion = zincVersion, scalaVersion = scalaVersion ) def set(time: Long) = if(compileStatusFile.exists) Files.setLastModifiedTime(compileStatusFile.toPath, FileTime.fromMillis(time) ) @@ -73,9 +72,8 @@ class DottyLib( logger: Logger, cbtLastModified: Long, mavenCache: File, - classLoaderCache: ClassLoaderCache, - dependency: DependencyImplementation -)(implicit transientCache: java.util.Map[AnyRef,AnyRef]){ + dottyCompiler: DependencyImplementation +)(implicit transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache){ val lib = new Lib(logger) import lib._ @@ -85,11 +83,11 @@ class DottyLib( "dotty.tools.dotc.repl.Main", Seq( "-bootclasspath", - dependency.classpath.string, + dottyCompiler.classpath.string, "-classpath", classpath.string ) ++ args, - dependency.classLoader(classLoaderCache) + dottyCompiler.classLoader ) } @@ -105,7 +103,7 @@ class DottyLib( docTarget.mkdirs val args = Seq( // FIXME: can we use compiler dependency here? - "-bootclasspath", dependency.classpath.string, // FIXME: does this break for builds that don't have scalac dependencies? + "-bootclasspath", dottyCompiler.classpath.string, // FIXME: does this break for builds that don't have scalac dependencies? "-classpath", dependencyClasspath.string, // FIXME: does this break for builds that don't have scalac dependencies? "-d", docTarget.toString ) ++ compileArgs ++ sourceFiles.map(_.toString) @@ -114,7 +112,7 @@ class DottyLib( runMain( "dotty.tools.dottydoc.DocDriver", args, - dependency.classLoader(classLoaderCache), + dottyCompiler.classLoader, fakeInstance = true // this is a hack as Dottydoc's main method is not static ) } @@ -147,7 +145,8 @@ class DottyLib( "-d", compileTarget.toString ) val singleArgs = dottyOptions.map( "-S" ++ _ ) - val cl = dependency.classLoader(classLoaderCache) + val urls = dottyCompiler.classpath.strings.map("file://"+_).map(new java.net.URL(_)) + val cl = new java.net.URLClassLoader( urls.to ) val code = try{ System.err.println("Compiling with Dotty to " ++ compileTarget.toString) @@ -156,7 +155,7 @@ class DottyLib( lib.runMain( _class, dualArgs ++ singleArgs ++ Seq( - "-bootclasspath", dependency.classpath.string + "-bootclasspath", dottyCompiler.classpath.string ) ++ ( if(cp.isEmpty) Nil else Seq("-classpath", cp) // let's put cp last. It so long ) ++ sourceFiles.map(_.toString), @@ -169,7 +168,7 @@ class DottyLib( System.err.println(cl) System.out.println(s""" java -cp \\ -${dependency.classpath.strings.mkString(":\\\n")} \\ +${dottyCompiler.classpath.strings.mkString(":\\\n")} \\ \\ ${_class} \\ \\ @@ -178,7 +177,7 @@ ${dualArgs.grouped(2).map(_.mkString(" ")).mkString(" \\\n")} \\ ${singleArgs.mkString(" \\\n")} \\ \\ -bootclasspath \\ -${dependency.classpath.strings.mkString(":\\\n")} \\ +${dottyCompiler.classpath.strings.mkString(":\\\n")} \\ ${if(cp.isEmpty) "" else (" -classpath \\\n" ++ classpath.strings.mkString(":\\\n"))} \\ \\ ${sourceFiles.sorted.mkString(" \\\n")} diff --git a/stage2/plugins/Frege.scala b/stage2/plugins/Frege.scala index b5a4dd0..ae82f6b 100644 --- a/stage2/plugins/Frege.scala +++ b/stage2/plugins/Frege.scala @@ -21,7 +21,7 @@ trait Frege extends BaseBuild{ private lazy val fregeLib = new FregeLib( logger, context.cbtLastModified, context.paths.mavenCache, - context.classLoaderCache, fregeVersion = fregeVersion, classifier = classifier, + fregeVersion = fregeVersion, classifier = classifier, fregeDependencies = fregeDependencies, fregeTarget = fregeTarget ) @@ -43,12 +43,11 @@ class FregeLib( logger: Logger, cbtLastModified: Long, mavenCache: File, - classLoaderCache: ClassLoaderCache, fregeVersion: String, classifier: Option[String], fregeDependencies: Seq[Dependency], fregeTarget: String -)(implicit transientCache: java.util.Map[AnyRef,AnyRef]){ +)(implicit transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache){ val lib = new Lib(logger) import lib._ @@ -63,7 +62,7 @@ class FregeLib( statusFile: File, dependencies: Seq[Dependency], fregeOptions: Seq[String] - ): Option[Long] = { + )(implicit classLoaderCache: ClassLoaderCache): Option[Long] = { val d = Dependencies(dependencies) val classpath = d.classpath val cp = classpath.string @@ -93,7 +92,7 @@ class FregeLib( lib.runMain( _class, dualArgs ++ singleArgs ++ sourceFiles.map(_.toString), - fregeDependency.classLoader(classLoaderCache) + fregeDependency.classLoader ) } } catch { diff --git a/test/test.scala b/test/test.scala index ca9d87b..7247e6b 100644 --- a/test/test.scala +++ b/test/test.scala @@ -105,6 +105,7 @@ object Main{ val mavenCache = cache ++ "/maven" val cbtLastModified = System.currentTimeMillis implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap + implicit val classLoaderCache: ClassLoaderCache = new ClassLoaderCache( new java.util.HashMap ) def Resolver(urls: URL*) = MavenResolver(cbtLastModified, mavenCache, urls: _*) { -- cgit v1.2.3 From 349e4b3546973a30f2823fa5461767322a606d9a Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:12:22 -0500 Subject: support flatClassLoader and run at Dependency level --- stage1/resolver.scala | 13 +++++++++++++ stage2/BasicBuild.scala | 30 ++---------------------------- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/stage1/resolver.scala b/stage1/resolver.scala index 4731b0c..e02f931 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -79,8 +79,21 @@ trait DependencyImplementation extends Dependency{ } */ + def runMain( className: String, args: String* ) = lib.runMain( className, args, classLoader ) + def flatClassLoader: Boolean = false + def mainClasses: Seq[Class[_]] = exportedClasspath.files.flatMap( lib.mainClasses( _, classLoader ) ) + + def runClass: Option[String] = lib.runClass( mainClasses ).map( _.getName ) + + def run( args: String* ): ExitCode = { + runClass.map( runMain( _, args: _* ) ).getOrElse{ + logger.task( "No main class found for " ++ show ) + ExitCode.Success + } + } + def classLoader: ClassLoader = { if( flatClassLoader ){ new java.net.URLClassLoader(classpath.strings.map(f => new URL("file://" ++ f)).toArray) diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 5f73568..ad41dd4 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -152,34 +152,6 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge ) } - def mainClasses: Seq[Class[_]] = exportedClasspath.files.flatMap( lib.mainClasses( _, classLoader ) ) - - def runClass: Option[String] = lib.runClass( mainClasses ).map( _.getName ) - - def runMain( className: String, args: String* ) = lib.runMain( className, args, classLoader ) - - def flatClassLoader: Boolean = false - - def run: ExitCode = { - if(flatClassLoader){ - runClass.map( - lib.runMain( - _, - context.args, - new java.net.URLClassLoader(classpath.strings.map(f => new URL("file://" ++ f)).toArray) - ) - ).getOrElse{ - logger.task( "No main class found for " ++ projectDirectory.string ) - ExitCode.Success - } - } else { - runClass.map( runMain( _, context.args: _* ) ).getOrElse{ - logger.task( "No main class found for " ++ projectDirectory.string ) - ExitCode.Success - } - } - } - def clean: ExitCode = { lib.clean( target, @@ -211,6 +183,8 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge ) } + def run: ExitCode = run( context.args: _* ) + def test: Option[ExitCode] = Some(new lib.ReflectBuild( DirectoryDependency(projectDirectory++"/test").build -- cgit v1.2.3 From 465b9bfc84c21c0a599362624fa46febfa5e09c8 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:18:54 -0500 Subject: ignore classes in randomly nested subdirectories useful for `dotty run ` --- stage1/Stage1Lib.scala | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 67c1f4e..d44f30b 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -156,14 +156,19 @@ class Stage1Lib( logger: Logger ) extends BaseLib{ .collect{ // no $ to avoid inner classes case path if !path.contains("$") && path.endsWith(".class") => - classLoader.loadClass( - path - .stripSuffix(".class") - .stripPrefix(targetDirectory.getPath) - .stripPrefix(File.separator) // 1 for the slash - .replace(File.separator, ".") - ) - }.filter( + try{ + classLoader.loadClass( + path + .stripSuffix(".class") + .stripPrefix(targetDirectory.getPath) + .stripPrefix(File.separator) // 1 for the slash + .replace(File.separator, ".") + ) + } catch { + case e: ClassNotFoundException => null + case e: NoClassDefFoundError => null + } + }.filterNot(_ == null).filter( _.getDeclaredMethods().exists( m => m.getName == "main" && m.getParameterTypes.toList == List(arrayClass) -- cgit v1.2.3 From 8f694428e1f206702c3172440ccf896c8b501941 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:19:35 -0500 Subject: allow overwriting test with nested build --- stage2/BasicBuild.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index ad41dd4..4ac1903 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -185,7 +185,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge def run: ExitCode = run( context.args: _* ) - def test: Option[ExitCode] = + def test: Any = Some(new lib.ReflectBuild( DirectoryDependency(projectDirectory++"/test").build ).callNullary(Some("run"))) -- cgit v1.2.3 From 39a716a4cd54bf9e35ba60b5d40ed0f9a117e55b Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:20:04 -0500 Subject: more debugging info for a bug observed with compiling dotty --- stage1/Stage1Lib.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index d44f30b..cbf62dc 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -413,7 +413,11 @@ ${sourceFiles.sorted.mkString(" \\\n")} def actual(current: Dependency, latest: Map[(String,String),Dependency]) = current match { - case d: ArtifactInfo => latest((d.groupId,d.artifactId)) + case d: ArtifactInfo => + val key = (d.groupId,d.artifactId) + latest.get(key).getOrElse( + throw new Exception( s"This should never happend. Could not find $key in \n"++latest.map{case (k,v) => k+" -> "+v}.mkString("\n") ) + ) case d => d } -- cgit v1.2.3 From e0c12a39e634bc88d0128992eabb16fa3b38b3b4 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:20:37 -0500 Subject: now really cache classloaders for builds should be safe now that we rebuild based on lastModified --- stage1/Stage1Lib.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index cbf62dc..505b298 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -436,14 +436,10 @@ ${sourceFiles.sorted.mkString(" \\\n")} new MultiClassLoader( dependencies.map( classLoaderRecursion(_, latest) ) ) - if(dependency.isInstanceOf[BuildInterface]) - cl // Don't cache builds right now. We need to fix invalidation first. - else{ - if( !cache.containsKey( cp, lastModified ) ){ - cache.put( cp, cl, lastModified ) - } - cache.get( cp, lastModified ) + if( !cache.containsKey( cp, lastModified ) ){ + cache.put( cp, cl, lastModified ) } + cache.get( cp, lastModified ) } } -- cgit v1.2.3 From 6b7ccbe48f858e8c5d075672db85caa9dd44bd19 Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:21:01 -0500 Subject: minor whitespace and name changes --- plugins/scalatest/ScalaTest.scala | 12 ++++++------ stage2/BasicBuild.scala | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/plugins/scalatest/ScalaTest.scala b/plugins/scalatest/ScalaTest.scala index 21f656b..7f805fd 100644 --- a/plugins/scalatest/ScalaTest.scala +++ b/plugins/scalatest/ScalaTest.scala @@ -27,16 +27,16 @@ object ScalaTestLib{ } } - def discoverSuites(discoveryPath: File, _classLoader: ClassLoader): Seq[String] = { - _classLoader + def discoverSuites(discoveryPath: File, classLoader: ClassLoader): Seq[String] = { + classLoader .loadClass("org.scalatest.tools.SuiteDiscoveryHelper") .getMethod("discoverSuiteNames", classOf[List[_]], classOf[ClassLoader], classOf[Option[_]]) - .invoke(null, List(discoveryPath.string ++ "/"), _classLoader, None) + .invoke(null, List(discoveryPath.string ++ "/"), classLoader, None) .asInstanceOf[Set[String]] .to } - def loadSuite(name: String, _classLoader: ClassLoader) = { - _classLoader.loadClass(name).getConstructor().newInstance().asInstanceOf[Suite] - } + def loadSuite(name: String, classLoader: ClassLoader) = { + classLoader.loadClass(name).getConstructor().newInstance().asInstanceOf[Suite] + } } diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 4ac1903..5212270 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -125,9 +125,9 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge def resourceClasspath: ClassPath = { val resourcesDirectory = projectDirectory ++ "/resources" - ClassPath( if(resourcesDirectory.exists) Seq(resourcesDirectory) else Nil ) + ClassPath(Seq(resourcesDirectory).filter(_.exists)) } - def exportedClasspath : ClassPath = { + def exportedClasspath: ClassPath = { compile ClassPath(Seq(compileTarget).filter(_.exists)) ++ resourceClasspath } @@ -189,6 +189,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge Some(new lib.ReflectBuild( DirectoryDependency(projectDirectory++"/test").build ).callNullary(Some("run"))) + def t = test def rt = recursiveUnsafe(Some("test")) @@ -230,7 +231,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge ExitCode.Success } catch { case e: Throwable => println(e.getClass); throw e - } + } } ExitCode.Success } -- cgit v1.2.3 From 69b3380ad301b50e540ef784c5ada1f3560dffab Mon Sep 17 00:00:00 2001 From: Christopher Vogt Date: Tue, 14 Feb 2017 00:21:35 -0500 Subject: a (probably insufficient) attempt at detecting task cache conflicts --- stage2/BasicBuild.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 5212270..e5b3507 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -258,6 +258,24 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge // a method that can be called only to trigger any side-effects final def `void` = () + final override def transitiveDependencies: Seq[Dependency] = + taskCache[BaseBuild]( "transitiveDependencies" ).memoize{ + val res = super.transitiveDependencies + val duplicateBuilds = res.collect{ + case b: BaseBuild => b + }.groupBy( + b => ( b.projectDirectory, b.moduleKey ) + ).filter( _._2.size > 1 ).mapValues(_.map(_.getClass)) + duplicateBuilds.foreach{ case ((projectDirectory, moduleKey), classes) => + assert( + classes.distinct.size == 1, + "multiple builds found for\nprojectDirectory: $projectDirectory\nmoduleKey: $moduleKey\nbut different classes: " + classes.mkString(", ") + ) + } + res + } + + @deprecated("use the MultipleScalaVersions plugin instead","") final def crossScalaVersionsArray = Array(scalaVersion) } -- cgit v1.2.3