src/Pure/Tools/build_cluster.scala
changeset 78436 5f5f909206bb
parent 78434 b4ec7ea073da
child 78440 126a12483c67
--- a/src/Pure/Tools/build_cluster.scala	Sat Jul 22 16:01:46 2023 +0200
+++ b/src/Pure/Tools/build_cluster.scala	Sat Jul 22 20:37:56 2023 +0200
@@ -3,6 +3,10 @@
 
 Management of build cluster: independent ssh hosts with access to shared
 PostgreSQL server.
+
+NB: extensible classes allow quite different implementations in user-space,
+via the service class Build.Engine and overridable methods
+Build.Engine.open_build_process(), Build_Process.open_build_cluster().
 */
 
 package isabelle
@@ -83,7 +87,7 @@
     }
   }
 
-  final class Host private(
+  class Host(
     val name: String,
     val user: String,
     val port: Int,
@@ -91,46 +95,45 @@
     val numa: Boolean,
     val options: List[Options.Spec]
   ) {
-    def is_local: Boolean = SSH.is_local(name)
+    host =>
+
+    def is_local: Boolean = SSH.is_local(host.name)
 
     override def toString: String = print
 
     def print: String = {
       val params =
         List(
-          if (user.isEmpty) "" else Properties.Eq(Host.USER, Host.print_name(user)),
-          if (port == 0) "" else Properties.Eq(Host.PORT, port.toString),
-          if (jobs == 1) "" else Properties.Eq(Host.JOBS, jobs.toString),
-          if_proper(numa, Host.NUMA)
+          if (host.user.isEmpty) "" else Properties.Eq(Host.USER, Host.print_name(host.user)),
+          if (host.port == 0) "" else Properties.Eq(Host.PORT, host.port.toString),
+          if (host.jobs == 1) "" else Properties.Eq(Host.JOBS, host.jobs.toString),
+          if_proper(host.numa, Host.NUMA)
         ).filter(_.nonEmpty)
-      val rest = (params ::: options.map(Host.print_option)).mkString(",")
+      val rest = (params ::: host.options.map(Host.print_option)).mkString(",")
 
-      SSH.print_local(name) + if_proper(rest, ":" + rest)
+      SSH.print_local(host.name) + if_proper(rest, ":" + rest)
     }
 
-    def message(msg: String): String = "Host " + quote(name) + if_proper(msg, ": " + msg)
+    def message(msg: String): String = "Host " + quote(host.name) + if_proper(msg, ": " + msg)
+
+    def open_session(options: Options, progress: Progress = new Progress): Session = {
+      val session_options = options ++ host.options
+      val ssh = SSH.open_session(session_options, host.name, port = host.port, user = host.user)
+      new Session(host, session_options, ssh, progress)
+    }
   }
 
 
-  /* remote sessions */
+  /* SSH sessions */
 
-  object Session {
-    def open(options: Options, host: Host, progress: Progress = new Progress): Session = {
-      val ssh_options = options ++ host.options
-      val ssh = SSH.open_session(ssh_options, host.name, port = host.port, user = host.user)
-      new Session(host, ssh, progress)
-    }
-  }
-
-  final class Session private(
+  class Session(
     val host: Host,
-    val ssh: SSH.Session,
+    val options: Options,
+    val ssh: SSH.System,
     val progress: Progress
   ) extends AutoCloseable {
     override def toString: String = ssh.toString
 
-    def options: Options = ssh.options
-
     def start(): Process_Result = {
       Process_Result.ok  // FIXME
     }
@@ -138,7 +141,7 @@
     override def close(): Unit = ssh.close()
   }
 
-  sealed case class Result(host: Host, process_result: Exn.Result[Process_Result]) {
+  class Result(val host: Host, val process_result: Exn.Result[Process_Result]) {
     def ok: Boolean =
       process_result match {
         case Exn.Res(res) => res.ok
@@ -149,7 +152,9 @@
 
   /* build clusters */
 
-  val none: Build_Cluster = new No_Build_Cluster
+  object none extends Build_Cluster {
+    override def toString: String = "Build_Cluster.none"
+  }
 
   def make(build_context: Build.Context, progress: Progress = new Progress): Build_Cluster = {
     val remote_hosts = build_context.build_hosts.filterNot(_.is_local)
@@ -169,14 +174,10 @@
   override def close(): Unit = ()
 }
 
-final class No_Build_Cluster extends Build_Cluster {
-  override def toString: String = "Build_Cluster.none"
-}
-
 class Remote_Build_Cluster(
-  build_context: Build.Context,
-  remote_hosts: List[Build_Cluster.Host],
-  progress: Progress = new Progress
+  val build_context: Build.Context,
+  val remote_hosts: List[Build_Cluster.Host],
+  val progress: Progress = new Progress
 ) extends Build_Cluster {
   require(remote_hosts.nonEmpty && !remote_hosts.exists(_.is_local), "remote hosts required")
 
@@ -194,7 +195,7 @@
     val attempts =
       Par_List.map((host: Build_Cluster.Host) =>
         progress.capture(
-          Build_Cluster.Session.open(build_context.build_options, host, progress = progress),
+          host.open_session(build_context.build_options, progress = progress),
           msg = host.message("open ..."),
           err = exn => host.message("failed to open\n" + Exn.message(exn))),
         remote_hosts, thread = true)