diff options
-rw-r--r-- | stage1/Stage1Lib.scala | 54 | ||||
-rw-r--r-- | stage2/BuildBuild.scala | 30 | ||||
-rw-r--r-- | stage2/Scaffold.scala | 3 | ||||
-rw-r--r-- | test/broken-build/build-class-with-wrong-arguments/build/build.scala | 3 | ||||
-rw-r--r-- | test/broken-build/build-class-with-wrong-parent/build/build.scala (renamed from test/forgot-extend/build/build.scala) | 0 | ||||
-rw-r--r-- | test/broken-build/empty-build-file/Main.scala (renamed from test/empty-build-file/Main.scala) | 0 | ||||
-rw-r--r-- | test/broken-build/empty-build-file/build/build.scala (renamed from test/empty-build-file/build/build.scala) | 0 | ||||
-rw-r--r-- | test/broken-build/no-build-file/Main.scala (renamed from test/no-build-file/Main.scala) | 0 | ||||
-rw-r--r-- | test/broken-build/no-build-file/build/foo.scala (renamed from test/no-build-file/build/foo.scala) | 0 | ||||
-rw-r--r-- | test/test.scala | 19 |
10 files changed, 71 insertions, 38 deletions
diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 505b298..79df450 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -146,35 +146,43 @@ class Stage1Lib( logger: Logger ) extends BaseLib{ pickOne( "Which one do you want to run?", mainClasses )( _.toString ) } - def mainClasses( targetDirectory: File, classLoader : ClassLoader ): Seq[Class[_]] = { - val arrayClass = classOf[Array[String]] - val unitClass = classOf[Unit] - - listFilesRecursive(targetDirectory) + /** Given a directory corresponding to the root package, iterate + the names of all classes derived from the class files found */ + def iterateClassNames( classesRootDirectory: File ): Seq[String] = + listFilesRecursive(classesRootDirectory) .filter(_.isFile) .map(_.getPath) .collect{ // no $ to avoid inner classes case path if !path.contains("$") && path.endsWith(".class") => - try{ - classLoader.loadClass( - path - .stripSuffix(".class") - .stripPrefix(targetDirectory.getPath) - .stripPrefix(File.separator) // 1 for the slash - .replace(File.separator, ".") - ) - } catch { - case e: ClassNotFoundException => null - case e: NoClassDefFoundError => null - } - }.filterNot(_ == null).filter( - _.getDeclaredMethods().exists( m => - m.getName == "main" - && m.getParameterTypes.toList == List(arrayClass) - && m.getReturnType == unitClass - ) + path.stripSuffix(".class") + .stripPrefix(classesRootDirectory.getPath) + .stripPrefix(File.separator) // 1 for the slash + .replace(File.separator, ".") + } + + /** ignoreMissingClasses allows ignoring other classes root directories which are subdirectories of this one */ + def iterateClasses( classesRootDirectory: File, classLoader: ClassLoader, ignoreMissingClasses: Boolean ) = + iterateClassNames(classesRootDirectory).map{ name => + try{ + classLoader.loadClass(name) + } catch { + case e: ClassNotFoundException if ignoreMissingClasses => null + case e: NoClassDefFoundError if ignoreMissingClasses => null + } + }.filterNot(ignoreMissingClasses && _ == null) + + def mainClasses( classesRootDirectory: File, classLoader: ClassLoader ): Seq[Class[_]] = { + val arrayClass = classOf[Array[String]] + val unitClass = classOf[Unit] + + iterateClasses( classesRootDirectory, classLoader, true ).filter( + _.getDeclaredMethods().exists( m => + m.getName == "main" + && m.getParameterTypes.toList == List(arrayClass) + && m.getReturnType == unitClass ) + ) } implicit class ClassLoaderExtensions(classLoader: ClassLoader){ diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index 798bd7d..2eebcbc 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -63,15 +63,29 @@ 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) + } } } ) diff --git a/stage2/Scaffold.scala b/stage2/Scaffold.scala index b110258..68a966b 100644 --- a/stage2/Scaffold.scala +++ b/stage2/Scaffold.scala @@ -59,7 +59,8 @@ object Main{ 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. diff --git a/test/broken-build/build-class-with-wrong-arguments/build/build.scala b/test/broken-build/build-class-with-wrong-arguments/build/build.scala new file mode 100644 index 0000000..cf040a1 --- /dev/null +++ b/test/broken-build/build-class-with-wrong-arguments/build/build.scala @@ -0,0 +1,3 @@ +package cbt_build.build_class_with_wrong_arguments +import cbt._ +class Build(i: Int, val context: Context) extends BaseBuild diff --git a/test/forgot-extend/build/build.scala b/test/broken-build/build-class-with-wrong-parent/build/build.scala index 9181a5d..9181a5d 100644 --- a/test/forgot-extend/build/build.scala +++ b/test/broken-build/build-class-with-wrong-parent/build/build.scala diff --git a/test/empty-build-file/Main.scala b/test/broken-build/empty-build-file/Main.scala index 19d4beb..19d4beb 100644 --- a/test/empty-build-file/Main.scala +++ b/test/broken-build/empty-build-file/Main.scala diff --git a/test/empty-build-file/build/build.scala b/test/broken-build/empty-build-file/build/build.scala index e69de29..e69de29 100644 --- a/test/empty-build-file/build/build.scala +++ b/test/broken-build/empty-build-file/build/build.scala diff --git a/test/no-build-file/Main.scala b/test/broken-build/no-build-file/Main.scala index 19d4beb..19d4beb 100644 --- a/test/no-build-file/Main.scala +++ b/test/broken-build/no-build-file/Main.scala diff --git a/test/no-build-file/build/foo.scala b/test/broken-build/no-build-file/build/foo.scala index e69de29..e69de29 100644 --- a/test/no-build-file/build/foo.scala +++ b/test/broken-build/no-build-file/build/foo.scala diff --git a/test/test.scala b/test/test.scala index 778fcda..d8714c0 100644 --- a/test/test.scala +++ b/test/test.scala @@ -240,21 +240,28 @@ object Main{ } { - val res = runCbt("forgot-extend", Seq("run")) + val res = runCbt("broken-build/build-class-with-wrong-arguments", Seq("run")) assert(!res.exit0) - assert(res.err contains s"${lib.buildClassName} cannot be cast to cbt.BuildInterface", res.err) + assert(res.err contains s"Expected class ${lib.buildClassName}(val context: Context), but found different constructor", res.err) + assert(res.err contains s"${lib.buildClassName}(int, interface cbt.Context)", res.err) } { - val res = runCbt("no-build-file", Seq("run")) + val res = runCbt("broken-build/build-class-with-wrong-parent", Seq("run")) assert(!res.exit0) - assert(res.err contains s"No file ${lib.buildFileName} (lower case) found in", res.err) + assert(res.err contains s"You need to define a class ${lib.buildClassName} extending an appropriate super class", res.err) } { - val res = runCbt("empty-build-file", Seq("run")) + val res = runCbt("broken-build/no-build-file", Seq("run")) assert(!res.exit0) - assert(res.err contains s"You need to define a class ${lib.buildClassName} in", res.err) + assert(res.err contains s"No file ${lib.buildFileName} (lower case) found", res.err) + } + + { + val res = runCbt("broken-build/empty-build-file", Seq("run")) + assert(!res.exit0) + assert(res.err contains s"You need to define a class ${lib.buildClassName}", res.err) } { |