summaryrefslogblamecommitdiff
path: root/core/src/main/scala/mill/main/MainRunner.scala
blob: f354e83863598447a5d30ef17f56bc179402c315 (plain) (tree)
1
2
3
4
5
6
7
8
                 
                                   
                        
                                               

                               
                 
 




                                                                          

                                                  



                                                             
                                                                     







                                                                      

                                                   


                                                                       
                         
                                       
                                                         
                                                           
                                                                                    







                                       















                                                                    
                                            
                                                                                           
   
 






























                                                                                            
package mill.main
import ammonite.interp.Preprocessor
import ammonite.ops.Path
import ammonite.util.{Imports, Name, Res, Util}
import mill.discover.Discovered
import mill.eval.Evaluator
import upickle.Js

/**
  * Customized version of [[ammonite.MainRunner]], allowing us to run Mill
  * `build.sc` scripts with mill-specific tweaks such as a custom
  * `scriptCodeWrapper` or with a persistent evaluator between runs.
  */
class MainRunner(config: ammonite.main.Cli.Config,
                 show: Boolean)
  extends ammonite.MainRunner(
    config,
    System.out, System.err, System.in, System.out, System.err
  ){
  var lastEvaluator: Option[(Seq[(Path, Long)], Evaluator[_])] = None
  override def runScript(scriptPath: Path, scriptArgs: List[String]) =
    watchLoop(
      isRepl = false,
      printing = true,
      mainCfg => {
        mainCfg.instantiateInterpreter() match{
          case Left(problems) => problems
          case Right(interp) =>
            val interpWatched = interp.watchedFiles

            val result = RunScript.runScript(
              mainCfg.wd, scriptPath, interp, scriptArgs, lastEvaluator
            )
            result match{
              case Res.Success(data) =>
                val (eval, evaluationWatches, res) = data
                lastEvaluator = Some((interpWatched, eval))
                (Res.Success(res.flatMap(_._2)), interpWatched ++ evaluationWatches)
              case _ =>
                (result, interpWatched)
            }


        }
      }
    )

  override def handleWatchRes[T](res: Res[T], printing: Boolean) = {
    res match{
      case Res.Success(value) =>
        if (show){
          for(json <- value.asInstanceOf[Seq[Js.Value]]){
            System.out.println(json)
          }
        }

        true

      case _ => super.handleWatchRes(res, printing)
    }

  }
  override def initMain(isRepl: Boolean) = {
    super.initMain(isRepl).copy(scriptCodeWrapper = mill.main.MainRunner.CustomCodeWrapper)
  }
}

object MainRunner{
  object CustomCodeWrapper extends Preprocessor.CodeWrapper {
    def top(pkgName: Seq[Name], imports: Imports, indexedWrapperName: Name) = {
      val wrapName = indexedWrapperName.backticked
      s"""
         |package ${pkgName.head.encoded}
         |package ${Util.encodeScalaSourcePath(pkgName.tail)}
         |$imports
         |import mill._
         |
         |object $wrapName extends $wrapName{
         |  // Stub to make sure Ammonite has something to call after it evaluates a script,
         |  // even if it does nothing...
         |  def $$main() = Iterator[String]()
         |  lazy val mapping = mill.discover.Discovered.make[$wrapName].mapping(this)
         |}
         |
         |sealed abstract class $wrapName extends mill.Module{
         |""".stripMargin
    }


    def bottom(printCode: String, indexedWrapperName: Name, extraCode: String) = {
      // We need to disable the `$main` method definition inside the wrapper class,
      // because otherwise it might get picked up by Ammonite and run as a static
      // class method, which blows up since it's defined as an instance method
      "\n}"
    }
  }
}