aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--build/build.scala5
-rw-r--r--circle.yml4
-rw-r--r--doc/design.txt5
-rw-r--r--examples/build-info-example/build/build.scala2
-rw-r--r--examples/scalajs-plain-example/js/build/build.scala4
-rw-r--r--examples/scalajs-react-example/js/build/build.scala4
-rw-r--r--examples/scalatest-example/build/build.scala11
-rw-r--r--examples/uber-jar-example/README.md2
-rw-r--r--examples/uber-jar-example/build/build.scala4
-rw-r--r--libraries/eval/build/build.scala6
-rw-r--r--nailgun_launcher/CbtURLClassLoader.java2
-rw-r--r--nailgun_launcher/ClassLoaderCache.java2
-rw-r--r--nailgun_launcher/Stage0Lib.java14
-rw-r--r--plugins/essentials/build/build.scala2
-rw-r--r--plugins/sbt_layout/SbtLayout.scala2
-rw-r--r--plugins/scalafmt/Scalafmt.scala64
-rw-r--r--plugins/scalafmt/build/build.scala3
-rw-r--r--plugins/scalajs/ScalaJsBuild.scala13
-rw-r--r--plugins/scalajs/ScalaJsLib.scala19
-rw-r--r--plugins/sonatype-release/src/SonatypeRelease.scala1
-rw-r--r--plugins/uber-jar/src/UberJar.scala2
-rw-r--r--stage1/Stage1Lib.scala20
-rw-r--r--stage1/URLClassLoader.scala4
-rw-r--r--stage1/cbt.scala32
-rw-r--r--stage1/logger.scala4
-rw-r--r--stage1/resolver.scala23
-rw-r--r--stage2/BasicBuild.scala33
-rw-r--r--stage2/BuildDependency.scala1
-rw-r--r--stage2/Lib.scala56
-rw-r--r--stage2/ToolsTasks.scala2
-rw-r--r--test/build/build.scala1
-rw-r--r--test/test.scala7
-rw-r--r--tools/gui/resources/template-project/build/build.scala2
-rw-r--r--tools/gui/src/ProjectBuilder.scala2
35 files changed, 206 insertions, 153 deletions
diff --git a/.gitignore b/.gitignore
index 953f0a3..5a580e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ node_modules
*fullopt*
examples/dotty-example/_site
examples/scalajs-plain-example/server/public/generated
+examples/scalajs-react-example/server/public/generated
diff --git a/build/build.scala b/build/build.scala
index 70fc268..b4a39ea 100644
--- a/build/build.scala
+++ b/build/build.scala
@@ -6,7 +6,6 @@ class Build(val context: Context) extends Publish{
super.dependencies ++ Resolver(mavenCentral).bind(
MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
MavenDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r"),
- MavenDependency("com.typesafe.zinc","zinc",constants.zincVersion),
ScalaDependency("org.scala-lang.modules","scala-xml","1.0.5")
)
}
@@ -16,8 +15,8 @@ class Build(val context: Context) extends Publish{
def groupId: String = "org.cvogt"
- def version: String = "0.1"
- def name: String = "cbt"
+ def version: String = "0.9"
+ override def name: String = "cbt"
// Members declared in cbt.Publish
def description: String = "Fast, intuitive Build Tool for Scala"
diff --git a/circle.yml b/circle.yml
index a25dc35..d3f66e8 100644
--- a/circle.yml
+++ b/circle.yml
@@ -13,7 +13,7 @@ dependencies:
test:
override:
- rm ~/.gitconfig # avoid url replacement breaking jgit
- - ./cbt direct test:
+ - ./cbt direct test.run:
timeout: 1800
- - ./cbt test:
+ - ./cbt test.run:
timeout: 1800
diff --git a/doc/design.txt b/doc/design.txt
new file mode 100644
index 0000000..9478d31
--- /dev/null
+++ b/doc/design.txt
@@ -0,0 +1,5 @@
+
+
+## Related gitter chats
+### Why CBT uses inheritance
+https://gitter.im/cvogt/cbt?at=58a95663de50490822e869e5
diff --git a/examples/build-info-example/build/build.scala b/examples/build-info-example/build/build.scala
index 4d28598..b5ea86b 100644
--- a/examples/build-info-example/build/build.scala
+++ b/examples/build-info-example/build/build.scala
@@ -2,7 +2,7 @@ import cbt._
import java.nio.file.Files._
class Build(val context: Context) extends PackageJars{
- def name = "build-info-example"
+ override def name = "build-info-example"
def groupId = "cbt.examples"
override def defaultScalaVersion = "2.11.8"
def version = "0.1"
diff --git a/examples/scalajs-plain-example/js/build/build.scala b/examples/scalajs-plain-example/js/build/build.scala
index 06e4876..4c251cd 100644
--- a/examples/scalajs-plain-example/js/build/build.scala
+++ b/examples/scalajs-plain-example/js/build/build.scala
@@ -1,6 +1,6 @@
import cbt._
class Build(val context: Context) extends ScalaJsBuild{
- override def projectName = "my-project"
+ override def name = "my-project"
override def sources = super.sources ++ Seq(
projectDirectory.getParentFile ++ "/shared"
@@ -14,5 +14,5 @@ class Build(val context: Context) extends ScalaJsBuild{
)
override def scalaJsTargetFile =
- projectDirectory.getParentFile ++ ("/server/public/generated/" ++ projectName ++ ".js")
+ projectDirectory.getParentFile ++ ("/server/public/generated/" ++ name ++ ".js")
}
diff --git a/examples/scalajs-react-example/js/build/build.scala b/examples/scalajs-react-example/js/build/build.scala
index 6db866b..d8e8c16 100644
--- a/examples/scalajs-react-example/js/build/build.scala
+++ b/examples/scalajs-react-example/js/build/build.scala
@@ -1,6 +1,6 @@
import cbt._
class Build(val context: Context) extends ScalaJsBuild{
- override def projectName = "my-project"
+ override def name = "my-project"
override def sources = super.sources ++ Seq(
projectDirectory.getParentFile ++ "/shared"
@@ -17,5 +17,5 @@ class Build(val context: Context) extends ScalaJsBuild{
)
override def scalaJsTargetFile =
- projectDirectory.getParentFile ++ ("/server/public/generated/" ++ projectName ++ ".js")
+ projectDirectory.getParentFile ++ ("/server/public/generated/" ++ name ++ ".js")
}
diff --git a/examples/scalatest-example/build/build.scala b/examples/scalatest-example/build/build.scala
index 48248fd..2c0ec21 100644
--- a/examples/scalatest-example/build/build.scala
+++ b/examples/scalatest-example/build/build.scala
@@ -1,9 +1,14 @@
import cbt._
class Build(val context: Context) extends SbtLayoutMain {
outer =>
- override def test: Option[ExitCode] = Some{
+ /* FIXME: calling `cbt rt` for `examples/scalatest-example` leads to
+java.lang.Exception: This should never happend. Could not find (org.scala-lang,scala-reflect) in
+(org.scala-lang,scala-library) -> BoundMavenDependency(1488121318000,cbt/cache/maven,MavenDependency(org.scala-lang,scala-library,2.11.8,Classifier(None)),Vector(https://repo1.maven.org/maven2))
+ at cbt.Stage1Lib$$anonfun$actual$1.apply(Stage1Lib.scala:425)
+ */
+ override def test: Dependency = {
new BasicBuild(context) with ScalaTest with SbtLayoutTest{
override def dependencies = outer +: super.dependencies
- }.run
- }
+ }
+ }
}
diff --git a/examples/uber-jar-example/README.md b/examples/uber-jar-example/README.md
index 2460084..e4f8da0 100644
--- a/examples/uber-jar-example/README.md
+++ b/examples/uber-jar-example/README.md
@@ -4,7 +4,7 @@ This example shows how to build uber jar(aka fat jar) with `UberJar` plugin.
In order to create uber jar: execute `cbt uberJar`. Produced jar will be in target folder.
-By default, jar name is your `cbt projectName`, you can provide other name via overriding `uberJarName` task.
+By default, jar name is your `cbt name`, you can provide other name via overriding `uberJarName` task.
By default, main class is `Main`. You can provide custom main class via overriding `uberJarMainClass` task.
diff --git a/examples/uber-jar-example/build/build.scala b/examples/uber-jar-example/build/build.scala
index fec58ae..181098f 100644
--- a/examples/uber-jar-example/build/build.scala
+++ b/examples/uber-jar-example/build/build.scala
@@ -2,7 +2,7 @@ import cbt._
class Build(val context: Context) extends BaseBuild with UberJar {
- override def projectName: String = "uber-jar-example"
+ override def name: String = "uber-jar-example"
override def dependencies = super.dependencies ++
Resolver( mavenCentral ).bind(
@@ -11,6 +11,6 @@ class Build(val context: Context) extends BaseBuild with UberJar {
ScalaDependency("org.typelevel", "cats", "0.6.0")
)
- override def uberJarName = projectName + "-0.0.1" + ".jar"
+ override def uberJarName = name + "-0.0.1" + ".jar"
}
diff --git a/libraries/eval/build/build.scala b/libraries/eval/build/build.scala
index a869ace..29c6d6f 100644
--- a/libraries/eval/build/build.scala
+++ b/libraries/eval/build/build.scala
@@ -4,11 +4,11 @@ class Build(val context: Context) extends BaseBuild{
override def dependencies = super.dependencies :+
new ScalaCompilerDependency( context.cbtLastModified, context.paths.mavenCache, scalaVersion )
- override def test: Option[ExitCode] = Some{
+ override def test: Dependency = {
new BasicBuild(context.copy(workingDirectory = projectDirectory ++ "/test")) with ScalaTest{
override def dependencies = super.dependencies ++ Seq(
DirectoryDependency(projectDirectory++"/..")
)
- }.run
- }
+ }
+ }
}
diff --git a/nailgun_launcher/CbtURLClassLoader.java b/nailgun_launcher/CbtURLClassLoader.java
index 10add77..b7eb366 100644
--- a/nailgun_launcher/CbtURLClassLoader.java
+++ b/nailgun_launcher/CbtURLClassLoader.java
@@ -11,7 +11,7 @@ public class CbtURLClassLoader extends java.net.URLClassLoader{
+ "(\n "
+ Arrays.toString(getURLs())
+ ",\n "
- + join("\n ",(getParent() == null?"":getParent().toString()).split("\n"))
+ + mkString("\n ",(getParent() == null?"":getParent().toString()).split("\n"))
+ "\n)"
);
}
diff --git a/nailgun_launcher/ClassLoaderCache.java b/nailgun_launcher/ClassLoaderCache.java
index 6bffad0..4898687 100644
--- a/nailgun_launcher/ClassLoaderCache.java
+++ b/nailgun_launcher/ClassLoaderCache.java
@@ -55,7 +55,7 @@ final public class ClassLoaderCache{
for( Object key: hashMap.keySet() ){
if( key instanceof String )
res.append(
- join( "\n", key.toString().split(":") ) + " -> " + hashMap.get( hashMap.get(key) )
+ mkString( "\n", key.toString().split(":") ) + " -> " + hashMap.get( hashMap.get(key) )
+ "\n\n"
);
}
diff --git a/nailgun_launcher/Stage0Lib.java b/nailgun_launcher/Stage0Lib.java
index 0880bbd..6057c21 100644
--- a/nailgun_launcher/Stage0Lib.java
+++ b/nailgun_launcher/Stage0Lib.java
@@ -45,7 +45,7 @@ public class Stage0Lib{
public static String classpath( String... files ){
Arrays.sort(files);
- return join( pathSeparator, files );
+ return mkString( pathSeparator, files );
}
public static long lastModified( String... files ){
@@ -216,10 +216,10 @@ public class Stage0Lib{
return (new HexBinaryAdapter()).marshal(sha1.digest()).toLowerCase();
}
- public static String join(String separator, String[] parts){
- String result = parts[0];
+ public static String mkString(String separator, Object[] parts){
+ String result = parts[0].toString();
for(int i = 1; i < parts.length; i++){
- result += separator + parts[i];
+ result += separator + parts[i].toString();
}
return result;
}
@@ -229,4 +229,10 @@ public class Stage0Lib{
copy[array.length] = item;
return copy;
}
+
+ public static String[] concat( String[] left, String[] right ){
+ String[] result = Arrays.copyOf(left, left.length + right.length);
+ System.arraycopy(right, 0, result, left.length, right.length);
+ return result;
+ }
}
diff --git a/plugins/essentials/build/build.scala b/plugins/essentials/build/build.scala
index 91c3a0f..eef4921 100644
--- a/plugins/essentials/build/build.scala
+++ b/plugins/essentials/build/build.scala
@@ -1,4 +1,6 @@
import cbt._
+// TODO: maybe move this back into stage2 to avoid having to call zinc separately for this as a plugin
+// and to avoid the special casing "BuildBuildWithoutEssentials"
class Build(val context: Context) extends BaseBuild{
override def dependencies = (
super.dependencies
diff --git a/plugins/sbt_layout/SbtLayout.scala b/plugins/sbt_layout/SbtLayout.scala
index 5cd7a03..3e8706d 100644
--- a/plugins/sbt_layout/SbtLayout.scala
+++ b/plugins/sbt_layout/SbtLayout.scala
@@ -1,5 +1,5 @@
package cbt
-
+// TODO: move this into stage2 to avoid having to call zinc separately for this as a plugin
trait SbtLayoutTest extends BaseBuild{
override def sources = Seq(projectDirectory ++ "/src/test/scala")
override def compileTarget = super.compileTarget.getParentFile ++ "/test-classes"
diff --git a/plugins/scalafmt/Scalafmt.scala b/plugins/scalafmt/Scalafmt.scala
index 1f8bf2d..e3c3c3e 100644
--- a/plugins/scalafmt/Scalafmt.scala
+++ b/plugins/scalafmt/Scalafmt.scala
@@ -6,7 +6,7 @@ import org.scalafmt.cli.StyleCache
import org.scalafmt.config.ScalafmtConfig
import java.io.File
import java.nio.file.Files._
-import java.nio.file.{ FileSystems, Path, Paths }
+import java.nio.file._
/**
* This plugin provides scalafmt support for cbt.
@@ -18,10 +18,7 @@ trait Scalafmt extends BaseBuild {
*
* @return always returns `ExitCode.Success`
*/
- final def scalafmt: ExitCode = {
- Scalafmt.format(sourceFiles, scalafmtConfig)
- ExitCode.Success
- }
+ final def scalafmt: ExitCode = Scalafmt.format(sourceFiles, scalafmtConfig)
/**
* Scalafmt formatting config.
@@ -54,46 +51,31 @@ object Scalafmt {
customStyle.getOrElse(ScalafmtConfig.default)
}
- def format(files: Seq[File], style: ScalafmtConfig): Unit = {
- var reformattedCount: Int = 0
- scalaSourceFiles(files) foreach { path =>
- handleFormatted(path, style) { case (original, result) =>
- result match {
- case Formatted.Success(formatted) =>
- if (original != formatted) {
- write(path, formatted.getBytes)
- reformattedCount += 1
- }
- case Formatted.Failure(e: Incomplete) =>
- System.err.println(s"Couldn't complete file reformat: $path")
- case Formatted.Failure(e) =>
- System.err.println(s"Failed to format file: $path, cause: ${e}")
- }
+ def format(files: Seq[File], style: ScalafmtConfig): ExitCode = {
+ val results = files.filter(_.string endsWith ".scala").map(_.toPath).map{ path =>
+ val original = new String(readAllBytes(path))
+ org.scalafmt.Scalafmt.format(original, style) match {
+ case Formatted.Success(formatted) =>
+ if (original != formatted) {
+ val tmpPath = Paths.get(path.toString ++ ".scalafmt-tmp")
+ write(tmpPath, formatted.getBytes)
+ move(tmpPath, path, StandardCopyOption.REPLACE_EXISTING)
+ Some(1)
+ }
+ Some(0)
+ case Formatted.Failure(e) =>
+ System.err.println(s"Scalafmt failed for $path\nCause: $e\n")
+ None
}
}
- if (reformattedCount > 0) System.err.println(s"Formatted $reformattedCount Scala sources")
- }
-
- private val scalaFileMatcher = FileSystems.getDefault.getPathMatcher("glob:**.scala")
-
- private def scalaSourceFiles(files: Seq[File]): Seq[Path] = {
- files collect {
- case f if f.exists
- && scalaFileMatcher.matches(f.toPath) => f.toPath
- }
- }
-
- private def handleFormatted[T](path: Path, style: ScalafmtConfig)(handler: (String, Formatted) => T): T = {
- val original = new String(readAllBytes(path))
- val result = org.scalafmt.Scalafmt.format(original, style)
- handler(original, result)
+ if(results.forall(_.nonEmpty)){
+ System.err.println(s"Formatted ${results.flatten.sum} Scala sources")
+ ExitCode.Success
+ } else ExitCode.Failure
}
private def getConfigPath(base: Path): Option[Path] = {
- val location = base.resolve(".scalafmt.conf").toFile
- Option(location.exists && location.isFile) collect {
- case true => location.toPath.toAbsolutePath
- }
+ Some( base.resolve(".scalafmt.conf").toFile )
+ .collect{ case f if f.exists && f.isFile => f.toPath.toAbsolutePath }
}
-
}
diff --git a/plugins/scalafmt/build/build.scala b/plugins/scalafmt/build/build.scala
index 2631908..b37d769 100644
--- a/plugins/scalafmt/build/build.scala
+++ b/plugins/scalafmt/build/build.scala
@@ -1,12 +1,11 @@
import cbt._
class Build(val context: Context) extends Plugin {
- private val ScalafmtVersion = "0.4.2"
+ private val ScalafmtVersion = "0.5.7"
override def dependencies =
super.dependencies ++
Resolver( mavenCentral ).bind(
- ScalaDependency("com.geirsson", "scalafmt", ScalafmtVersion),
ScalaDependency("com.geirsson", "scalafmt-cli", ScalafmtVersion)
)
}
diff --git a/plugins/scalajs/ScalaJsBuild.scala b/plugins/scalajs/ScalaJsBuild.scala
index 0c7222c..b6df9e9 100644
--- a/plugins/scalajs/ScalaJsBuild.scala
+++ b/plugins/scalajs/ScalaJsBuild.scala
@@ -2,6 +2,7 @@ package cbt
import java.io.File
import java.net.URL
+// TODO: maybe move this into stage2 to avoid having to call zinc separately for this as a plugin
trait ScalaJsBuild extends DynamicOverrides{
final protected val scalaJsLib = ScalaJsLib(
scalaJsVersion, scalaVersion, context.cbtLastModified, context.paths.mavenCache
@@ -23,17 +24,17 @@ trait ScalaJsBuild extends DynamicOverrides{
}
override def compile = {
- super.compile
- scalaJsLib.link(
- scalaJsTargetFile, scalaJsOptions, target +: dependencies.collect{case d: BoundMavenDependency => d.jar}
- )
- None // FIXME: we need to rethink the concept of a "compile" task I think. There is no time to return here.
+ val res = super.compile
+ scalaJsLib.link( scalaJsTargetFile, scalaJsOptions, target +: dependencyClasspath.files )
+ res
+ // FIXME: we need to rethink the concept of a "compile" task I think.
+ // An exit code would probably be more appropriate here.
}
def scalaJsOptions: Seq[String] = Seq()
/** Where to put the generated js file */
- def scalaJsTargetFile: File
+ def scalaJsTargetFile: File = target / "app.js"
override def cleanFiles = super.cleanFiles :+ scalaJsTargetFile :+ (scalaJsTargetFile ++ ".map")
diff --git a/plugins/scalajs/ScalaJsLib.scala b/plugins/scalajs/ScalaJsLib.scala
index ae37bde..7886478 100644
--- a/plugins/scalajs/ScalaJsLib.scala
+++ b/plugins/scalajs/ScalaJsLib.scala
@@ -4,28 +4,15 @@ import java.io.File
case class ScalaJsLib(
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
- }
- case object FastOptJS extends ScalaJsOutputMode{
- override val option = "--fastOpt"
- override val fileSuffix = "fastopt"
- }
- case object FullOptJS extends ScalaJsOutputMode{
- override val option = "--fullOpt"
- override val fileSuffix = "fullopt"
- }
-
val lib = new Lib(logger)
def dep(artifactId: String) = MavenResolver( cbtLastModified, mavenCache, mavenCentral ).bindOne(
MavenDependency("org.scala-js", artifactId, scalaJsVersion)
)
def link(
- outputPath: File,
- scalaJsOptions: Seq[String], entriesToLink: Seq[File]
- ) = {
+ outputPath: File, scalaJsOptions: Seq[String], entriesToLink: Seq[File]
+ ): ExitCode = {
+ outputPath.getParentFile.mkdirs
val scalaJsCliDep = dep( "scalajs-cli_"++lib.libMajorVersion(scalaVersion) )
outputPath.getParentFile.mkdirs
lib.runMain(
diff --git a/plugins/sonatype-release/src/SonatypeRelease.scala b/plugins/sonatype-release/src/SonatypeRelease.scala
index 32303ad..cc2932a 100644
--- a/plugins/sonatype-release/src/SonatypeRelease.scala
+++ b/plugins/sonatype-release/src/SonatypeRelease.scala
@@ -1,4 +1,5 @@
package cbt
+// TODO: maybe move this into stage2 to avoid having to call zinc separately for this as a plugin
import cbt.sonatype.SonatypeLib
diff --git a/plugins/uber-jar/src/UberJar.scala b/plugins/uber-jar/src/UberJar.scala
index 3783367..79b87a1 100644
--- a/plugins/uber-jar/src/UberJar.scala
+++ b/plugins/uber-jar/src/UberJar.scala
@@ -15,7 +15,7 @@ trait UberJar extends BaseBuild {
def uberJarMainClass: Option[String] = runClass
- def uberJarName: String = projectName + ".jar"
+ def uberJarName: String = name + ".jar"
}
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala
index 7f8f600..71e6ee5 100644
--- a/stage1/Stage1Lib.scala
+++ b/stage1/Stage1Lib.scala
@@ -12,7 +12,10 @@ import java.util.{Set=>_,Map=>_,List=>_,_}
import javax.xml.bind.annotation.adapters.HexBinaryAdapter
// CLI interop
-case class ExitCode(integer: Int)
+case class ExitCode(integer: Int){
+ def ||( other: => ExitCode ) = if( this == ExitCode.Success ) this else other
+ def &&( other: => ExitCode ) = if( this != ExitCode.Success ) this else other
+}
object ExitCode{
val Success = ExitCode(0)
val Failure = ExitCode(1)
@@ -71,7 +74,7 @@ class Stage1Lib( logger: Logger ) extends BaseLib{
try{
Files.copy(stream, incomplete, StandardCopyOption.REPLACE_EXISTING)
} finally {
- stream.close()
+ stream.close
}
sha1.foreach{
hash =>
@@ -86,17 +89,11 @@ class Stage1Lib( logger: Logger ) extends BaseLib{
}
}
- def listFilesRecursive(f: File): Seq[File] = {
- f +: (
- if( f.isDirectory ) f.listFiles.flatMap(listFilesRecursive).toVector else Seq[File]()
- )
- }
-
// ========== compilation / execution ==========
def runMain( cls: String, args: Seq[String], classLoader: ClassLoader, fakeInstance: Boolean = false ): ExitCode = {
import java.lang.reflect.Modifier
- logger.lib(s"Running $cls.main($args) with classLoader: " ++ classLoader.toString)
+ logger.run(s"Running $cls.main($args) with classLoader: " ++ classLoader.toString)
trapExitCode{
val c = classLoader.loadClass(cls)
val m = c.getMethod( "main", classOf[Array[String]] )
@@ -149,7 +146,8 @@ class Stage1Lib( logger: Logger ) extends BaseLib{
/** Given a directory corresponding to the root package, iterate
the names of all classes derived from the class files found */
def iterateClassNames( classesRootDirectory: File ): Seq[String] =
- listFilesRecursive(classesRootDirectory)
+ classesRootDirectory
+ .listRecursive
.filter(_.isFile)
.map(_.getPath)
.collect{
@@ -270,7 +268,7 @@ class Stage1Lib( logger: Logger ) extends BaseLib{
_class,
dualArgs ++ singleArgs ++ (
if(cp.isEmpty) Nil else Seq("-cp", cp)
- ) ++ sourceFiles.map(_.toString),
+ ) ++ sourceFiles.map(_.string),
zinc.classLoader
)
} catch {
diff --git a/stage1/URLClassLoader.scala b/stage1/URLClassLoader.scala
index ff8d2a1..e93b1a4 100644
--- a/stage1/URLClassLoader.scala
+++ b/stage1/URLClassLoader.scala
@@ -8,6 +8,10 @@ case class URLClassLoader( classPath: ClassPath, parent: ClassLoader )( implicit
classPath.strings.map( p => new URL("file:" ++ p) ).toArray,
parent
) with CachingClassLoader{
+ override def loadClass(name: String) = {
+ logger.log("classloader","loadClass " + name)
+ super.loadClass(name)
+ }
val id = Math.abs( new java.util.Random().nextInt )
override def toString = (
scala.Console.BLUE
diff --git a/stage1/cbt.scala b/stage1/cbt.scala
index 4caa085..bc0e944 100644
--- a/stage1/cbt.scala
+++ b/stage1/cbt.scala
@@ -28,6 +28,28 @@ object `package`{
def /(s: String): File = new File( file, s )
def parent = lib.realpath(file ++ "/..")
def string = file.toString
+ /* recursively deletes folders*/
+ def deleteRecursive: Unit = {
+ val s = file.string
+ // some desperate attempts to keep people from accidentally deleting their hard drive
+ assert( file == file.getCanonicalFile, "deleteRecursive requires previous .getCanonicalFile" )
+ assert( file.isAbsolute, "deleteRecursive requires absolute path" )
+ assert( file.string != "", "deleteRecursive requires non-empty file path" )
+ assert( s.split("/").size > 4, "deleteRecursive requires absolute path of at least depth 4" )
+ assert( s.split("\\").size > 4, "deleteRecursive requires absolute path of at least depth 4" )
+ assert( !listRecursive.exists(_.isHidden), "deleteRecursive requires no files to be hidden" )
+ assert( listRecursive.forall(_.canWrite), "deleteRecursive requires all files to be writable" )
+ if( file.isDirectory ){
+ file.listFiles.map(_.deleteRecursive)
+ }
+ //file.delete
+ }
+
+ def listRecursive: Seq[File] = {
+ file +: (
+ if( file.isDirectory ) file.listFiles.flatMap(_.listRecursive).toVector else Seq[File]()
+ )
+ }
}
implicit class URLExtensionMethods( url: URL ){
def ++( s: String ): URL = new URL( url.toString ++ s )
@@ -38,6 +60,16 @@ object `package`{
case e:java.lang.UnsupportedOperationException if e.getMessage === "empty.max" => None
}
}
+ implicit class ClassLoaderExtensions(classLoader: ClassLoader){
+ def canLoad(className: String) = {
+ try{
+ classLoader.loadClass(className)
+ true
+ } catch {
+ case e: ClassNotFoundException => false
+ }
+ }
+ }
implicit class BuildInterfaceExtensions(build: BuildInterface){
import build._
// TODO: if every build has a method triggers a callback if files change
diff --git a/stage1/logger.scala b/stage1/logger.scala
index 8c8431a..373a954 100644
--- a/stage1/logger.scala
+++ b/stage1/logger.scala
@@ -20,7 +20,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) {
def log(name: String, msg: => String) = {
if(
(
- (enabledLoggers contains name)
+ (enabledLoggers contains name)
|| (enabledLoggers contains "all")
) && !(disabledLoggers contains name)
){
@@ -41,6 +41,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) {
final def git(msg: => String) = log(names.git, msg)
final def pom(msg: => String) = log(names.pom, msg)
final def dynamic(msg: => String) = log(names.dynamic, msg)
+ final def run(msg: => String) = log(names.run, msg)
final def transientCache(msg: => String) = log(names.transientCache, msg)
private object names{
@@ -53,6 +54,7 @@ case class Logger(enabledLoggers: Set[String], start: Long) {
val lib = "lib"
val test = "test"
val pom = "pom"
+ val run = "run"
val git = "git"
val dynamic = "dynamic"
val transientCache = "transientCache"
diff --git a/stage1/resolver.scala b/stage1/resolver.scala
index e02f931..ab3196a 100644
--- a/stage1/resolver.scala
+++ b/stage1/resolver.scala
@@ -89,6 +89,10 @@ trait DependencyImplementation extends Dependency{
def run( args: String* ): ExitCode = {
runClass.map( runMain( _, args: _* ) ).getOrElse{
+ // FIXME: this just doing nothing when class is not found has been repeatedly
+ // surprising. Let's try to make this more visible than just logging an error.
+ // Currently blocked on task `recursive` trying every subbuild and would error
+ // for all that don't have a run class. Maybe that's ok actually.
logger.task( "No main class found for " ++ show )
ExitCode.Success
}
@@ -205,13 +209,6 @@ object Classifier{
abstract class DependenciesProxy{
}
-class BoundMavenDependencies(
- cbtLastModified: Long, mavenCache: File, urls: Seq[URL], mavenDependencies: Seq[MavenDependency]
-)(
- implicit logger: Logger, transientCache: java.util.Map[AnyRef,AnyRef], classLoaderCache: ClassLoaderCache
-) extends Dependencies(
- mavenDependencies.map( BoundMavenDependency(cbtLastModified,mavenCache,_,urls) )
-)
case class MavenDependency(
groupId: String, artifactId: String, version: String, classifier: Classifier = Classifier.none
){
@@ -229,6 +226,11 @@ case class BoundMavenDependency(
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 ++ ")"
+ override def hashCode = mavenDependency.hashCode
+ override def equals(other: Any) = other match{
+ case o: BoundMavenDependency => o.mavenDependency == mavenDependency && o.repositories == repositories
+ case _ => false
+ }
val MavenDependency( groupId, artifactId, version, classifier ) = mavenDependency
assert(
Option(groupId).collect{
@@ -261,7 +263,7 @@ case class BoundMavenDependency(
import scala.collection.JavaConversions._
private def resolve(suffix: String, hash: Option[String], useClassifier: Boolean): File = {
- logger.resolver("Resolving "+this)
+ logger.resolver(lib.blue("Resolving ")+this)
val file = mavenCache ++ basePath(useClassifier) ++ "." ++ suffix
val urls = repositories.map(_ ++ basePath(useClassifier) ++ "." ++ suffix)
urls.find(
@@ -284,7 +286,10 @@ case class BoundMavenDependency(
def jar: File = taskCache[BoundMavenDependency]("jar").memoize{ resolve("jar", Some(jarSha1), true) }
def pom: File = taskCache[BoundMavenDependency]("pom").memoize{ resolve("pom", Some(pomSha1), false) }
- private def pomXml = XML.loadFile(pom.string)
+ private def pomXml = {
+ logger.resolver( "Loading pom file: " ++ pom.string )
+ XML.loadFile(pom.string)
+ }
// ========== pom traversal ==========
private lazy val transitivePom: Seq[BoundMavenDependency] = {
diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala
index 8d72f9a..3c3cbec 100644
--- a/stage2/BasicBuild.scala
+++ b/stage2/BasicBuild.scala
@@ -32,7 +32,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
s"You need to extend ${lib.buildBuildClassName} in: " + projectDirectory + "/" ++ lib.buildDirectoryName
)
- final def usage: String = lib.usage(this.getClass, show)
+ final def help: String = lib.usage(this.getClass, show)
final def taskNames: String = lib.taskNames(this.getClass).sorted.mkString("\n")
@@ -41,7 +41,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
def defaultScalaVersion: String = constants.scalaVersion
final def scalaVersion = context.scalaVersion getOrElse defaultScalaVersion
final def scalaMajorVersion: String = lib.libMajorVersion(scalaVersion)
- def projectName = "default"
+ def name = projectDirectory.getName
// TODO: get rid of this in favor of newBuild.
// currently blocked on DynamicOverride being not parts
@@ -85,7 +85,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
def sources: Seq[File] = Seq(defaultSourceDirectory) ++ projectDirectory.listFiles.toVector.filter(sourceFileFilter)
/** Which file endings to consider being source files. */
- def sourceFileFilter(file: File): Boolean = file.toString.endsWith(".scala") || file.toString.endsWith(".java")
+ def sourceFileFilter(file: File) = lib.sourceFileFilter(file)
/** Absolute path names for all individual files found in sources directly or contained in directories. */
final def sourceFiles: Seq[File] = lib.sourceFiles(sources, sourceFileFilter)
@@ -187,16 +187,22 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
}
def run: ExitCode = run( context.args: _* )
-
- def test: Any =
- lib.callReflective(
- DirectoryDependency(projectDirectory++"/test").dependency,
- Some("run"),
- context
- )
-
- def t = test
- def rt = recursiveUnsafe(Some("test"))
+ def test: Dependency = {
+ val testDirectory = projectDirectory / "test"
+ if( (testDirectory / lib.buildDirectoryName / lib.buildFileName).exists ){
+ // FIYME: maybe we can make loadRoot(...).finalBuild an Option some
+ DirectoryDependency( testDirectory ).dependency
+ } else {
+ new BasicBuild( context.copy(workingDirectory = testDirectory) ){
+ override def dependencies = Seq(
+ DirectoryDependency(projectDirectory++"/..")
+ )
+ def apply = run
+ }
+ }
+ }
+ def t: Any = lib.callReflective( test, Some("run"), context )
+ def rt = recursiveUnsafe(Some("test.run"))
def recursiveSafe(_run: BuildInterface => Any): ExitCode = {
val builds = (this +: transitiveDependencies).collect{
@@ -265,6 +271,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
}
override def show = this.getClass.getSimpleName ++ "(" ++ projectDirectory.string ++ ")"
+ override def toString = show
// a method that can be called only to trigger any side-effects
final def `void` = ()
diff --git a/stage2/BuildDependency.scala b/stage2/BuildDependency.scala
index 0162791..9a2918a 100644
--- a/stage2/BuildDependency.scala
+++ b/stage2/BuildDependency.scala
@@ -25,6 +25,7 @@ final case class DirectoryDependency(context: Context, pathToNestedBuild: String
def transientCache = context.transientCache
private lazy val root = lib.loadRoot( context )
lazy val dependency: Dependency = {
+ // TODO: move this into finalBuild probably
def selectNestedBuild( build: Dependency, names: Seq[String], previous: Seq[String] ): Dependency = {
names.headOption.map{ name =>
if( lib.taskNames(build.getClass).contains(name) ){
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index b6187ce..33bfe1a 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -140,22 +140,19 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
).flatMap(lib.taskNames).distinct.sorted
val thisTasks = lib.taskNames(buildClass) diff baseTasks
(
- (
+ s"Methods provided by $show\n\n"
+ ++ (
if( thisTasks.nonEmpty ){
- s"""Methods provided by ${show}
-
- ${thisTasks.mkString(" ")}
-
-"""
- } else ""
- ) ++ s"""Methods provided by CBT (but possibly overwritten)
-
- ${baseTasks.mkString(" ")}"""
- ) ++ "\n"
+ thisTasks.mkString(" ") ++ "\n\n"
+ } else "<none>"
+ )
+ ++ s"\n\nMethods provided by CBT (but possibly overwritten)\n\n"
+ ++ baseTasks.mkString(" ") + "\n"
+ )
}
def callReflective[T <: AnyRef]( obj: T, code: Option[String], context: Context ): ExitCode = {
- callInternal( obj, code.toSeq.flatMap(_.split("\\.").map( NameTransformer.encode )), Nil, context ) match {
+ callInternal( obj, code.toSeq.flatMap(_.split("\\.").map( NameTransformer.encode )), Nil, context ).map {
case (obj, code, None) =>
val s = render(obj)
if(s.nonEmpty)
@@ -168,7 +165,7 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
if(s.nonEmpty)
System.err.println(s)
code getOrElse ExitCode.Failure
- }
+ }.reduceOption(_ && _).getOrElse( ExitCode.Failure )
}
private def render[T]( obj: T ): String = {
@@ -177,12 +174,12 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
case None => ""
case d: Dependency => lib.usage(d.getClass, d.show())
case c: ClassPath => c.string
- case t:ToolsStage2.type => "Available methods: " ++ lib.taskNames(t.getClass).mkString(" ")
+ case ExitCode(int) => System.err.println(int); System.exit(int); ???
case _ => obj.toString
}
}
- private def callInternal[T <: AnyRef]( obj: T, members: Seq[String], previous: Seq[String], context: Context ): (Option[Object], Option[ExitCode], Option[String]) = {
+ private def callInternal[T <: AnyRef]( obj: T, members: Seq[String], previous: Seq[String], context: Context ): Seq[(Option[Object], Option[ExitCode], Option[String])] = {
members.headOption.map{ taskName =>
logger.lib("Calling task " ++ taskName.toString)
taskMethods(obj.getClass).get(taskName).map{ method =>
@@ -190,12 +187,12 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
result match {
case code if code.getClass.getSimpleName == "ExitCode" =>
// FIXME: ExitCode needs to be part of the compatibility interfaces
- (None, Some(ExitCode(Stage0Lib.get(code,"integer").asInstanceOf[Int])), None)
- case Seq(bs @ _*) if bs.forall(_.isInstanceOf[BaseBuild]) =>
- bs.map( b => callInternal(b.asInstanceOf[BaseBuild], members.tail, previous :+ taskName, context) ).head
+ Seq((None, Some(ExitCode(Stage0Lib.get(code,"integer").asInstanceOf[Int])), None))
+ case bs: Seq[_] if bs.size > 0 && bs.forall(_.isInstanceOf[BaseBuild]) =>
+ bs.flatMap( b => callInternal(b.asInstanceOf[BaseBuild], members.tail, previous :+ taskName, context) )
case _ => callInternal(result, members.tail, previous :+ taskName, context)
}
- }.getOrElse( (None, None, None) )
+ }.getOrElse( Seq( (None, None, None) ) )
}.getOrElse{
val folder = NameTransformer.decode(taskName)
if( context != null && (context.workingDirectory / folder).exists ){
@@ -209,11 +206,19 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
newContext
)
} else {
- ( Some(obj), None, Some("\nMethod not found: " ++ (previous :+ taskName).mkString(".") ++ "\n") )
+ Seq( ( Some(obj), None, Some("\nMethod not found: " ++ (previous :+ taskName).mkString(".") ++ "\n") ) )
}
}
}.getOrElse{
- ( Some(obj), None, None )
+ Seq((
+ Some(
+ obj.getClass.getMethods.find(m => m.getName == "apply" && m.getParameterCount == 0).map(
+ _.invoke(obj)
+ ).getOrElse( obj )
+ ),
+ None,
+ None
+ ))
}
}
@@ -280,10 +285,13 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
def dirname(path: File): File = new File(realpath(path).string.stripSuffix("/").split("/").dropRight(1).mkString("/"))
def nameAndContents(file: File) = basename(file) -> readAllBytes(file.toPath)
- def sourceFiles( sources: Seq[File], sourceFileFilter: File => Boolean ): Seq[File] = {
+ /** Which file endings to consider being source files. */
+ def sourceFileFilter(file: File): Boolean = file.toString.endsWith(".scala") || file.toString.endsWith(".java")
+
+ def sourceFiles( sources: Seq[File], sourceFileFilter: File => Boolean = sourceFileFilter ): Seq[File] = {
for {
base <- sources.filter(_.exists).map(lib.realpath)
- file <- lib.listFilesRecursive(base) if file.isFile && sourceFileFilter(file)
+ file <- base.listRecursive if file.isFile && sourceFileFilter(file)
} yield file
}
@@ -309,7 +317,7 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
try{
val names = for {
base <- files.filter(_.exists).map(realpath)
- file <- listFilesRecursive(base) if file.isFile
+ file <- base.listRecursive if file.isFile
} yield {
val strip = Some( base ).filter(_.isDirectory) ++ stripBaseCanonical
val name = strip.foldLeft( file.getCanonicalPath )(
diff --git a/stage2/ToolsTasks.scala b/stage2/ToolsTasks.scala
index 0cfd501..b5e94d4 100644
--- a/stage2/ToolsTasks.scala
+++ b/stage2/ToolsTasks.scala
@@ -10,6 +10,8 @@ class ToolsTasks(
cbtHome: File,
cbtLastModified: Long
)(implicit classLoaderCache: ClassLoaderCache){
+ def apply: String = "Available methods: " ++ lib.taskNames(getClass).mkString(" ")
+
private val paths = CbtPaths(cbtHome, cache)
import paths._
implicit val logger: Logger = lib.logger
diff --git a/test/build/build.scala b/test/build/build.scala
index 5a138fb..9e02144 100644
--- a/test/build/build.scala
+++ b/test/build/build.scala
@@ -1,4 +1,5 @@
import cbt._
class Build(val context: cbt.Context) extends BaseBuild{
override def dependencies = super.dependencies :+ context.cbtDependency
+ def apply = run
}
diff --git a/test/test.scala b/test/test.scala
index 9a70b6c..3305926 100644
--- a/test/test.scala
+++ b/test/test.scala
@@ -331,9 +331,14 @@ object Main{
assert(res.exit0)
assert(res.out startsWith "Bar2: Some(DynamicBuild", res.out ++ res.err)
}
+ {
+ val res = runCbt("../examples/cross-build-example", Seq("cross.scalaVersion"))
+ assert(res.exit0)
+ assert(res.out == "2.10.5\n2.11.7\n", res.out)
+ }
{
- val res = runCbt("../libraries/eval", Seq("test"))
+ val res = runCbt("../libraries/eval", Seq("test.run"))
assert(res.exit0)
assert(res.out.contains("All tests passed"), res.out)
}
diff --git a/tools/gui/resources/template-project/build/build.scala b/tools/gui/resources/template-project/build/build.scala
index 3ec5db9..b632d97 100644
--- a/tools/gui/resources/template-project/build/build.scala
+++ b/tools/gui/resources/template-project/build/build.scala
@@ -2,4 +2,4 @@ import cbt._
class Build(val context: Context) extends BaseBuild##with## {
-##projectName####dependencies##}
+##name####dependencies##}
diff --git a/tools/gui/src/ProjectBuilder.scala b/tools/gui/src/ProjectBuilder.scala
index ceba376..4204942 100644
--- a/tools/gui/src/ProjectBuilder.scala
+++ b/tools/gui/src/ProjectBuilder.scala
@@ -95,7 +95,7 @@ class ProjectBuilder(
writeTemplate(
templateDir / "build" / "build.scala",
buildDir / "build.scala",
- (name, s""" override def projectName = "$name"$blankLine""", "##projectName##"),
+ (name, s""" override def name = "$name"$blankLine""", "##name##"),
(dependencyString, dependencies + blankLine, "##dependencies##"),
(plugins, plugins, "##with##")
)