src/Pure/System/build.scala
changeset 48674 03e88e4619a2
parent 48671 951bc4c3ee17
child 48675 10f5303f86e5
equal deleted inserted replaced
48673:b2b09970c571 48674:03e88e4619a2
   293 
   293 
   294           if (verbose) {
   294           if (verbose) {
   295             val groups =
   295             val groups =
   296               if (info.groups.isEmpty) ""
   296               if (info.groups.isEmpty) ""
   297               else info.groups.mkString(" (", " ", ")")
   297               else info.groups.mkString(" (", " ", ")")
   298             echo("Checking " + name + groups + " ...")
   298             echo("Session " + name + groups)
   299           }
   299           }
   300 
   300 
   301           val thy_deps =
   301           val thy_deps =
   302             thy_info.dependencies(
   302             thy_info.dependencies(
   303               info.theories.map(_._2).flatten.
   303               info.theories.map(_._2).flatten.
   330       }))
   330       }))
   331 
   331 
   332 
   332 
   333   /* jobs */
   333   /* jobs */
   334 
   334 
   335   private class Job(dir: Path, env: Map[String, String], script: String, args: String,
   335   private class Job(name: String, info: Session.Info, output: Path, do_output: Boolean,
   336     val parent_heap: String, output: Path, do_output: Boolean, time: Time)
   336     verbose: Boolean, browser_info: Path)
   337   {
       
   338     private val args_file = File.tmp_file("args")
       
   339     private val env1 = env + ("ARGS_FILE" -> Isabelle_System.posix_path(args_file.getPath))
       
   340     File.write(args_file, args)
       
   341 
       
   342     private val (thread, result) =
       
   343       Simple_Thread.future("build") { Isabelle_System.bash_env(dir.file, env1, script) }
       
   344 
       
   345     def terminate: Unit = thread.interrupt
       
   346     def is_finished: Boolean = result.is_finished
       
   347 
       
   348     @volatile private var timeout = false
       
   349     private val timer: Option[Timer] =
       
   350       if (time.seconds > 0.0) {
       
   351         val t = new Timer("build", true)
       
   352         t.schedule(new TimerTask { def run = { terminate; timeout = true } }, time.ms)
       
   353         Some(t)
       
   354       }
       
   355       else None
       
   356 
       
   357     def join: (String, String, Int) = {
       
   358       val (out, err, rc) = result.join
       
   359       args_file.delete
       
   360       timer.map(_.cancel())
       
   361 
       
   362       val err1 =
       
   363         if (rc == 130)
       
   364           (if (err.isEmpty || err.endsWith("\n")) err else err + "\n") +
       
   365           (if (timeout) "*** Timeout\n" else "*** Interrupt\n")
       
   366         else err
       
   367       (out, err1, rc)
       
   368     }
       
   369 
       
   370     def output_path: Option[Path] = if (do_output) Some(output) else None
       
   371   }
       
   372 
       
   373   private def start_job(name: String, info: Session.Info, parent_heap: String,
       
   374     output: Path, do_output: Boolean, options: Options, verbose: Boolean, browser_info: Path): Job =
       
   375   {
   337   {
   376     // global browser info dir
   338     // global browser info dir
   377     if (options.bool("browser_info") && !(browser_info + Path.explode("index.html")).is_file)
   339     if (info.options.bool("browser_info") && !(browser_info + Path.explode("index.html")).is_file)
   378     {
   340     {
   379       browser_info.file.mkdirs()
   341       browser_info.file.mkdirs()
   380       File.copy(Path.explode("~~/lib/logo/isabelle.gif"),
   342       File.copy(Path.explode("~~/lib/logo/isabelle.gif"),
   381         browser_info + Path.explode("isabelle.gif"))
   343         browser_info + Path.explode("isabelle.gif"))
   382       File.write(browser_info + Path.explode("index.html"),
   344       File.write(browser_info + Path.explode("index.html"),
   383         File.read(Path.explode("~~/lib/html/library_index_header.template")) +
   345         File.read(Path.explode("~~/lib/html/library_index_header.template")) +
   384         File.read(Path.explode("~~/lib/html/library_index_content.template")) +
   346         File.read(Path.explode("~~/lib/html/library_index_content.template")) +
   385         File.read(Path.explode("~~/lib/html/library_index_footer.template")))
   347         File.read(Path.explode("~~/lib/html/library_index_footer.template")))
   386     }
   348     }
   387 
   349 
   388     val parent = info.parent.getOrElse("")
   350     def output_path: Option[Path] = if (do_output) Some(output) else None
   389 
   351 
   390     val env =
   352     private val parent = info.parent.getOrElse("")
       
   353 
       
   354     private val env =
   391       Map("INPUT" -> parent, "TARGET" -> name, "OUTPUT" -> Isabelle_System.standard_path(output))
   355       Map("INPUT" -> parent, "TARGET" -> name, "OUTPUT" -> Isabelle_System.standard_path(output))
   392     val script =
   356     private val script =
   393       if (is_pure(name)) {
   357       if (is_pure(name)) {
   394         if (do_output) "./build " + name + " \"$OUTPUT\""
   358         if (do_output) "./build " + name + " \"$OUTPUT\""
   395         else """ rm -f "$OUTPUT"; ./build """ + name
   359         else """ rm -f "$OUTPUT"; ./build """ + name
   396       }
   360       }
   397       else {
   361       else {
   416         fi
   380         fi
   417 
   381 
   418         exit "$RC"
   382         exit "$RC"
   419         """
   383         """
   420       }
   384       }
   421     val args_xml =
   385     private val args_xml =
   422     {
   386     {
   423       import XML.Encode._
   387       import XML.Encode._
   424           pair(bool, pair(Options.encode, pair(bool, pair(Path.encode, pair(string,
   388           pair(bool, pair(Options.encode, pair(bool, pair(Path.encode, pair(string,
   425             pair(string, list(pair(Options.encode, list(Path.encode)))))))))(
   389             pair(string, list(pair(Options.encode, list(Path.encode)))))))))(
   426           (do_output, (options, (verbose, (browser_info, (parent,
   390           (do_output, (info.options, (verbose, (browser_info, (parent,
   427             (name, info.theories)))))))
   391             (name, info.theories)))))))
   428     }
   392     }
   429     new Job(info.dir, env, script, YXML.string_of_body(args_xml), parent_heap,
   393     private val args_file = File.tmp_file("args")
   430       output, do_output, Time.seconds(options.real("timeout")))
   394     private val env1 = env + ("ARGS_FILE" -> Isabelle_System.posix_path(args_file.getPath))
       
   395     File.write(args_file, YXML.string_of_body(args_xml))
       
   396 
       
   397     private val (thread, result) =
       
   398       Simple_Thread.future("build") { Isabelle_System.bash_env(info.dir.file, env1, script) }
       
   399 
       
   400     def terminate: Unit = thread.interrupt
       
   401     def is_finished: Boolean = result.is_finished
       
   402 
       
   403     @volatile private var timeout = false
       
   404     private val time = Time.seconds(info.options.real("timeout"))
       
   405     private val timer: Option[Timer] =
       
   406       if (time.seconds > 0.0) {
       
   407         val t = new Timer("build", true)
       
   408         t.schedule(new TimerTask { def run = { terminate; timeout = true } }, time.ms)
       
   409         Some(t)
       
   410       }
       
   411       else None
       
   412 
       
   413     def join: (String, String, Int) = {
       
   414       val (out, err, rc) = result.join
       
   415       args_file.delete
       
   416       timer.map(_.cancel())
       
   417 
       
   418       val err1 =
       
   419         if (rc == 130)
       
   420           (if (err.isEmpty || err.endsWith("\n")) err else err + "\n") +
       
   421           (if (timeout) "*** Timeout\n" else "*** Interrupt\n")
       
   422         else err
       
   423       (out, err1, rc)
       
   424     }
   431   }
   425   }
   432 
   426 
   433 
   427 
   434   /* log files and corresponding heaps */
   428   /* log files and corresponding heaps */
   435 
   429 
   519     // scheduler loop
   513     // scheduler loop
   520     case class Result(current: Boolean, heap: String, rc: Int)
   514     case class Result(current: Boolean, heap: String, rc: Int)
   521 
   515 
   522     @tailrec def loop(
   516     @tailrec def loop(
   523       pending: Session.Queue,
   517       pending: Session.Queue,
   524       running: Map[String, Job],
   518       running: Map[String, (String, Job)],
   525       results: Map[String, Result]): Map[String, Result] =
   519       results: Map[String, Result]): Map[String, Result] =
   526     {
   520     {
   527       if (pending.is_empty) results
   521       if (pending.is_empty) results
   528       else
   522       else
   529         running.find({ case (_, job) => job.is_finished }) match {
   523         running.find({ case (_, (_, job)) => job.is_finished }) match {
   530           case Some((name, job)) =>
   524           case Some((name, (parent_heap, job))) =>
   531             // finish job
   525             // finish job
   532 
   526 
   533             val (out, err, rc) = job.join
   527             val (out, err, rc) = job.join
   534             echo(Library.trim_line(err))
   528             echo(Library.trim_line(err))
   535 
   529 
   538                 (output_dir + log(name)).file.delete
   532                 (output_dir + log(name)).file.delete
   539 
   533 
   540                 val sources = make_stamp(name)
   534                 val sources = make_stamp(name)
   541                 val heap = heap_stamp(job.output_path)
   535                 val heap = heap_stamp(job.output_path)
   542                 File.write_gzip(output_dir + log_gz(name),
   536                 File.write_gzip(output_dir + log_gz(name),
   543                   sources + "\n" + job.parent_heap + "\n" + heap + "\n" + out)
   537                   sources + "\n" + parent_heap + "\n" + heap + "\n" + out)
   544 
   538 
   545                 heap
   539                 heap
   546               }
   540               }
   547               else {
   541               else {
   548                 (output_dir + Path.basic(name)).file.delete
   542                 (output_dir + Path.basic(name)).file.delete
   593                   loop(pending - name, running, results + (name -> Result(true, heap, 0)))
   587                   loop(pending - name, running, results + (name -> Result(true, heap, 0)))
   594                 else if (no_build)
   588                 else if (no_build)
   595                   loop(pending - name, running, results + (name -> Result(false, heap, 1)))
   589                   loop(pending - name, running, results + (name -> Result(false, heap, 1)))
   596                 else if (parent_result.rc == 0) {
   590                 else if (parent_result.rc == 0) {
   597                   echo((if (do_output) "Building " else "Running ") + name + " ...")
   591                   echo((if (do_output) "Building " else "Running ") + name + " ...")
   598                   val job =
   592                   val job = new Job(name, info, output, do_output, verbose, browser_info)
   599                     start_job(name, info, parent_result.heap, output, do_output,
   593                   loop(pending, running + (name -> (parent_result.heap, job)), results)
   600                       info.options, verbose, browser_info)
       
   601                   loop(pending, running + (name -> job), results)
       
   602                 }
   594                 }
   603                 else {
   595                 else {
   604                   echo(name + " CANCELLED")
   596                   echo(name + " CANCELLED")
   605                   loop(pending - name, running, results + (name -> Result(false, heap, 1)))
   597                   loop(pending - name, running, results + (name -> Result(false, heap, 1)))
   606                 }
   598                 }