diff options
author | Jan Christopher Vogt <oss.nsp@cvogt.org> | 2016-10-02 15:09:11 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-02 15:09:11 -0400 |
commit | 3e35d0809240a3379dd3d71d42655e00b9cff421 (patch) | |
tree | 72afac7f4e6458572c319655c46c9ec11007029d | |
parent | 8515ca06ae5ae2501467f5af91bec2f5a80251c1 (diff) | |
parent | cea45c3b3dd7353ce1636467387bb8d47e7dd920 (diff) | |
download | cbt-3e35d0809240a3379dd3d71d42655e00b9cff421.tar.gz cbt-3e35d0809240a3379dd3d71d42655e00b9cff421.tar.bz2 cbt-3e35d0809240a3379dd3d71d42655e00b9cff421.zip |
Merge pull request #253 from cvogt/run
Run
-rw-r--r-- | examples/dotty-example/src/Main.scala | 3 | ||||
-rw-r--r-- | examples/scalafmt-example/build/build.scala | 2 | ||||
-rw-r--r-- | plugins/uber-jar/src/UberJar.scala | 2 | ||||
-rw-r--r-- | stage1/Stage1Lib.scala | 69 | ||||
-rw-r--r-- | stage2/BasicBuild.scala | 11 | ||||
-rw-r--r-- | stage2/Lib.scala | 2 | ||||
-rw-r--r-- | test/test.scala | 3 |
7 files changed, 78 insertions, 14 deletions
diff --git a/examples/dotty-example/src/Main.scala b/examples/dotty-example/src/Main.scala index 1963b51..fdc2068 100644 --- a/examples/dotty-example/src/Main.scala +++ b/examples/dotty-example/src/Main.scala @@ -1,5 +1,6 @@ +package dotty_example object Main extends Foo("Hello Dotty - trait parameters, yay"){ - def main(args: Array[String]) = { + def main(args: Array[String]): Unit = { println(hello) // Sanity check the classpath: this won't run if the dotty jar is not present. diff --git a/examples/scalafmt-example/build/build.scala b/examples/scalafmt-example/build/build.scala index a489616..b8a819b 100644 --- a/examples/scalafmt-example/build/build.scala +++ b/examples/scalafmt-example/build/build.scala @@ -1,7 +1,7 @@ import cbt._ import org.scalafmt.ScalafmtStyle -class Build(val context: Context) extends BuildBuild with Scalafmt { +class Build(val context: Context) extends BaseBuild with Scalafmt { override def compile = { scalafmt super.compile diff --git a/plugins/uber-jar/src/UberJar.scala b/plugins/uber-jar/src/UberJar.scala index c6815b4..3783367 100644 --- a/plugins/uber-jar/src/UberJar.scala +++ b/plugins/uber-jar/src/UberJar.scala @@ -13,7 +13,7 @@ trait UberJar extends BaseBuild { ExitCode.Success } - def uberJarMainClass: Option[String] = Some(runClass) + def uberJarMainClass: Option[String] = runClass def uberJarName: String = projectName + ".jar" diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index c427b77..5e65018 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -8,7 +8,7 @@ import java.nio.file._ import java.nio.file.attribute.FileTime import javax.tools._ import java.security._ -import java.util.{Set=>_,Map=>_,_} +import java.util.{Set=>_,Map=>_,List=>_,_} import java.util.concurrent.ConcurrentHashMap import javax.xml.bind.annotation.adapters.HexBinaryAdapter @@ -95,12 +95,6 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ // ========== compilation / execution ========== - def runMainIfFound(cls: String, args: Seq[String], classLoader: ClassLoader ): ExitCode = { - if( classLoader.canLoad(cls) ){ - runMain(cls, args, classLoader ) - } else ExitCode.Success - } - def runMain( cls: String, args: Seq[String], classLoader: ClassLoader, fakeInstance: Boolean = false ): ExitCode = { import java.lang.reflect.Modifier logger.lib(s"Running $cls.main($args) with classLoader: " ++ classLoader.toString) @@ -118,6 +112,67 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ } } + /** shows an interactive dialogue in the shell asking the user to pick one of many choices */ + def pickOne[T]( msg: String, choices: Seq[T] )( show: T => String ): Option[T] = { + if(choices.size == 0) None else if(choices.size == 1) Some(choices.head) else { + Option(System.console).map{ + console => + val indexedChoices: Map[Int, T] = choices.zipWithIndex.toMap.mapValues(_+1).map(_.swap) + System.err.println( + indexedChoices.map{ case (index,choice) => s"[${index}] "++show(choice)}.mkString("\n") + ) + val range = s"1 - ${indexedChoices.size}" + System.err.println() + System.err.println( msg ++ " [" ++ range ++ "] " ) + val answer = console.readLine() + val choice = try{ + Some(Integer.parseInt(answer)) + }catch{ + case e:java.lang.NumberFormatException => None + } + + choice.flatMap(indexedChoices.get).orElse{ + System.err.println("Not in range "++range) + None + } + }.getOrElse{ + System.err.println("Using '"++show(choices.head)++"' because System.console() == null. Use `cbt direct <task>` or see https://github.com/cvogt/cbt/issues/236") + None + } + } + } + + /** interactively pick one main class */ + def runClass( mainClasses: Seq[Class[_]] ): Option[Class[_]] = { + 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) + .filter(_.isFile) + .map(_.getPath) + .collect{ + // no $ to avoid inner classes + case path if !path.contains("$") && path.endsWith(".class") => + classLoader.loadClass( + path + .stripSuffix(".class") + .stripPrefix(targetDirectory.getPath) + .stripPrefix(File.separator) // 1 for the slash + .replace(File.separator, ".") + ) + }.filter( + _.getDeclaredMethods().exists( m => + m.getName == "main" + && m.getParameterTypes.toList == List(arrayClass) + && m.getReturnType == unitClass + ) + ) + } + implicit class ClassLoaderExtensions(classLoader: ClassLoader){ def canLoad(className: String) = { try{ diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index bcc3646..98deddc 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -136,8 +136,15 @@ trait BaseBuild extends DependencyImplementation with BuildInterface with Trigge ) } - def runClass: String = "Main" - def run: ExitCode = lib.runMainIfFound( runClass, context.args, classLoader(context.classLoaderCache) ) + + def mainClasses: Seq[Class[_]] = compile.toSeq.flatMap( lib.mainClasses( _, classLoader(classLoaderCache) ) ) + + def runClass: Option[String] = lib.runClass( mainClasses ).map( _.getName ) + + def run: ExitCode = runClass.map( lib.runMain( _, context.args, classLoader(context.classLoaderCache) ) ).getOrElse{ + logger.task( "No main class found for " ++ projectDirectory.string ) + ExitCode.Success + } def clean = { lib.clean( diff --git a/stage2/Lib.scala b/stage2/Lib.scala index 46fecf7..c18bf2e 100644 --- a/stage2/Lib.scala +++ b/stage2/Lib.scala @@ -201,7 +201,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ def consoleOrFail(msg: String) = { Option(System.console).getOrElse( - throw new Exception(msg + ". java.io.Console == null. See https://github.com/cvogt/cbt/issues/236") + throw new Exception(msg + ". System.console() == null. See https://github.com/cvogt/cbt/issues/236") ) } diff --git a/test/test.scala b/test/test.scala index dfc35d0..8845528 100644 --- a/test/test.scala +++ b/test/test.scala @@ -1,4 +1,5 @@ -import cbt._ +package cbt +package test import java.util.concurrent.ConcurrentHashMap import java.io.File import java.nio.file._ |