some actual build function on ML side;
authorwenzelm
Sat, 21 Jul 2012 16:41:55 +0200
changeset 48418 1a634f9614fb
parent 48417 bb1d4ec90f30
child 48419 6d7b6e47f3ef
some actual build function on ML side; further imitation of "usedir" shell script;
src/Pure/General/file.scala
src/Pure/IsaMakefile
src/Pure/ROOT.ML
src/Pure/System/build.ML
src/Pure/System/build.scala
src/Pure/System/isabelle_system.scala
src/Pure/System/session.ML
--- a/src/Pure/General/file.scala	Sat Jul 21 12:57:31 2012 +0200
+++ b/src/Pure/General/file.scala	Sat Jul 21 16:41:55 2012 +0200
@@ -83,10 +83,16 @@
 
   /* misc */
 
-  def with_tmp_file[A](prefix: String)(body: JFile => A): A =
+  def tmp_file(prefix: String): JFile =
   {
     val file = JFile.createTempFile(prefix, null)
     file.deleteOnExit
+    file
+  }
+
+  def with_tmp_file[A](prefix: String)(body: JFile => A): A =
+  {
+    val file = tmp_file(prefix)
     try { body(file) } finally { file.delete }
   }
 
--- a/src/Pure/IsaMakefile	Sat Jul 21 12:57:31 2012 +0200
+++ b/src/Pure/IsaMakefile	Sat Jul 21 16:41:55 2012 +0200
@@ -189,6 +189,7 @@
   Syntax/syntax_trans.ML				\
   Syntax/term_position.ML				\
   System/invoke_scala.ML				\
+  System/build.ML					\
   System/isabelle_process.ML				\
   System/isabelle_system.ML				\
   System/isar.ML					\
--- a/src/Pure/ROOT.ML	Sat Jul 21 12:57:31 2012 +0200
+++ b/src/Pure/ROOT.ML	Sat Jul 21 16:41:55 2012 +0200
@@ -268,6 +268,7 @@
 (* Isabelle/Isar system *)
 
 use "System/session.ML";
+use "System/build.ML";
 use "System/system_channel.ML";
 use "System/isabelle_process.ML";
 use "System/invoke_scala.ML";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/System/build.ML	Sat Jul 21 16:41:55 2012 +0200
@@ -0,0 +1,29 @@
+(*  Title:      Pure/System/build.ML
+    Author:     Makarius
+
+Build Isabelle sessions.
+*)
+
+signature BUILD =
+sig
+  val build: string -> unit
+end;
+
+structure Build: BUILD =
+struct
+
+fun build args_file =
+  let
+    val (build_images, (parent, (name, theories))) =
+      File.read (Path.explode args_file) |> YXML.parse_body |>
+        let open XML.Decode in pair bool (pair string (pair string (list string))) end;
+
+    val _ = Session.init false parent name;  (* FIXME reset!? *)
+    val _ = Thy_Info.use_thys theories;
+    val _ = Session.finish ();
+
+    val _ = if build_images then () else quit ();
+  in () end
+  handle exn => (Output.error_msg (ML_Compiler.exn_message exn); exit 1);
+
+end;
--- a/src/Pure/System/build.scala	Sat Jul 21 12:57:31 2012 +0200
+++ b/src/Pure/System/build.scala	Sat Jul 21 16:41:55 2012 +0200
@@ -40,9 +40,10 @@
 
     sealed case class Info(
       dir: Path,
+      parent: Option[String],
       description: String,
       options: Options,
-      theories: List[(Options, String)],
+      theories: List[(Options, List[String])],
       files: List[String])
 
     object Queue
@@ -56,7 +57,7 @@
     {
       def defined(name: String): Boolean = keys.isDefinedAt(name)
 
-      def + (key: Key, info: Info, parent: Option[String]): Queue =
+      def + (key: Key, info: Info): Queue =
       {
         val keys1 =
           if (defined(key.name)) error("Duplicate session: " + quote(key.name))
@@ -64,7 +65,7 @@
 
         val graph1 =
           try {
-            graph.new_node(key, info).add_deps_acyclic(key, parent.toList.map(keys(_)))
+            graph.new_node(key, info).add_deps_acyclic(key, info.parent.toList.map(keys(_)))
           }
           catch {
             case exn: Graph.Cycles[_] =>
@@ -184,10 +185,11 @@
           }
 
         val key = Session.Key(full_name, entry.order)
-        val info = Session.Info(dir + path, entry.description, entry.options,
-          entry.theories.map({ case (x, ys) => ys.map(y => (x, y)) }).flatten, entry.files)
+        val info =
+          Session.Info(dir + path, entry.parent,
+            entry.description, entry.options, entry.theories, entry.files)
 
-        queue1 + (key, info, entry.parent)
+        queue1 + (key, info)
       }
       catch {
         case ERROR(msg) =>
@@ -244,14 +246,57 @@
   private def echo(msg: String) { java.lang.System.out.println(msg) }
   private def echo_n(msg: String) { java.lang.System.out.print(msg) }
 
-  private def build_job(build_images: Boolean,  // FIXME
-    key: Session.Key, info: Session.Info): Isabelle_System.Bash_Job =
+  class Build_Job(cwd: JFile, env: Map[String, String], script: String, args: String)
   {
+    private val args_file = File.tmp_file("args")
+    private val env1 = env + ("ARGS_FILE" -> Isabelle_System.posix_path(args_file.getPath))
+    File.write(args_file, args)
+
+    private val (thread, result) = Simple_Thread.future("build_job") {
+      Isabelle_System.bash_env(cwd, env1, script)
+    }
+
+    def terminate: Unit = thread.interrupt
+    def is_finished: Boolean = result.is_finished
+    def join: (String, String, Int) = { val rc = result.join; args_file.delete; rc }
+  }
+
+  private def build_job(build_images: Boolean, name: String, info: Session.Info): Build_Job =
+  {
+    val parent = info.parent.getOrElse("")
+
     val cwd = info.dir.file
+    val env = Map("INPUT" -> parent, "TARGET" -> name)
     val script =
-      if (is_pure(key.name)) "./build " + (if (build_images) "-b " else "") + key.name
-      else """echo "Bad session" >&2; exit 2"""
-    new Isabelle_System.Bash_Job(cwd, null, script)
+      if (is_pure(name)) "./build " + (if (build_images) "-b " else "") + name
+      else {
+        """
+        . "$ISABELLE_HOME/lib/scripts/timestart.bash"
+        """ +
+          (if (build_images)
+            """ "$ISABELLE_PROCESS" -e "Build.build \"$ARGS_FILE\";" -q -w "$INPUT" "$TARGET" """
+          else
+            """ "$ISABELLE_PROCESS" -e "Build.build \"$ARGS_FILE\";" -r -q "$INPUT" """) +
+        """
+        RC="$?"
+
+        . "$ISABELLE_HOME/lib/scripts/timestop.bash"
+
+        if [ "$RC" -eq 0 ]; then
+          echo "Finished $TARGET ($TIMES_REPORT)" >&2
+        fi
+
+        exit "$RC"
+        """
+      }
+    val args_xml =
+    {
+      import XML.Encode._
+      def symbol_string: T[String] = (s => string(Symbol.encode(s)))
+      pair(bool, pair(symbol_string, pair(symbol_string, list(symbol_string))))(
+        build_images, (parent, (name, info.theories.map(_._2).flatten)))
+    }
+    new Build_Job(cwd, env, script, YXML.string_of_body(args_xml))
   }
 
   def build(all_sessions: Boolean, build_images: Boolean, list_only: Boolean,
@@ -292,10 +337,10 @@
       {
         if (list_only) { echo(key.name + " in " + info.dir); 0 }
         else {
-          if (build_images) echo("Building " + key.name + "...")
-          else echo("Running " + key.name + "...")
+          if (build_images) echo("Building " + key.name + " ...")
+          else echo("Running " + key.name + " ...")
 
-          val (out, err, rc) = build_job(build_images, key, info).join
+          val (out, err, rc) = build_job(build_images, key.name, info).join
           echo_n(err)
 
           val log = log_dir + Path.basic(key.name)
--- a/src/Pure/System/isabelle_system.scala	Sat Jul 21 12:57:31 2012 +0200
+++ b/src/Pure/System/isabelle_system.scala	Sat Jul 21 16:41:55 2012 +0200
@@ -260,17 +260,6 @@
 
   def bash(script: String): (String, String, Int) = bash_env(null, null, script)
 
-  class Bash_Job(cwd: JFile, env: Map[String, String], script: String)
-  {
-    private val (thread, result) = Simple_Thread.future("bash_job") { bash_env(cwd, env, script) }
-
-    def terminate: Unit = thread.interrupt
-    def is_finished: Boolean = result.is_finished
-    def join: (String, String, Int) = result.join
-
-    override def toString: String = if (is_finished) join._3.toString else "<running>"
-  }
-
 
   /* system tools */
 
--- a/src/Pure/System/session.ML	Sat Jul 21 12:57:31 2012 +0200
+++ b/src/Pure/System/session.ML	Sat Jul 21 16:41:55 2012 +0200
@@ -9,6 +9,7 @@
   val id: unit -> string list
   val name: unit -> string
   val welcome: unit -> string
+  val init: bool -> string -> string -> unit
   val use_dir: string -> string -> bool -> string list -> bool -> bool ->
     string -> bool -> string list -> string -> string -> bool * string ->
     string -> int -> bool -> bool -> int -> int -> int -> int -> unit