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 |
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 } |