aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md18
-rw-r--r--TODO.txt21
-rw-r--r--build/build.scala9
-rw-r--r--circle.yml4
-rw-r--r--nailgun_launcher/CBTUrlClassLoader.java3
-rw-r--r--nailgun_launcher/EarlyDependencies.java1
-rw-r--r--nailgun_launcher/NailgunLauncher.java120
-rw-r--r--nailgun_launcher/Stage0Lib.java123
-rw-r--r--stage1/MavenRepository.scala22
-rw-r--r--stage1/Stage1.scala32
-rw-r--r--stage1/Stage1Lib.scala77
-rw-r--r--stage1/logger.scala10
-rw-r--r--stage1/resolver.scala153
-rw-r--r--stage2/AdminTasks.scala43
-rw-r--r--stage2/BasicBuild.scala35
-rw-r--r--stage2/BuildBuild.scala7
-rw-r--r--stage2/BuildDependency.scala1
-rw-r--r--stage2/GitDependency.scala5
-rw-r--r--stage2/Lib.scala4
-rw-r--r--stage2/SbtDependencyDsl.scala43
-rw-r--r--stage2/Stage2.scala8
-rw-r--r--stage2/mixins.scala4
-rw-r--r--test/simple/build/build.scala34
-rw-r--r--test/test.scala57
24 files changed, 474 insertions, 360 deletions
diff --git a/README.md b/README.md
index 36f1f50..84259da 100644
--- a/README.md
+++ b/README.md
@@ -48,14 +48,16 @@ class Build(context: cbt.Context) extends PackageBuild(context){
override def version = "0.6.1-SNAPSHOT"
override def groupId = "org.cvogt"
override def artifactId = "play-json-extensions"
- override def dependencies = super.dependencies ++ Vector(
- // encouraged way to declare dependencies
- ScalaDependency("com.typesafe.play", "play-json", "2.4.4"),
- JavaDependency("joda-time", "joda-time", "2.9.2")
- // also supported for SBT syntax compatibility:
- // "com.typesafe.play" %% "play-json" % "2.4.4"
- // "joda-time" % "joda-time % "2.9.2"
- )
+ override def dependencies =
+ super.dependencies :+
+ MavenRepository.central.resolve(
+ // encouraged way to declare dependencies
+ ScalaDependency("com.typesafe.play", "play-json", "2.4.4"),
+ MavenDependency("joda-time", "joda-time", "2.9.2")
+ // also supported for SBT syntax compatibility:
+ // "com.typesafe.play" %% "play-json" % "2.4.4"
+ // Maven.central % "joda-time" % "joda-time % "2.9.2"
+ )
override def compile = {
println("Compiling...")
super.compile
diff --git a/TODO.txt b/TODO.txt
index e5c99f1..3da49f5 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,45 +1,26 @@
TODO:
- in progress
- - automated tests
- improve logging
- - bugs
- - condition guarding zinc is too eager, needs to invalid
-
- immediate features
- maybe rename context.cwd
- - add another class that makes all pom required fields abstract
- fix main project main method being run during tests
- - DI lib into depencies
- - fix conflicts in classpath stemming from dependencies
- - cleanup classpath/classloader stuff
- investigate and solve multiple compilations of the same SourceDependency Build. Maybe introduce global Build map.
- cleanup
- move from java File to nio Path
- - defs for all tasks and cached where needed
- - unify work classpath
- - unify argument order
- near future features
- - strip out ammonite dependency
- make cbt's own re-build concurrency safe
- unify with sbts key names where sensible
- allow updating snapshots
- cbt cli options inject add dependencies into default build
- - write cached macro
- - add "debug" mode that shows lots of logging
- - running subproject tasks in parallel
- http://stackoverflow.com/questions/743288/java-synchronization-utility
- dependency exclusion, etc.
- - cache class loader per dependency in global, synchronized mutable Map
- use cli friendly responses by default everywhere
- class path debugging
- - duplicate class detection
- - missing/broken jars detection
+ - broken jars detection
- invalid files in lib folder
- integrate / build out maven search
- - proper exit codes
- use zinc nailgun multi platform nailgun wrapper https://github.com/typesafehub/zinc/tree/7af98ba11d27d7667301c2222c1e702c7092bc44/src/universal/bin
diff --git a/build/build.scala b/build/build.scala
index aa5d27a..6dfd395 100644
--- a/build/build.scala
+++ b/build/build.scala
@@ -5,11 +5,10 @@ import scala.collection.immutable.Seq
class Build(context: Context) extends BasicBuild(context){
// FIXME: somehow consolidate this with cbt's own boot-strapping from source.
- override def dependencies = super.dependencies ++ Seq(
- JavaDependency("org.scala-lang","scala-library",constants.scalaVersion),
- JavaDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
- JavaDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r"),
- JavaDependency("com.typesafe.zinc","zinc","0.3.9"),
+ override def dependencies = super.dependencies :+ MavenRepository.central.resolve(
+ 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","0.3.9"),
ScalaDependency("org.scala-lang.modules","scala-xml","1.0.5")
)
override def sources = Seq(
diff --git a/circle.yml b/circle.yml
index 35620d8..7d7be3e 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,11 +1,9 @@
machine:
java:
- version: oraclejdk8
+ version: oraclejdk7
dependencies:
cache_directories:
- - "bootstrap_scala/cache"
- - "bootstrap_scala/target"
- "cache"
- "nailgun_launcher/target"
- "stage1/target"
diff --git a/nailgun_launcher/CBTUrlClassLoader.java b/nailgun_launcher/CBTUrlClassLoader.java
index 88bf4a3..c05391b 100644
--- a/nailgun_launcher/CBTUrlClassLoader.java
+++ b/nailgun_launcher/CBTUrlClassLoader.java
@@ -2,6 +2,7 @@ package cbt;
import java.io.*;
import java.net.*;
import java.util.*;
+import static cbt.Stage0Lib.*;
class CbtURLClassLoader extends java.net.URLClassLoader{
public String toString(){
return (
@@ -9,7 +10,7 @@ class CbtURLClassLoader extends java.net.URLClassLoader{
+ "(\n "
+ Arrays.toString(getURLs())
+ ",\n "
- + String.join("\n ",getParent().toString().split("\n"))
+ + join("\n ",getParent().toString().split("\n"))
+ "\n)"
);
}
diff --git a/nailgun_launcher/EarlyDependencies.java b/nailgun_launcher/EarlyDependencies.java
index 1e129c7..f4d446c 100644
--- a/nailgun_launcher/EarlyDependencies.java
+++ b/nailgun_launcher/EarlyDependencies.java
@@ -4,6 +4,7 @@ import java.io.*;
import java.nio.file.*;
import java.net.*;
import java.security.*;
+import static cbt.Stage0Lib.*;
import static cbt.NailgunLauncher.*;
class EarlyDependencies{
diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java
index 50a3c91..a12d059 100644
--- a/nailgun_launcher/NailgunLauncher.java
+++ b/nailgun_launcher/NailgunLauncher.java
@@ -2,13 +2,10 @@ package cbt;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
-import java.nio.*;
-import java.nio.file.*;
-import static java.io.File.pathSeparator;
import java.security.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
-import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
+import static cbt.Stage0Lib.*;
/**
* This launcher allows to start the JVM without loading anything else permanently into its
@@ -47,7 +44,7 @@ public class NailgunLauncher{
MalformedURLException,
IOException,
NoSuchAlgorithmException {
- long now = System.currentTimeMillis();
+ long start = System.currentTimeMillis();
//System.err.println("ClassLoader: "+stage1classLoader);
//System.err.println("lastSuccessfullCompile: "+lastSuccessfullCompile);
//System.err.println("now: "+now);
@@ -69,20 +66,20 @@ public class NailgunLauncher{
}
}
- Boolean stage1SourcesChanged = false;
+ Boolean changed = lastSuccessfullCompile == 0;
for( File file: stage1SourceFiles ){
if( file.lastModified() > lastSuccessfullCompile ){
- stage1SourcesChanged = true;
+ changed = true;
//System.err.println("File change: "+file.lastModified());
break;
}
}
- if(stage1SourcesChanged || stage1classLoader == null){
+ if(changed){
EarlyDependencies earlyDeps = new EarlyDependencies();
int exitCode = zinc(earlyDeps, stage1SourceFiles);
if( exitCode == 0 ){
- lastSuccessfullCompile = now;
+ lastSuccessfullCompile = start;
} else {
System.exit( exitCode );
}
@@ -102,113 +99,12 @@ public class NailgunLauncher{
Integer exitCode =
(Integer) stage1classLoader
.loadClass("cbt.Stage1")
- .getMethod("run", String[].class, ClassLoader.class, Boolean.class)
- .invoke( null, (Object) args, stage1classLoader, stage1SourcesChanged);
+ .getMethod("run", String[].class, ClassLoader.class, Boolean.class, Long.class)
+ .invoke( null, (Object) args, stage1classLoader, changed, start);
System.exit(exitCode);
}catch(Exception e){
System.err.println(stage1classLoader);
throw e;
}
}
-
- public static void _assert(Boolean condition, Object msg){
- if(!condition){
- throw new AssertionError("Assertion failed: "+msg);
- }
- }
-
- public static int runMain(String cls, String[] args, ClassLoader cl) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException{
- try{
- System.setSecurityManager( new TrapSecurityManager() );
- cl.loadClass(cls)
- .getMethod("main", String[].class)
- .invoke( null, (Object) args);
- return 0;
- }catch( InvocationTargetException exception ){
- Throwable cause = exception.getCause();
- if(cause instanceof TrappedExitCode){
- return ((TrappedExitCode) cause).exitCode;
- }
- throw exception;
- } finally {
- System.setSecurityManager(NailgunLauncher.defaultSecurityManager);
- }
- }
-
- static int zinc( EarlyDependencies earlyDeps, List<File> sourceFiles ) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException{
- String cp = NAILGUN+TARGET + pathSeparator + earlyDeps.scalaXml_1_0_5_File + pathSeparator + earlyDeps.scalaLibrary_2_11_8_File;
- List<String> zincArgs = new ArrayList<String>(
- Arrays.asList(
- new String[]{
- "-scala-compiler", earlyDeps.scalaCompiler_2_11_8_File,
- "-scala-library", earlyDeps.scalaLibrary_2_11_8_File,
- "-scala-extra", earlyDeps.scalaReflect_2_11_8_File,
- "-sbt-interface", earlyDeps.sbtInterface_0_13_9_File,
- "-compiler-interface", earlyDeps.compilerInterface_0_13_9_File,
- "-cp", cp,
- "-d", STAGE1+TARGET
- }
- )
- );
-
- for( File f: sourceFiles ){
- zincArgs.add(f.toString());
- }
-
- PrintStream oldOut = System.out;
- try{
- System.setOut(System.err);
- return runMain( "com.typesafe.zinc.Main", zincArgs.toArray(new String[zincArgs.size()]), earlyDeps.zinc );
- } finally {
- System.setOut(oldOut);
- }
- }
-
- static ClassLoader classLoader( String file ) throws MalformedURLException{
- return new CbtURLClassLoader(
- new URL[]{ new URL("file:"+file) }
- );
- }
- static ClassLoader classLoader( String file, ClassLoader parent ) throws MalformedURLException{
- return new CbtURLClassLoader(
- new URL[]{ new URL("file:"+file) }, parent
- );
- }
- static ClassLoader cacheGet( String key ){
- return classLoaderCacheValues.get(
- classLoaderCacheKeys.get( key )
- );
- }
- static ClassLoader cachePut( ClassLoader classLoader, String... jars ){
- String key = String.join( pathSeparator, jars );
- Object keyObject = new Object();
- classLoaderCacheKeys.put( key, keyObject );
- classLoaderCacheValues.put( keyObject, classLoader );
- return classLoader;
- }
-
- public static void download(URL urlString, Path target, String sha1) throws IOException, NoSuchAlgorithmException {
- final Path unverified = Paths.get(target+".unverified");
- if(!Files.exists(target)) {
- new File(target.toString()).getParentFile().mkdirs();
- System.err.println("downloading " + urlString);
- System.err.println("to " + target);
- final InputStream stream = urlString.openStream();
- Files.copy(stream, unverified, StandardCopyOption.REPLACE_EXISTING);
- stream.close();
- final String checksum = sha1(Files.readAllBytes(unverified));
- if(sha1 == null || sha1.toUpperCase().equals(checksum)) {
- Files.move(unverified, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
- } else {
- System.err.println(target + " checksum does not match.\nExpected: |" + sha1 + "|\nFound: |" + checksum + "|");
- System.exit(1);
- }
- }
- }
-
- public static String sha1(byte[] bytes) throws NoSuchAlgorithmException {
- final MessageDigest sha1 = MessageDigest.getInstance("SHA1");
- sha1.update(bytes, 0, bytes.length);
- return (new HexBinaryAdapter()).marshal(sha1.digest());
- }
}
diff --git a/nailgun_launcher/Stage0Lib.java b/nailgun_launcher/Stage0Lib.java
new file mode 100644
index 0000000..d6f33e1
--- /dev/null
+++ b/nailgun_launcher/Stage0Lib.java
@@ -0,0 +1,123 @@
+package cbt;
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.nio.*;
+import java.nio.file.*;
+import java.security.*;
+import java.util.*;
+import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
+import static java.io.File.pathSeparator;
+import static cbt.Stage0Lib.*;
+import static cbt.NailgunLauncher.*;
+
+public class Stage0Lib{
+ public static void _assert(Boolean condition, Object msg){
+ if(!condition){
+ throw new AssertionError("Assertion failed: "+msg);
+ }
+ }
+
+ public static int runMain(String cls, String[] args, ClassLoader cl) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException{
+ try{
+ System.setSecurityManager( new TrapSecurityManager() );
+ cl.loadClass(cls)
+ .getMethod("main", String[].class)
+ .invoke( null, (Object) args);
+ return 0;
+ }catch( InvocationTargetException exception ){
+ Throwable cause = exception.getCause();
+ if(cause instanceof TrappedExitCode){
+ return ((TrappedExitCode) cause).exitCode;
+ }
+ throw exception;
+ } finally {
+ System.setSecurityManager(NailgunLauncher.defaultSecurityManager);
+ }
+ }
+
+ public static int zinc( EarlyDependencies earlyDeps, List<File> sourceFiles ) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException{
+ String cp = NAILGUN+TARGET + pathSeparator + earlyDeps.scalaXml_1_0_5_File + pathSeparator + earlyDeps.scalaLibrary_2_11_8_File;
+ List<String> zincArgs = new ArrayList<String>(
+ Arrays.asList(
+ new String[]{
+ "-scala-compiler", earlyDeps.scalaCompiler_2_11_8_File,
+ "-scala-library", earlyDeps.scalaLibrary_2_11_8_File,
+ "-scala-extra", earlyDeps.scalaReflect_2_11_8_File,
+ "-sbt-interface", earlyDeps.sbtInterface_0_13_9_File,
+ "-compiler-interface", earlyDeps.compilerInterface_0_13_9_File,
+ "-cp", cp,
+ "-d", STAGE1+TARGET
+ }
+ )
+ );
+
+ for( File f: sourceFiles ){
+ zincArgs.add(f.toString());
+ }
+
+ PrintStream oldOut = System.out;
+ try{
+ System.setOut(System.err);
+ return runMain( "com.typesafe.zinc.Main", zincArgs.toArray(new String[zincArgs.size()]), earlyDeps.zinc );
+ } finally {
+ System.setOut(oldOut);
+ }
+ }
+
+ public static ClassLoader classLoader( String file ) throws MalformedURLException{
+ return new CbtURLClassLoader(
+ new URL[]{ new URL("file:"+file) }
+ );
+ }
+ public static ClassLoader classLoader( String file, ClassLoader parent ) throws MalformedURLException{
+ return new CbtURLClassLoader(
+ new URL[]{ new URL("file:"+file) }, parent
+ );
+ }
+ public static ClassLoader cacheGet( String key ){
+ return classLoaderCacheValues.get(
+ classLoaderCacheKeys.get( key )
+ );
+ }
+ public static ClassLoader cachePut( ClassLoader classLoader, String... jars ){
+ String key = join( pathSeparator, jars );
+ Object keyObject = new Object();
+ classLoaderCacheKeys.put( key, keyObject );
+ classLoaderCacheValues.put( keyObject, classLoader );
+ return classLoader;
+ }
+
+ public static void download(URL urlString, Path target, String sha1) throws IOException, NoSuchAlgorithmException {
+ final Path unverified = Paths.get(target+".unverified");
+ if(!Files.exists(target)) {
+ new File(target.toString()).getParentFile().mkdirs();
+ System.err.println("downloading " + urlString);
+ System.err.println("to " + target);
+ final InputStream stream = urlString.openStream();
+ Files.copy(stream, unverified, StandardCopyOption.REPLACE_EXISTING);
+ stream.close();
+ final String checksum = sha1(Files.readAllBytes(unverified));
+ if(sha1 == null || sha1.toUpperCase().equals(checksum)) {
+ Files.move(unverified, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
+ } else {
+ System.err.println(target + " checksum does not match.\nExpected: |" + sha1 + "|\nFound: |" + checksum + "|");
+ System.exit(1);
+ }
+ }
+ }
+
+ public static String sha1(byte[] bytes) throws NoSuchAlgorithmException {
+ final MessageDigest sha1 = MessageDigest.getInstance("SHA1");
+ sha1.update(bytes, 0, bytes.length);
+ return (new HexBinaryAdapter()).marshal(sha1.digest());
+ }
+
+ public static String join(String separator, String[] parts){
+ String result = parts[0];
+ for(int i = 1; i < parts.length; i++){
+ result += separator + parts[i];
+ }
+ return result;
+ }
+} \ No newline at end of file
diff --git a/stage1/MavenRepository.scala b/stage1/MavenRepository.scala
new file mode 100644
index 0000000..bfd52a7
--- /dev/null
+++ b/stage1/MavenRepository.scala
@@ -0,0 +1,22 @@
+package cbt
+import scala.collection.immutable.Seq
+import java.net._
+case class MavenRepository(url: URL){
+ def resolve( dependencies: MavenDependency* )(implicit logger: Logger): BoundMavenDependencies
+ = new BoundMavenDependencies( Seq(url), dependencies.to )
+ def resolveOne( dependency: MavenDependency )(implicit logger: Logger): BoundMavenDependency
+ = BoundMavenDependency( dependency, Seq(url) )
+}
+
+object MavenRepository{
+ case class combine(repositories: MavenRepository*){
+ def resolve( dependencies: MavenDependency* )(implicit logger: Logger): BoundMavenDependencies
+ = new BoundMavenDependencies( repositories.map(_.url).to, dependencies.to )
+ }
+ def central = MavenRepository(new URL(NailgunLauncher.MAVEN_URL))
+ def jcenter = MavenRepository(new URL("https://jcenter.bintray.com/releases"))
+ def bintray(owner: String) = MavenRepository(new URL(s"https://dl.bintray.com/$owner/maven"))
+ private val sonatypeBase = new URL("https://oss.sonatype.org/content/repositories/")
+ def sonatype = MavenRepository(sonatypeBase ++ "releases")
+ def sonatypeSnapshots = MavenRepository(sonatypeBase ++ "snapshots")
+}
diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala
index e8245c4..3456e1f 100644
--- a/stage1/Stage1.scala
+++ b/stage1/Stage1.scala
@@ -1,7 +1,6 @@
package cbt
import java.io._
-import java.time.LocalTime.now
import scala.collection.immutable.Seq
import scala.collection.JavaConverters._
@@ -50,41 +49,32 @@ object Stage1{
a.lastModified > b.lastModified
}
- def run(_args: Array[String], classLoader: ClassLoader, stage1SourcesChanged: java.lang.Boolean): Int = {
+ def run(_args: Array[String], classLoader: ClassLoader, _cbtChanged: java.lang.Boolean, start: java.lang.Long): Int = {
val args = Stage1ArgsParser(_args.toVector)
- val logger = new Logger(args.enabledLoggers)
+ val logger = new Logger(args.enabledLoggers, start)
logger.stage1(s"Stage1 start")
val lib = new Stage1Lib(logger)
import lib._
-
- val sourceFiles = stage2.listFiles.toVector.filter(_.isFile).filter(_.toString.endsWith(".scala"))
- val changeIndicator = stage2Target ++ "/cbt/Build.class"
-
- val deps = Dependencies(
- JavaDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
- JavaDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r")
- )
-
val classLoaderCache = new ClassLoaderCache(logger)
- val stage2SourcesChanged = lib.needsUpdate(sourceFiles, stage2StatusFile)
+ val sourceFiles = stage2.listFiles.toVector.filter(_.isFile).filter(_.toString.endsWith(".scala"))
+ val cbtHasChanged = _cbtChanged || lib.needsUpdate(sourceFiles, stage2StatusFile)
logger.stage1("Compiling stage2 if necessary")
- val scalaXml = JavaDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,constants.scalaXmlVersion)
compile(
- stage2SourcesChanged,
+ cbtHasChanged,
sourceFiles, stage2Target, stage2StatusFile,
- nailgunTarget +: stage1Target +: Dependencies(deps, scalaXml).classpath,
+ CbtDependency().dependencyClasspath,
Seq("-deprecation"), classLoaderCache,
zincVersion = "0.3.9", scalaVersion = constants.scalaVersion
)
- logger.stage1(s"[$now] calling CbtDependency.classLoader")
- if(NailgunLauncher.stage2classLoader == null){
+ logger.stage1(s"calling CbtDependency.classLoader")
+ if(cbtHasChanged){
NailgunLauncher.stage2classLoader = CbtDependency().classLoader(classLoaderCache)
}
- logger.stage1(s"[$now] Run Stage2")
+ logger.stage1(s"Run Stage2")
val exitCode = (
NailgunLauncher.stage2classLoader.loadClass(
if(args.admin) "cbt.AdminStage2" else "cbt.Stage2"
@@ -96,7 +86,7 @@ object Stage1{
new File( args.args(0) ),
args.args.drop(1).toVector,
// launcher changes cause entire nailgun restart, so no need for them here
- cbtHasChanged = stage1SourcesChanged || stage2SourcesChanged,
+ cbtHasChanged = cbtHasChanged,
logger
)
) match {
@@ -104,7 +94,7 @@ object Stage1{
case _ => ExitCode.Success
}
).integer
- logger.stage1(s"[$now] Stage1 end")
+ logger.stage1(s"Stage1 end")
return exitCode;
}
}
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala
index 105fe3e..da9f8dd 100644
--- a/stage1/Stage1Lib.scala
+++ b/stage1/Stage1Lib.scala
@@ -31,7 +31,7 @@ object CatchTrappedExitCode{
}
}
-case class Context( cwd: File, args: Seq[String], logger: Logger, classLoaderCache: ClassLoaderCache )
+case class Context( cwd: File, args: Seq[String], logger: Logger, cbtHasChanged: Boolean, classLoaderCache: ClassLoaderCache )
class BaseLib{
def realpath(name: File) = new File(Paths.get(name.getAbsolutePath).normalize.toString)
@@ -56,23 +56,35 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
def blue(string: String) = scala.Console.BLUE++string++scala.Console.RESET
def green(string: String) = scala.Console.GREEN++string++scala.Console.RESET
- def download(urlString: URL, target: File, sha1: Option[String]){
- val incomplete = Paths.get( target.string ++ ".incomplete" );
- if( !target.exists ){
- target.getParentFile.mkdirs
- logger.resolver(blue("downloading ") ++ urlString.string)
- logger.resolver(blue("to ") ++ target.string)
- val stream = urlString.openStream
- Files.copy(stream, incomplete, StandardCopyOption.REPLACE_EXISTING)
- sha1.foreach{
- hash =>
- val expected = hash
- val actual = this.sha1(Files.readAllBytes(incomplete))
- assert( expected == actual, s"$expected == $actual" )
- logger.resolver( green("verified") ++ " checksum for " ++ target.string)
+ def download(url: URL, target: File, sha1: Option[String]): Boolean = {
+ if( target.exists ){
+ true
+ } else {
+ val incomplete = Paths.get( target.string ++ ".incomplete" );
+ val connection = url.openConnection.asInstanceOf[HttpURLConnection]
+ if(connection.getResponseCode != HttpURLConnection.HTTP_OK){
+ logger.resolver(blue("not found: ") ++ url.string)
+ false
+ } else {
+ logger.resolver(blue("downloading ") ++ url.string)
+ logger.resolver(blue("to ") ++ target.string)
+ target.getParentFile.mkdirs
+ val stream = connection.getInputStream
+ try{
+ Files.copy(stream, incomplete, StandardCopyOption.REPLACE_EXISTING)
+ } finally {
+ stream.close()
+ }
+ sha1.foreach{
+ hash =>
+ val expected = hash
+ val actual = this.sha1(Files.readAllBytes(incomplete))
+ assert( expected == actual, s"$expected == $actual" )
+ logger.resolver( green("verified") ++ " checksum for " ++ target.string)
+ }
+ Files.move(incomplete, Paths.get(target.string), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
+ true
}
- stream.close
- Files.move(incomplete, Paths.get(target.string), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
}
}
@@ -137,26 +149,37 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
None
}else{
if( needsRecompile ){
- val zinc = JavaDependency("com.typesafe.zinc","zinc", zincVersion)
+ import MavenRepository.central
+ val zinc = central.resolveOne(MavenDependency("com.typesafe.zinc","zinc", zincVersion))
val zincDeps = zinc.transitiveDependencies
val sbtInterface =
zincDeps
- .collect{ case d @ JavaDependency( "com.typesafe.sbt", "sbt-interface", _, Classifier.none ) => d }
+ .collect{ case d @
+ BoundMavenDependency(
+ MavenDependency( "com.typesafe.sbt", "sbt-interface", _, Classifier.none),
+ _
+ ) => d
+ }
.headOption
.getOrElse( throw new Exception(s"cannot find sbt-interface in zinc $zincVersion dependencies: "++zincDeps.toString) )
.jar
val compilerInterface =
zincDeps
- .collect{ case d @ JavaDependency( "com.typesafe.sbt", "compiler-interface", _, Classifier.sources ) => d }
+ .collect{ case d @
+ BoundMavenDependency(
+ MavenDependency( "com.typesafe.sbt", "compiler-interface", _, Classifier.sources),
+ _
+ ) => d
+ }
.headOption
.getOrElse( throw new Exception(s"cannot find compiler-interface in zinc $zincVersion dependencies: "++zincDeps.toString) )
.jar
- val scalaLibrary = JavaDependency("org.scala-lang","scala-library",scalaVersion).jar
- val scalaReflect = JavaDependency("org.scala-lang","scala-reflect",scalaVersion).jar
- val scalaCompiler = JavaDependency("org.scala-lang","scala-compiler",scalaVersion).jar
+ val scalaLibrary = central.resolveOne(MavenDependency("org.scala-lang","scala-library",scalaVersion)).jar
+ val scalaReflect = central.resolveOne(MavenDependency("org.scala-lang","scala-reflect",scalaVersion)).jar
+ val scalaCompiler = central.resolveOne(MavenDependency("org.scala-lang","scala-compiler",scalaVersion)).jar
val start = System.currentTimeMillis
@@ -212,9 +235,9 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{
def ScalaDependency(
groupId: String, artifactId: String, version: String, classifier: Classifier = Classifier.none,
- scalaVersion: String
+ scalaMajorVersion: String
) =
- JavaDependency(
- groupId, artifactId ++ "_" ++ scalaVersion, version, classifier
+ MavenDependency(
+ groupId, artifactId ++ "_" ++ scalaMajorVersion, version, classifier
)
-} \ No newline at end of file
+}
diff --git a/stage1/logger.scala b/stage1/logger.scala
index e513443..91a2412 100644
--- a/stage1/logger.scala
+++ b/stage1/logger.scala
@@ -1,7 +1,5 @@
package cbt
-import java.time._
-
/**
* This represents a logger with namespaces that can be enabled or disabled as needed. The
* namespaces are defined using {{enabledLoggers}}. Possible values are defined in the subobject
@@ -9,13 +7,11 @@ import java.time._
*
* We can replace this with something more sophisticated eventually.
*/
-case class Logger(enabledLoggers: Set[String]) {
- def this(enabledLoggers: Option[String]) = this( enabledLoggers.toVector.flatMap( _.split(",") ).toSet )
-
- val start = LocalTime.now()
+case class Logger(enabledLoggers: Set[String], start: Long) {
+ def this(enabledLoggers: Option[String], start: Long) = this( enabledLoggers.toVector.flatMap( _.split(",") ).toSet, start )
def log(name: String, msg: => String) = {
- val timeTaken = (Duration.between(start, LocalTime.now()).toMillis.toDouble / 1000).toString
+ val timeTaken = ((start - System.currentTimeMillis) / 1000).toString
System.err.println( s"[${" "*(6-timeTaken.size)}$timeTaken][$name] $msg" )
}
diff --git a/stage1/resolver.scala b/stage1/resolver.scala
index 701871c..e8bfc07 100644
--- a/stage1/resolver.scala
+++ b/stage1/resolver.scala
@@ -1,5 +1,6 @@
package cbt
import java.nio.file._
+import java.nio.charset.StandardCharsets
import java.net._
import java.io._
import scala.collection.immutable.Seq
@@ -35,7 +36,7 @@ abstract class Dependency{
def exportedJars: Seq[File]
def jars: Seq[File] = exportedJars ++ dependencyJars
- def canBeCached = false
+ def canBeCached: Boolean
//private type BuildCache = KeyLockedLazyCache[Dependency, Future[ClassPath]]
def exportClasspathConcurrently: ClassPath = {
@@ -68,7 +69,7 @@ abstract class Dependency{
d =>
// find out latest version of the required dependency
val l = d match {
- case m: JavaDependency => latest( (m.groupId,m.artifactId) )
+ case m: BoundMavenDependency => latest( (m.groupId,m.artifactId) )
case _ => d
}
// // trigger compilation if not already triggered
@@ -166,7 +167,7 @@ abstract class Dependency{
case _:ArtifactInfo => false
case _ => true
}
- noInfo ++ JavaDependency.updateOutdated( hasInfo ).reverse.distinct
+ noInfo ++ BoundMavenDependency.updateOutdated( hasInfo ).reverse.distinct
}
def show: String = this.getClass.getSimpleName
@@ -182,9 +183,9 @@ abstract class Dependency{
}
// TODO: all this hard codes the scala version, needs more flexibility
-class ScalaCompilerDependency(version: String)(implicit logger: Logger) extends JavaDependency("org.scala-lang","scala-compiler",version)
-class ScalaLibraryDependency (version: String)(implicit logger: Logger) extends JavaDependency("org.scala-lang","scala-library",version)
-class ScalaReflectDependency (version: String)(implicit logger: Logger) extends JavaDependency("org.scala-lang","scala-reflect",version)
+class ScalaCompilerDependency(version: String)(implicit logger: Logger) extends BoundMavenDependency(MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(MavenRepository.central.url))
+class ScalaLibraryDependency (version: String)(implicit logger: Logger) extends BoundMavenDependency(MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(MavenRepository.central.url))
+class ScalaReflectDependency (version: String)(implicit logger: Logger) extends BoundMavenDependency(MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(MavenRepository.central.url))
case class ScalaDependencies(version: String)(implicit val logger: Logger) extends Dependency{ sd =>
override final val needsUpdate = false
@@ -199,7 +200,7 @@ case class ScalaDependencies(version: String)(implicit val logger: Logger) exten
)
}
-case class BinaryDependency( path: File, dependencies: Seq[Dependency] )(implicit val logger: Logger) extends Dependency{
+case class BinaryDependency( path: File, dependencies: Seq[Dependency], canBeCached: Boolean )(implicit val logger: Logger) extends Dependency{
def exportedClasspath = ClassPath(Seq(path))
def exportedJars = Seq[File](path)
override def needsUpdate = false
@@ -207,16 +208,19 @@ case class BinaryDependency( path: File, dependencies: Seq[Dependency] )(implici
}
/** Allows to easily assemble a bunch of dependencies */
-case class Dependencies( _dependencies: Dependency* )(implicit val logger: Logger) extends Dependency{
- override def dependencies = _dependencies.to
- def needsUpdate = dependencies.exists(_.needsUpdate)
- def exportedClasspath = ClassPath(Seq())
- def exportedJars = Seq()
- def targetClasspath = ClassPath(Seq())
+case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Logger) extends Dependency{
+ override def needsUpdate = dependencies.exists(_.needsUpdate)
+ override def canBeCached = dependencies.forall(_.canBeCached)
+ override def exportedClasspath = ClassPath(Seq())
+ override def exportedJars = Seq()
+ override def targetClasspath = ClassPath(Seq())
+}
+object Dependencies{
+ def apply( dependencies: Dependency* )(implicit logger: Logger): Dependencies = Dependencies( dependencies.to )
}
case class Stage1Dependency()(implicit val logger: Logger) extends Dependency{
- def needsUpdate = false // FIXME: think this through, might allow simplifications and/or optimizations
+ override def needsUpdate = false // FIXME: think this through, might allow simplifications and/or optimizations
override def canBeCached = false
/*
private object classLoaderRecursionCache extends Cache[ClassLoader]
@@ -232,23 +236,27 @@ case class Stage1Dependency()(implicit val logger: Logger) extends Dependency{
override def exportedClasspath = ClassPath( Seq(nailgunTarget, stage1Target) )
override def exportedJars = ???//Seq[File]()
override def dependencies = Seq(
- JavaDependency("org.scala-lang","scala-library",constants.scalaVersion),
- JavaDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,"1.0.5")
+ MavenRepository.central.resolve(
+ MavenDependency("org.scala-lang","scala-library",constants.scalaVersion),
+ MavenDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,"1.0.5")
+ )
)
// FIXME: implement sanity check to prevent using incompatible scala-library and xml version on cp
override def classLoaderRecursion( latest: Map[(String,String),Dependency], cache: ClassLoaderCache )
= getClass.getClassLoader
}
case class CbtDependency()(implicit val logger: Logger) extends Dependency{
- def needsUpdate = false // FIXME: think this through, might allow simplifications and/or optimizations
+ override def needsUpdate = false // FIXME: think this through, might allow simplifications and/or optimizations
override def canBeCached = false
override def targetClasspath = exportedClasspath
override def exportedClasspath = ClassPath( Seq( stage2Target ) )
override def exportedJars = ???
override def dependencies = Seq(
Stage1Dependency(),
- JavaDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
- JavaDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r")
+ MavenRepository.central.resolve(
+ MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
+ MavenDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r")
+ )
)
}
@@ -258,19 +266,30 @@ object Classifier{
object javadoc extends Classifier(Some("javadoc"))
object sources extends Classifier(Some("sources"))
}
+abstract class DependenciesProxy{
-case class JavaDependency(
+}
+class BoundMavenDependencies(
+ urls: Seq[URL], mavenDependencies: Seq[MavenDependency]
+)(implicit logger: Logger) extends Dependencies(
+ mavenDependencies.map( BoundMavenDependency(_,urls) )
+)
+case class MavenDependency(
groupId: String, artifactId: String, version: String, classifier: Classifier = Classifier.none
+)
+case class BoundMavenDependency(
+ mavenDependency: MavenDependency, repositories: Seq[URL]
)(implicit val logger: Logger) extends ArtifactInfo{
+ val MavenDependency( groupId, artifactId, version, classifier ) = mavenDependency
assert(
Option(groupId).collect{
- case JavaDependency.ValidIdentifier(_) =>
+ case BoundMavenDependency.ValidIdentifier(_) =>
}.nonEmpty,
s"not a valid groupId: '$groupId'"
)
assert(
Option(artifactId).collect{
- case JavaDependency.ValidIdentifier(_) =>
+ case BoundMavenDependency.ValidIdentifier(_) =>
}.nonEmpty,
s"not a valid artifactId: '$artifactId'"
)
@@ -280,62 +299,61 @@ case class JavaDependency(
)
override def needsUpdate = false
- override def canBeCached = true
+ override def canBeCached = dependencies.forall(_.canBeCached)
private val groupPath = groupId.split("\\.").mkString("/")
- def basePath = s"/$groupPath/$artifactId/$version/$artifactId-$version" ++ classifier.name.map("-"++_).getOrElse("")
+ protected[cbt] def basePath = s"/$groupPath/$artifactId/$version/$artifactId-$version" ++ classifier.name.map("-"++_).getOrElse("")
- private def resolverUrl:URL = new URL(
- if(version.endsWith("-SNAPSHOT")) "https://oss.sonatype.org/content/repositories/snapshots" else "https://repo1.maven.org/maven2"
- )
- private def baseUrl: URL = resolverUrl ++ basePath
- private def baseFile: File = mavenCache ++ basePath
- private def pomFile: File = baseFile ++ ".pom"
- private def jarFile: File = baseFile ++ ".jar"
//private def coursierJarFile = userHome++"/.coursier/cache/v1/https/repo1.maven.org/maven2"++basePath++".jar"
- private def pomUrl: URL = baseUrl ++ ".pom"
- private[cbt] def jarUrl: URL = baseUrl ++ ".jar"
- def exportedJars = Seq( jar )
- def exportedClasspath = ClassPath( exportedJars )
- def targetClasspath = exportedClasspath
+ override def exportedJars = Seq( jar )
+ override def exportedClasspath = ClassPath( exportedJars )
+ override def targetClasspath = exportedClasspath
import scala.collection.JavaConversions._
-
- def jarSha1 = {
- val file = jarFile ++ ".sha1"
- lib.download( jarUrl ++ ".sha1" , file, None )
- // split(" ") here so checksum file contents in this format work: df7f15de037a1ee4d57d2ed779739089f560338c jna-3.2.2.pom
- Files.readAllLines(Paths.get(file.string)).mkString("\n").split(" ").head.trim
+
+ private def resolve(suffix: String, hash: Option[String]): File = {
+ val file = mavenCache ++ basePath ++ "." ++ suffix
+ val urls = repositories.map(_ ++ basePath ++ "." ++ suffix)
+ urls.find(
+ lib.download(_, file, hash)
+ ).getOrElse(
+ throw new Exception(s"\nCannot resolve\n$this\nCan't find any of\n"++urls.mkString("\n"))
+ )
+ file
}
- def pomSha1 = {
- val file = pomFile++".sha1"
- lib.download( pomUrl++".sha1" , file, None )
- // split(" ") here so checksum file contents in this format work: df7f15de037a1ee4d57d2ed779739089f560338c jna-3.2.2.pom
- Files.readAllLines(Paths.get(file.string)).mkString("\n").split(" ").head.trim
+ private def resolveHash(suffix: String) = {
+ Files.readAllLines(
+ resolve( suffix ++ ".sha1", None ).toPath,
+ StandardCharsets.UTF_8
+ ).mkString("\n").split(" ").head.trim
}
+
+ private object jarSha1Cache extends Cache[String]
+ def jarSha1: String = jarSha1Cache{ resolveHash("jar") }
+
+ private object pomSha1Cache extends Cache[String]
+ def pomSha1: String = pomSha1Cache{ resolveHash("pom") }
private object jarCache extends Cache[File]
- def jar = jarCache{
- lib.download( jarUrl, jarFile, Some(jarSha1) )
- jarFile
- }
- def pomXml = XML.loadFile(pom.toString)
+ def jar: File = jarCache{ resolve("jar", Some(jarSha1)) }
- def pom = {
- lib.download( pomUrl, pomFile, Some(pomSha1) )
- pomFile
- }
+ private object pomCache extends Cache[File]
+ def pom: File = pomCache{ resolve("pom", Some(pomSha1)) }
+ def pomXml = XML.loadFile(pom.string)
// ========== pom traversal ==========
- lazy val transitivePom: Seq[JavaDependency] = {
+ lazy val transitivePom: Seq[BoundMavenDependency] = {
(pomXml \ "parent").collect{
case parent =>
- JavaDependency(
- (parent \ "groupId").text,
- (parent \ "artifactId").text,
- (parent \ "version").text
+ BoundMavenDependency(
+ MavenDependency(
+ (parent \ "groupId").text,
+ (parent \ "artifactId").text,
+ (parent \ "version").text
+ ),
+ repositories
)(logger)
}.flatMap(_.transitivePom) :+ this
}
@@ -362,7 +380,7 @@ case class JavaDependency(
}
).toMap
- def dependencies: Seq[JavaDependency] = {
+ def dependencies: Seq[BoundMavenDependency] = {
if(classifier == Classifier.sources) Seq()
else (pomXml \ "dependencies" \ "dependency").collect{
case xml if (xml \ "scope").text == "" && (xml \ "optional").text != "true" =>
@@ -383,9 +401,12 @@ case class JavaDependency(
throw new Exception(s"$artifactId not found in \n$dependencyVersions")
)
)
- JavaDependency(
- groupId, artifactId, version,
- Classifier( Some( (xml \ "classifier").text ).filterNot(_ == "").filterNot(_ == null) )
+ BoundMavenDependency(
+ MavenDependency(
+ groupId, artifactId, version,
+ Classifier( Some( (xml \ "classifier").text ).filterNot(_ == "").filterNot(_ == null) )
+ ),
+ repositories
)
}.toVector
}
@@ -411,7 +432,7 @@ case class JavaDependency(
}
}
}
-object JavaDependency{
+object BoundMavenDependency{
def ValidIdentifier = "^([A-Za-z0-9_\\-.]+)$".r // according to maven's DefaultModelValidator.java
def semanticVersionLessThan(left: String, right: String) = {
// FIXME: this ignores ends when different size
diff --git a/stage2/AdminTasks.scala b/stage2/AdminTasks.scala
index a61e767..655b2b0 100644
--- a/stage2/AdminTasks.scala
+++ b/stage2/AdminTasks.scala
@@ -9,7 +9,7 @@ class AdminTasks(lib: Lib, args: Seq[String], cwd: File){
args(1).split(",").toVector.map{
d =>
val v = d.split(":")
- new JavaDependency(v(0),v(1),v(2)).classpath
+ MavenRepository.central.resolveOne(MavenDependency(v(0),v(1),v(2))).classpath
}
)
}
@@ -17,15 +17,17 @@ class AdminTasks(lib: Lib, args: Seq[String], cwd: File){
args(1).split(",").toVector.map{
d =>
val v = d.split(":")
- new JavaDependency(v(0),v(1),v(2)).dependencyTree
+ MavenRepository.central.resolveOne(MavenDependency(v(0),v(1),v(2))).dependencyTree
}.mkString("\n\n")
}
def amm = ammonite
def ammonite = {
val version = args.lift(1).getOrElse(constants.scalaVersion)
val scalac = new ScalaCompilerDependency( version )
- val d = JavaDependency(
- "com.lihaoyi","ammonite-repl_2.11.7",args.lift(1).getOrElse("0.5.7")
+ val d = MavenRepository.central.resolveOne(
+ MavenDependency(
+ "com.lihaoyi","ammonite-repl_2.11.7",args.lift(1).getOrElse("0.5.7")
+ )
)
// FIXME: this does not work quite yet, throws NoSuchFileException: /ammonite/repl/frontend/ReplBridge$.class
lib.runMain(
@@ -46,41 +48,25 @@ class AdminTasks(lib: Lib, args: Seq[String], cwd: File){
val scalaMajorVersion = scalaVersion.split("\\.").take(2).mkString(".")
val scalaXmlVersion = args.lift(2).getOrElse(constants.scalaXmlVersion)
val zincVersion = args.lift(3).getOrElse(constants.zincVersion)
- /*
- def tree(d: JavaDependency, indent: Int): String ={
- val dependencies = {
- if( d.dependencies.nonEmpty ){
- d.dependencies.map{
- case d: JavaDependency => tree(d,indent + 1)
- }.mkString(",\n" ++ ( " " * indent ),",\n" ++ ( " " * indent ), "")
- } else ""
- }
- (
- s"""new EarlyDependency( "${d.groupId}", "${d.artifactId}", "${d.version}", "${d.jarSha1}"$dependencies)"""
- )
- }*/
val scalaDeps = Seq(
- JavaDependency("org.scala-lang","scala-reflect",scalaVersion),
- JavaDependency("org.scala-lang","scala-compiler",scalaVersion)
+ MavenRepository.central.resolveOne(MavenDependency("org.scala-lang","scala-reflect",scalaVersion)),
+ MavenRepository.central.resolveOne(MavenDependency("org.scala-lang","scala-compiler",scalaVersion))
)
val scalaXml = Dependencies(
- JavaDependency("org.scala-lang.modules","scala-xml_"+scalaMajorVersion,scalaXmlVersion),
- JavaDependency("org.scala-lang","scala-library",scalaVersion)
+ MavenRepository.central.resolveOne(MavenDependency("org.scala-lang.modules","scala-xml_"+scalaMajorVersion,scalaXmlVersion)),
+ MavenRepository.central.resolveOne(MavenDependency("org.scala-lang","scala-library",scalaVersion))
)
- val zinc = JavaDependency("com.typesafe.zinc","zinc",zincVersion)
- println(zinc.dependencyTree)
+ val zinc = MavenRepository.central.resolveOne(MavenDependency("com.typesafe.zinc","zinc",zincVersion))
- def valName(dep: JavaDependency) = {
+ def valName(dep: BoundMavenDependency) = {
val words = dep.artifactId.split("_").head.split("-")
words(0) ++ words.drop(1).map(s => s(0).toString.toUpperCase ++ s.drop(1)).mkString ++ "_" ++ dep.version.replace(".","_") ++ "_"
}
- def vals(d: JavaDependency) = s""" """
-
- def jarVal(dep: JavaDependency) = "_" + valName(dep) +"Jar"
- def transitive(dep: Dependency) = (dep +: dep.transitiveDependencies.reverse).collect{case d: JavaDependency => d}
+ def jarVal(dep: BoundMavenDependency) = "_" + valName(dep) +"Jar"
+ def transitive(dep: Dependency) = (dep +: dep.transitiveDependencies.reverse).collect{case d: BoundMavenDependency => d}
def codeEach(dep: Dependency) = {
transitive(dep).tails.map(_.reverse).toVector.reverse.drop(1).map{
deps =>
@@ -105,6 +91,7 @@ import java.io.*;
import java.nio.file.*;
import java.net.*;
import java.security.*;
+import static cbt.Stage0Lib.*;
import static cbt.NailgunLauncher.*;
class EarlyDependencies{
diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala
index 9ed8c26..39cc9e3 100644
--- a/stage2/BasicBuild.scala
+++ b/stage2/BasicBuild.scala
@@ -12,14 +12,16 @@ import scala.collection.immutable.Seq
import scala.util._
class BasicBuild( context: Context ) extends Build( context )
-class Build(val context: Context) extends Dependency with TriggerLoop{
+class Build(val context: Context) extends Dependency with TriggerLoop with SbtDependencyDsl{
// library available to builds
implicit final val logger: Logger = context.logger
implicit final val classLoaderCache: ClassLoaderCache = context.classLoaderCache
+ implicit final val _context = context
override final protected val lib: Lib = new Lib(logger)
// ========== general stuff ==========
+ override def canBeCached = false
def enableConcurrency = false
final def projectDirectory: File = lib.realpath(context.cwd)
assert( projectDirectory.exists, "projectDirectory does not exist: " ++ projectDirectory.string )
@@ -32,7 +34,9 @@ class Build(val context: Context) extends Dependency with TriggerLoop{
def zincVersion = "0.3.9"
def dependencies: Seq[Dependency] = Seq(
- "org.scala-lang" % "scala-library" % scalaVersion
+ MavenRepository.central.resolve(
+ "org.scala-lang" % "scala-library" % scalaVersion
+ )
)
// ========== paths ==========
@@ -84,22 +88,6 @@ class Build(val context: Context) extends Dependency with TriggerLoop{
scalaVersion: String = scalaMajorVersion
) = lib.ScalaDependency( groupId, artifactId, version, classifier, scalaVersion )
- /** SBT-like dependency builder DSL for syntax compatibility */
- class DependencyBuilder2( groupId: String, artifactId: String, scalaVersion: Option[String] ){
- def %(version: String) = scalaVersion.map(
- v => ScalaDependency(groupId, artifactId, version, scalaVersion = v)
- ).getOrElse(
- JavaDependency(groupId, artifactId, version)
- )
- }
- implicit class DependencyBuilder(groupId: String){
- def %%(artifactId: String) = new DependencyBuilder2( groupId, artifactId, Some(scalaMajorVersion) )
- def %(artifactId: String) = new DependencyBuilder2( groupId, artifactId, None )
- }
- implicit class DependencyBuilder3(d: JavaDependency){
- def %(classifier: String) = d.copy(classifier = Classifier(Some(classifier)))
- }
-
final def BuildDependency(path: File) = cbt.BuildDependency(
context.copy( cwd = path, args = Seq() )
)
@@ -125,12 +113,11 @@ class Build(val context: Context) extends Dependency with TriggerLoop{
def scalacOptions: Seq[String] = Seq( "-feature", "-deprecation", "-unchecked" )
private object needsUpdateCache extends Cache[Boolean]
- def needsUpdate: Boolean = {
- needsUpdateCache(
- lib.needsUpdate( sourceFiles, compileStatusFile )
- || transitiveDependencies.exists(_.needsUpdate)
- )
- }
+ def needsUpdate: Boolean = needsUpdateCache(
+ context.cbtHasChanged
+ || lib.needsUpdate( sourceFiles, compileStatusFile )
+ || transitiveDependencies.exists(_.needsUpdate)
+ )
private object compileCache extends Cache[Option[File]]
def compile: Option[File] = compileCache{
diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala
index 9746d8c..813b44b 100644
--- a/stage2/BuildBuild.scala
+++ b/stage2/BuildBuild.scala
@@ -5,7 +5,7 @@ import scala.collection.immutable.Seq
class BuildBuild(context: Context) extends Build(context){
override def dependencies = Seq( CbtDependency()(context.logger) ) ++ super.dependencies
def managedBuildDirectory: File = lib.realpath( projectDirectory.parent )
- val managedBuild = {
+ val managedBuild = try{
val managedContext = context.copy( cwd = managedBuildDirectory )
val cl = new cbt.URLClassLoader(
exportedClasspath,
@@ -16,6 +16,11 @@ class BuildBuild(context: Context) extends Build(context){
.getConstructor(classOf[Context])
.newInstance(managedContext)
.asInstanceOf[Build]
+ } catch {
+ case e: ClassNotFoundException if e.getMessage == lib.buildClassName =>
+ throw new Exception("You need to remove the directory or define a class Build in: "+context.cwd)
+ case e: Exception =>
+ throw new Exception("during build: "+context.cwd, e)
}
override def triggerLoopFiles = super.triggerLoopFiles ++ managedBuild.triggerLoopFiles
override def finalBuild = managedBuild.finalBuild
diff --git a/stage2/BuildDependency.scala b/stage2/BuildDependency.scala
index e3a01c7..19357f9 100644
--- a/stage2/BuildDependency.scala
+++ b/stage2/BuildDependency.scala
@@ -21,6 +21,7 @@ case class BuildDependency(context: Context) extends TriggerLoop{
final override lazy val lib: Lib = new Lib(logger)
private val root = lib.loadRoot( context.copy(args=Seq()) )
lazy val build = root.finalBuild
+ override def canBeCached = build.canBeCached
def exportedClasspath = ClassPath(Seq())
def exportedJars = Seq()
def dependencies = Seq(build)
diff --git a/stage2/GitDependency.scala b/stage2/GitDependency.scala
index 59de98a..27bf253 100644
--- a/stage2/GitDependency.scala
+++ b/stage2/GitDependency.scala
@@ -7,9 +7,10 @@ import org.eclipse.jgit.lib.Ref
case class GitDependency(
url: String, ref: String // example: git://github.com/cvogt/cbt.git#<some-hash>
-)(implicit val logger: Logger, classLoaderCache: ClassLoaderCache ) extends Dependency{
+)(implicit val logger: Logger, classLoaderCache: ClassLoaderCache, context: Context ) extends Dependency{
override def lib = new Lib(logger)
+ override def canBeCached = true
// TODO: add support for authentication via ssh and/or https
// See http://www.codeaffine.com/2014/12/09/jgit-authentication/
@@ -37,7 +38,7 @@ case class GitDependency(
}
val managedBuild = lib.loadDynamic(
- Context( cwd = checkoutDirectory, args = Seq(), logger, classLoaderCache )
+ context.copy( cwd = checkoutDirectory, args = Seq() )
)
Seq( managedBuild )
}
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index dd4a12f..6b6263c 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -133,7 +133,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{
.filter{ m =>
java.lang.reflect.Modifier.isPublic(m.getModifiers)
}
- .filter( _.getParameterCount == 0 )
+ .filter( _.getParameterTypes.length == 0 )
.map(m => NameTransformer.decode(m.getName) -> m)
).toMap
@@ -145,7 +145,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{
(
(
if( thisTasks.nonEmpty ){
- s"""Methods provided by Build ${context}
+ s"""Methods provided by Build ${context.cwd}
${thisTasks.mkString(" ")}
diff --git a/stage2/SbtDependencyDsl.scala b/stage2/SbtDependencyDsl.scala
new file mode 100644
index 0000000..4fd4250
--- /dev/null
+++ b/stage2/SbtDependencyDsl.scala
@@ -0,0 +1,43 @@
+package cbt
+trait SbtDependencyDsl{ self: Build =>
+ /** SBT-like dependency builder DSL for syntax compatibility */
+ class DependencyBuilder2( groupId: String, artifactId: String, scalaVersion: Option[String] ){
+ def %(version: String) = scalaVersion.map(
+ v => ScalaDependency(groupId, artifactId, version, scalaVersion = v)
+ ).getOrElse(
+ MavenDependency(groupId, artifactId, version)
+ )
+ }
+ implicit class DependencyBuilder(groupId: String){
+ def %%(artifactId: String) = new DependencyBuilder2( groupId, artifactId, Some(scalaMajorVersion) )
+ def %(artifactId: String) = new DependencyBuilder2( groupId, artifactId, None )
+ }
+ implicit class DependencyBuilder3(d: MavenDependency){
+ def %(classifier: String) = d.copy(classifier = Classifier(Some(classifier)))
+ }
+
+ /*
+ /** SBT-like dependency builder DSL for syntax compatibility */
+ implicit class DependencyBuilder0(repository: Maven){
+ def %(groupId: String) = new DependencyBuilder1b(repository, groupId)
+ }
+ implicit class DependencyBuilder1a(groupId: String){
+ def %%(artifactId: String) = new DependencyBuilder2( Maven.central, groupId, artifactId, Some(scalaMajorVersion) )
+ def %(artifactId: String) = new DependencyBuilder2( Maven.central, groupId, artifactId, None )
+ }
+ class DependencyBuilder1b(repository: Maven, groupId: String){
+ def %%(artifactId: String) = new DependencyBuilder2( repository, groupId, artifactId, Some(scalaMajorVersion) )
+ def %(artifactId: String) = new DependencyBuilder2( repository, groupId, artifactId, None )
+ }
+ class DependencyBuilder2( repository: Maven, groupId: String, artifactId: String, scalaMajorVersion: Option[String] ){
+ def %(version: String) = scalaMajorVersion.map(
+ v => repository(groupId, artifactId, version, scalaMajorVersion = v)
+ ).getOrElse(
+ repository.java(groupId, artifactId, version)
+ )
+ }
+ implicit class DependencyBuilder3(d: MavenDependency){
+ def %(classifier: String) = d.copy(classifier = Classifier(Some(classifier)))
+ }
+ */
+} \ No newline at end of file
diff --git a/stage2/Stage2.scala b/stage2/Stage2.scala
index e893a06..4ae149c 100644
--- a/stage2/Stage2.scala
+++ b/stage2/Stage2.scala
@@ -1,8 +1,6 @@
package cbt
import java.io._
-import java.time._
-import java.time.LocalTime.now
import scala.collection.immutable.Seq
@@ -14,7 +12,7 @@ object Stage2 extends Stage2Base{
val lib = new Lib(args.logger)
- logger.stage2(s"[$now] Stage2 start")
+ logger.stage2(s"Stage2 start")
val loop = args.args.lift(0) == Some("loop")
val direct = args.args.lift(0) == Some("direct")
@@ -25,7 +23,7 @@ object Stage2 extends Stage2Base{
}
val task = args.args.lift( taskIndex )
- val context = Context( args.cwd, args.args.drop( taskIndex ), logger, /*args.cbtHasChanged,*/ new ClassLoaderCache(logger) )
+ val context = Context( args.cwd, args.args.drop( taskIndex ), logger, args.cbtHasChanged, new ClassLoaderCache(logger) )
val first = lib.loadRoot( context )
val build = first.finalBuild
@@ -54,6 +52,6 @@ object Stage2 extends Stage2Base{
new lib.ReflectBuild(build).callNullary(task)
}
- logger.stage2(s"[$now] Stage2 end")
+ logger.stage2(s"Stage2 end")
}
}
diff --git a/stage2/mixins.scala b/stage2/mixins.scala
index c3a57da..4dedd09 100644
--- a/stage2/mixins.scala
+++ b/stage2/mixins.scala
@@ -16,9 +16,9 @@ trait SbtTest extends Test{
trait ScalaTest extends Build with Test{
def scalaTestVersion: String
- override def dependencies = Seq(
+ override def dependencies = super.dependencies :+ MavenRepository.central.resolve(
"org.scalatest" %% "scalatest" % scalaTestVersion
- ) ++ super.dependencies
+ )
override def run: ExitCode = {
val discoveryPath = compile.toString++"/"
diff --git a/test/simple/build/build.scala b/test/simple/build/build.scala
index d3887b3..190bad9 100644
--- a/test/simple/build/build.scala
+++ b/test/simple/build/build.scala
@@ -1,14 +1,30 @@
import cbt._
import scala.collection.immutable.Seq
import java.io.File
+
class Build(context: cbt.Context) extends BasicBuild(context){
- override def dependencies = Seq(
- ScalaDependency("com.typesafe.play", "play-json", "2.4.4"),
- JavaDependency("joda-time", "joda-time", "2.9.2"),
- GitDependency("https://github.com/xdotai/diff.git", "2e275642041006ff39efde22da7742c2e9a0f63f"),
- // the below tests pom inheritance with dependencyManagement and variable substitution for pom properties
- JavaDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r"),
- // the below tests pom inheritance with variable substitution for pom xml tag contents
- JavaDependency("com.spotify", "missinglink-core", "0.1.1")
- ) ++ super.dependencies
+ override def dependencies = (
+ super.dependencies
+ ++
+ Seq(
+ GitDependency("https://github.com/xdotai/diff.git", "8b501902999fe76d49e04937c4bd6d0b9e07b4a6"),
+ MavenRepository.central.resolve(
+ ScalaDependency("com.typesafe.play", "play-json", "2.4.4"),
+ MavenDependency("joda-time", "joda-time", "2.9.2"),
+ // the below tests pom inheritance with dependencyManagement and variable substitution for pom properties
+ MavenDependency("org.eclipse.jgit", "org.eclipse.jgit", "4.2.0.201601211800-r"),
+ // the below tests pom inheritance with variable substitution for pom xml tag contents
+ MavenDependency("com.spotify", "missinglink-core", "0.1.1")
+ ),
+ MavenRepository.combine(
+ MavenRepository.central,
+ MavenRepository.bintray("tpolecat"),
+ MavenRepository.sonatypeSnapshots
+ ).resolve(
+ "org.cvogt" %% "play-json-extensions" % "0.8.0",
+ "org.tpolecat" %% "tut-core" % "0.4.2",
+ "ai.x" %% "lens" % "1.0.0-SNAPSHOT"
+ )
+ )
+ )
}
diff --git a/test/test.scala b/test/test.scala
index 242b639..7bd2c6a 100644
--- a/test/test.scala
+++ b/test/test.scala
@@ -1,12 +1,14 @@
import cbt._
import cbt.paths._
import scala.collection.immutable.Seq
+import java.io.File
// micro framework
object Main{
def main(_args: Array[String]): Unit = {
val args = new Stage1ArgsParser(_args.toVector)
- implicit val logger: Logger = new Logger(args.enabledLoggers)
+ implicit val logger: Logger = new Logger(args.enabledLoggers, System.currentTimeMillis)
+ val lib = new Lib(logger)
var successes = 0
var failures = 0
@@ -69,19 +71,14 @@ object Main{
logger.test( "Running tests " ++ _args.toList.toString )
- usage("nothing")
- compile("nothing")
- usage("multi-build")
- compile("multi-build")
- usage("simple")
- compile("simple")
-
{
- val noContext = Context(cbtHome ++ "/test/nothing", Seq(), logger, new ClassLoaderCache(logger))
+ val noContext = Context(cbtHome ++ "/test/nothing", Seq(), logger, false, new ClassLoaderCache(logger))
val b = new Build(noContext){
override def dependencies = Seq(
- JavaDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
- JavaDependency("net.incongru.watchservice","barbary-watchservice","1.0")
+ MavenRepository.central.resolve(
+ MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0"),
+ MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0")
+ )
)
}
val cp = b.classpath
@@ -90,22 +87,48 @@ object Main{
// test that messed up artifacts crash with an assertion (which should tell the user what's up)
assertException[AssertionError](){
- JavaDependency("com.jcraft", "jsch", " 0.1.53").classpath
+ MavenRepository.central.resolveOne( MavenDependency("com.jcraft", "jsch", " 0.1.53") ).classpath
}
assertException[AssertionError](){
- JavaDependency("com.jcraft", null, "0.1.53").classpath
+ MavenRepository.central.resolveOne( MavenDependency("com.jcraft", null, "0.1.53") ).classpath
}
assertException[AssertionError](){
- JavaDependency("com.jcraft", "", " 0.1.53").classpath
+ MavenRepository.central.resolveOne( MavenDependency("com.jcraft", "", " 0.1.53") ).classpath
}
assertException[AssertionError](){
- JavaDependency("com.jcraft%", "jsch", " 0.1.53").classpath
+ MavenRepository.central.resolveOne( MavenDependency("com.jcraft%", "jsch", " 0.1.53") ).classpath
}
assertException[AssertionError](){
- JavaDependency("", "jsch", " 0.1.53").classpath
+ MavenRepository.central.resolveOne( MavenDependency("", "jsch", " 0.1.53") ).classpath
}
-
+ (
+ MavenRepository.combine(
+ MavenRepository.central, MavenRepository.bintray("tpolecat")
+ ).resolve(
+ lib.ScalaDependency("org.tpolecat","tut-core","0.4.2", scalaMajorVersion="2.11")
+ ).classpath.strings
+ ++
+ MavenRepository.sonatype.resolve(
+ MavenDependency("org.cvogt","play-json-extensions_2.11","0.8.0")
+ ).classpath.strings
+ ++
+ MavenRepository.combine(
+ MavenRepository.central, MavenRepository.sonatypeSnapshots
+ ).resolve(
+ MavenDependency("ai.x","lens_2.11","1.0.0-SNAPSHOT")
+ ).classpath.strings
+ ).foreach{
+ path => assert(new File(path).exists, path)
+ }
+
+ usage("nothing")
+ compile("nothing")
+ usage("multi-build")
+ compile("multi-build")
+ usage("simple")
+ compile("simple")
+
System.err.println(" DONE!")
System.err.println( successes.toString ++ " succeeded, "++ failures.toString ++ " failed" )
if(failures > 0) System.exit(1) else System.exit(0)