aboutsummaryrefslogtreecommitdiff
path: root/stage2
diff options
context:
space:
mode:
authorJan Christopher Vogt <oss.nsp@cvogt.org>2017-02-15 04:21:05 -0500
committerGitHub <noreply@github.com>2017-02-15 04:21:05 -0500
commit7ad65aeafc9d4fc9e0102c7d2ee8c9a31bd0be74 (patch)
tree12396906bde5f51cc8fc274c387d77e438bd2c23 /stage2
parent2a1bf81eccf6b91e0dcdd2d7a05664da2049f3a1 (diff)
parent4f4c34f3f52b87057626682dd43a21cd83e2ff7a (diff)
downloadcbt-7ad65aeafc9d4fc9e0102c7d2ee8c9a31bd0be74.tar.gz
cbt-7ad65aeafc9d4fc9e0102c7d2ee8c9a31bd0be74.tar.bz2
cbt-7ad65aeafc9d4fc9e0102c7d2ee8c9a31bd0be74.zip
Merge pull request #346 from cvogt/generate-packages
Generate packages
Diffstat (limited to 'stage2')
-rw-r--r--stage2/BasicBuild.scala4
-rw-r--r--stage2/BuildBuild.scala42
-rw-r--r--stage2/Lib.scala28
-rw-r--r--stage2/Scaffold.scala73
-rw-r--r--stage2/ToolsTasks.scala5
5 files changed, 119 insertions, 33 deletions
diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala
index e5b3507..f32d4d9 100644
--- a/stage2/BasicBuild.scala
+++ b/stage2/BasicBuild.scala
@@ -24,12 +24,12 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with Trigge
def projectDirectory: File = lib.realpath(context.workingDirectory)
assert( projectDirectory.exists, "projectDirectory does not exist: " ++ projectDirectory.string )
assert(
- projectDirectory.getName =!= "build" ||
+ projectDirectory.getName =!= lib.buildDirectoryName ||
{
def transitiveInterfaces(cls: Class[_]): Vector[Class[_]] = cls.getInterfaces.toVector.flatMap(i => i +: transitiveInterfaces(i))
transitiveInterfaces(this.getClass).contains(classOf[BuildBuildWithoutEssentials])
},
- "You need to extend BuildBuild in: " + projectDirectory + "/build"
+ s"You need to extend ${lib.buildBuildClassName} in: " + projectDirectory + "/" ++ lib.buildDirectoryName
)
final def usage: String = lib.usage(this.getClass, show)
diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala
index 474599a..2eebcbc 100644
--- a/stage2/BuildBuild.scala
+++ b/stage2/BuildBuild.scala
@@ -7,8 +7,8 @@ trait BuildBuild extends BuildBuildWithoutEssentials{
}
trait BuildBuildWithoutEssentials extends BaseBuild{
assert(
- projectDirectory.getName === "build",
- "You can't extend BuildBuild in: " + projectDirectory + "/build"
+ projectDirectory.getName === lib.buildDirectoryName,
+ "You can't extend ${lib.buildBuildClassName} in: " + projectDirectory + "/" + lib.buildDirectoryName
)
protected final val managedContext = context.copy(
@@ -33,12 +33,12 @@ trait BuildBuildWithoutEssentials extends BaseBuild{
super.dependencies :+ context.cbtDependency
def managedBuildDirectory: java.io.File = lib.realpath( projectDirectory.parent )
def managedBuild = taskCache[BuildBuildWithoutEssentials]("managedBuild").memoize{
- val managedBuildFile = projectDirectory++"/build.scala"
+ val managedBuildFile = projectDirectory++("/"++lib.buildFileName)
logger.composition("Loading build at " ++ managedBuildDirectory.toString)
val build = (
if( !managedBuildFile.exists ){
throw new Exception(
- "No file build.scala (lower case) found in " ++ projectDirectory.getPath
+ s"No file ${lib.buildFileName} (lower case) found in " ++ projectDirectory.getPath
)
} else {
val contents = new String(Files.readAllBytes(managedBuildFile.toPath))
@@ -63,23 +63,37 @@ trait BuildBuildWithoutEssentials extends BaseBuild{
.invoke( null, ctx )
}
}.getOrElse{
- try{
- classLoader
- .loadClass(lib.buildClassName)
- .getConstructors.head
- .newInstance(managedContext)
- } catch {
- case e: ClassNotFoundException if e.getMessage == lib.buildClassName =>
- throw new Exception("You need to define a class Build in build.scala in: "+projectDirectory)
+ val buildClasses =
+ lib.iterateClasses( compileTarget, classLoader, false )
+ .filter(_.getSimpleName == lib.buildClassName)
+ .filter(classOf[BaseBuild] isAssignableFrom _)
+ if( buildClasses.size == 0 ){
+ throw new Exception(
+ s"You need to define a class ${lib.buildClassName} extending an appropriate super class in\n"
+ + (projectDirectory / lib.buildFileName) ++ "\nbut none found."
+ )
+ } else if( buildClasses.size > 1 ){
+ throw new Exception(
+ s"You need to define exactly one class ${lib.buildClassName} extending an appropriate build super class, but multiple found in " + projectDirectory + ":\n" + buildClasses.mkString("\n")
+ )
+ } else {
+ val buildClass = buildClasses.head
+ if( !buildClass.getConstructors.exists(_.getParameterTypes.toList == List(classOf[Context])) ){
+ throw new Exception(
+ s"Expected class ${lib.buildClassName}(val context: Context), but found different constructor in\n"
+ + projectDirectory ++ "\n"
+ + buildClass ++ "(" ++ buildClass.getConstructors.map(_.getParameterTypes.mkString(", ")).mkString("; ") + ")" )
}
+ buildClass.getConstructors.head.newInstance(managedContext)
+ }
}
}
)
try{
build.asInstanceOf[BuildInterface]
} catch {
- case e: ClassCastException if e.getMessage.contains("Build cannot be cast to cbt.BuildInterface") =>
- throw new Exception("Your Build class needs to extend BaseBuild in: "+projectDirectory, e)
+ case e: ClassCastException if e.getMessage.contains(s"${lib.buildClassName} cannot be cast to cbt.BuildInterface") =>
+ throw new Exception(s"Your ${lib.buildClassName} class needs to extend BaseBuild in: "+projectDirectory, e)
}
}
override def triggerLoopFiles = super.triggerLoopFiles ++ managedBuild.triggerLoopFiles
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index 2642ec9..fc53c4f 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -15,9 +15,11 @@ import scala.util._
case class Developer(id: String, name: String, timezone: String, url: URL)
/** Don't extend. Create your own libs :). */
-final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{
+final class Lib(val logger: Logger) extends Stage1Lib(logger){
lib =>
+ val buildFileName = "build.scala"
+ val buildDirectoryName = "build"
val buildClassName = "Build"
val buildBuildClassName = "BuildBuild"
@@ -26,18 +28,13 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{
This can either the Build itself, of if exists a BuildBuild or a BuildBuild for a BuildBuild and so on.
*/
def loadRoot(context: Context): BuildInterface = {
- def findStartDir(directory: File): File = {
- val buildDir = realpath( directory ++ "/build" )
- if(buildDir.exists) findStartDir(buildDir) else directory
- }
-
val directory = context.workingDirectory
context.logger.composition( context.logger.showInvocation("Build.loadRoot",directory) )
- val start = findStartDir(directory)
+ val start = lib.findInnerMostModuleDirectory(directory)
- val useBasicBuild = directory == start && start.getName != "build"
+ val useBasicBuild = directory == start && start.getName != buildDirectoryName
try{
if(useBasicBuild) {
@@ -54,8 +51,8 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{
else
new cbt.BasicBuild( context.copy( workingDirectory = start ) ) with BuildBuild
} catch {
- case e:ClassNotFoundException if e.getMessage == "Build" =>
- throw new Exception(s"no class Build found in " ++ start.string)
+ case e:ClassNotFoundException if e.getMessage == buildClassName =>
+ throw new Exception(s"no class ${buildClassName} found in " ++ start.string)
}
}
@@ -532,4 +529,15 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger) with Scaffold{
}
}
}
+
+ def findInnerMostModuleDirectory(directory: File): File = {
+ val buildDir = realpath( directory ++ ("/" ++ lib.buildDirectoryName) )
+ // do not appent buildFileName here, so that we detect empty build folders
+ if(buildDir.exists) findInnerMostModuleDirectory(buildDir) else directory
+ }
+ def findOuterMostModuleDirectory(directory: File): File = {
+ if(
+ ( directory.getParentFile ++ ("/" ++ lib.buildDirectoryName) ).exists
+ ) findOuterMostModuleDirectory(directory.getParentFile) else directory
+ }
}
diff --git a/stage2/Scaffold.scala b/stage2/Scaffold.scala
index 866e5da..68a966b 100644
--- a/stage2/Scaffold.scala
+++ b/stage2/Scaffold.scala
@@ -2,8 +2,8 @@ package cbt
import java.io._
import java.nio.file._
import java.net._
-trait Scaffold{
- def logger: Logger
+class Scaffold( logger: Logger ){
+ val lib = new Lib(logger)
private def createFile( projectDirectory: File, fileName: String, code: String ){
val outputFile = projectDirectory ++ ("/" ++ fileName)
@@ -12,10 +12,42 @@ trait Scaffold{
println( GREEN ++ "Created " ++ fileName ++ RESET )
}
+ private[cbt] def packageName(name: String) = {
+ def stripNonAlPrefix = (_:String).dropWhile(
+ !(('a' to 'z') ++ ('A' to 'Z') ++ Seq('_')).contains(_)
+ )
+ def removeNonAlNumPlusSelected = "([^-a-zA-Z0-9_\\.\\\\/])".r.replaceAllIn(_:String, "")
+ def replaceSpecialWithUnderscore = "([-\\. ])".r.replaceAllIn(_:String, "_")
+ def removeRepeatedDots = "\\.+".r.replaceAllIn(_:String, ".")
+ val transform = (
+ (
+ stripNonAlPrefix
+ andThen
+ removeNonAlNumPlusSelected
+ andThen
+ replaceSpecialWithUnderscore
+ ).andThen(
+ (_:String).replace("/",".").replace("\\",".").toLowerCase
+ ) andThen removeRepeatedDots
+
+ )
+
+ transform( name )
+ }
+
+ private[cbt] def packageFromDirectory(directory: File) = {
+ packageName(
+ directory.getAbsolutePath.stripPrefix(
+ lib.findOuterMostModuleDirectory( directory ).getParentFile.getAbsolutePath
+ )
+ )
+ }
+
def createMain(
projectDirectory: File
- ): Unit = {
- createFile(projectDirectory, "Main.scala", s"""object Main{
+ ): Unit = {
+ createFile(projectDirectory, "Main.scala", s"""package ${packageFromDirectory(projectDirectory)}
+object Main{
def main( args: Array[String] ): Unit = {
println( Console.GREEN ++ "Hello World" ++ Console.RESET )
}
@@ -27,7 +59,8 @@ trait Scaffold{
def createBuild(
projectDirectory: File
): Unit = {
- createFile(projectDirectory, "build/build.scala", s"""import cbt._
+ createFile(projectDirectory, lib.buildDirectoryName++"/"++lib.buildFileName, s"""package cbt_build.${packageFromDirectory(projectDirectory)}
+import cbt._
class Build(val context: Context) extends BaseBuild{
override def dependencies =
super.dependencies ++ // don't forget super.dependencies here for scala-library, etc.
@@ -50,3 +83,33 @@ class Build(val context: Context) extends BaseBuild{
)
}
}
+object ScaffoldTest{
+ val scaffold = new Scaffold(new Logger(None,System.currentTimeMillis))
+ import scaffold._
+ def main(args: Array[String]): Unit = {
+ def assertEquals[T](left: T, right: T) = {
+ assert( left == right, left + " == " + right )
+ }
+ assertEquals(
+ packageName( "AsdfAsdfAsdf" ), "asdfasdfasdf"
+ )
+ assertEquals(
+ packageName( "_AsdfA4sdf" ), "_asdfa4sdf"
+ )
+ assertEquals(
+ packageName( "-AsdfAsdf" ), "asdfasdf"
+ )
+ assertEquals(
+ packageName( "asdf 4aSdf" ), "asdf4asdf"
+ )
+ assertEquals(
+ packageName( "&/(&%$&&/(asdf" ), "asdf"
+ )
+ assertEquals(
+ packageName( "AAA" ), "aaa"
+ )
+ assertEquals(
+ packageName( "/AAA/a_a/a.a" ), "aaa.a_a.a_a"
+ )
+ }
+}
diff --git a/stage2/ToolsTasks.scala b/stage2/ToolsTasks.scala
index 25156fb..943f096 100644
--- a/stage2/ToolsTasks.scala
+++ b/stage2/ToolsTasks.scala
@@ -15,8 +15,9 @@ class ToolsTasks(
implicit val logger: Logger = lib.logger
implicit val transientCache: java.util.Map[AnyRef,AnyRef] = new java.util.HashMap
private def Resolver( urls: URL* ) = MavenResolver(cbtLastModified,mavenCache,urls: _*)
- def createMain: Unit = lib.createMain( cwd )
- def createBuild: Unit = lib.createBuild( cwd )
+ val scaffold = new Scaffold(logger)
+ def createMain: Unit = scaffold.createMain( cwd )
+ def createBuild: Unit = scaffold.createBuild( cwd )
def gui = NailgunLauncher.main(Array(
"0.0",
(cbtHome / "tools" / "gui").getAbsolutePath,