src/Pure/Tools/build_cluster.scala
changeset 78408 092f1e435b3a
parent 78401 822ddccda899
child 78413 6f3066a9b609
equal deleted inserted replaced
78407:b262ecc98319 78408:092f1e435b3a
     8 package isabelle
     8 package isabelle
     9 
     9 
    10 
    10 
    11 object Build_Cluster {
    11 object Build_Cluster {
    12   object Host {
    12   object Host {
    13     val PORT = "port"
    13     private val rfc822_specials = """()<>@,;:\"[]"""
    14     val JOBS = "jobs"
    14 
    15     val NUMA = "numa"
    15     private val USER = "user"
       
    16     private val PORT = "port"
       
    17     private val JOBS = "jobs"
       
    18     private val NUMA = "numa"
       
    19 
       
    20     val parameters: Options =
       
    21       Options.inline("""
       
    22         option user : string = ""   -- "explicit SSH user"
       
    23         option port : int = 0       -- "explicit SSH port"
       
    24         option jobs : int = 1       -- "maximum number of parallel jobs"
       
    25         option numa : bool = false  -- "cyclic shuffling of NUMA CPU nodes"
       
    26       """)
       
    27 
       
    28     def is_parameter(spec: Options.Spec): Boolean = parameters.defined(spec.name)
       
    29 
       
    30     lazy val test_options: Options = Options.init0()
    16 
    31 
    17     def apply(
    32     def apply(
    18       host: String,
    33       host: String = "",
    19       user: String = "",
    34       user: String = parameters.string(USER),
    20       port: Int = 0,
    35       port: Int = parameters.int(PORT),
    21       jobs: Int = 1,
    36       jobs: Int = parameters.int(JOBS),
    22       numa: Boolean = false,
    37       numa: Boolean = parameters.bool(NUMA),
    23       options: List[Options.Spec] = Nil
    38       options: List[Options.Spec] = Nil
    24     ): Host = new Host(host, user, port, jobs, numa, options)
    39     ): Host = new Host(host, user, port, jobs, numa, options)
    25 
    40 
    26     def parse(str: String): Host = Host(host = str)  // FIXME proper parse
    41     def parse(str: String): Host = {
       
    42       val host = str.takeWhile(c => !rfc822_specials.contains(c))
       
    43       val (params, options) =
       
    44         try {
       
    45           val rest = {
       
    46             val n = str.length
       
    47             val m = host.length
       
    48             val l =
       
    49               if (m == n) n
       
    50               else if (str(m) == ':') m + 1
       
    51               else error("Colon (:) expected after host name")
       
    52             str.substring(l)
       
    53           }
       
    54           val (specs1, specs2) = Options.parse_specs(rest).partition(is_parameter)
       
    55           (parameters ++ specs1, { test_options ++ specs2; specs2 })
       
    56         }
       
    57         catch {
       
    58           case ERROR(msg) =>
       
    59             cat_error(msg, "The error(s) above occurred in host specification " + quote(str))
       
    60         }
       
    61       apply(host = host,
       
    62         user = params.string(USER),
       
    63         port = params.int(PORT),
       
    64         jobs = params.int(JOBS),
       
    65         numa = params.bool(NUMA),
       
    66         options = options)
       
    67     }
    27   }
    68   }
    28 
    69 
    29   final class Host private(
    70   final class Host private(
    30     host: String,
    71     host: String,
    31     user: String,
    72     user: String,
    32     port: Int,
    73     port: Int,
    33     jobs: Int,
    74     jobs: Int,
    34     numa: Boolean,
    75     numa: Boolean,
    35     options: List[Options.Spec]
    76     options: List[Options.Spec]
    36   ) {
    77   ) {
    37     require(host.nonEmpty, "Undefined host name")
    78     override def toString: String = print
    38 
    79 
    39     override def toString: String = print
       
    40     def print: String = {
    80     def print: String = {
    41       val props =
    81       val params =
    42         List(
    82         List(
       
    83           if (user.isEmpty) "" else Properties.Eq(Host.USER, user),
    43           if (port == 0) "" else Properties.Eq(Host.PORT, port.toString),
    84           if (port == 0) "" else Properties.Eq(Host.PORT, port.toString),
    44           if (jobs == 1) "" else Properties.Eq(Host.JOBS, jobs.toString),
    85           if (jobs == 1) "" else Properties.Eq(Host.JOBS, jobs.toString),
    45           if_proper(numa, Host.NUMA)
    86           if_proper(numa, Host.NUMA)
    46         ).filter(_.nonEmpty)
    87         ).filter(_.nonEmpty)
    47       val rest = (props ::: options).mkString(",")
    88       val rest = (params ::: options).mkString(",")
    48       if_proper(user, user + "@") + host + if_proper(rest, ":" + rest)
    89 
       
    90       if (host.isEmpty) ":" + rest
       
    91       else if (rest.isEmpty) host
       
    92       else host + ":" + rest
    49     }
    93     }
    50 
    94 
    51     def open_ssh_session(options: Options): SSH.Session =
    95     def open_ssh_session(options: Options): SSH.Session =
    52       SSH.open_session(options, host, port = port, user = user)
    96       SSH.open_session(options, host, port = port, user = user)
    53   }
    97   }