diff options
-rw-r--r-- | TODO.txt | 2 | ||||
-rwxr-xr-x | cbt | 32 | ||||
-rw-r--r-- | nailgun_launcher/NailgunLauncher.java | 16 | ||||
-rw-r--r-- | stage1/ClassPath.scala | 30 | ||||
-rw-r--r-- | stage1/Stage1.scala | 4 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 64 | ||||
-rw-r--r-- | stage1/cbt.scala | 21 | ||||
-rw-r--r-- | stage1/classloader.scala | 55 | ||||
-rw-r--r-- | stage1/logger.scala | 2 | ||||
-rw-r--r-- | stage1/paths.scala | 22 | ||||
-rw-r--r-- | stage1/resolver.scala | 86 | ||||
-rw-r--r-- | stage2/AdminStage2.scala | 2 | ||||
-rw-r--r-- | stage2/BasicBuild.scala (renamed from stage2/DefaultBuild.scala) | 112 | ||||
-rw-r--r-- | stage2/BuildBuild.scala | 3 | ||||
-rw-r--r-- | stage2/BuildDependency.scala (renamed from stage2/dependencies.scala) | 2 | ||||
-rw-r--r-- | stage2/Lib.scala | 74 | ||||
-rw-r--r-- | stage2/PackageBuild.scala | 27 | ||||
-rw-r--r-- | stage2/PublishBuild.scala | 41 | ||||
-rw-r--r-- | stage2/Scaffold.scala | 8 | ||||
-rw-r--r-- | stage2/Stage2.scala | 4 | ||||
-rw-r--r-- | stage2/mixins.scala | 10 | ||||
-rw-r--r-- | test/test.scala | 117 |
22 files changed, 382 insertions, 352 deletions
@@ -7,6 +7,7 @@ TODO: - 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 @@ -15,6 +16,7 @@ TODO: - 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 @@ -13,11 +13,11 @@ log () { msg=$1 enabled=1 while test $# -gt 0; do - case "$1" in - "-Dlog=time") enabled=0 ;; - "-Dlog=all") enabled=0 ;; - esac - shift + case "$1" in + "-Dlog=time") enabled=0 ;; + "-Dlog=all") enabled=0 ;; + esac + shift done if [ $enabled -eq 0 ]; then which gdate 2>&1 > /dev/null @@ -89,17 +89,17 @@ nailgun_out=$NAILGUN/target/nailgun.stdout.log nailgun_err=$NAILGUN/target/nailgun.strerr.log foo(){ while test $# -gt 0; do - case "$1" in - "-Dlog=nailgun") + case "$1" in + "-Dlog=nailgun") nailgun_out=/dev/stderr nailgun_err=/dev/stderr - ;; - "-Dlog=all") + ;; + "-Dlog=all") nailgun_out=/dev/stderr nailgun_err=/dev/stderr - ;; - esac - shift + ;; + esac + shift done } @@ -147,11 +147,11 @@ SCALAC="java -Xmx256M -Xms32M\ -deprecation\ -feature" -stage1 () { +stage1 () { log "Checking for changes in cbt/nailgun_launcher" $* NAILGUN_INDICATOR=$NAILGUN$TARGET/cbt/NailgunLauncher.class changed=0 - for file in `ls $NAILGUN/*.java`; do + for file in `ls $NAILGUN/*.java`; do if [ $file -nt $NAILGUN_INDICATOR ]; then changed=1; fi done compiles=0 @@ -175,7 +175,7 @@ stage1 () { log "Checking for changes in cbt/stage1" $* STAGE1_INDICATOR=$STAGE1$TARGET/cbt/Stage1.class changed2=0 - for file in `ls $STAGE1*.scala`; do + for file in `ls $STAGE1*.scala`; do if [ $file -nt $STAGE1_INDICATOR ]; then changed2=1; fi done compiles2=0 @@ -229,7 +229,7 @@ stage1 () { fi exitCode=$? log "Done running $mainClass." $* -} +} while true; do stage1 $* diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java index 3765457..78da041 100644 --- a/nailgun_launcher/NailgunLauncher.java +++ b/nailgun_launcher/NailgunLauncher.java @@ -7,7 +7,7 @@ import java.nio.file.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -/** +/** * This launcher allows to start the JVM without loading anything else permanently into its * classpath except for the launcher itself. That's why it is written in Java without * dependencies outside the JDK. @@ -17,16 +17,16 @@ import java.util.concurrent.ConcurrentHashMap; */ public class NailgunLauncher{ - /** + /** * Persistent cache for caching classloaders for the JVM life time. Can be used as needed by user - * code to improve startup time. + * code to improve startup time. */ - public static ConcurrentHashMap<String,ClassLoader> classLoaderCache = + public static ConcurrentHashMap<String,ClassLoader> classLoaderCache = new ConcurrentHashMap<String,ClassLoader>(); - public static void main(String[] args) throws ClassNotFoundException, - NoSuchMethodException, - IllegalAccessException, + public static void main(String[] args) throws ClassNotFoundException, + NoSuchMethodException, + IllegalAccessException, InvocationTargetException, MalformedURLException { if (args.length < 3) { @@ -41,7 +41,7 @@ public class NailgunLauncher{ } String[] newArgs = new String[args.length-2]; - for(int i = 0; i < args.length-2; i++){ + for(int i = 0; i < args.length-2; i++){ newArgs[i] = args[i+2]; } diff --git a/stage1/ClassPath.scala b/stage1/ClassPath.scala new file mode 100644 index 0000000..66a1b44 --- /dev/null +++ b/stage1/ClassPath.scala @@ -0,0 +1,30 @@ +package cbt +import java.io._ +import java.net._ +import scala.collection.immutable.Seq + +object ClassPath{ + def apply(files: File*): ClassPath = ClassPath(files.toVector) + def flatten( classPaths: Seq[ClassPath] ): ClassPath = ClassPath( classPaths.map(_.files).flatten ) +} +case class ClassPath(files: Seq[File]){ + private val duplicates = (files diff files.distinct).distinct + assert( + duplicates.isEmpty, + "Duplicate classpath entries found:\n" ++ duplicates.mkString("\n") ++ "\nin classpath:\n"++string + ) + private val nonExisting = files.distinct.filterNot(_.exists) + assert( + duplicates.isEmpty, + "Classpath contains entires that don't exist on disk:\n" ++ nonExisting.mkString("\n") ++ "\nin classpath:\n"++string + ) + + def +:(file: File) = ClassPath(file +: files) + def :+(file: File) = ClassPath(files :+ file) + def ++(other: ClassPath) = ClassPath(files ++ other.files) + def string = strings.mkString( File.pathSeparator ) + def strings = files.map{ + f => f.string ++ ( if(f.isDirectory) "/" else "" ) + } + def toConsole = string +} diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index 8db12cf..1aa3f09 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -63,12 +63,12 @@ abstract class Stage1Base{ val cwd = args(0) val src = stage2.listFiles.toVector.filter(_.isFile).filter(_.toString.endsWith(".scala")) - val changeIndicator = new File(stage2Target+"/cbt/Build.class") + val changeIndicator = stage2Target ++ "/cbt/Build.class" logger.stage1("before conditionally running zinc to recompile CBT") if( src.exists(newerThan(_, changeIndicator)) ) { val stage1Classpath = CbtDependency(logger).dependencyClasspath - logger.stage1("cbt.lib has changed. Recompiling with cp: "+stage1Classpath) + logger.stage1("cbt.lib has changed. Recompiling with cp: " ++ stage1Classpath.string) zinc( true, src, stage2Target, stage1Classpath )( zincVersion = "0.3.9", scalaVersion = constants.scalaVersion ) } logger.stage1(s"[$now] calling CbtDependency.classLoader") diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index ac77a92..1ad3030 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -30,35 +30,13 @@ object TrappedExitCode{ } } +case class Context( cwd: File, args: Seq[String], logger: Logger ) -case class Context( cwd: String, args: Seq[String], logger: Logger ) - -case class ClassPath(files: Seq[File]){ - private val duplicates = (files diff files.distinct).distinct - assert( - duplicates.isEmpty, - "Duplicate classpath entries found:\n" + duplicates.mkString("\n") + "\nin classpath:\n"+string - ) - private val nonExisting = files.distinct.filterNot(_.exists) - assert( - duplicates.isEmpty, - "Classpath contains entires that don't exist on disk:\n" + nonExisting.mkString("\n") + "\nin classpath:\n"+string - ) - - def +:(file: File) = ClassPath(file +: files) - def :+(file: File) = ClassPath(files :+ file) - def ++(other: ClassPath) = ClassPath(files ++ other.files) - def string = strings.mkString( File.pathSeparator ) - def strings = files.map{ - f => f.toString + ( if(f.isDirectory) "/" else "" ) - } - def toConsole = string -} -object ClassPath{ - def flatten( classPaths: Seq[ClassPath] ): ClassPath = ClassPath( classPaths.map(_.files).flatten ) +class BaseLib{ + def realpath(name: File) = new File(Paths.get(name.getAbsolutePath).normalize.toString) } -class Stage1Lib( val logger: Logger ){ +class Stage1Lib( val logger: Logger ) extends BaseLib{ lib => // ========== reflection ========== @@ -76,24 +54,24 @@ class Stage1Lib( val logger: Logger ){ } // ========== file system / net ========== - + def array2hex(padTo: Int, array: Array[Byte]): String = { val hex = new java.math.BigInteger(1, array).toString(16) - ("0" * (padTo-hex.size)) + hex + ("0" * (padTo-hex.size)) ++ hex } def md5( bytes: Array[Byte] ): String = array2hex(32, MessageDigest.getInstance("MD5").digest(bytes)) def sha1( bytes: Array[Byte] ): String = array2hex(40, MessageDigest.getInstance("SHA-1").digest(bytes)) - def red(string: String) = scala.Console.RED+string+scala.Console.RESET - def blue(string: String) = scala.Console.BLUE+string+scala.Console.RESET - def green(string: String) = scala.Console.GREEN+string+scala.Console.RESET + def red(string: String) = scala.Console.RED++string++scala.Console.RESET + 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: Path, sha1: Option[String]){ - val incomplete = Paths.get(target+".incomplete"); - if( !Files.exists(target) ){ - new File(target.toString).getParentFile.mkdirs - logger.resolver(blue("downloading ")+urlString) - logger.resolver(blue("to ")+target) + 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{ @@ -101,10 +79,10 @@ class Stage1Lib( val logger: Logger ){ val expected = hash val actual = this.sha1(Files.readAllBytes(incomplete)) assert( expected == actual, s"$expected == $actual" ) - logger.resolver(green("verified")+" checksum for "+target) + logger.resolver( green("verified") ++ " checksum for " ++ target.string) } stream.close - Files.move(incomplete, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + Files.move(incomplete, Paths.get(target.string), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } } @@ -123,7 +101,7 @@ class Stage1Lib( val logger: Logger ){ } def runMain(cls: String, args: Seq[String], classLoader: ClassLoader ): ExitCode = { - logger.lib(s"Running $cls.main($args) with classLoader: "+classLoader) + logger.lib(s"Running $cls.main($args) with classLoader: " ++ classLoader.toString) trapExitCode{ classLoader .loadClass(cls) @@ -148,8 +126,8 @@ class Stage1Lib( val logger: Logger ){ )( zincVersion: String, scalaVersion: String ): Unit = { val cp = classpath.string - if(classpath.files.isEmpty) throw new Exception("Trying to compile with empty classpath. Source files: "+files) - if(files.isEmpty) throw new Exception("Trying to compile no files. ClassPath: "+cp) + if(classpath.files.isEmpty) throw new Exception("Trying to compile with empty classpath. Source files: " ++ files.toString) + if(files.isEmpty) throw new Exception("Trying to compile no files. ClassPath: " ++ cp) // only run zinc if files changed, for performance reasons // FIXME: this is broken, need invalidate on changes in dependencies as well @@ -187,7 +165,7 @@ class Stage1Lib( val logger: Logger ){ "-scala-extra", scalaReflect.toString, "-cp", cp, "-d", compileTarget.toString - ) ++ extraArgs.map("-S"+_) ++ files.map(_.toString), + ) ++ extraArgs.map("-S"++_) ++ files.map(_.toString), zinc.classLoader ) } diff --git a/stage1/cbt.scala b/stage1/cbt.scala new file mode 100644 index 0000000..01af0d5 --- /dev/null +++ b/stage1/cbt.scala @@ -0,0 +1,21 @@ +package cbt +import java.io._ +import java.nio.file._ +import java.net._ +object `package`{ + private val lib = new BaseLib + implicit class FileExtensionMethods( file: File ){ + def ++( s: String ): File = { + if(s endsWith "/") throw new Exception( + """Trying to append a String that ends in "/" to a File would loose it. Use .stripSuffix("/") if you need to.""" + ) + new File( file.toString ++ s ) + } + def parent = lib.realpath(file ++ "/..") + def string = file.toString + } + implicit class URLExtensionMethods( url: URL ){ + def ++( s: String ): URL = new URL( url.toString ++ s ) + def string = url.toString + } +} diff --git a/stage1/classloader.scala b/stage1/classloader.scala index 6f2213b..3293dd1 100644 --- a/stage1/classloader.scala +++ b/stage1/classloader.scala @@ -8,25 +8,29 @@ import scala.collection.immutable.Seq object ClassLoaderCache{ private val cache = NailgunLauncher.classLoaderCache - def classLoader( path: String, parent: ClassLoader ): ClassLoader = { - def realpath( name: String ) = Paths.get(new File(name).getAbsolutePath).normalize.toString - val normalized = realpath(path) - if( cache.containsKey(normalized) ){ - //println("FOUND: "+normalized) - cache.get(normalized) + def classLoader( classpath: ClassPath, parent: ClassLoader )(implicit logger: Logger): ClassLoader + = cache.synchronized{ + val lib = new Stage1Lib(logger) + val key = classpath.strings.sorted.mkString(":") + if( cache.containsKey(key) ){ + logger.resolver("CACHE HIT: "++key) + cache.get(key) } else { - //println("PUTTING: "+normalized) - //Try(???).recover{ case e=>e.printStackTrace} - val cl = new cbt.URLClassLoader( ClassPath(Seq(new File(normalized))), parent ) - cache.put( normalized, cl ) + logger.resolver("CACHE MISS: "++key) + val cl = new cbt.URLClassLoader( classpath, parent ) + cache.put( key, cl ) cl } } - def remove( path: String ) = cache.remove( path ) + def remove( classpath: ClassPath ) = { + val key = classpath.strings.sorted.mkString(":") + cache.remove( key ) + } } +/* class MultiClassLoader(parents: Seq[ClassLoader]) extends ClassLoader { override def loadClass(name: String) = { - //System.err.println("LOADING CLASS "+name); + //System.err.println("LOADING CLASS "++name); val c = parents.toStream.map{ parent => Try{ @@ -37,29 +41,24 @@ class MultiClassLoader(parents: Seq[ClassLoader]) extends ClassLoader { }.find(_.isDefined).flatten c.getOrElse( ClassLoader.getSystemClassLoader.loadClass(name) ) } - override def toString = "MultiClassLoader(" + parents.mkString(",") + ")" + override def toString = "MultiClassLoader(" ++ parents.mkString(",") ++ ")" } +*/ case class URLClassLoader(classPath: ClassPath, parent: ClassLoader) extends java.net.URLClassLoader( classPath.strings.map( - path => new URL("file:"+path) + path => new URL("file:"++path) ).toArray, parent ){ override def toString = ( - scala.Console.BLUE + "cbt.URLClassLoader" + scala.Console.RESET + "(\n " + getURLs.map(_.toString).sorted.mkString(",\n ") - + (if(getParent() != ClassLoader.getSystemClassLoader()) ",\n" + getParent().toString.split("\n").map(" "+_).mkString("\n") else "") - + "\n)" + scala.Console.BLUE ++ "cbt.URLClassLoader" ++ scala.Console.RESET + ++ "(\n " ++ getURLs.map(_.toString).sorted.mkString(",\n ") + ++ ( + if(getParent() != ClassLoader.getSystemClassLoader()) + ",\n" ++ getParent().toString.split("\n").map(" "++_).mkString("\n") + else "" + ) + ++ "\n)" ) - import scala.language.existentials - /*override def loadClass(name: String): Class[_] = { - //System.err.println("LOADING CLASS "+name+" in "+this); - try{ - super.loadClass(name) - } catch { - case e: ClassNotFoundException => - // FIXME: Shouldn't this happen automatically? - parent.loadClass(name) - } - }*/ } diff --git a/stage1/logger.scala b/stage1/logger.scala index ecc1579..b1d80a3 100644 --- a/stage1/logger.scala +++ b/stage1/logger.scala @@ -19,7 +19,7 @@ case class Logger(enabledLoggers: Set[String]) { System.err.println( s"[${" "*(6-timeTaken.size)}$timeTaken][$name] $msg" ) } - def showInvocation(method: String, args: Any) = method + "( " + args + " )" + def showInvocation(method: String, args: Any) = method ++ "( " ++ args.toString ++ " )" final def stage1(msg: => String) = logGuarded(names.stage1, msg) final def stage2(msg: => String) = logGuarded(names.stage2, msg) diff --git a/stage1/paths.scala b/stage1/paths.scala index f76c2f7..d3856c8 100644 --- a/stage1/paths.scala +++ b/stage1/paths.scala @@ -1,15 +1,15 @@ package cbt import java.io._ object paths{ - val cbtHome = new File(Option(System.getenv("CBT_HOME")).get) - val mavenCache = new File(cbtHome+"/cache/maven/") - val userHome = new File(Option(System.getProperty("user.home")).get) - val stage1 = new File(Option(System.getenv("STAGE1")).get) - val stage2 = new File(cbtHome + "/stage2/") - val nailgun = new File(Option(System.getenv("NAILGUN")).get) - private val target = Option(System.getenv("TARGET")).get - val stage1Target = new File(stage1 + "/" + target) - val stage2Target = new File(stage2 + "/" + target) - val nailgunTarget = new File(nailgun + "/" + target) - val sonatypeLogin = new File(cbtHome+"/sonatype.login") + val cbtHome: File = new File(Option(System.getenv("CBT_HOME")).get) + val mavenCache: File = cbtHome ++ "/cache/maven" + val userHome: File = new File(Option(System.getProperty("user.home")).get) + val stage1: File = new File(Option(System.getenv("STAGE1")).get) + val stage2: File = cbtHome ++ "/stage2" + val nailgun: File = new File(Option(System.getenv("NAILGUN")).get) + private val target = Option(System.getenv("TARGET")).get.stripSuffix("/") + val stage1Target: File = stage1 ++ ("/" ++ target) + val stage2Target: File = stage2 ++ ("/" ++ target) + val nailgunTarget: File = nailgun ++ ("/" ++ target) + val sonatypeLogin: File = cbtHome ++ "/sonatype.login" } diff --git a/stage1/resolver.scala b/stage1/resolver.scala index 880289c..9b3276b 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -10,7 +10,7 @@ private final class Tree( val root: Dependency, computeChildren: => Seq[Tree] ){ lazy val children = computeChildren def linearize: Seq[Dependency] = root +: children.flatMap(_.linearize) def show(indent: Int = 0): Stream[Char] = { - (" " * indent + root.show + "\n").toStream #::: children.map(_.show(indent+1)).foldLeft(Stream.empty[Char])(_ #::: _) + (" " * indent ++ root.show ++ "\n").toStream #::: children.map(_.show(indent+1)).foldLeft(Stream.empty[Char])(_ #::: _) } } @@ -20,9 +20,11 @@ trait ArtifactInfo extends Dependency{ def version: String protected def str = s"$groupId:$artifactId:$version" - override def show = super.show + s"($str)" + override def show = super.show ++ s"($str)" } abstract class Dependency{ + implicit def logger: Logger + protected def lib = new Stage1Lib(logger) def updated: Boolean //def cacheClassLoader: Boolean = false @@ -49,11 +51,10 @@ abstract class Dependency{ ).par.map(_.exportedClasspath).seq.sortBy(_.string) ) if(cacheDependencyClassLoader){ - val mavenClassPathKey = mavenClassPath.strings.sorted.mkString(":") new URLClassLoader( exportedClasspath ++ buildClassPath, ClassLoaderCache.classLoader( - mavenClassPathKey, new URLClassLoader( mavenClassPath, ClassLoader.getSystemClassLoader ) + mavenClassPath, new URLClassLoader( mavenClassPath, ClassLoader.getSystemClassLoader ) ) ) } else { @@ -85,11 +86,13 @@ abstract class Dependency{ def show: String = this.getClass.getSimpleName // ========== debug ========== def dependencyTree: String = dependencyTreeRecursion() - def logger: Logger - protected def lib = new Stage1Lib(logger) - private def dependencyTreeRecursion(indent: Int = 0): String = ( " " * indent ) + (if(updated) lib.red(show) else show) + dependencies.map(_.dependencyTreeRecursion(indent + 1)).map("\n"+_).mkString("") - - private object cacheDependencyClassLoaderBasicBuild extends Cache[ClassLoader] + private def dependencyTreeRecursion(indent: Int = 0): String = ( + ( " " * indent ) + ++ (if(updated) lib.red(show) else show) + ++ dependencies.map( + _.dependencyTreeRecursion(indent + 1) + ).map( "\n" ++ _.toString ).mkString("") + ) } // TODO: all this hard codes the scala version, needs more flexibility @@ -140,16 +143,18 @@ case class MavenDependency( groupId: String, artifactId: String, version: String def updated = false private val groupPath = groupId.split("\\.").mkString("/") - def basePath = s"/$groupPath/$artifactId/$version/$artifactId-$version"+(if(sources) "-sources" else "") + def basePath = s"/$groupPath/$artifactId/$version/$artifactId-$version"++(if(sources) "-sources" else "") - private def resolverUrl = if(version.endsWith("-SNAPSHOT")) "https://oss.sonatype.org/content/repositories/snapshots" else "https://repo1.maven.org/maven2" - private def baseUrl = resolverUrl + basePath - private def baseFile = mavenCache + basePath - private def pomFile = baseFile+".pom" - private def jarFile = baseFile+".jar" - //private def coursierJarFile = userHome+"/.coursier/cache/v1/https/repo1.maven.org/maven2"+basePath+".jar" - private def pomUrl = baseUrl+".pom" - private def jarUrl = baseUrl+".jar" + 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 def jarUrl: URL = baseUrl ++ ".jar" def exportedJars = Seq( jar ) def exportedClasspath = ClassPath( exportedJars ) @@ -157,33 +162,32 @@ case class MavenDependency( groupId: String, artifactId: String, version: String import scala.collection.JavaConversions._ def jarSha1 = { - val file = jarFile+".sha1" - def url = jarUrl+".sha1" + val file = jarFile ++ ".sha1" scala.util.Try{ - lib.download( new URL(url), Paths.get(file), None ) + 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)).mkString("\n").split(" ").head.trim - }.toOption // FIXME: .toOption is a temporary solution to ignore if libs don't have one + Files.readAllLines(Paths.get(file.string)).mkString("\n").split(" ").head.trim + }.toOption // FIXME: .toOption is a temporary solution to ignore if libs don't have one (not sure that's even possible) } + def pomSha1 = { - val file = pomFile+".sha1" - def url = pomUrl+".sha1" + val file = pomFile++".sha1" scala.util.Try{ - lib.download( new URL(url), Paths.get(file), None ) + 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)).mkString("\n").split(" ").head.trim - }.toOption // FIXME: .toOption is a temporary solution to ignore if libs don't have one + Files.readAllLines(Paths.get(file.string)).mkString("\n").split(" ").head.trim + }.toOption // FIXME: .toOption is a temporary solution to ignore if libs don't have one (not sure that's even possible) } + def jar = { - lib.download( new URL(jarUrl), Paths.get(jarFile), jarSha1 ) - new File(jarFile) - } - def pomXml = { - XML.loadFile(pom.toString) + lib.download( jarUrl, jarFile, jarSha1 ) + jarFile } + def pomXml = XML.loadFile(pom.toString) + def pom = { - lib.download( new URL(pomUrl), Paths.get(pomFile), pomSha1 ) - new File(pomFile) + lib.download( pomUrl, pomFile, pomSha1 ) + pomFile } // ========== pom traversal ========== @@ -211,13 +215,13 @@ case class MavenDependency( groupId: String, artifactId: String, version: String }.toVector } def lookup( xml: Node, accessor: Node => NodeSeq ): Option[String] = { - //println("lookup in "+pomUrl) - val Substitution = "\\$\\{([a-z0-9\\.]+)\\}".r + //println("lookup in "++pomUrl) + val Substitution = "\\$\\{([a-z0-9\\.]++)\\}".r accessor(xml).headOption.flatMap{v => - //println("found: "+v.text) + //println("found: "++v.text) v.text match { case Substitution(path) => - //println("lookup "+path + ": "+(pomXml\path).text) + //println("lookup "++path ++ ": "++(pomXml\path).text) lookup(pomXml, _ \ "properties" \ path) case value => Option(value) } @@ -247,7 +251,7 @@ object MavenDependency{ def removeOutdated( deps: Seq[ArtifactInfo], versionLessThan: (String, String) => Boolean = semanticVersionLessThan - ): Seq[ArtifactInfo] = { + )(implicit logger: Logger): Seq[ArtifactInfo] = { val latest = deps .groupBy( d => (d.groupId, d.artifactId) ) .mapValues( @@ -257,7 +261,7 @@ object MavenDependency{ deps.flatMap{ d => val l = latest.get((d.groupId,d.artifactId)) - //if(d != l) println("EVICTED: "+d.show) + if(d != l) logger.resolver("outdated: "++d.show) l }.distinct } diff --git a/stage2/AdminStage2.scala b/stage2/AdminStage2.scala index d3db3e7..4120b1c 100644 --- a/stage2/AdminStage2.scala +++ b/stage2/AdminStage2.scala @@ -5,7 +5,7 @@ object AdminStage2{ val lib = new Lib(init.logger) val adminTasks = new AdminTasks(lib, args.drop(3)) new lib.ReflectObject(adminTasks){ - def usage = "Available methods: " + lib.taskNames(subclassType) + def usage: String = "Available methods: " ++ lib.taskNames(subclassType).mkString(" ") }.callNullary(args.lift(2)) } } diff --git a/stage2/DefaultBuild.scala b/stage2/BasicBuild.scala index c98aea0..6da31b7 100644 --- a/stage2/DefaultBuild.scala +++ b/stage2/BasicBuild.scala @@ -15,80 +15,17 @@ import scala.util._ import ammonite.ops.{cwd => _,_} - - - -abstract class PackageBuild(context: Context) extends Build(context) with ArtifactInfo{ - def `package`: Seq[File] = lib.concurrently( enableConcurrency )( - Seq(() => jar, () => docJar, () => srcJar) - )( _() ) - - private object cacheJarBasicBuild extends Cache[File] - def jar: File = cacheJarBasicBuild{ - lib.jar( artifactId, version, compile, jarTarget ) - } - - private object cacheSrcJarBasicBuild extends Cache[File] - def srcJar: File = cacheSrcJarBasicBuild{ - lib.srcJar(sources, artifactId, version, scalaTarget) - } - - private object cacheDocBasicBuild extends Cache[File] - def docJar: File = cacheDocBasicBuild{ - lib.docJar( sources, dependencyClasspath, apiTarget, jarTarget, artifactId, version, scalacOptions ) - } - - override def jars = jar +: dependencyJars - override def exportedJars: Seq[File] = Seq(jar) -} -abstract class PublishBuild(context: Context) extends PackageBuild(context){ - def name = artifactId - def description: String - def url: URL - def developers: Seq[Developer] - def licenses: Seq[License] - def scmUrl: String - def scmConnection: String - def pomExtra: Seq[scala.xml.Node] = Seq() - - // ========== package ========== - - /** put additional xml that should go into the POM file in here */ - def pom: File = lib.pom( - groupId = groupId, - artifactId = artifactId, - version = version, - name = name, - description = description, - url = url, - developers = developers, - licenses = licenses, - scmUrl = scmUrl, - scmConnection = scmConnection, - dependencies = dependencies, - pomExtra = pomExtra, - jarTarget = jarTarget - ) - - // ========== publish ========== - final protected def releaseFolder = s"/${groupId.replace(".","/")}/$artifactId/$version/" - def snapshotUrl = new URL("https://oss.sonatype.org/content/repositories/snapshots") - def releaseUrl = new URL("https://oss.sonatype.org/service/local/staging/deploy/maven2") - def publishSnapshot: Unit = lib.publishSnapshot(sourceFiles, pom +: `package`, new URL(snapshotUrl + releaseFolder) ) - def publishSigned: Unit = lib.publishSigned(sourceFiles, pom +: `package`, new URL(releaseUrl + releaseFolder) ) -} - - class BasicBuild(context: Context) extends Build(context) class Build(val context: Context) extends Dependency with TriggerLoop{ // library available to builds final val logger = context.logger override final protected val lib: Lib = new Lib(logger) + // ========== general stuff ========== def enableConcurrency = false - final def projectDirectory: File = new File(context.cwd) - assert( projectDirectory.exists, "projectDirectory does not exist: "+projectDirectory ) + final def projectDirectory: File = context.cwd + assert( projectDirectory.exists, "projectDirectory does not exist: " ++ projectDirectory.string ) final def usage: Unit = new lib.ReflectBuild(this).usage /* def scaffold: Unit = lib.generateBasicBuildFile( @@ -106,18 +43,18 @@ class Build(val context: Context) extends Dependency with TriggerLoop{ ) // ========== paths ========== - final private val defaultSourceDirectory = new File(projectDirectory+"/src/") + final private val defaultSourceDirectory = projectDirectory ++ "/src" /** base directory where stuff should be generated */ - def target = new File(projectDirectory+"/target") + def target: File = projectDirectory ++ "/target" /** base directory where stuff should be generated for this scala version*/ - def scalaTarget = new File(target + s"/scala-$scalaMajorVersion") + def scalaTarget: File = target ++ s"/scala-$scalaMajorVersion" /** directory where jars (and the pom file) should be put */ - def jarTarget = scalaTarget + def jarTarget: File = scalaTarget /** directory where the scaladoc should be put */ - def apiTarget = new File(scalaTarget + "/api") + def apiTarget: File = scalaTarget ++ "/api" /** directory where the class files should be put (in package directories) */ - def compileTarget = new File(scalaTarget + "/classes") + def compileTarget: File = scalaTarget ++ "/classes" /** Source directories and files. Defaults to .scala and .java files in src/ and top-level. */ def sources: Seq[File] = Seq(defaultSourceDirectory) ++ projectDirectory.listFiles.toVector.filter(sourceFileFilter) @@ -138,36 +75,29 @@ class Build(val context: Context) extends Dependency with TriggerLoop{ .diff( Seq(defaultSourceDirectory) ) assert( nonExisting.isEmpty, - "Some sources do not exist: \n"+nonExisting.mkString("\n") + "Some sources do not exist: \n"++nonExisting.mkString("\n") ) } assertSourceDirectories() - - /** SBT-like dependency builder DSL */ class GroupIdAndArtifactId( groupId: String, artifactId: String ){ def %(version: String) = new MavenDependency(groupId, artifactId, version)(lib.logger) } implicit class DependencyBuilder(groupId: String){ - def %%(artifactId: String) = new GroupIdAndArtifactId( groupId, artifactId+"_"+scalaMajorVersion ) + def %%(artifactId: String) = new GroupIdAndArtifactId( groupId, artifactId++"_"++scalaMajorVersion ) def %(artifactId: String) = new GroupIdAndArtifactId( groupId, artifactId ) } - final def BuildDependency(path: String) = cbt.BuildDependency( - context.copy( - cwd = path, - args = Seq() - ) + final def BuildDependency(path: File) = cbt.BuildDependency( + context.copy( cwd = path, args = Seq() ) ) def triggerLoopFiles: Seq[File] = sources ++ transitiveDependencies.collect{ case b: TriggerLoop => b.triggerLoopFiles }.flatten - def localJars : Seq[File] = - Seq(projectDirectory + "/lib/") - .map(new File(_)) + Seq(projectDirectory ++ "/lib") .filter(_.exists) .flatMap(_.listFiles) .filter(_.toString.endsWith(".jar")) @@ -220,15 +150,15 @@ class Build(val context: Context) extends Dependency with TriggerLoop{ def test: ExitCode = lib.test(context) context.logger.composition(">"*80) - context.logger.composition("class "+this.getClass) - context.logger.composition("dir "+context.cwd) - context.logger.composition("sources "+sources.toList.mkString(" ")) - context.logger.composition("target "+target) - context.logger.composition("context "+context) - context.logger.composition("dependencyTree\n"+dependencyTree) + context.logger.composition("class " ++ this.getClass.toString) + context.logger.composition("dir " ++ context.cwd.string) + context.logger.composition("sources " ++ sources.toList.mkString(" ")) + context.logger.composition("target " ++ target.string) + context.logger.composition("context " ++ context.toString) + context.logger.composition("dependencyTree\n" ++ dependencyTree) context.logger.composition("<"*80) // ========== cbt internals ========== private[cbt] def finalBuild = this - override def show = this.getClass.getSimpleName + "("+context.cwd+")" + override def show = this.getClass.getSimpleName ++ "(" ++ context.cwd.string ++ ")" } diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index 41589db..9283cdf 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -1,9 +1,10 @@ package cbt +import java.io.File import scala.collection.immutable.Seq class BuildBuild(context: Context) extends Build(context){ override def dependencies = Seq( CbtDependency(context.logger) ) ++ super.dependencies - def managedBuildDirectory = lib.realpath(projectDirectory + "/../") + def managedBuildDirectory: File = lib.realpath( projectDirectory.parent ) val managedBuild = { val managedContext = context.copy( cwd = managedBuildDirectory ) val cl = new cbt.URLClassLoader( diff --git a/stage2/dependencies.scala b/stage2/BuildDependency.scala index 8ed36eb..f7b6b78 100644 --- a/stage2/dependencies.scala +++ b/stage2/BuildDependency.scala @@ -16,7 +16,7 @@ trait TriggerLoop extends Dependency{ } /** You likely want to use the factory method in the BasicBuild class instead of this. */ case class BuildDependency(context: Context) extends TriggerLoop{ - override def show = this.getClass.getSimpleName + "("+context.cwd+")" + override def show = this.getClass.getSimpleName ++ "(" ++ context.cwd.string ++ ")" final override lazy val logger = context.logger final override lazy val lib: Lib = new Lib(logger) private val root = lib.loadRoot( context.copy(args=Seq()) ) diff --git a/stage2/Lib.scala b/stage2/Lib.scala index 9971b55..6bb9c0b 100644 --- a/stage2/Lib.scala +++ b/stage2/Lib.scala @@ -37,9 +37,9 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ */ def loadRoot(context: Context, default: Context => Build = new Build(_)): Build = { context.logger.composition( context.logger.showInvocation("Build.loadRoot",context) ) - def findStartDir(cwd: String): String = { - val buildDir = realpath(cwd+"/build") - if(new File(buildDir).exists) findStartDir(buildDir) else cwd + def findStartDir(cwd: File): File = { + val buildDir = realpath( cwd ++ "/build" ) + if(buildDir.exists) findStartDir(buildDir) else cwd } val start = findStartDir(context.cwd) @@ -51,7 +51,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ if(useBasicBuildBuild) default( context ) else new cbt.BuildBuild( context.copy( cwd = start ) ) } catch { case e:ClassNotFoundException if e.getMessage == rootBuildClassName => - throw new Exception(s"no class $rootBuildClassName found in "+start) + throw new Exception(s"no class $rootBuildClassName found in " ++ start.string) } } @@ -68,13 +68,13 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ } def srcJar(sources: Seq[File], artifactId: String, version: String, jarTarget: File): File = { - val file = new File(jarTarget+"/"+artifactId+"-"+version+"-sources.jar") + val file = jarTarget ++ ("/"++artifactId++"-"++version++"-sources.jar") lib.jarFile(file, sources) file } def jar(artifactId: String, version: String, compileTarget: File, jarTarget: File): File = { - val file = new File(jarTarget+"/"+artifactId+"-"+version+".jar") + val file = jarTarget ++ ("/"++artifactId++"-"++version++".jar") lib.jarFile(file, Seq(compileTarget)) file } @@ -102,7 +102,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ "scala.tools.nsc.ScalaDoc", Seq( // FIXME: can we use compiler dependency here? - "-cp", /*javacp+":"+*/ScalaDependencies(logger).classpath.string + ":" + dependenyClasspath.string, + "-cp", /*javacp++":"++*/ScalaDependencies(logger).classpath.string ++ ":" ++ dependenyClasspath.string, "-d", apiTarget.toString ) ++ compileArgs ++ sourceFiles.map(_.toString), new URLClassLoader( @@ -113,7 +113,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ } } } - val docJar = new File(jarTarget+"/"+artifactId+"-"+version+"-javadoc.jar") + val docJar = jarTarget ++ ("/"++artifactId++"-"++version++"-javadoc.jar") lib.jarFile(docJar, Vector(apiTarget)) docJar } @@ -122,11 +122,11 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ val loggers = logger.enabledLoggers.mkString(",") // FIXME: this is a hack to pass logger args on to the tests. // should probably have a more structured way - val loggerArg = if(loggers != "") Some("-Dlog="+loggers) else None + val loggerArg = if(loggers != "") Some("-Dlog="++loggers) else None logger.lib(s"invoke testDefault( $context )") val exitCode: ExitCode = loadDynamic( - context.copy( cwd = context.cwd+"/test/", args = loggerArg.toVector ++ context.args ), + context.copy( cwd = context.cwd ++ "/test", args = loggerArg.toVector ++ context.args ), new Build(_) with mixins.Test ).run logger.lib(s"return testDefault( $context )") @@ -135,9 +135,9 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ // task reflection helpers import ru._ - private lazy val anyRefMembers = ru.typeOf[AnyRef].members.toVector.map(taskName) - def taskNames(tpe: Type) = tpe.members.toVector.flatMap(lib.toTask).map(taskName).sorted - private def taskName(method: Symbol) = method.name.decodedName.toString + private lazy val anyRefMembers: Set[String] = ru.typeOf[AnyRef].members.toSet.map(taskName) + def taskNames(tpe: Type): Seq[String] = tpe.members.toVector.flatMap(lib.toTask).map(taskName).sorted + private def taskName(method: Symbol): String = method.name.decodedName.toString def toTask(symbol: Symbol): Option[MethodSymbol] = { Option(symbol) .filter(_.isPublic) @@ -161,10 +161,10 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ """ } else "" - ) + s"""Methods provided by CBT (but possibly overwritten) + ) ++ s"""Methods provided by CBT (but possibly overwritten) ${baseTasks.mkString(" ")}""" - ) + "\n" + ) ++ "\n" } } @@ -202,17 +202,13 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ } } - // file system helpers - def basename(path: String) = path.stripSuffix("/").split("/").last - def basename(path: File) = path.toString.stripSuffix("/").split("/").last - def dirname(path: String) = realpath(path).stripSuffix("/").split("/").dropRight(1).mkString("/") - def realpath(name: String) = Paths.get(new File(name).getAbsolutePath).normalize.toString - def realpath(name: File) = new File(Paths.get(name.getAbsolutePath).normalize.toString) - def nameAndContents(file: File) = basename(file.toString) -> readAllBytes(Paths.get(file.toString)) + def basename(path: File): String = path.toString.stripSuffix("/").split("/").last + def dirname(path: File): File = new File(realpath(path).string.stripSuffix("/").split("/").dropRight(1).mkString("/")) + def nameAndContents(file: File) = basename(file) -> readAllBytes(Paths.get(file.toString)) def jarFile( jarFile: File, files: Seq[File] ): Unit = { - logger.lib("Start packaging "+jarFile) + logger.lib("Start packaging "++jarFile.string) val manifest = new Manifest manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0") val jar = new JarOutputStream(new FileOutputStream(jarFile.toString), manifest) @@ -227,7 +223,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ val entry = new JarEntry( name ) entry.setTime(file.lastModified) jar.putNextEntry(entry) - jar.write( Files.readAllBytes( Paths.get(file.toString) ) ) + jar.write( readAllBytes( Paths.get(file.toString) ) ) jar.closeEntry name } @@ -235,11 +231,11 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ val duplicateFiles = (names diff names.distinct).distinct assert( duplicateFiles.isEmpty, - s"Conflicting file names when trying to create $jarFile: "+duplicateFiles.mkString(", ") + s"Conflicting file names when trying to create $jarFile: "++duplicateFiles.mkString(", ") ) jar.close - logger.lib("Done packaging "+jarFile) + logger.lib("Done packaging " ++ jarFile.toString) } lazy val passphrase = @@ -255,9 +251,9 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ new ProcessBuilder( "gpg", "--batch", "--yes", "-a", "-b", "-s", "--passphrase", passphrase, file.toString ) .inheritIO.start.waitFor - if( 0 != statusCode ) throw new Exception("gpg exited with status code "+statusCode) + if( 0 != statusCode ) throw new Exception("gpg exited with status code " ++ statusCode.toString) - new File(file+".asc") + file ++ ".asc" } //def requiredForPom[T](name: String): T = throw new Exception(s"You need to override `def $name` in order to generate a valid pom.") @@ -324,9 +320,9 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ } </dependencies> </project> - val path = new File(jarTarget+"/"+artifactId+"-"+version+".pom") - write.over(Path(path), "<?xml version='1.0' encoding='UTF-8'?>\n" + xml.toString) - path + val path = jarTarget.toString ++ ( "/" ++ artifactId ++ "-" ++ version ++ ".pom" ) + write.over(Path(path), "<?xml version='1.0' encoding='UTF-8'?>\n" ++ xml.toString) + new File(path) } def concurrently[T,R]( concurrencyEnabled: Boolean )( items: Seq[T] )( projection: T => R ): Seq[R] = { @@ -347,8 +343,8 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ val files = (artifacts ++ artifacts.map(sign)).map(nameAndContents) lazy val checksums = files.flatMap{ case (name, content) => Seq( - name+".md5" -> md5(content).toArray.map(_.toByte), - name+".sha1" -> sha1(content).toArray.map(_.toByte) + name++".md5" -> md5(content).toArray.map(_.toByte), + name++".sha1" -> sha1(content).toArray.map(_.toByte) ) } val all = (files ++ checksums) @@ -363,16 +359,14 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ def upload(fileName: String, fileContents: Array[Byte], baseUrl: URL): Unit = { import java.net._ import java.io._ - logger.task("uploading "+fileName) - val url = new URL( - baseUrl + fileName - ) + logger.task("uploading "++fileName) + val url = baseUrl ++ fileName val httpCon = url.openConnection.asInstanceOf[HttpURLConnection] httpCon.setDoOutput(true) httpCon.setRequestMethod("PUT") val userPassword = read(Path(sonatypeLogin)).trim val encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes) - httpCon.setRequestProperty("Authorization", "Basic " + encoding) + httpCon.setRequestProperty("Authorization", "Basic " ++ encoding) httpCon.setRequestProperty("Content-Type", "application/binary") httpCon.getOutputStream.write( fileContents @@ -389,7 +383,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ files.map{ file => - if(file.isFile) new File( dirname(file.toString) ) + if(file.isFile) dirname(file) else file }.distinct.map{ file => val watchableFile = new WatchableFile(file) @@ -411,7 +405,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ .filterNot(_.kind == StandardWatchEventKind.OVERFLOW) .map(_.context.toString) .map(new File(_)) - changedFiles.foreach( f => logger.loop("Changed: "+f) ) + changedFiles.foreach( f => logger.loop( "Changed: " ++ f.toString ) ) changedFiles.collect(action) key.reset } diff --git a/stage2/PackageBuild.scala b/stage2/PackageBuild.scala new file mode 100644 index 0000000..96c7b6f --- /dev/null +++ b/stage2/PackageBuild.scala @@ -0,0 +1,27 @@ +package cbt +import java.io.File +import java.net.URL +import scala.collection.immutable.Seq +abstract class PackageBuild(context: Context) extends Build(context) with ArtifactInfo{ + def `package`: Seq[File] = lib.concurrently( enableConcurrency )( + Seq(() => jar, () => docJar, () => srcJar) + )( _() ) + + private object cacheJarBasicBuild extends Cache[File] + def jar: File = cacheJarBasicBuild{ + lib.jar( artifactId, version, compile, jarTarget ) + } + + private object cacheSrcJarBasicBuild extends Cache[File] + def srcJar: File = cacheSrcJarBasicBuild{ + lib.srcJar(sources, artifactId, version, scalaTarget) + } + + private object cacheDocBasicBuild extends Cache[File] + def docJar: File = cacheDocBasicBuild{ + lib.docJar( sources, dependencyClasspath, apiTarget, jarTarget, artifactId, version, scalacOptions ) + } + + override def jars = jar +: dependencyJars + override def exportedJars: Seq[File] = Seq(jar) +} diff --git a/stage2/PublishBuild.scala b/stage2/PublishBuild.scala new file mode 100644 index 0000000..e4e8fd7 --- /dev/null +++ b/stage2/PublishBuild.scala @@ -0,0 +1,41 @@ +package cbt +import java.io.File +import java.net.URL +import scala.collection.immutable.Seq + +abstract class PublishBuild(context: Context) extends PackageBuild(context){ + def name = artifactId + def description: String + def url: URL + def developers: Seq[Developer] + def licenses: Seq[License] + def scmUrl: String + def scmConnection: String + def pomExtra: Seq[scala.xml.Node] = Seq() + + // ========== package ========== + + /** put additional xml that should go into the POM file in here */ + def pom: File = lib.pom( + groupId = groupId, + artifactId = artifactId, + version = version, + name = name, + description = description, + url = url, + developers = developers, + licenses = licenses, + scmUrl = scmUrl, + scmConnection = scmConnection, + dependencies = dependencies, + pomExtra = pomExtra, + jarTarget = jarTarget + ) + + // ========== publish ========== + final protected def releaseFolder = s"/${groupId.replace(".","/")}/$artifactId/$version/" + def snapshotUrl = new URL("https://oss.sonatype.org/content/repositories/snapshots") + def releaseUrl = new URL("https://oss.sonatype.org/service/local/staging/deploy/maven2") + def publishSnapshot: Unit = lib.publishSnapshot(sourceFiles, pom +: `package`, snapshotUrl ++ releaseFolder ) + def publishSigned: Unit = lib.publishSigned(sourceFiles, pom +: `package`, releaseUrl ++ releaseFolder ) +} diff --git a/stage2/Scaffold.scala b/stage2/Scaffold.scala index 00c8706..18b2cc3 100644 --- a/stage2/Scaffold.scala +++ b/stage2/Scaffold.scala @@ -49,7 +49,7 @@ class Build(context: Context) extends BuildBuild(context){ override def scalaVersion: String = "2.11.7" override def dependencies = super.dependencies ++ Seq( - BuildDependency( projectDirectory + "/../build-shared/") + BuildDependency( projectDirectory.parent ++ "/build-shared") // , "com.lihaoyi" %% "ammonite-ops" % "0.5.5" ) } @@ -85,7 +85,7 @@ class Build(context: Context) extends BuildBuild(context){ override def scalaVersion: String = "2.11.7" override def dependencies = super.dependencies ++ Seq( - BuildDependency( projectDirectory + "/../../build-shared/") + BuildDependency( projectDirectory.parent.parent ++ "/build-shared") // , "com.lihaoyi" %% "ammonite-ops" % "0.5.5" ) } @@ -132,9 +132,9 @@ trait BuildShared extends BasicBuild{ generatedFiles.map{ case ( fileName, code ) => scala.util.Try{ - write( Path(projectDirectory+"/"+fileName), code ) + write( Path( projectDirectory.string ++ "/" ++ fileName ), code ) import scala.Console._ - println( GREEN + "Created " + fileName + RESET ) + println( GREEN ++ "Created " ++ fileName ++ RESET ) } }.foreach( _.recover{ diff --git a/stage2/Stage2.scala b/stage2/Stage2.scala index c6783d4..ed63cf1 100644 --- a/stage2/Stage2.scala +++ b/stage2/Stage2.scala @@ -27,7 +27,7 @@ object Stage2{ } val task = argsV.lift( taskIndex ) - val context = Context( argsV(0), argsV.drop( taskIndex + 1 ), logger ) + val context = Context( new File(argsV(0)), argsV.drop( taskIndex + 1 ), logger ) val first = lib.loadRoot( context ) val build = first.finalBuild @@ -38,7 +38,7 @@ object Stage2{ val triggerCbtFiles = Seq( nailgun, stage1, stage2 ).map(lib.realpath _) val allTriggerFiles = triggerFiles ++ triggerCbtFiles - logger.loop("Looping change detection over:\n - "+allTriggerFiles.mkString("\n - ")) + logger.loop("Looping change detection over:\n - "++allTriggerFiles.mkString("\n - ")) lib.watch(allTriggerFiles) { case file if triggerCbtFiles.exists(file.toString startsWith _.toString) => diff --git a/stage2/mixins.scala b/stage2/mixins.scala index 4d72325..2b38cdf 100644 --- a/stage2/mixins.scala +++ b/stage2/mixins.scala @@ -3,15 +3,15 @@ package mixins import scala.collection.immutable.Seq import java.io._ trait Test extends Build{ - lazy val testedBuild = BuildDependency(projectDirectory+"/../") + lazy val testedBuild = BuildDependency( projectDirectory.parent ) override def dependencies = Seq( testedBuild ) ++ super.dependencies override def scalaVersion = testedBuild.build.scalaVersion } trait Sbt extends Build{ - override def sources = Seq(new File(projectDirectory+"/src/main/scala/")) + override def sources = Seq( projectDirectory ++ "/src/main/scala" ) } trait SbtTest extends Test{ - override def sources = Vector(new File(projectDirectory+"/../src/test/scala")) + override def sources = Vector( projectDirectory.parent ++ "/src/test/scala" ) } trait ScalaTest extends Build with Test{ def scalaTestVersion: String @@ -24,8 +24,8 @@ trait ScalaTest extends Build with Test{ override def cacheDependencyClassLoader = false override def run: ExitCode = { - val discoveryPath = compile.toString+"/" - context.logger.lib("discoveryPath: "+discoveryPath) + val discoveryPath = compile.toString++"/" + context.logger.lib("discoveryPath: " ++ discoveryPath) lib.runMain( "org.scalatest.tools.Runner", Seq("-R", discoveryPath, "-oF") ++ context.args.drop(1), diff --git a/test/test.scala b/test/test.scala index 3befa4a..feab89f 100644 --- a/test/test.scala +++ b/test/test.scala @@ -2,68 +2,71 @@ import cbt._ import cbt.paths._ import scala.collection.immutable.Seq +// micro framework object Main{ - // micro framework - var successes = 0 - var failures = 0 - def assert(condition: Boolean, msg: String = "")(implicit logger: Logger) = { - scala.util.Try{ - Predef.assert(condition, msg) - }.map{ _ => - print(".") - successes += 1 - }.recover{ - case e: AssertionError => - println("FAILED") - e.printStackTrace - failures += 1 - }.get - } - - def runCbt(path: String, args: Seq[String])(implicit logger: Logger): Result = { - import java.io._ - val allArgs = ((cbtHome + "/cbt") +: args :+ "-Dlog=all") - logger.test(allArgs.toString) - val pb = new ProcessBuilder( allArgs :_* ) - pb.directory(new File(cbtHome + "/test/" + path)) - val p = pb.inheritIO.start - p.waitFor - val berr = new BufferedReader(new InputStreamReader(p.getErrorStream)); - val bout = new BufferedReader(new InputStreamReader(p.getInputStream)); - p.waitFor - import collection.JavaConversions._ - val err = Stream.continually(berr.readLine()).takeWhile(_ != null).mkString("\n") - val out = Stream.continually(bout.readLine()).takeWhile(_ != null).mkString("\n") - Result(out, err, p.exitValue == 0) - } - case class Result(out: String, err: String, exit0: Boolean) - def assertSuccess(res: Result)(implicit logger: Logger) = { - assert(res.exit0,res.toString) - } - - // tests - def usage(path: String)(implicit logger: Logger) = { - val usageString = "Methods provided by CBT" - val res = runCbt(path, Seq()) - logger.test(res.toString) - assertSuccess(res) - assert(res.out == "", "#"+res.out+"#") - assert(res.err contains usageString, res.err) - } - def compile(path: String)(implicit logger: Logger) = { - val res = runCbt(path, Seq("compile")) - assertSuccess(res) - // assert(res.err == "", res.err) // FIXME: enable this - } def main(args: Array[String]): Unit = { - implicit val logger: Logger = new Init(args).logger + val init = new Init(args) + implicit val logger: Logger = init.logger - System.err.println("Running tests "+args.toList) + var successes = 0 + var failures = 0 + def assert(condition: Boolean, msg: String = "")(implicit logger: Logger) = { + scala.util.Try{ + Predef.assert(condition, "["++msg++"]") + }.map{ _ => + print(".") + successes += 1 + }.recover{ + case e: AssertionError => + println("FAILED") + e.printStackTrace + failures += 1 + }.get + } + + def runCbt(path: String, args: Seq[String])(implicit logger: Logger): Result = { + import java.io._ + val allArgs: Seq[String] = ((cbtHome.string ++ "/cbt") +: "direct" +: (args ++ init.propsRaw)) + logger.test(allArgs.toString) + val pb = new ProcessBuilder( allArgs :_* ) + pb.directory(cbtHome ++ ("/test/" ++ path)) + val p = pb.inheritIO.start + p.waitFor + val berr = new BufferedReader(new InputStreamReader(p.getErrorStream)); + val bout = new BufferedReader(new InputStreamReader(p.getInputStream)); + p.waitFor + import collection.JavaConversions._ + val err = Stream.continually(berr.readLine()).takeWhile(_ != null).mkString("\n") + val out = Stream.continually(bout.readLine()).takeWhile(_ != null).mkString("\n") + Result(out, err, p.exitValue == 0) + } + case class Result(out: String, err: String, exit0: Boolean) + def assertSuccess(res: Result)(implicit logger: Logger) = { + assert(res.exit0, res.toString) + } + + // tests + def usage(path: String)(implicit logger: Logger) = { + val usageString = "Methods provided by CBT" + val res = runCbt(path, Seq()) + logger.test(res.toString) + assertSuccess(res) + assert(res.out == "", res.toString) + assert(res.err contains usageString, res.toString) + } + def compile(path: String)(implicit logger: Logger) = { + val res = runCbt(path, Seq("compile")) + assertSuccess(res) + // assert(res.err == "", res.err) // FIXME: enable this + } + + logger.test( "Running tests " ++ args.toList.toString ) + usage("nothing") compile("nothing") { - val noContext = Context(cbtHome + "/test/" + "nothing",Seq(),logger) + val noContext = Context(cbtHome ++ "/test/nothing", Seq(), logger) val b = new Build(noContext){ override def dependencies = Seq( MavenDependency("net.incongru.watchservice","barbary-watchservice","1.0")(logger), @@ -71,11 +74,11 @@ object Main{ ) } val cp = b.classpath - assert(cp.strings.distinct == cp.strings, "duplicates in classpath: "+cp) + assert(cp.strings.distinct == cp.strings, "duplicates in classpath: " ++ cp.string) } System.err.println(" DONE!") - System.err.println(successes+" succeeded, "+ failures+" failed" ) + System.err.println( successes.toString ++ " succeeded, "++ failures.toString ++ " failed" ) if(failures > 0) System.exit(1) else System.exit(0) } } |