proper Build_Cluster.Host.parse for parameters and system options;
clarified Build_Cluster.Host: empty "host" means local;
--- a/src/Pure/Tools/build.scala Wed Jul 19 15:40:02 2023 +0200
+++ b/src/Pure/Tools/build.scala Wed Jul 19 15:56:32 2023 +0200
@@ -304,7 +304,7 @@
Options are:
-B NAME include session NAME and all descendants
-D DIR include session directory and select its sessions
- -H HOST add host for distrubuted build
+ -H HOST additional host for distributed build ("NAME:PARAMETERS")
-N cyclic shuffling of NUMA CPU nodes (performance tuning)
-P DIR enable HTML/PDF presentation in directory (":" for default)
-R refer to requirements of selected sessions
@@ -327,10 +327,14 @@
Build and manage Isabelle sessions: ML heaps, session databases, documents.
+ Parameters for host specifications (option -H), apart from system options:
+""" + Library.indent_lines(4, Build_Cluster.Host.parameters.print()) +
+"""
+
Notable system options: see "isabelle options -l -t build"
Notable system settings:
-""" + Library.indent_lines(4, Build_Log.Settings.show()) + "\n",
+""" + Library.indent_lines(4, Build_Log.Settings.show()) + "\n",
"B:" -> (arg => base_sessions += arg),
"D:" -> (arg => select_dirs += Path.explode(arg)),
"H:" -> (arg => build_hosts += Build_Cluster.Host.parse(arg)),
--- a/src/Pure/Tools/build_cluster.scala Wed Jul 19 15:40:02 2023 +0200
+++ b/src/Pure/Tools/build_cluster.scala Wed Jul 19 15:56:32 2023 +0200
@@ -10,20 +10,61 @@
object Build_Cluster {
object Host {
- val PORT = "port"
- val JOBS = "jobs"
- val NUMA = "numa"
+ private val rfc822_specials = """()<>@,;:\"[]"""
+
+ private val USER = "user"
+ private val PORT = "port"
+ private val JOBS = "jobs"
+ private val NUMA = "numa"
+
+ val parameters: Options =
+ Options.inline("""
+ option user : string = "" -- "explicit SSH user"
+ option port : int = 0 -- "explicit SSH port"
+ option jobs : int = 1 -- "maximum number of parallel jobs"
+ option numa : bool = false -- "cyclic shuffling of NUMA CPU nodes"
+ """)
+
+ def is_parameter(spec: Options.Spec): Boolean = parameters.defined(spec.name)
+
+ lazy val test_options: Options = Options.init0()
def apply(
- host: String,
- user: String = "",
- port: Int = 0,
- jobs: Int = 1,
- numa: Boolean = false,
+ host: String = "",
+ user: String = parameters.string(USER),
+ port: Int = parameters.int(PORT),
+ jobs: Int = parameters.int(JOBS),
+ numa: Boolean = parameters.bool(NUMA),
options: List[Options.Spec] = Nil
): Host = new Host(host, user, port, jobs, numa, options)
- def parse(str: String): Host = Host(host = str) // FIXME proper parse
+ def parse(str: String): Host = {
+ val host = str.takeWhile(c => !rfc822_specials.contains(c))
+ val (params, options) =
+ try {
+ val rest = {
+ val n = str.length
+ val m = host.length
+ val l =
+ if (m == n) n
+ else if (str(m) == ':') m + 1
+ else error("Colon (:) expected after host name")
+ str.substring(l)
+ }
+ val (specs1, specs2) = Options.parse_specs(rest).partition(is_parameter)
+ (parameters ++ specs1, { test_options ++ specs2; specs2 })
+ }
+ catch {
+ case ERROR(msg) =>
+ cat_error(msg, "The error(s) above occurred in host specification " + quote(str))
+ }
+ apply(host = host,
+ user = params.string(USER),
+ port = params.int(PORT),
+ jobs = params.int(JOBS),
+ numa = params.bool(NUMA),
+ options = options)
+ }
}
final class Host private(
@@ -34,18 +75,21 @@
numa: Boolean,
options: List[Options.Spec]
) {
- require(host.nonEmpty, "Undefined host name")
+ override def toString: String = print
- override def toString: String = print
def print: String = {
- val props =
+ val params =
List(
+ if (user.isEmpty) "" else Properties.Eq(Host.USER, 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)
).filter(_.nonEmpty)
- val rest = (props ::: options).mkString(",")
- if_proper(user, user + "@") + host + if_proper(rest, ":" + rest)
+ val rest = (params ::: options).mkString(",")
+
+ if (host.isEmpty) ":" + rest
+ else if (rest.isEmpty) host
+ else host + ":" + rest
}
def open_ssh_session(options: Options): SSH.Session =