| author | Fabian Huch <huch@in.tum.de> | 
| Wed, 06 Aug 2025 16:51:58 +0200 | |
| changeset 82915 | b7422567c507 | 
| parent 82466 | d5ef492dd673 | 
| permissions | -rw-r--r-- | 
| 80246 | 1 | /* Title: Pure/Build/build_manager.scala | 
| 2 | Author: Fabian Huch, TU Muenchen | |
| 3 | ||
| 4 | Isabelle manager for automated and quasi-interactive builds, with web frontend. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 10 | import scala.collection.mutable | |
| 11 | import scala.annotation.tailrec | |
| 12 | ||
| 13 | ||
| 14 | object Build_Manager {
 | |
| 80344 | 15 | /** task state synchronized via db **/ | 
| 80246 | 16 | |
| 17 |   object Component {
 | |
| 18 | def parse(s: String): Component = | |
| 19 |       space_explode('/', s) match {
 | |
| 80546 
d507229c5771
proper parse (amending dd86d35375a7);
 Fabian Huch <huch@in.tum.de> parents: 
80545diff
changeset | 20 | case name :: Nil => Component(name) | 
| 80246 | 21 | case name :: rev :: Nil => Component(name, rev) | 
| 22 |         case _ => error("Malformed component: " + quote(s))
 | |
| 23 | } | |
| 24 | ||
| 80543 | 25 | val Isabelle = "Isabelle" | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 26 | val AFP = "AFP" | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 27 | |
| 80543 | 28 | def isabelle(rev: String = "") = Component(Isabelle, rev) | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 29 | def afp(rev: String = "") = Component(AFP, rev) | 
| 80246 | 30 | } | 
| 31 | ||
| 32 |   case class Component(name: String, rev: String = "") {
 | |
| 80542 
dd86d35375a7
log and display components with empty (unknown) revisions to indicate that they are present;
 Fabian Huch <huch@in.tum.de> parents: 
80541diff
changeset | 33 | override def toString: String = name + if_proper(rev, "/" + rev) | 
| 80407 | 34 | |
| 35 | def is_local: Boolean = rev.isEmpty | |
| 80246 | 36 | } | 
| 37 | ||
| 38 |   sealed trait Build_Config {
 | |
| 39 | def name: String | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 40 | def extra_components: List[Component] | 
| 80246 | 41 | def fresh_build: Boolean | 
| 80319 
f83f402bc9a4
use build_cluster in ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80315diff
changeset | 42 | def build_cluster: Boolean | 
| 80411 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 43 | def command(job_url: Url, build_hosts: List[Build_Cluster.Host]): String | 
| 80246 | 44 | } | 
| 45 | ||
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 46 |   object CI_Build {
 | 
| 80412 
a7f8249533e9
moved ci_build module to build_ci;
 Fabian Huch <huch@in.tum.de> parents: 
80411diff
changeset | 47 | def apply(job: Build_CI.Job): CI_Build = | 
| 80319 
f83f402bc9a4
use build_cluster in ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80315diff
changeset | 48 | CI_Build(job.name, job.hosts.build_cluster, job.components.map(Component(_, "default"))) | 
| 80416 | 49 | |
| 50 | def task(job: Build_CI.Job): Task = | |
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 51 | Task(CI_Build(job), job.hosts.hosts_spec, job.timeout, other_settings = job.other_settings, | 
| 80416 | 52 | isabelle_rev = "default") | 
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 53 | } | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 54 | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 55 | case class CI_Build(name: String, build_cluster: Boolean, extra_components: List[Component]) | 
| 80319 
f83f402bc9a4
use build_cluster in ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80315diff
changeset | 56 |     extends Build_Config {
 | 
| 80246 | 57 | def fresh_build: Boolean = true | 
| 80411 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 58 | def command(job_url: Url, build_hosts: List[Build_Cluster.Host]): String = | 
| 80412 
a7f8249533e9
moved ci_build module to build_ci;
 Fabian Huch <huch@in.tum.de> parents: 
80411diff
changeset | 59 | " build_ci" + | 
| 80411 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 60 | " -u " + Bash.string(job_url.toString) + | 
| 80319 
f83f402bc9a4
use build_cluster in ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80315diff
changeset | 61 | if_proper(build_cluster, build_hosts.map(host => " -H " + Bash.string(host.print)).mkString) + | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 62 | " " + name | 
| 80246 | 63 | } | 
| 64 | ||
| 65 |   object User_Build {
 | |
| 66 | val name: String = "user" | |
| 67 | } | |
| 68 | ||
| 69 | case class User_Build( | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 70 | user: String, | 
| 80246 | 71 | afp_rev: Option[String] = None, | 
| 72 | prefs: List[Options.Spec] = Nil, | |
| 73 | requirements: Boolean = false, | |
| 74 | all_sessions: Boolean = false, | |
| 75 | base_sessions: List[String] = Nil, | |
| 76 | exclude_session_groups: List[String] = Nil, | |
| 77 | exclude_sessions: List[String] = Nil, | |
| 78 | session_groups: List[String] = Nil, | |
| 79 | sessions: List[String] = Nil, | |
| 80 | build_heap: Boolean = false, | |
| 81 | clean_build: Boolean = false, | |
| 82 | export_files: Boolean = false, | |
| 83 | fresh_build: Boolean = false, | |
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 84 | presentation: Boolean = false, | 
| 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 85 | verbose: Boolean = false | 
| 80246 | 86 |   ) extends Build_Config {
 | 
| 87 | def name: String = User_Build.name | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 88 | def extra_components: List[Component] = afp_rev.map(Component.afp).toList | 
| 80319 
f83f402bc9a4
use build_cluster in ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80315diff
changeset | 89 | def build_cluster: Boolean = true | 
| 80411 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 90 |     def command(job_url: Url, build_hosts: List[Build_Cluster.Host]): String = {
 | 
| 80246 | 91 | " build" + | 
| 92 | if_proper(afp_rev, " -A:") + | |
| 93 | base_sessions.map(session => " -B " + Bash.string(session)).mkString + | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 94 | build_hosts.map(host => " -H " + Bash.string(host.print)).mkString + | 
| 80246 | 95 | if_proper(presentation, " -P:") + | 
| 96 | if_proper(requirements, " -R") + | |
| 80422 | 97 | exclude_session_groups.map(session => " -X " + Bash.string(session)).mkString + | 
| 80246 | 98 | if_proper(all_sessions, " -a") + | 
| 99 | if_proper(build_heap, " -b") + | |
| 100 | if_proper(clean_build, " -c") + | |
| 101 | if_proper(export_files, " -e") + | |
| 102 | if_proper(fresh_build, " -f") + | |
| 80422 | 103 | session_groups.map(session => " -g " + Bash.string(session)).mkString + | 
| 80246 | 104 | Options.Spec.bash_strings(prefs, bg = true) + | 
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 105 | if_proper(verbose, " -v") + | 
| 80422 | 106 | exclude_sessions.map(session => " -x " + Bash.string(session)).mkString + | 
| 80246 | 107 | sessions.map(session => " " + Bash.string(session)).mkString | 
| 108 | } | |
| 109 | } | |
| 110 | ||
| 111 |   enum Priority { case low, normal, high }
 | |
| 112 | ||
| 80339 | 113 |   object Build {
 | 
| 114 | def name(kind: String, id: Long): String = kind + "/" + id | |
| 115 | } | |
| 80410 | 116 | |
| 80339 | 117 | sealed trait Build extends Name.T | 
| 80246 | 118 | |
| 119 | sealed case class Task( | |
| 120 | build_config: Build_Config, | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 121 | hosts_spec: String, | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 122 | timeout: Time, | 
| 80414 
4b10ae56ed01
add Isabelle settings to managed tasks and ci jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80412diff
changeset | 123 | other_settings: List[String] = Nil, | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 124 | uuid: UUID.T = UUID.random(), | 
| 80246 | 125 | submit_date: Date = Date.now(), | 
| 126 | priority: Priority = Priority.normal, | |
| 127 | isabelle_rev: String = "" | |
| 80339 | 128 |   ) extends Build {
 | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 129 | def name: String = uuid.toString | 
| 80246 | 130 | def kind: String = build_config.name | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 131 |     def user: Option[String] = Some(build_config).collect { case build: User_Build => build.user }
 | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 132 | def components: List[Component] = Component.isabelle(isabelle_rev) :: extra_components | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 133 | def extra_components: List[Component] = build_config.extra_components | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 134 | |
| 80319 
f83f402bc9a4
use build_cluster in ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80315diff
changeset | 135 | def build_cluster = build_config.build_cluster | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 136 | def build_hosts: List[Build_Cluster.Host] = | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 137 | Build_Cluster.Host.parse(Registry.global, hosts_spec) | 
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 138 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 139 | def >(t: Task): Boolean = | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 140 | priority.ordinal > t.priority.ordinal || | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 141 | (priority == t.priority && submit_date.time < t.submit_date.time) | 
| 80246 | 142 | } | 
| 143 | ||
| 144 | sealed case class Job( | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 145 | uuid: UUID.T, | 
| 80246 | 146 | kind: String, | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 147 | id: Long, | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 148 | build_cluster: Boolean, | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 149 | hostnames: List[String], | 
| 80246 | 150 | components: List[Component], | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 151 | timeout: Time, | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 152 | user: Option[String], | 
| 80246 | 153 | start_date: Date = Date.now(), | 
| 154 | cancelled: Boolean = false | |
| 80339 | 155 |   ) extends Build { def name: String = Build.name(kind, id) }
 | 
| 80246 | 156 | |
| 157 |   object Status {
 | |
| 158 |     def from_result(result: Process_Result): Status = {
 | |
| 159 | if (result.ok) Status.ok | |
| 160 | else if (result.interrupted) Status.cancelled | |
| 161 | else Status.failed | |
| 162 | } | |
| 163 | } | |
| 164 | ||
| 80502 | 165 |   enum Status { case ok, cancelled, aborted, failed }
 | 
| 80246 | 166 | |
| 167 | sealed case class Result( | |
| 168 | kind: String, | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 169 | id: Long, | 
| 80246 | 170 | status: Status, | 
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 171 | uuid: Option[UUID.T], | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 172 | build_host: String, | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 173 | start_date: Date, | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 174 | end_date: Option[Date], | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 175 | isabelle_version: Option[String], | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 176 | afp_version: Option[String], | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 177 | user: Option[String], | 
| 80246 | 178 | serial: Long = 0, | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 179 |   ) extends Build {
 | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 180 | def name: String = Build.name(kind, id) | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 181 | def components: List[Component] = | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 182 | isabelle_version.map(Component.isabelle).toList ::: afp_version.map(Component.afp).toList | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 183 | } | 
| 80246 | 184 | |
| 185 |   object State {
 | |
| 186 | def max_serial(serials: Iterable[Long]): Long = serials.maxOption.getOrElse(0L) | |
| 187 |     def inc_serial(serial: Long): Long = {
 | |
| 188 | require(serial < Long.MaxValue, "number overflow") | |
| 189 | serial + 1 | |
| 190 | } | |
| 191 | ||
| 80272 | 192 | type Pending = Name.Data[Task] | 
| 193 | type Running = Name.Data[Job] | |
| 80246 | 194 | type Finished = Map[String, Result] | 
| 195 | } | |
| 196 | ||
| 197 | sealed case class State( | |
| 198 | serial: Long = 0, | |
| 199 | pending: State.Pending = Map.empty, | |
| 200 | running: State.Running = Map.empty, | |
| 201 | finished: State.Finished = Map.empty | |
| 202 |   ) {
 | |
| 203 | def next_serial: Long = State.inc_serial(serial) | |
| 204 | ||
| 205 | def add_pending(task: Task): State = copy(pending = pending + (task.name -> task)) | |
| 206 | def remove_pending(name: String): State = copy(pending = pending - name) | |
| 207 | ||
| 208 | def num_builds = running.size + finished.size | |
| 209 | ||
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 210 |     def next(build_hosts: List[Build_Cluster.Host]): Option[Task] = {
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 211 | val cluster_running = running.values.exists(_.build_cluster) | 
| 80346 | 212 | val available = build_hosts.map(_.hostname).toSet -- running.values.flatMap(_.hostnames).toSet | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 213 | val ready = | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 214 |         for {
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 215 | (_, task) <- pending | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 216 | if !task.build_cluster || !cluster_running | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 217 | if task.build_hosts.map(_.hostname).forall(available.contains) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 218 | } yield task | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 219 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 220 | if (ready.isEmpty) None | 
| 80246 | 221 |       else {
 | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 222 | val priority = ready.map(_.priority).maxBy(_.ordinal) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 223 | ready.filter(_.priority == priority).toList.sortBy(_.submit_date)(Date.Ordering).headOption | 
| 80246 | 224 | } | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 225 | } | 
| 80246 | 226 | |
| 227 | def add_running(job: Job): State = copy(running = running + (job.name -> job)) | |
| 228 | def remove_running(name: String): State = copy(running = running - name) | |
| 80468 | 229 | def cancel_running(name: String): State = | 
| 230 |       running.get(name) match {
 | |
| 231 | case Some(job) => copy(running = (running - name) + (name -> job.copy(cancelled = true))) | |
| 232 | case None => this | |
| 233 | } | |
| 80246 | 234 | |
| 235 | def add_finished(result: Result): State = copy(finished = finished + (result.name -> result)) | |
| 236 | ||
| 237 | lazy val kinds = ( | |
| 238 | pending.values.map(_.kind) ++ | |
| 239 | running.values.map(_.kind) ++ | |
| 240 | finished.values.map(_.kind)).toList.distinct | |
| 241 | ||
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 242 |     def next_id(kind: String): Long = {
 | 
| 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 243 | val serials = get_finished(kind).map(_.id) ::: get_running(kind).map(_.id) | 
| 80246 | 244 | State.inc_serial(State.max_serial(serials)) | 
| 245 | } | |
| 246 | ||
| 247 | def get_running(kind: String): List[Job] = | |
| 248 | (for ((_, job) <- running if job.kind == kind) yield job).toList | |
| 249 | ||
| 250 | def get_finished(kind: String): List[Result] = | |
| 251 | (for ((_, result) <- finished if result.kind == kind) yield result).toList | |
| 252 | ||
| 80339 | 253 | def get(name: String): Option[Build] = | 
| 80246 | 254 | pending.get(name).orElse(running.get(name)).orElse(finished.get(name)) | 
| 255 | ||
| 80339 | 256 | def get(uuid: UUID.T): Option[Build] = | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 257 | pending.values.find(_.uuid == uuid).orElse( | 
| 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 258 | running.values.find(_.uuid == uuid)).orElse( | 
| 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 259 | finished.values.find(_.uuid.contains(uuid))) | 
| 80246 | 260 | } | 
| 261 | ||
| 262 | ||
| 80344 | 263 | /** SQL data model **/ | 
| 80246 | 264 | |
| 265 |   object private_data extends SQL.Data("isabelle_build_manager") {
 | |
| 266 | /* tables */ | |
| 267 | ||
| 268 | override lazy val tables: SQL.Tables = | |
| 269 | SQL.Tables(State.table, Pending.table, Running.table, Finished.table) | |
| 270 | ||
| 271 | ||
| 272 | /* state */ | |
| 273 | ||
| 274 |     object State {
 | |
| 275 |       val serial = SQL.Column.long("serial").make_primary_key
 | |
| 276 | ||
| 277 | val table = make_table(List(serial), name = "state") | |
| 278 | } | |
| 279 | ||
| 280 | def read_serial(db: SQL.Database): Long = | |
| 281 | db.execute_query_statementO[Long]( | |
| 282 | State.table.select(List(State.serial.max)), | |
| 283 | _.long(State.serial)).getOrElse(0L) | |
| 284 | ||
| 285 |     def pull_state(db: SQL.Database, state: State): State = {
 | |
| 286 | val serial_db = read_serial(db) | |
| 287 | if (serial_db == state.serial) state | |
| 288 |       else {
 | |
| 289 | val serial = serial_db max state.serial | |
| 290 | ||
| 291 | val pending = pull_pending(db) | |
| 292 | val running = pull_running(db) | |
| 293 | val finished = pull_finished(db, state.finished) | |
| 294 | ||
| 295 | state.copy(serial = serial, pending = pending, running = running, finished = finished) | |
| 296 | } | |
| 297 | } | |
| 298 | ||
| 299 |     def push_state(db: SQL.Database, old_state: State, state: State): State = {
 | |
| 300 | val finished = push_finished(db, state.finished) | |
| 301 | val updates = | |
| 302 | List( | |
| 303 | update_pending(db, old_state.pending, state.pending), | |
| 304 | update_running(db, old_state.running, state.running), | |
| 305 | ).filter(_.defined) | |
| 306 | ||
| 307 | if (updates.isEmpty && finished == old_state.finished) state | |
| 308 |       else {
 | |
| 309 | val serial = state.next_serial | |
| 310 | db.execute_statement(State.table.delete(State.serial.where_equal(old_state.serial))) | |
| 311 | db.execute_statement(State.table.insert(), body = | |
| 312 |           { (stmt: SQL.Statement) =>
 | |
| 313 | stmt.long(1) = serial | |
| 314 | }) | |
| 315 | state.copy(serial = serial, finished = finished) | |
| 316 | } | |
| 317 | } | |
| 318 | ||
| 319 | ||
| 320 | /* pending */ | |
| 321 | ||
| 322 |     object Pending {
 | |
| 323 |       val kind = SQL.Column.string("kind")
 | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 324 |       val build_cluster = SQL.Column.bool("build_cluster")
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 325 |       val hosts_spec = SQL.Column.string("hosts_spec")
 | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 326 |       val timeout = SQL.Column.long("timeout")
 | 
| 80414 
4b10ae56ed01
add Isabelle settings to managed tasks and ci jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80412diff
changeset | 327 |       val other_settings = SQL.Column.string("other_settings")
 | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 328 |       val uuid = SQL.Column.string("uuid").make_primary_key
 | 
| 80246 | 329 |       val submit_date = SQL.Column.date("submit_date")
 | 
| 330 |       val priority = SQL.Column.string("priority")
 | |
| 331 |       val isabelle_rev = SQL.Column.string("isabelle_rev")
 | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 332 |       val extra_components = SQL.Column.string("extra_components")
 | 
| 80246 | 333 | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 334 |       val user = SQL.Column.string("user")
 | 
| 80246 | 335 |       val prefs = SQL.Column.string("prefs")
 | 
| 336 |       val requirements = SQL.Column.bool("requirements")
 | |
| 337 |       val all_sessions = SQL.Column.bool("all_sessions")
 | |
| 338 |       val base_sessions = SQL.Column.string("base_sessions")
 | |
| 339 |       val exclude_session_groups = SQL.Column.string("exclude_session_groups")
 | |
| 340 |       val exclude_sessions = SQL.Column.string("exclude_sessions")
 | |
| 341 |       val session_groups = SQL.Column.string("session_groups")
 | |
| 342 |       val sessions = SQL.Column.string("sessions")
 | |
| 343 |       val build_heap = SQL.Column.bool("build_heap")
 | |
| 344 |       val clean_build = SQL.Column.bool("clean_build")
 | |
| 345 |       val export_files = SQL.Column.bool("export_files")
 | |
| 346 |       val fresh_build = SQL.Column.bool("fresh_build")
 | |
| 347 |       val presentation = SQL.Column.bool("presentation")
 | |
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 348 |       val verbose = SQL.Column.bool("verbose")
 | 
| 80246 | 349 | |
| 350 | val table = | |
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 351 | make_table(List(kind, build_cluster, hosts_spec, timeout, other_settings, uuid, submit_date, | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 352 | priority, isabelle_rev, extra_components, user, prefs, requirements, all_sessions, | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 353 | base_sessions, exclude_session_groups, exclude_sessions, session_groups, sessions, | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 354 | build_heap, clean_build, export_files, fresh_build, presentation, verbose), | 
| 80246 | 355 | name = "pending") | 
| 356 | } | |
| 357 | ||
| 358 | def pull_pending(db: SQL.Database): Build_Manager.State.Pending = | |
| 359 | db.execute_query_statement(Pending.table.select(), Map.from[String, Task], get = | |
| 360 |         { res =>
 | |
| 361 | val kind = res.string(Pending.kind) | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 362 | val build_cluster = res.bool(Pending.build_cluster) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 363 | val hosts_spec = res.string(Pending.hosts_spec) | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 364 | val timeout = Time.ms(res.long(Pending.timeout)) | 
| 80414 
4b10ae56ed01
add Isabelle settings to managed tasks and ci jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80412diff
changeset | 365 | val other_settings = split_lines(res.string(Pending.other_settings)) | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 366 | val uuid = res.string(Pending.uuid) | 
| 80246 | 367 | val submit_date = res.date(Pending.submit_date) | 
| 368 | val priority = Priority.valueOf(res.string(Pending.priority)) | |
| 369 | val isabelle_rev = res.string(Pending.isabelle_rev) | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 370 | val extra_components = | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 371 |             space_explode(',', res.string(Pending.extra_components)).map(Component.parse)
 | 
| 80246 | 372 | |
| 373 | val build_config = | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 374 | if (kind != User_Build.name) CI_Build(kind, build_cluster, extra_components) | 
| 80246 | 375 |             else {
 | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 376 | val user = res.string(Pending.user) | 
| 80246 | 377 | val prefs = Options.Spec.parse(res.string(Pending.prefs)) | 
| 378 | val requirements = res.bool(Pending.requirements) | |
| 379 | val all_sessions = res.bool(Pending.all_sessions) | |
| 380 |               val base_sessions = space_explode(',', res.string(Pending.base_sessions))
 | |
| 381 | val exclude_session_groups = | |
| 382 |                 space_explode(',', res.string(Pending.exclude_session_groups))
 | |
| 383 |               val exclude_sessions = space_explode(',', res.string(Pending.exclude_sessions))
 | |
| 384 |               val session_groups = space_explode(',', res.string(Pending.session_groups))
 | |
| 385 |               val sessions = space_explode(',', res.string(Pending.sessions))
 | |
| 386 | val build_heap = res.bool(Pending.build_heap) | |
| 387 | val clean_build = res.bool(Pending.clean_build) | |
| 388 | val export_files = res.bool(Pending.export_files) | |
| 389 | val fresh_build = res.bool(Pending.fresh_build) | |
| 390 | val presentation = res.bool(Pending.presentation) | |
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 391 | val verbose = res.bool(Pending.verbose) | 
| 80246 | 392 | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 393 | val afp_rev = extra_components.find(_.name == Component.AFP).map(_.rev) | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 394 | User_Build(user, afp_rev, prefs, requirements, all_sessions, base_sessions, | 
| 80246 | 395 | exclude_session_groups, exclude_sessions, session_groups, sessions, build_heap, | 
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 396 | clean_build, export_files, fresh_build, presentation, verbose) | 
| 80246 | 397 | } | 
| 398 | ||
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 399 | val task = Task(build_config, hosts_spec, timeout, other_settings, UUID.make(uuid), | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 400 | submit_date, priority, isabelle_rev) | 
| 80246 | 401 | |
| 402 | task.name -> task | |
| 403 | }) | |
| 404 | ||
| 405 | def update_pending( | |
| 406 | db: SQL.Database, | |
| 407 | old_pending: Build_Manager.State.Pending, | |
| 408 | pending: Build_Manager.State.Pending | |
| 80274 | 409 |     ): Update = {
 | 
| 410 | val update = Update.make(old_pending, pending) | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 411 | val delete = update.delete.map(old_pending(_).uuid.toString) | 
| 80246 | 412 | |
| 413 | if (update.deletes) | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 414 | db.execute_statement(Pending.table.delete(Pending.uuid.where_member(delete))) | 
| 80246 | 415 | |
| 416 |       if (update.inserts) {
 | |
| 417 | db.execute_batch_statement(Pending.table.insert(), batch = | |
| 418 |           for (name <- update.insert) yield { (stmt: SQL.Statement) =>
 | |
| 419 | val task = pending(name) | |
| 420 | stmt.string(1) = task.kind | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 421 | stmt.bool(2) = task.build_cluster | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 422 | stmt.string(3) = task.hosts_spec | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 423 | stmt.long(4) = task.timeout.ms | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 424 | stmt.string(5) = cat_lines(task.other_settings) | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 425 | stmt.string(6) = task.uuid.toString | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 426 | stmt.date(7) = task.submit_date | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 427 | stmt.string(8) = task.priority.toString | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 428 | stmt.string(9) = task.isabelle_rev | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 429 |             stmt.string(10) = task.extra_components.mkString(",")
 | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 430 | stmt.string(11) = task.user | 
| 80246 | 431 | |
| 432 | def get[A](f: User_Build => A): Option[A] = | |
| 433 |               task.build_config match {
 | |
| 434 | case user_build: User_Build => Some(f(user_build)) | |
| 435 | case _ => None | |
| 436 | } | |
| 437 | ||
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 438 |             stmt.string(12) = get(user_build => user_build.prefs.map(_.print).mkString(","))
 | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 439 | stmt.bool(13) = get(_.requirements) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 440 | stmt.bool(14) = get(_.all_sessions) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 441 |             stmt.string(15) = get(_.base_sessions.mkString(","))
 | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 442 |             stmt.string(16) = get(_.exclude_session_groups.mkString(","))
 | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 443 |             stmt.string(17) = get(_.exclude_sessions.mkString(","))
 | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 444 |             stmt.string(18) = get(_.session_groups.mkString(","))
 | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 445 |             stmt.string(19) = get(_.sessions.mkString(","))
 | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 446 | stmt.bool(20) = get(_.build_heap) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 447 | stmt.bool(21) = get(_.clean_build) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 448 | stmt.bool(22) = get(_.export_files) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 449 | stmt.bool(23) = get(_.fresh_build) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 450 | stmt.bool(24) = get(_.presentation) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 451 | stmt.bool(25) = get(_.verbose) | 
| 80246 | 452 | }) | 
| 453 | } | |
| 454 | ||
| 455 | update | |
| 456 | } | |
| 457 | ||
| 458 | ||
| 459 | /* running */ | |
| 460 | ||
| 461 |     object Running {
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 462 |       val uuid = SQL.Column.string("uuid").make_primary_key
 | 
| 80246 | 463 |       val kind = SQL.Column.string("kind")
 | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 464 |       val id = SQL.Column.long("id")
 | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 465 |       val build_cluster = SQL.Column.bool("build_cluster")
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 466 |       val hostnames = SQL.Column.string("hostnames")
 | 
| 80246 | 467 |       val components = SQL.Column.string("components")
 | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 468 |       val timeout = SQL.Column.long("timeout")
 | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 469 |       val user = SQL.Column.string("user")
 | 
| 80246 | 470 |       val start_date = SQL.Column.date("start_date")
 | 
| 471 |       val cancelled = SQL.Column.bool("cancelled")
 | |
| 472 | ||
| 473 | val table = | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 474 | make_table(List(uuid, kind, id, build_cluster, hostnames, components, timeout, user, | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 475 | start_date, cancelled), | 
| 80246 | 476 | name = "running") | 
| 477 | } | |
| 478 | ||
| 479 | def pull_running(db: SQL.Database): Build_Manager.State.Running = | |
| 480 | db.execute_query_statement(Running.table.select(), Map.from[String, Job], get = | |
| 481 |         { res =>
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 482 | val uuid = res.string(Running.uuid) | 
| 80246 | 483 | val kind = res.string(Running.kind) | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 484 | val id = res.long(Running.id) | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 485 | val build_cluster = res.bool(Running.build_cluster) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 486 |           val hostnames = space_explode(',', res.string(Running.hostnames))
 | 
| 80246 | 487 |           val components = space_explode(',', res.string(Running.components)).map(Component.parse)
 | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 488 | val timeout = Time.ms(res.long(Running.timeout)) | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 489 | val user = res.get_string(Running.user) | 
| 80246 | 490 | val start_date = res.date(Running.start_date) | 
| 491 | val cancelled = res.bool(Running.cancelled) | |
| 492 | ||
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 493 | val job = Job(UUID.make(uuid), kind, id, build_cluster, hostnames, components, timeout, | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 494 | user, start_date, cancelled) | 
| 80246 | 495 | |
| 496 | job.name -> job | |
| 497 | }) | |
| 498 | ||
| 499 | def update_running( | |
| 500 | db: SQL.Database, | |
| 501 | old_running: Build_Manager.State.Running, | |
| 502 | running: Build_Manager.State.Running | |
| 80274 | 503 |     ): Update = {
 | 
| 504 | val update = Update.make(old_running, running) | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 505 | val delete = update.delete.map(old_running(_).uuid.toString) | 
| 80246 | 506 | |
| 507 | if (update.deletes) | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 508 | db.execute_statement(Running.table.delete(Running.uuid.where_member(delete))) | 
| 80246 | 509 | |
| 510 |       if (update.inserts) {
 | |
| 511 | db.execute_batch_statement(Running.table.insert(), batch = | |
| 512 |           for (name <- update.insert) yield { (stmt: SQL.Statement) =>
 | |
| 513 | val job = running(name) | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 514 | stmt.string(1) = job.uuid.toString | 
| 80246 | 515 | stmt.string(2) = job.kind | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 516 | stmt.long(3) = job.id | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 517 | stmt.bool(4) = job.build_cluster | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 518 |             stmt.string(5) = job.hostnames.mkString(",")
 | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 519 |             stmt.string(6) = job.components.mkString(",")
 | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 520 | stmt.long(7) = job.timeout.ms | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 521 | stmt.string(8) = job.user | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 522 | stmt.date(9) = job.start_date | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 523 | stmt.bool(10) = job.cancelled | 
| 80246 | 524 | }) | 
| 525 | } | |
| 526 | update | |
| 527 | } | |
| 528 | ||
| 529 | ||
| 530 | /* finished */ | |
| 531 | ||
| 532 |     object Finished {
 | |
| 533 |       val kind = SQL.Column.string("kind")
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 534 |       val id = SQL.Column.long("id")
 | 
| 80246 | 535 |       val status = SQL.Column.string("status")
 | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 536 |       val uuid = SQL.Column.string("uuid")
 | 
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 537 |       val build_host = SQL.Column.string("build_host")
 | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 538 |       val start_date = SQL.Column.date("start_date")
 | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 539 |       val end_date = SQL.Column.date("end_date")
 | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 540 |       val isabelle_version = SQL.Column.string("isabelle_version")
 | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 541 |       val afp_version = SQL.Column.string("afp_version")
 | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 542 |       val user = SQL.Column.string("user")
 | 
| 80246 | 543 |       val serial = SQL.Column.long("serial").make_primary_key
 | 
| 544 | ||
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 545 | val table = | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 546 | make_table( | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 547 | List(kind, id, status, uuid, build_host, start_date, end_date, isabelle_version, | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 548 | afp_version, user, serial), | 
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 549 | name = "finished") | 
| 80246 | 550 | } | 
| 551 | ||
| 552 | def read_finished_serial(db: SQL.Database): Long = | |
| 553 | db.execute_query_statementO[Long]( | |
| 554 | Finished.table.select(List(Finished.serial.max)), | |
| 555 | _.long(Finished.serial)).getOrElse(0L) | |
| 556 | ||
| 557 | def pull_finished( | |
| 558 | db: SQL.Database, | |
| 559 | finished: Build_Manager.State.Finished | |
| 560 |     ): Build_Manager.State.Finished = {
 | |
| 561 | val max_serial0 = Build_Manager.State.max_serial(finished.values.map(_.serial)) | |
| 562 | val max_serial1 = read_finished_serial(db) | |
| 563 | val missing = (max_serial0 + 1) to max_serial1 | |
| 564 | finished ++ db.execute_query_statement( | |
| 565 | Finished.table.select(sql = Finished.serial.where_member_long(missing)), | |
| 566 | Map.from[String, Result], get = | |
| 567 |         { res =>
 | |
| 568 | val kind = res.string(Finished.kind) | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 569 | val id = res.long(Finished.id) | 
| 80246 | 570 | val status = Status.valueOf(res.string(Finished.status)) | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 571 | val uuid = res.get_string(Finished.uuid).map(UUID.make) | 
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 572 | val build_host = res.string(Finished.build_host) | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 573 | val start_date = res.date(Finished.start_date) | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 574 | val end_date = res.get_date(Finished.end_date) | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 575 | val isabelle_version = res.get_string(Finished.isabelle_version) | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 576 | val afp_version = res.get_string(Finished.afp_version) | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 577 | val user = res.get_string(Finished.user) | 
| 80246 | 578 | val serial = res.long(Finished.serial) | 
| 579 | ||
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 580 | val result = Result(kind, id, status, uuid, build_host, start_date, end_date, | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 581 | isabelle_version, afp_version, user, serial) | 
| 80246 | 582 | result.name -> result | 
| 583 | } | |
| 584 | ) | |
| 585 | } | |
| 586 | ||
| 587 | def push_finished( | |
| 588 | db: SQL.Database, | |
| 589 | finished: Build_Manager.State.Finished | |
| 590 |     ): Build_Manager.State.Finished = {
 | |
| 591 | val (insert0, old) = finished.partition(_._2.serial == 0L) | |
| 592 | val max_serial = Build_Manager.State.max_serial(finished.map(_._2.serial)) | |
| 593 | val insert = | |
| 594 | for (((_, result), n) <- insert0.zipWithIndex) | |
| 595 | yield result.copy(serial = max_serial + 1 + n) | |
| 596 | ||
| 597 | if (insert.nonEmpty) | |
| 598 | db.execute_batch_statement(Finished.table.insert(), batch = | |
| 599 |           for (result <- insert) yield { (stmt: SQL.Statement) =>
 | |
| 600 | stmt.string(1) = result.kind | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 601 | stmt.long(2) = result.id | 
| 80246 | 602 | stmt.string(3) = result.status.toString | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 603 | stmt.string(4) = result.uuid.map(_.toString) | 
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 604 | stmt.string(5) = result.build_host | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 605 | stmt.date(6) = result.start_date | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 606 | stmt.date(7) = result.end_date | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 607 | stmt.string(8) = result.isabelle_version | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 608 | stmt.string(9) = result.afp_version | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 609 | stmt.string(10) = result.user | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 610 | stmt.long(11) = result.serial | 
| 80246 | 611 | }) | 
| 612 | ||
| 613 | old ++ insert.map(result => result.serial.toString -> result) | |
| 614 | } | |
| 615 | } | |
| 616 | ||
| 617 | ||
| 80497 | 618 | /** build reports **/ | 
| 619 | ||
| 620 |   object Report {
 | |
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 621 | case class Data( | 
| 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 622 | build_log: String, | 
| 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 623 | component_logs: List[(String, String)], | 
| 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 624 | component_diffs: List[(String, String)]) | 
| 80497 | 625 | } | 
| 626 | ||
| 627 |   case class Report(kind: String, id: Long, dir: Path) {
 | |
| 628 | private val log_name = "build-manager" | |
| 80531 | 629 | private val diff_ext = "diff" | 
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 630 | private val log_ext = "log" | 
| 80497 | 631 | |
| 632 | private def log_file = dir + Path.basic(log_name).log | |
| 80498 | 633 | private def log_file_gz = dir + Path.basic(log_name).log.gz | 
| 80497 | 634 | |
| 635 | def init(): Unit = Isabelle_System.make_directory(dir) | |
| 636 | ||
| 80498 | 637 | def ok: Boolean = log_file.is_file != log_file_gz.is_file | 
| 80497 | 638 | |
| 639 | def progress: Progress = new File_Progress(log_file) | |
| 640 | ||
| 80531 | 641 | private def read_gz(file: Path, ext: String): Option[(String, String)] = | 
| 642 | if (!File.is_gz(file.file_name) || file.drop_ext.get_ext != ext) None | |
| 643 | else Some(file.drop_ext.drop_ext.file_name -> File.read_gzip(file)) | |
| 644 | ||
| 80498 | 645 |     def read: Report.Data = {
 | 
| 80532 | 646 | val build_log = | 
| 80498 | 647 | if_proper(ok, if (log_file.is_file) File.read(log_file) else File.read_gzip(log_file_gz)) | 
| 80531 | 648 | |
| 80532 | 649 | val component_diffs = | 
| 650 | File.read_dir(dir).flatMap(name => read_gz(dir + Path.basic(name), diff_ext)) | |
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 651 | val component_logs = | 
| 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 652 | File.read_dir(dir).flatMap(name => read_gz(dir + Path.basic(name), log_ext)) | 
| 80531 | 653 | |
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 654 | Report.Data(build_log, component_logs, component_diffs) | 
| 80498 | 655 | } | 
| 80497 | 656 | |
| 80544 | 657 | def write_log( | 
| 658 | component: String, | |
| 659 | repository: Mercurial.Repository, | |
| 660 | rev0: String, | |
| 661 | rev: String | |
| 662 | ): Unit = | |
| 663 |       if (rev0.nonEmpty && rev.nonEmpty && rev0 != rev) {
 | |
| 664 | val log_opts = "--graph --color always" | |
| 665 |         val rev1 = "children(" + rev0 + ")"
 | |
| 666 |         val cmd = repository.command_line("log", Mercurial.opt_rev(rev1 + ":" + rev), log_opts)
 | |
| 82466 | 667 |         val log = Isabelle_System.bash(Bash.exports("HGPLAINEXCEPT=color") + cmd).check.out
 | 
| 80544 | 668 | if (log.nonEmpty) File.write_gzip(dir + Path.basic(component).ext(log_ext).gz, log) | 
| 669 | } | |
| 80500 | 670 | |
| 80544 | 671 | def write_diff( | 
| 672 | component: String, | |
| 673 | repository: Mercurial.Repository, | |
| 674 | rev0: String, | |
| 675 | rev: String | |
| 676 | ): Unit = | |
| 677 |       if (rev0.nonEmpty && rev.nonEmpty) {
 | |
| 678 | val diff_opts = "--noprefix --nodates --ignore-all-space --color always" | |
| 679 |         val cmd = repository.command_line("diff", Mercurial.opt_rev(rev0 + ":" + rev), diff_opts)
 | |
| 82466 | 680 |         val diff = Isabelle_System.bash(Bash.exports("HGPLAINEXCEPT=color") + cmd).check.out
 | 
| 80544 | 681 | if (diff.nonEmpty) File.write_gzip(dir + Path.basic(component).ext(diff_ext).gz, diff) | 
| 682 | } | |
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 683 | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 684 |     def result(uuid: Option[UUID.T] = None, user: Option[String] = None): Result = {
 | 
| 80497 | 685 | val End = """^Job ended at [^,]+, with status (\w+)$""".r | 
| 686 | ||
| 80532 | 687 | val build_log_file = Build_Log.Log_File(log_name, Library.trim_split_lines(read.build_log)) | 
| 80497 | 688 | |
| 689 | val meta_info = build_log_file.parse_meta_info() | |
| 690 | val status = | |
| 691 |         build_log_file.lines.last match {
 | |
| 692 | case End(status) => Status.valueOf(status) | |
| 693 | case _ => Status.aborted | |
| 694 | } | |
| 695 |       val build_host = meta_info.get_build_host.getOrElse(error("No build host"))
 | |
| 696 |       val start_date = meta_info.get_build_start.getOrElse(error("No start date"))
 | |
| 697 | val end_date = meta_info.get_build_end | |
| 698 | val isabelle_version = meta_info.get(Build_Log.Prop.isabelle_version) | |
| 699 | val afp_version = meta_info.get(Build_Log.Prop.afp_version) | |
| 700 | ||
| 80498 | 701 |       if (log_file.is_file) {
 | 
| 702 | File.write_gzip(log_file_gz, build_log_file.text) | |
| 703 | Isabelle_System.rm_tree(log_file) | |
| 704 | } | |
| 705 | ||
| 80497 | 706 | Result(kind, id, status, uuid, build_host, start_date, end_date, isabelle_version, | 
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 707 | afp_version, user) | 
| 80497 | 708 | } | 
| 709 | } | |
| 710 | ||
| 711 | ||
| 80344 | 712 | /** running build manager processes **/ | 
| 80246 | 713 | |
| 714 | abstract class Loop_Process[A](name: String, store: Store, progress: Progress) | |
| 715 |     extends Runnable {
 | |
| 716 | val options = store.options | |
| 717 | ||
| 718 | private val _database = | |
| 719 |       try { store.open_database() }
 | |
| 720 |       catch { case exn: Throwable => close(); throw exn }
 | |
| 721 | ||
| 722 | def close(): Unit = Option(_database).foreach(_.close()) | |
| 723 | ||
| 724 | protected var _state = State() | |
| 725 | ||
| 726 |     protected def synchronized_database[A](label: String)(body: => A): A = synchronized {
 | |
| 727 |       Build_Manager.private_data.transaction_lock(_database, label = name + "." + label) {
 | |
| 728 | val old_state = Build_Manager.private_data.pull_state(_database, _state) | |
| 729 | _state = old_state | |
| 730 | val res = body | |
| 731 | _state = Build_Manager.private_data.push_state(_database, old_state, _state) | |
| 732 | res | |
| 733 | } | |
| 734 | } | |
| 735 | ||
| 736 |     protected def delay = options.seconds("build_manager_delay")
 | |
| 737 | ||
| 738 | def init: A | |
| 739 | def loop_body(a: A): A | |
| 740 | def stopped(a: A): Boolean = progress.stopped | |
| 741 | ||
| 742 | private val interrupted = Synchronized(false) | |
| 743 | private def sleep(time_limit: Time): Unit = | |
| 744 | interrupted.timed_access(_ => Some(time_limit), b => if (b) Some((), false) else None) | |
| 745 | def interrupt(): Unit = interrupted.change(_ => true) | |
| 746 | ||
| 747 | @tailrec private def loop(a: A): Unit = | |
| 748 |       if (!stopped(a)) {
 | |
| 749 | val start = Time.now() | |
| 750 | val a1 = loop_body(a) | |
| 751 |         if (!stopped(a)) {
 | |
| 752 | sleep(start + delay) | |
| 753 | loop(a1) | |
| 754 | } | |
| 755 | } | |
| 756 | ||
| 757 |     override def run(): Unit = {
 | |
| 758 |       progress.echo("Started " + name)
 | |
| 759 | loop(init) | |
| 760 | close() | |
| 761 |       progress.echo("Stopped " + name)
 | |
| 762 | } | |
| 763 | ||
| 764 | def echo(msg: String) = progress.echo(name + ": " + msg) | |
| 765 | def echo_error_message(msg: String) = progress.echo_error_message(name + ": " + msg) | |
| 766 | } | |
| 767 | ||
| 768 | ||
| 769 | /* build runner */ | |
| 770 | ||
| 771 |   object Runner {
 | |
| 772 |     object State {
 | |
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 773 | def init(options: Options): State = | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 774 |         new State(Map.empty, Map.empty, Map.empty, options.seconds("build_manager_cancel_timeout"))
 | 
| 80246 | 775 | } | 
| 776 | ||
| 777 | class State private( | |
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 778 | process_futures: Map[String, Future[Build_Process]], | 
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 779 | result_futures: Map[String, Future[Process_Result]], | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 780 | cancelling_until: Map[String, Time], | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 781 | cancel_timeout: Time | 
| 80246 | 782 |     ) {
 | 
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 783 | private def copy( | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 784 | process_futures: Map[String, Future[Build_Process]] = process_futures, | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 785 | result_futures: Map[String, Future[Process_Result]] = result_futures, | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 786 | cancelling_until: Map[String, Time] = cancelling_until, | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 787 | ): State = new State(process_futures, result_futures, cancelling_until, cancel_timeout) | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 788 | |
| 80277 | 789 | def is_empty = process_futures.isEmpty && result_futures.isEmpty | 
| 80246 | 790 | |
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 791 |       def init(context: Context): State = {
 | 
| 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 792 | val process_future = Future.fork(Build_Process.open(context)) | 
| 80277 | 793 | val result_future = | 
| 80246 | 794 | Future.fork( | 
| 80277 | 795 |             process_future.join_result match {
 | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 796 | case Exn.Res(process) => process.run() | 
| 80284 
7a5bbc2e4bad
build manager: echo error messages to server output;
 Fabian Huch <huch@in.tum.de> parents: 
80283diff
changeset | 797 | case Exn.Exn(exn) => Process_Result(Process_Result.RC.interrupt).error(exn.getMessage) | 
| 80246 | 798 | }) | 
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 799 | |
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 800 | copy( | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 801 | process_futures + (context.name -> process_future), | 
| 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 802 | result_futures + (context.name -> result_future)) | 
| 80246 | 803 | } | 
| 804 | ||
| 80779 
a1b3abc629af
manage runner state properly (amending be4c1fbccfe8);
 Fabian Huch <huch@in.tum.de> parents: 
80731diff
changeset | 805 | def running: List[String] = process_futures.keys.toList.filterNot(cancelling_until.contains) | 
| 80246 | 806 | |
| 80781 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 807 | private def maybe_result(name: String): Option[Process_Result] = | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 808 | for (future <- result_futures.get(name) if future.is_finished) yield | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 809 |           future.join_result match {
 | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 810 | case Exn.Res(result) => result | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 811 | case Exn.Exn(exn) => Process_Result(Process_Result.RC.interrupt).error(exn.getMessage) | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 812 | } | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 813 | |
| 80730 | 814 |       private def do_terminate(name: String): Boolean = {
 | 
| 80779 
a1b3abc629af
manage runner state properly (amending be4c1fbccfe8);
 Fabian Huch <huch@in.tum.de> parents: 
80731diff
changeset | 815 | val is_late = Time.now() > cancelling_until(name) | 
| 80730 | 816 | if (is_late) process_futures(name).join.terminate() | 
| 817 | is_late | |
| 818 | } | |
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 819 | |
| 80246 | 820 |       def update: (State, Map[String, Process_Result]) = {
 | 
| 80731 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 821 | val finished0 = | 
| 80781 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 822 |           for {
 | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 823 | (name, _) <- result_futures | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 824 | result <- maybe_result(name) | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 825 | } yield name -> result | 
| 80246 | 826 | |
| 80731 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 827 | val (terminated, cancelling_until1) = | 
| 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 828 | cancelling_until | 
| 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 829 | .filterNot((name, _) => finished0.contains(name)) | 
| 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 830 | .partition((name, _) => do_terminate(name)) | 
| 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 831 | |
| 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 832 | val finished = | 
| 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 833 | finished0 ++ | 
| 80781 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 834 | terminated.map((name, _) => | 
| 
11e33f3d5ef1
better results for terminated jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80780diff
changeset | 835 | name -> maybe_result(name).getOrElse(Process_Result(Process_Result.RC.timeout))) | 
| 80731 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 836 | |
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 837 | val state1 = | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 838 | copy( | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 839 | process_futures.filterNot((name, _) => finished.contains(name)), | 
| 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 840 | result_futures.filterNot((name, _) => finished.contains(name)), | 
| 80731 
834849b55910
remove terminated jobs, even if futures do not complete;
 Fabian Huch <huch@in.tum.de> parents: 
80730diff
changeset | 841 | cancelling_until1) | 
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 842 | (state1, finished) | 
| 80246 | 843 | } | 
| 844 | ||
| 80730 | 845 |       private def do_cancel(process_future: Future[Build_Process]): Boolean = {
 | 
| 846 | val is_finished = process_future.is_finished | |
| 847 | if (is_finished) process_future.join.cancel() else process_future.cancel() | |
| 848 | is_finished | |
| 849 | } | |
| 80246 | 850 | |
| 80730 | 851 |       def cancel(cancelled: List[String]): State = {
 | 
| 852 | val cancelling_until1 = | |
| 853 |           for {
 | |
| 854 | name <- cancelled | |
| 855 | process_future <- process_futures.get(name) | |
| 856 | if do_cancel(process_future) | |
| 857 | } yield name -> (Time.now() + cancel_timeout) | |
| 858 | ||
| 80779 
a1b3abc629af
manage runner state properly (amending be4c1fbccfe8);
 Fabian Huch <huch@in.tum.de> parents: 
80731diff
changeset | 859 | copy(cancelling_until = cancelling_until ++ cancelling_until1) | 
| 80730 | 860 | } | 
| 80246 | 861 | } | 
| 862 | } | |
| 863 | ||
| 864 | class Runner( | |
| 865 | store: Store, | |
| 866 | build_hosts: List[Build_Cluster.Host], | |
| 867 | isabelle_repository: Mercurial.Repository, | |
| 868 | sync_dirs: List[Sync.Dir], | |
| 869 | progress: Progress | |
| 870 |   ) extends Loop_Process[Runner.State]("Runner", store, progress) {
 | |
| 871 | val rsync_context = Rsync.Context() | |
| 872 | ||
| 873 |     private def sync(repository: Mercurial.Repository, rev: String, target: Path): String = {
 | |
| 82352 
fedac12c7e0e
start jobs even if repository is unreachable, e.g. due to high load;
 Fabian Huch <huch@in.tum.de> parents: 
82046diff
changeset | 874 | val pull_result = Exn.capture(repository.pull()) | 
| 
fedac12c7e0e
start jobs even if repository is unreachable, e.g. due to high load;
 Fabian Huch <huch@in.tum.de> parents: 
82046diff
changeset | 875 |       if (Exn.is_exn(pull_result)) {
 | 
| 
fedac12c7e0e
start jobs even if repository is unreachable, e.g. due to high load;
 Fabian Huch <huch@in.tum.de> parents: 
82046diff
changeset | 876 |         echo_error_message("Could not read from repository: " + Exn.the_exn(pull_result).getMessage)
 | 
| 
fedac12c7e0e
start jobs even if repository is unreachable, e.g. due to high load;
 Fabian Huch <huch@in.tum.de> parents: 
82046diff
changeset | 877 | } | 
| 80246 | 878 | |
| 879 | if (rev.nonEmpty) repository.sync(rsync_context, target, rev = rev) | |
| 880 | ||
| 881 |       Exn.capture(repository.id(File.read(target + Mercurial.Hg_Sync.PATH_ID))) match {
 | |
| 882 | case Exn.Res(res) => res | |
| 80647 | 883 | case Exn.Exn(_) => "" | 
| 80246 | 884 | } | 
| 885 | } | |
| 886 | ||
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 887 | private def start_next(): Option[Context] = | 
| 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 888 |       synchronized_database("start_next") {
 | 
| 80424 
6ed82923d51d
abort tasks with invalid host specs;
 Fabian Huch <huch@in.tum.de> parents: 
80423diff
changeset | 889 |         for ((name, task) <- _state.pending if Exn.is_exn(Exn.capture(task.build_hosts))) {
 | 
| 
6ed82923d51d
abort tasks with invalid host specs;
 Fabian Huch <huch@in.tum.de> parents: 
80423diff
changeset | 890 |           progress.echo("Invalid host spec for task " + name + ": " + quote(task.hosts_spec))
 | 
| 
6ed82923d51d
abort tasks with invalid host specs;
 Fabian Huch <huch@in.tum.de> parents: 
80423diff
changeset | 891 | _state = _state.remove_pending(name) | 
| 
6ed82923d51d
abort tasks with invalid host specs;
 Fabian Huch <huch@in.tum.de> parents: 
80423diff
changeset | 892 | } | 
| 
6ed82923d51d
abort tasks with invalid host specs;
 Fabian Huch <huch@in.tum.de> parents: 
80423diff
changeset | 893 | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 894 |         _state.next(build_hosts).flatMap { task =>
 | 
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 895 |           echo("Initializing " + task.name)
 | 
| 80246 | 896 | |
| 897 | _state = _state.remove_pending(task.name) | |
| 898 | ||
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 899 | val id = _state.next_id(task.kind) | 
| 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 900 | val context = Context(store, task, id) | 
| 80246 | 901 | |
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 902 | val start_date = Date.now() | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 903 | |
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 904 | val start_msg = | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 905 | "Starting job " + Build.name(task.kind, id) + | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 906 | " at " + Build_Log.print_date(start_date) + "," + | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 907 | " on " + ( | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 908 | if (task.build_cluster) "cluster" | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 909 | else Library.the_single(task.build_hosts).hostname) | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 910 | |
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 911 | echo(start_msg + " (id " + task.uuid + ")") | 
| 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 912 | |
| 80246 | 913 |           Exn.capture {
 | 
| 80497 | 914 | context.report.init() | 
| 915 | context.report.progress.echo(start_msg) | |
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 916 | |
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 917 | store.sync_permissions(context.task_dir) | 
| 80255 
1844c169e360
ensure permissions when starting build task (e.g., due to misconfigured client);
 Fabian Huch <huch@in.tum.de> parents: 
80254diff
changeset | 918 | |
| 80409 | 919 | val isabelle_rev = sync(isabelle_repository, task.isabelle_rev, context.task_dir) | 
| 80246 | 920 | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 921 | val hostnames = task.build_hosts.map(_.hostname).distinct | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 922 | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 923 | val extra_components = | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 924 | for (extra_component <- task.extra_components) | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 925 |               yield sync_dirs.find(_.name == extra_component.name) match {
 | 
| 80246 | 926 | case Some(sync_dir) => | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 927 | val target = context.task_dir + sync_dir.target | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 928 | val rev = sync(sync_dir.hg, extra_component.rev, target) | 
| 80408 
e6d3d1db6136
add root entry for non-local components;
 Fabian Huch <huch@in.tum.de> parents: 
80407diff
changeset | 929 | |
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 930 | if (!extra_component.is_local) | 
| 80408 
e6d3d1db6136
add root entry for non-local components;
 Fabian Huch <huch@in.tum.de> parents: 
80407diff
changeset | 931 | File.append(context.task_dir + Sync.DIRS_ROOTS, sync_dir.roots_entry + "\n") | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 932 | extra_component.copy(rev = rev) | 
| 80246 | 933 | case None => | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 934 | if (extra_component.is_local) extra_component | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 935 |                   else error("Unknown component " + extra_component)
 | 
| 80246 | 936 | } | 
| 937 | ||
| 80500 | 938 |             if (task.kind != User_Build.name && _state.get_finished(task.kind).nonEmpty) {
 | 
| 939 | val previous = _state.get_finished(task.kind).maxBy(_.id) | |
| 940 | ||
| 941 |               for (isabelle_rev0 <- previous.isabelle_version) {
 | |
| 80544 | 942 | context.report.write_log(Component.Isabelle, | 
| 943 | isabelle_repository, isabelle_rev0, isabelle_rev) | |
| 944 | context.report.write_diff(Component.Isabelle, | |
| 945 | isabelle_repository, isabelle_rev0, isabelle_rev) | |
| 80500 | 946 | } | 
| 947 | ||
| 948 |               for {
 | |
| 949 | afp_rev0 <- previous.afp_version | |
| 950 | afp <- extra_components.find(_.name == Component.AFP) | |
| 951 | sync_dir <- sync_dirs.find(_.name == afp.name) | |
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 952 |               } {
 | 
| 80544 | 953 | context.report.write_log(afp.name, sync_dir.hg, afp_rev0, afp.rev) | 
| 954 | context.report.write_diff(afp.name, sync_dir.hg, afp_rev0, afp.rev) | |
| 80533 
464266fc956e
store hg log in addition to diff;
 Fabian Huch <huch@in.tum.de> parents: 
80532diff
changeset | 955 | } | 
| 80500 | 956 | } | 
| 957 | ||
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 958 | val components = Component.isabelle(isabelle_rev) :: extra_components | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 959 | |
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 960 | Job(task.uuid, task.kind, id, task.build_cluster, hostnames, components, task.timeout, | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 961 | task.user, start_date) | 
| 80246 | 962 |           } match {
 | 
| 963 | case Exn.Res(job) => | |
| 964 | _state = _state.add_running(job) | |
| 965 | ||
| 80542 
dd86d35375a7
log and display components with empty (unknown) revisions to indicate that they are present;
 Fabian Huch <huch@in.tum.de> parents: 
80541diff
changeset | 966 | for (component <- job.components) | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 967 |                 context.report.progress.echo("Using " + component.toString)
 | 
| 80246 | 968 | |
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 969 | Some(context) | 
| 80246 | 970 | case Exn.Exn(exn) => | 
| 80497 | 971 |               context.report.progress.echo_error_message("Failed to start job: " + exn.getMessage)
 | 
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 972 |               echo_error_message("Failed to start " + task.uuid + ": " + exn.getMessage)
 | 
| 80246 | 973 | |
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 974 | Isabelle_System.rm_tree(context.task_dir) | 
| 80246 | 975 | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 976 | _state = _state.add_finished(context.report.result(Some(task.uuid), task.user)) | 
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 977 | |
| 80246 | 978 | None | 
| 979 | } | |
| 980 | } | |
| 981 | } | |
| 982 | ||
| 983 | private def stop_cancelled(state: Runner.State): Runner.State = | |
| 984 |       synchronized_database("stop_cancelled") {
 | |
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 985 | val now = Date.now() | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 986 |         for {
 | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 987 | name <- state.running | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 988 | job = _state.running(name) | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 989 | if now - job.start_date > job.timeout | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 990 |         } {
 | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 991 | _state = _state.cancel_running(name) | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 992 | |
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 993 | val timeout_msg = "Timeout after " + job.timeout.message_hms | 
| 80497 | 994 | store.report(job.kind, job.id).progress.echo_error_message(timeout_msg) | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 995 | echo(job.name + ": " + timeout_msg) | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 996 | } | 
| 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 997 | |
| 80644 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 998 | val cancelled = | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 999 |           for {
 | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1000 | name <- state.running | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1001 | job = _state.running(name) | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1002 | if job.cancelled | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1003 | } yield job | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1004 | |
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1005 |         cancelled.foreach(job => store.report(job.kind, job.id).progress.echo("Cancelling ..."))
 | 
| 
6a996ad11af2
build_manager: log message when job is cancelled;
 Fabian Huch <huch@in.tum.de> parents: 
80575diff
changeset | 1006 | state.cancel(cancelled.map(_.name)) | 
| 80246 | 1007 | } | 
| 1008 | ||
| 1009 | private def finish_job(name: String, process_result: Process_Result): Unit = | |
| 1010 |       synchronized_database("finish_job") {
 | |
| 1011 | val job = _state.running(name) | |
| 1012 | ||
| 80342 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 1013 | val end_date = Date.now() | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 1014 | val status = Status.from_result(process_result) | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 1015 | val end_msg = "Job ended at " + Build_Log.print_date(end_date) + ", with status " + status | 
| 
35bee9c44e1a
use build log in build manager to store meta-data persistently;
 Fabian Huch <huch@in.tum.de> parents: 
80340diff
changeset | 1016 | |
| 80497 | 1017 | val report = store.report(job.kind, job.id) | 
| 1018 | report.progress.echo(end_msg) | |
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 1019 | |
| 80284 
7a5bbc2e4bad
build manager: echo error messages to server output;
 Fabian Huch <huch@in.tum.de> parents: 
80283diff
changeset | 1020 | val interrupted_error = process_result.interrupted && process_result.err.nonEmpty | 
| 
7a5bbc2e4bad
build manager: echo error messages to server output;
 Fabian Huch <huch@in.tum.de> parents: 
80283diff
changeset | 1021 | val err_msg = if_proper(interrupted_error, ": " + process_result.err) | 
| 80340 
992bd899a027
improve build manager log (for build_log);
 Fabian Huch <huch@in.tum.de> parents: 
80339diff
changeset | 1022 | echo(end_msg + " (code " + process_result.rc + ")" + err_msg) | 
| 80246 | 1023 | |
| 1024 | _state = _state | |
| 1025 | .remove_running(job.name) | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1026 | .add_finished(report.result(Some(job.uuid), job.user)) | 
| 80246 | 1027 | } | 
| 1028 | ||
| 1029 | override def stopped(state: Runner.State): Boolean = progress.stopped && state.is_empty | |
| 1030 | ||
| 80780 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1031 |     def init: Runner.State = synchronized_database("init") {
 | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1032 |       for ((name, job) <- _state.running) {
 | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1033 |         echo("Cleaned up job " + job.uuid)
 | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1034 | |
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1035 | val report = store.report(job.kind, job.id) | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1036 | |
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1037 | _state = _state | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1038 | .remove_running(job.name) | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1039 | .add_finished(report.result(Some(job.uuid), job.user)) | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1040 | } | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1041 | |
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1042 | Runner.State.init(store.options) | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1043 | } | 
| 
d6417e967a7c
more robust: clean up unfinished jobs on init, e.g. if build_manager process was forcefully terminated;
 Fabian Huch <huch@in.tum.de> parents: 
80779diff
changeset | 1044 | |
| 80246 | 1045 |     def loop_body(state: Runner.State): Runner.State = {
 | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1046 | val state1 = | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1047 | if (progress.stopped) state | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1048 |         else {
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1049 |           start_next() match {
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1050 | case None => state | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1051 | case Some(context) => state.init(context) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1052 | } | 
| 80246 | 1053 | } | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1054 | val state2 = stop_cancelled(state1) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1055 | val (state3, results) = state2.update | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1056 | results.foreach(finish_job) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1057 | state3 | 
| 80246 | 1058 | } | 
| 1059 | } | |
| 1060 | ||
| 1061 | ||
| 1062 | /* repository poller */ | |
| 1063 | ||
| 1064 |   object Poller {
 | |
| 80574 | 1065 | case class State(current: List[Component], next: Future[List[Component]]) | 
| 80246 | 1066 | } | 
| 1067 | ||
| 1068 | class Poller( | |
| 80412 
a7f8249533e9
moved ci_build module to build_ci;
 Fabian Huch <huch@in.tum.de> parents: 
80411diff
changeset | 1069 | ci_jobs: List[Build_CI.Job], | 
| 80246 | 1070 | store: Store, | 
| 1071 | isabelle_repository: Mercurial.Repository, | |
| 1072 | sync_dirs: List[Sync.Dir], | |
| 1073 | progress: Progress | |
| 1074 |   ) extends Loop_Process[Poller.State]("Poller", store, progress) {
 | |
| 1075 | ||
| 1076 |     override def delay = options.seconds("build_manager_poll_delay")
 | |
| 1077 | ||
| 80574 | 1078 | private def current: List[Component] = | 
| 1079 |       Component.isabelle(isabelle_repository.id("default")) ::
 | |
| 1080 |         sync_dirs.map(dir => Component(dir.name, dir.hg.id("default")))
 | |
| 80246 | 1081 | |
| 80574 | 1082 |     private def poll: Future[List[Component]] = Future.fork {
 | 
| 80246 | 1083 | Par_List.map((repo: Mercurial.Repository) => repo.pull(), | 
| 1084 | isabelle_repository :: sync_dirs.map(_.hg)) | |
| 1085 | ||
| 80260 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1086 | current | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1087 | } | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1088 | |
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1089 | val init: Poller.State = Poller.State(current, poll) | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1090 | |
| 80574 | 1091 |     private def add_tasks(current: List[Component], next: List[Component]): Unit = {
 | 
| 80575 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1092 | val next_rev = next.map(component => component.name -> component.rev).toMap | 
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1093 | |
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1094 | def is_unchanged(components: List[Component]): Boolean = | 
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1095 | components.forall(component => next_rev.get(component.name).contains(component.rev)) | 
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1096 | |
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1097 | def is_changed(component_names: List[String]): Boolean = | 
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1098 | !is_unchanged(current.filter(component => component_names.contains(component.name))) | 
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1099 | |
| 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1100 | def is_current(job: Job): Boolean = is_unchanged(job.components) | 
| 80246 | 1101 | |
| 80260 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1102 |       synchronized_database("add_tasks") {
 | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1103 |         for {
 | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1104 | ci_job <- ci_jobs | 
| 80412 
a7f8249533e9
moved ci_build module to build_ci;
 Fabian Huch <huch@in.tum.de> parents: 
80411diff
changeset | 1105 | if ci_job.trigger == Build_CI.On_Commit | 
| 80575 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1106 | if is_changed(Component.Isabelle :: ci_job.components) | 
| 80260 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1107 | if !_state.pending.values.exists(_.kind == ci_job.name) | 
| 80575 
01edf83f6dee
better poller: don't start job when same version is already running;
 Fabian Huch <huch@in.tum.de> parents: 
80574diff
changeset | 1108 | if !_state.running.values.filter(_.kind == ci_job.name).exists(is_current) | 
| 80416 | 1109 | } _state = _state.add_pending(CI_Build.task(ci_job)) | 
| 80246 | 1110 | } | 
| 1111 | } | |
| 1112 | ||
| 1113 | def loop_body(state: Poller.State): Poller.State = | |
| 1114 | if (!state.next.is_finished) state | |
| 1115 |       else {
 | |
| 1116 |         state.next.join_result match {
 | |
| 1117 | case Exn.Exn(exn) => | |
| 1118 |             echo_error_message("Could not reach repository: " + exn.getMessage)
 | |
| 80260 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1119 | Poller.State(state.current, poll) | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1120 | case Exn.Res(next) => | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1121 |             if (state.current != next) {
 | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1122 |               echo("Found new revisions: " + next)
 | 
| 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1123 | add_tasks(state.current, next) | 
| 80246 | 1124 | } | 
| 80260 
ed9b1598d293
manage components of ci builds;
 Fabian Huch <huch@in.tum.de> parents: 
80259diff
changeset | 1125 | Poller.State(next, poll) | 
| 80246 | 1126 | } | 
| 1127 | } | |
| 1128 | } | |
| 1129 | ||
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1130 | class Timer( | 
| 80412 
a7f8249533e9
moved ci_build module to build_ci;
 Fabian Huch <huch@in.tum.de> parents: 
80411diff
changeset | 1131 | ci_jobs: List[Build_CI.Job], | 
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1132 | store: Store, | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1133 | progress: Progress | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1134 |   ) extends Loop_Process[Date]("Timer", store, progress) {
 | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1135 | |
| 80406 
d85ad13d8cf3
extra timer delay, to limit db transactions;
 Fabian Huch <huch@in.tum.de> parents: 
80405diff
changeset | 1136 |     override def delay = options.seconds("build_manager_timer_delay")
 | 
| 80410 | 1137 | |
| 80405 | 1138 |     private def add_tasks(previous: Date, next: Date): Unit = synchronized_database("add_tasks") {
 | 
| 1139 | for (ci_job <- ci_jobs) | |
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1140 |         ci_job.trigger match {
 | 
| 81882 | 1141 | case timer: Build_CI.Timed if timer.next(previous, next) => | 
| 80416 | 1142 | val task = CI_Build.task(ci_job) | 
| 80349 | 1143 |             echo("Triggered task " + task.kind)
 | 
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1144 | _state = _state.add_pending(task) | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1145 | case _ => | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1146 | } | 
| 80405 | 1147 | } | 
| 80261 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1148 | |
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1149 | def init: Date = Date.now() | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1150 |     def loop_body(previous: Date): Date = {
 | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1151 | val now = Date.now() | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1152 | add_tasks(previous, now) | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1153 | now | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1154 | } | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1155 | } | 
| 
e3f472221f8f
add triggers to ci jobs: on commit vs timed;
 Fabian Huch <huch@in.tum.de> parents: 
80260diff
changeset | 1156 | |
| 80246 | 1157 | |
| 1158 | /* web server */ | |
| 1159 | ||
| 1160 |   object Web_Server {
 | |
| 80338 | 1161 | val Id = new Properties.String(Markup.ID) | 
| 1162 | ||
| 80246 | 1163 |     object Page {
 | 
| 1164 |       val HOME = Path.basic("home")
 | |
| 1165 |       val OVERVIEW = Path.basic("overview")
 | |
| 1166 |       val BUILD = Path.basic("build")
 | |
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1167 |       val DIFF = Path.basic("diff")
 | 
| 80246 | 1168 | } | 
| 1169 | ||
| 80348 | 1170 | def paths(store: Store): Web_App.Paths = | 
| 1171 | Web_App.Paths(store.address, Path.current, serve_frontend = true, landing = Page.HOME) | |
| 1172 | ||
| 80246 | 1173 |     object API {
 | 
| 1174 |       val BUILD_CANCEL = Path.explode("api/build/cancel")
 | |
| 1175 | } | |
| 1176 | ||
| 1177 |     object Cache {
 | |
| 1178 | def empty: Cache = new Cache() | |
| 1179 | } | |
| 1180 | ||
| 1181 |     class Cache private(keep: Time = Time.minutes(1)) {
 | |
| 80497 | 1182 | private var cached: Map[Report, (Time, Report.Data)] = Map.empty | 
| 80246 | 1183 | |
| 80497 | 1184 |       def update(): Unit = synchronized {
 | 
| 1185 | cached = | |
| 80246 | 1186 |           for {
 | 
| 80497 | 1187 | (report, (time, _)) <- cached | 
| 80246 | 1188 | if time + keep > Time.now() | 
| 80497 | 1189 | } yield report -> (time, report.read) | 
| 80246 | 1190 | } | 
| 1191 | ||
| 80497 | 1192 |       def lookup(report: Report): Report.Data = synchronized {
 | 
| 1193 |         cached.get(report) match {
 | |
| 1194 | case Some((_, data)) => | |
| 1195 | cached += report -> (Time.now(), data) | |
| 80246 | 1196 | case None => | 
| 80497 | 1197 | cached += report -> (Time.now(), report.read) | 
| 80246 | 1198 | } | 
| 80497 | 1199 | cached(report)._2 | 
| 80246 | 1200 | } | 
| 1201 | } | |
| 1202 | } | |
| 1203 | ||
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1204 | class Web_Server( | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1205 | port: Int, | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1206 | store: Store, | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1207 | build_hosts: List[Build_Cluster.Host], | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1208 | progress: Progress | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1209 |   ) extends Loop_Process[Unit]("Web_Server", store, progress) {
 | 
| 80246 | 1210 | import Web_App.* | 
| 1211 | import Web_Server.* | |
| 1212 | ||
| 80348 | 1213 | val paths = Web_Server.paths(store) | 
| 80246 | 1214 | val cache = Cache.empty | 
| 1215 | ||
| 1216 |     enum Model {
 | |
| 1217 | case Error extends Model | |
| 1218 | case Cancelled extends Model | |
| 1219 | case Home(state: State) extends Model | |
| 1220 | case Overview(kind: String, state: State) extends Model | |
| 80339 | 1221 | case Details(build: Build, state: State, public: Boolean = true) extends Model | 
| 80647 | 1222 | case Diff(build: Build) extends Model | 
| 80246 | 1223 | } | 
| 1224 | ||
| 1225 |     object View {
 | |
| 1226 | import HTML.* | |
| 1227 | import More_HTML.* | |
| 1228 | ||
| 1229 | def render_if(cond: Boolean, body: XML.Body): XML.Body = if (cond) body else Nil | |
| 1230 | ||
| 80534 | 1231 | def page_link(path: Path, s: String, props: Properties.T = Nil): XML.Elem = | 
| 1232 |         link(paths.frontend_url(path, props).toString, text(s)) + ("target" -> "_parent")
 | |
| 80246 | 1233 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1234 | def link_build(name: String, id: Long): XML.Elem = | 
| 80534 | 1235 | page_link(Page.BUILD, "#" + id, Markup.Name(name)) | 
| 80246 | 1236 | |
| 80647 | 1237 | private def render_page(name: String)(body: => XML.Body): XML.Body = | 
| 1238 | More_HTML.header(List(nav(List(page_link(Page.HOME, "home"))))) :: | |
| 80258 | 1239 | main(chapter(name) :: body ::: Nil) :: Nil | 
| 1240 | ||
| 80419 | 1241 | private def summary(start: Date): XML.Body = | 
| 1242 |         text(" running since " + Build_Log.print_date(start))
 | |
| 1243 | ||
| 1244 | private def summary(status: Status, start: Date, end: Option[Date]): XML.Body = | |
| 1245 |         text(" (" + status.toString + if_proper(end, " in " + (end.get - start).message_hms) +
 | |
| 1246 | ") on " + Build_Log.print_date(start)) | |
| 1247 | ||
| 80258 | 1248 |       def render_home(state: State): XML.Body = render_page("Dashboard") {
 | 
| 80246 | 1249 |         def render_kind(kind: String): XML.Elem = {
 | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1250 | val running = state.get_running(kind).sortBy(_.id).reverse | 
| 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1251 | val finished = state.get_finished(kind).sortBy(_.id).reverse | 
| 80246 | 1252 | |
| 1253 |           def render_previous(finished: List[Result]): XML.Body = {
 | |
| 1254 | val (failed, rest) = finished.span(_.status != Status.ok) | |
| 1255 | val first_failed = failed.lastOption.map(result => | |
| 1256 | par( | |
| 80419 | 1257 |                 text("first failure: ") ::: link_build(result.name, result.id) ::
 | 
| 1258 | summary(result.status, result.start_date, result.end_date))) | |
| 80246 | 1259 | val last_success = rest.headOption.map(result => | 
| 1260 | par( | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1261 |                 text("last success: ") ::: link_build(result.name, result.id) ::
 | 
| 80419 | 1262 | summary(result.status, result.start_date, result.end_date))) | 
| 80246 | 1263 | first_failed.toList ::: last_success.toList | 
| 1264 | } | |
| 1265 | ||
| 1266 | def render_job(job: Job): XML.Body = | |
| 80419 | 1267 | par(link_build(job.name, job.id) :: summary(job.start_date)) :: | 
| 80283 
c19f44f6525a
omit showing previous failures for user builds;
 Fabian Huch <huch@in.tum.de> parents: 
80282diff
changeset | 1268 | render_if( | 
| 
c19f44f6525a
omit showing previous failures for user builds;
 Fabian Huch <huch@in.tum.de> parents: 
80282diff
changeset | 1269 | finished.headOption.exists(_.status != Status.ok) && job.kind != User_Build.name, | 
| 
c19f44f6525a
omit showing previous failures for user builds;
 Fabian Huch <huch@in.tum.de> parents: 
80282diff
changeset | 1270 | render_previous(finished)) | 
| 80246 | 1271 | |
| 1272 | def render_result(result: Result): XML.Body = | |
| 1273 | par( | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1274 | link_build(result.name, result.id) :: | 
| 80419 | 1275 | summary(result.status, result.start_date, result.end_date)) :: | 
| 80258 | 1276 | render_if(result.status != Status.ok && result.kind != User_Build.name, | 
| 1277 | render_previous(finished.tail)) | |
| 80246 | 1278 | |
| 1279 | fieldset( | |
| 80534 | 1280 |             XML.elem("legend", List(page_link(Page.OVERVIEW, kind, Markup.Kind(kind)))) ::
 | 
| 80246 | 1281 | (if (running.nonEmpty) render_job(running.head) | 
| 1282 | else if (finished.nonEmpty) render_result(finished.head) | |
| 1283 | else Nil)) | |
| 1284 | } | |
| 1285 | ||
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1286 | val running = state.running.values.toList | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1287 | val idle = (build_hosts.map(_.hostname).toSet -- running.flatMap(_.hostnames).toSet).toList | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1288 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1289 | def render_rows(hostnames: List[String], body: XML.Body): XML.Body = | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1290 |           hostnames match {
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1291 | case Nil => Nil | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1292 | case hostname :: Nil => List(tr(List(td(text(hostname)), td(body)))) | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1293 | case hostname :: hostnames1 => | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1294 | tr(List(td(text(hostname)), td.apply(rowspan(hostnames.length), body))) :: | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1295 | hostnames1.map(hostname => tr(List(td(text(hostname))))) | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1296 | } | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1297 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1298 | def render_job(job: Job): XML.Body = | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1299 | render_rows(job.hostnames, | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1300 | page_link(Page.BUILD, job.name, Markup.Name(job.name)) :: summary(job.start_date)) | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1301 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1302 |         par(text("Queue: " + state.pending.size + " tasks waiting")) ::
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1303 |         table(tr(List(th(text("Host")), th(text("Activity")))) ::
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1304 | running.sortBy(_.name).flatMap(render_job) ::: | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1305 |           idle.sorted.map(List(_)).flatMap(render_rows(_, text("idle")))) ::
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1306 |         section("Builds") ::
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1307 |         par(text("Total: " + state.num_builds + " builds")) ::
 | 
| 80421 | 1308 | state.kinds.sorted.map(render_kind) | 
| 80246 | 1309 | } | 
| 1310 | ||
| 80258 | 1311 | def render_overview(kind: String, state: State): XML.Body = | 
| 1312 |         render_page("Overview: " + kind + " job ") {
 | |
| 1313 | def render_job(job: Job): XML.Body = | |
| 80419 | 1314 | List(par(link_build(job.name, job.id) :: summary(job.start_date))) | 
| 80246 | 1315 | |
| 80258 | 1316 | def render_result(result: Result): XML.Body = | 
| 1317 | List(par( | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1318 | link_build(result.name, result.id) :: | 
| 80419 | 1319 | summary(result.status, result.start_date, result.end_date))) | 
| 80246 | 1320 | |
| 1321 | itemize( | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1322 | state.get_running(kind).sortBy(_.id).reverse.map(render_job) ::: | 
| 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1323 | state.get_finished(kind).sortBy(_.id).reverse.map(render_result)) :: Nil | 
| 80258 | 1324 | } | 
| 80246 | 1325 | |
| 1326 | private val ID = Params.key(Markup.ID) | |
| 1327 | ||
| 80339 | 1328 | def render_details(build: Build, state: State, public: Boolean): XML.Body = | 
| 1329 |         render_page("Build: " + build.name) {
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1330 | def render_cancel(uuid: UUID.T): XML.Body = | 
| 80258 | 1331 | render_if(!public, List( | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1332 |               submit_form("", List(hidden(ID, uuid.toString),
 | 
| 80258 | 1333 | api_button(paths.api_route(API.BUILD_CANCEL), "cancel build"))))) | 
| 80246 | 1334 | |
| 80542 
dd86d35375a7
log and display components with empty (unknown) revisions to indicate that they are present;
 Fabian Huch <huch@in.tum.de> parents: 
80541diff
changeset | 1335 |           def render_rev(components: List[Component], data: Report.Data): XML.Body = {
 | 
| 
dd86d35375a7
log and display components with empty (unknown) revisions to indicate that they are present;
 Fabian Huch <huch@in.tum.de> parents: 
80541diff
changeset | 1336 | val hg_info = data.component_logs.map(_._1) ++ data.component_diffs.map(_._1) | 
| 
dd86d35375a7
log and display components with empty (unknown) revisions to indicate that they are present;
 Fabian Huch <huch@in.tum.de> parents: 
80541diff
changeset | 1337 |             val s = components.mkString(", ")
 | 
| 80501 | 1338 | |
| 80547 | 1339 |             if (!components.map(_.name).exists(hg_info.toSet)) text("Components: " + s)
 | 
| 1340 |             else text("Components: ") :+ page_link(Page.DIFF, s, Markup.Name(build.name))
 | |
| 80501 | 1341 | } | 
| 80500 | 1342 | |
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1343 | def waiting_for(host: Build_Cluster.Host): XML.Body = | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1344 |             build_hosts.find(_.hostname == host.hostname) match {
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1345 | case None => break ::: text(quote(host.hostname) + " is not a build host") | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1346 | case Some(host) => | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1347 | val active = state.running.values.filter(_.hostnames.contains(host.hostname)) | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1348 | if (active.isEmpty) Nil | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1349 | else break ::: | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1350 |                   text(host.hostname + " is busy with " + active.map(_.name).mkString(" and "))
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1351 | } | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1352 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1353 |           def waiting(task: Task): XML.Body = {
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1354 | val num_before = state.pending.values.count(_ > task) | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1355 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1356 |             if (num_before > 0) text("Waiting for " + num_before + " tasks to complete")
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1357 |             else Exn.capture(task.build_hosts) match {
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1358 |               case Exn.Res(hosts) => text("Hosts not ready:") ::: hosts.flatMap(waiting_for)
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1359 |               case _ => text("Unkown host spec")
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1360 | } | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1361 | } | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1362 | |
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1363 | def started(user: Option[String], date: Date): String = | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1364 | "Started" + if_proper(user, " by " + user.get) + " on " + Build_Log.print_date(date) | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1365 | |
| 80339 | 1366 |           build match {
 | 
| 80258 | 1367 | case task: Task => | 
| 80420 | 1368 |               par(text("Task from " + Build_Log.print_date(task.submit_date) + ". ")) ::
 | 
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1369 |               par(text("Components: " + task.components.mkString(", "))) ::
 | 
| 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1370 | par(List(bold(waiting(task)))) :: | 
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1371 | render_cancel(task.uuid) | 
| 80502 | 1372 | |
| 80258 | 1373 | case job: Job => | 
| 80497 | 1374 | val report_data = cache.lookup(store.report(job.kind, job.id)) | 
| 1375 | ||
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1376 | par(text(started(job.user, job.start_date))) :: | 
| 80258 | 1377 | par( | 
| 80518 
d3b96e19ccc7
tuned messages: whitespace following usual Isabelle conventions;
 wenzelm parents: 
80502diff
changeset | 1378 |                 if (job.cancelled) text("Cancelling ...")
 | 
| 
d3b96e19ccc7
tuned messages: whitespace following usual Isabelle conventions;
 wenzelm parents: 
80502diff
changeset | 1379 |                 else text("Running ...") ::: render_cancel(job.uuid)) ::
 | 
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1380 | par(render_rev(job.components, report_data)) :: | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1381 | par(List(source(report_data.build_log))) :: Nil | 
| 80502 | 1382 | |
| 80258 | 1383 | case result: Result => | 
| 80497 | 1384 | val report_data = cache.lookup(store.report(result.kind, result.id)) | 
| 1385 | ||
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1386 | par(text(started(result.user, result.start_date) + | 
| 80420 | 1387 | if_proper(result.end_date, | 
| 1388 | ", took " + (result.end_date.get - result.start_date).message_hms))) :: | |
| 80258 | 1389 |               par(text("Status: " + result.status)) ::
 | 
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1390 | par(render_rev(result.components, report_data)) :: | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1391 | par(List(source(report_data.build_log))) :: Nil | 
| 80258 | 1392 | } | 
| 1393 | } | |
| 80246 | 1394 | |
| 80647 | 1395 |       def render_diff(build: Build): XML.Body = render_page("Diff: " + build.name) {
 | 
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1396 |         def colored(s: String): XML.Body = {
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1397 | val Colored = "([^\u001b]*)\u001b\\[([0-9;]+)m(.*)\u001b\\[0m([^\u001b]*)".r | 
| 80536 
63afde05a820
tuned HTML display of ANSI colors for better readability;
 Fabian Huch <huch@in.tum.de> parents: 
80535diff
changeset | 1398 |           val colors = List("black", "maroon", "green", "olive", "navy", "purple", "teal", "silver")
 | 
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1399 | |
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1400 |           val lines = split_lines(s).map {
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1401 | case Colored(pre, code, s, post) => | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1402 |               val codes = space_explode(';', code.stripSuffix(";1")).map(Value.Int.parse)
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1403 |               val fg = codes match { case 0 :: i :: Nil => colors.unapply(i - 30) case _ => None }
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1404 | |
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1405 |               val sp = span(if (code.endsWith(";1")) List(bold(text(s))) else text(s))
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1406 |               val sp1 = fg.map(color => sp + ("style" -> ("color:" + color))).getOrElse(sp)
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1407 | List(span(text(pre)), sp1, span(text(post))) | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1408 | case line => text(Library.strip_ansi_color(line)) | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1409 | } | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1410 | |
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1411 | List(source(Library.separate(nl, lines).flatten)) | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1412 | } | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1413 | |
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1414 | def render_diff(data: Report.Data, components: List[Component]): XML.Body = | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1415 | par(List(page_link(Page.BUILD, "back to build", Markup.Name(build.name)))) :: | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1416 |           (for (component <- components if !component.is_local) yield {
 | 
| 81881 | 1417 | val infos = | 
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1418 | data.component_logs.toMap.get(component.name).toList.flatMap(colored) ::: | 
| 80538 | 1419 | data.component_diffs.toMap.get(component.name).toList.flatMap(colored) | 
| 1420 | ||
| 80547 | 1421 | val header = if (infos.isEmpty) component.toString else component.name + ":" | 
| 1422 | par(subsubsection(header) :: infos) | |
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1423 | }) | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1424 | |
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1425 |         build match {
 | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1426 | case job: Job => | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1427 | render_diff(cache.lookup(store.report(job.kind, job.id)), job.components) | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1428 | case result: Result => | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1429 | render_diff(cache.lookup(store.report(result.kind, result.id)), result.components) | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1430 | case _ => Nil | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1431 | } | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1432 | } | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1433 | |
| 80534 | 1434 | def render_cancelled: XML.Body = | 
| 1435 |         render_page("Build cancelled")(List(page_link(Page.HOME, "Home")))
 | |
| 80246 | 1436 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1437 | def parse_uuid(params: Params.Data): Option[UUID.T] = | 
| 80246 | 1438 |         for {
 | 
| 1439 | id <- params.get(ID) | |
| 1440 | uuid <- UUID.unapply(id) | |
| 1441 | } yield uuid | |
| 1442 | } | |
| 1443 | ||
| 1444 |     private val server = new Server[Model](paths, port, progress = progress) {
 | |
| 1445 | /* control */ | |
| 1446 | ||
| 1447 | def overview: Some[Model.Home] = Some(Model.Home(_state)) | |
| 1448 | ||
| 1449 | def get_overview(props: Properties.T): Option[Model.Overview] = | |
| 1450 |         props match {
 | |
| 1451 | case Markup.Kind(kind) => Some(Model.Overview(kind, _state)) | |
| 1452 | case _ => None | |
| 1453 | } | |
| 1454 | ||
| 80339 | 1455 | def get_build(props: Properties.T): Option[Model.Details] = | 
| 80246 | 1456 |         props match {
 | 
| 1457 | case Markup.Name(name) => | |
| 1458 | val state = _state | |
| 80339 | 1459 | state.get(name).map(Model.Details(_, state)) | 
| 80338 | 1460 | case Web_Server.Id(UUID(uuid)) => | 
| 80246 | 1461 | val state = _state | 
| 80339 | 1462 | state.get(uuid).map(Model.Details(_, state, public = false)) | 
| 80246 | 1463 | case _ => None | 
| 1464 | } | |
| 1465 | ||
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1466 | def get_diff(props: Properties.T): Option[Model.Diff] = | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1467 |         props match {
 | 
| 80647 | 1468 | case Markup.Name(name) => _state.get(name).map(Model.Diff(_)) | 
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1469 | case _ => None | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1470 | } | 
| 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1471 | |
| 80246 | 1472 | def cancel_build(params: Params.Data): Option[Model] = | 
| 1473 |         for {
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1474 | uuid <- View.parse_uuid(params) | 
| 80246 | 1475 | model <- | 
| 1476 |             synchronized_database("cancel_build") {
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1477 |               _state.get(uuid).map {
 | 
| 80246 | 1478 | case task: Task => | 
| 1479 | _state = _state.remove_pending(task.name) | |
| 1480 | Model.Cancelled | |
| 1481 | case job: Job => | |
| 80468 | 1482 | _state = _state.cancel_running(job.name) | 
| 80467 | 1483 | Model.Cancelled | 
| 80339 | 1484 | case result: Result => Model.Details(result, _state, public = false) | 
| 80246 | 1485 | } | 
| 1486 | } | |
| 1487 | } yield model | |
| 1488 | ||
| 1489 | def render(model: Model): XML.Body = | |
| 1490 |         HTML.title("Isabelle Build Manager") :: (
 | |
| 1491 |           model match {
 | |
| 1492 |             case Model.Error => HTML.text("invalid request")
 | |
| 1493 | case Model.Home(state) => View.render_home(state) | |
| 1494 | case Model.Overview(kind, state) => View.render_overview(kind, state) | |
| 80339 | 1495 | case Model.Details(build, state, public) => View.render_details(build, state, public) | 
| 80647 | 1496 | case Model.Diff(build) => View.render_diff(build) | 
| 80246 | 1497 | case Model.Cancelled => View.render_cancelled | 
| 1498 | }) | |
| 1499 | ||
| 1500 | val error_model: Model = Model.Error | |
| 1501 | val endpoints = List( | |
| 1502 | Get(Page.HOME, "home", _ => overview), | |
| 1503 | Get(Page.OVERVIEW, "overview", get_overview), | |
| 1504 | Get(Page.BUILD, "build", get_build), | |
| 80535 
417fcf9f5e71
render hg diff and log (on separate page);
 Fabian Huch <huch@in.tum.de> parents: 
80534diff
changeset | 1505 | Get(Page.DIFF, "diff", get_diff), | 
| 80259 
06a473ad2777
use external CSS for build manager page;
 Fabian Huch <huch@in.tum.de> parents: 
80258diff
changeset | 1506 | Post(API.BUILD_CANCEL, "cancel build", cancel_build)) | 
| 80315 | 1507 |       val logo = Bytes.read(Path.explode("$ISABELLE_HOME/lib/logo/isabelle_transparent-48.gif"))
 | 
| 80259 
06a473ad2777
use external CSS for build manager page;
 Fabian Huch <huch@in.tum.de> parents: 
80258diff
changeset | 1508 | val head = | 
| 
06a473ad2777
use external CSS for build manager page;
 Fabian Huch <huch@in.tum.de> parents: 
80258diff
changeset | 1509 | List( | 
| 80320 | 1510 |           HTML.title("Isabelle Build Manager"),
 | 
| 80393 
6138c5b803be
Base64: proper support for large Bytes, with subtle change of types (Bytes instead of String);
 wenzelm parents: 
80346diff
changeset | 1511 |           Web_App.More_HTML.icon("data:image/x-icon;base64," + logo.encode_base64.text),
 | 
| 80259 
06a473ad2777
use external CSS for build manager page;
 Fabian Huch <huch@in.tum.de> parents: 
80258diff
changeset | 1512 |           HTML.style_file("https://hawkz.github.io/gdcss/gd.css"),
 | 
| 80650 
5555a40b2ed4
build_manager: change colors;
 Fabian Huch <huch@in.tum.de> parents: 
80649diff
changeset | 1513 |           HTML.style("""
 | 
| 81881 | 1514 | :root {
 | 
| 80650 
5555a40b2ed4
build_manager: change colors;
 Fabian Huch <huch@in.tum.de> parents: 
80649diff
changeset | 1515 | --color-secondary: var(--color-tertiary); | 
| 
5555a40b2ed4
build_manager: change colors;
 Fabian Huch <huch@in.tum.de> parents: 
80649diff
changeset | 1516 | --color-secondary-hover: var(--color-tertiary-hover); | 
| 
5555a40b2ed4
build_manager: change colors;
 Fabian Huch <huch@in.tum.de> parents: 
80649diff
changeset | 1517 | } | 
| 
5555a40b2ed4
build_manager: change colors;
 Fabian Huch <huch@in.tum.de> parents: 
80649diff
changeset | 1518 | html { background-color: white; }"""))
 | 
| 80246 | 1519 | } | 
| 1520 | ||
| 80782 | 1521 |     override def close(): Unit = {
 | 
| 1522 | server.stop() | |
| 1523 | super.close() | |
| 1524 | } | |
| 1525 | ||
| 80246 | 1526 | def init: Unit = server.start() | 
| 80782 | 1527 | def loop_body(u: Unit): Unit = | 
| 1528 |       if (!progress.stopped) synchronized_database("iterate") { cache.update() }
 | |
| 80246 | 1529 | } | 
| 1530 | ||
| 1531 | ||
| 80344 | 1532 | /** context **/ | 
| 80246 | 1533 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1534 |   case class Context(store: Store, task: Task, id: Long) {
 | 
| 80339 | 1535 | def name = Build.name(task.kind, id) | 
| 80497 | 1536 | def report: Report = store.report(task.kind, id) | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1537 | def task_dir: Path = store.task_dir(task) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1538 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1539 | def isabelle_identifier: String = | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1540 |       if (task.build_cluster) store.options.string("build_cluster_identifier") else store.identifier
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1541 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1542 |     def open_ssh(): SSH.System = {
 | 
| 82040 
0dc7b3253aaa
clarified options: extra ssh connection to cluster of build_manager;
 Fabian Huch <huch@in.tum.de> parents: 
82039diff
changeset | 1543 | if (task.build_cluster) store.open_cluster_ssh() | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1544 | else Library.the_single(task.build_hosts).open_ssh(store.options) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1545 | } | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1546 | } | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1547 | |
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1548 | |
| 80344 | 1549 | /** build process **/ | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1550 | |
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1551 |   object Build_Process {
 | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1552 | def open(context: Context): Build_Process = new Build_Process(context.open_ssh(), context) | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1553 | } | 
| 80246 | 1554 | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1555 |   class Build_Process(ssh: SSH.System, context: Context) {
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1556 | private val task = context.task | 
| 80497 | 1557 | private val progress = context.report.progress | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1558 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1559 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1560 | /* resources with cleanup operations */ | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1561 | |
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1562 | private val _dir = ssh.tmp_dir() | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1563 | private val _isabelle = | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1564 |       try {
 | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1565 | val rsync_context = Rsync.Context(ssh = ssh) | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1566 | val source = File.standard_path(context.task_dir) | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1567 |         Rsync.exec(rsync_context, clean = true, args = List("--", Url.direct_path(source),
 | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1568 | rsync_context.target(_dir))).check | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1569 | |
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1570 | Isabelle_System.rm_tree(context.task_dir) | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1571 | Other_Isabelle(_dir, context.isabelle_identifier, ssh, progress) | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1572 | } | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1573 |       catch { case exn: Throwable => close(); throw exn }
 | 
| 80246 | 1574 | |
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1575 | private val _process = | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1576 |       try {
 | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1577 | val init_components = | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1578 |           for {
 | 
| 80499 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 1579 | extra_component <- task.build_config.extra_components | 
| 
433475f17d73
clarified: components vs. extra components;
 Fabian Huch <huch@in.tum.de> parents: 
80498diff
changeset | 1580 | target = _dir + Sync.DIRS + Path.basic(extra_component.name) | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1581 | if Components.is_component_dir(target) | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1582 | } yield "init_component " + quote(target.absolute.implode) | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1583 | |
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1584 | _isabelle.init( | 
| 80414 
4b10ae56ed01
add Isabelle settings to managed tasks and ci jobs;
 Fabian Huch <huch@in.tum.de> parents: 
80412diff
changeset | 1585 | other_settings = _isabelle.init_components() ::: init_components ::: task.other_settings, | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1586 | fresh = task.build_config.fresh_build, echo = true) | 
| 80246 | 1587 | |
| 80411 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 1588 | val paths = Web_Server.paths(context.store) | 
| 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 1589 | val job_url = paths.frontend_url(Web_Server.Page.BUILD, Markup.Name(context.name)) | 
| 
a9fce67fb8b2
overhauled ci_build: clarified, removed unused, removed implicit Jenkins assumptions;
 Fabian Huch <huch@in.tum.de> parents: 
80410diff
changeset | 1590 | val cmd = task.build_config.command(job_url, task.build_hosts) | 
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1591 |         progress.echo("isabelle" + cmd)
 | 
| 80246 | 1592 | |
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1593 | val script = File.bash_path(Isabelle_Tool.exe(_isabelle.isabelle_home)) + cmd | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1594 | ssh.bash_process(_isabelle.bash_context(script), settings = false) | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1595 | } | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1596 |       catch { case exn: Throwable => close(); throw exn }
 | 
| 80246 | 1597 | |
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1598 | def cancel(): Unit = Option(_process).foreach(_.interrupt()) | 
| 80645 
a1dce0cc6c26
build_manager: terminate processes if cancelling does not work;
 Fabian Huch <huch@in.tum.de> parents: 
80644diff
changeset | 1599 | def terminate(): Unit = Option(_process).foreach(_.terminate()) | 
| 80279 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1600 | |
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1601 |     def close(): Unit = {
 | 
| 
02424b81472a
clarified: add explicit build process;
 Fabian Huch <huch@in.tum.de> parents: 
80278diff
changeset | 1602 | Option(_dir).foreach(ssh.rm_tree) | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1603 | Isabelle_System.rm_tree(context.task_dir) | 
| 80246 | 1604 | ssh.close() | 
| 1605 | } | |
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1606 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1607 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1608 | /* execution */ | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1609 | |
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1610 |     def run(): Process_Result = {
 | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1611 | val process_result = | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1612 | _process.result(progress_stdout = progress.echo(_), progress_stderr = progress.echo(_)) | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1613 | close() | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1614 | process_result | 
| 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1615 | } | 
| 80246 | 1616 | } | 
| 1617 | ||
| 1618 | ||
| 80344 | 1619 | /** build manager store **/ | 
| 80246 | 1620 | |
| 1621 |   case class Store(options: Options) {
 | |
| 1622 |     val base_dir = Path.explode(options.string("build_manager_dir"))
 | |
| 82043 
65ac068f9d17
use ssh host for default address;
 Fabian Huch <huch@in.tum.de> parents: 
82041diff
changeset | 1623 |     val address = {
 | 
| 
65ac068f9d17
use ssh host for default address;
 Fabian Huch <huch@in.tum.de> parents: 
82041diff
changeset | 1624 |       Url(proper_string(options.string("build_manager_address")) getOrElse
 | 
| 
65ac068f9d17
use ssh host for default address;
 Fabian Huch <huch@in.tum.de> parents: 
82041diff
changeset | 1625 |         "https://" + options.string("build_manager_ssh_host"))
 | 
| 
65ac068f9d17
use ssh host for default address;
 Fabian Huch <huch@in.tum.de> parents: 
82041diff
changeset | 1626 | } | 
| 80246 | 1627 | |
| 80336 | 1628 |     val pending = base_dir + Path.basic("pending")
 | 
| 80252 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1629 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1630 | def task_dir(task: Task) = pending + Path.basic(task.uuid.toString) | 
| 80252 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1631 | |
| 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1632 |     def sync_permissions(dir: Path, ssh: SSH.System = SSH.Local): Unit = {
 | 
| 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1633 |       ssh.execute("chmod -R g+rwx " + File.bash_path(dir))
 | 
| 82046 | 1634 |       ssh.execute("chown -R :" + unix_group + " " + File.bash_path(dir))
 | 
| 80252 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1635 | } | 
| 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1636 | |
| 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1637 | def init_dirs(): Unit = | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1638 | List(pending, finished).foreach(dir => sync_permissions(Isabelle_System.make_directory(dir))) | 
| 80252 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1639 | |
| 82046 | 1640 |     val unix_group: String = options.string("build_manager_group")
 | 
| 80246 | 1641 | |
| 1642 | def open_database(server: SSH.Server = SSH.no_server): PostgreSQL.Database = | |
| 1643 | PostgreSQL.open_database_server(options, server = server, | |
| 1644 |         user = options.string("build_manager_database_user"),
 | |
| 1645 |         password = options.string("build_manager_database_password"),
 | |
| 1646 |         database = options.string("build_manager_database_name"),
 | |
| 1647 |         host = options.string("build_manager_database_host"),
 | |
| 1648 |         port = options.int("build_manager_database_port"),
 | |
| 1649 |         ssh_host = options.string("build_manager_database_ssh_host"),
 | |
| 1650 |         ssh_port = options.int("build_manager_database_ssh_port"),
 | |
| 1651 |         ssh_user = options.string("build_manager_database_ssh_user"))
 | |
| 1652 | ||
| 82044 | 1653 | |
| 1654 | /* server */ | |
| 1655 | ||
| 1656 |     val identifier = options.string("build_manager_identifier")
 | |
| 1657 | ||
| 1658 |     val finished = base_dir + Path.basic("finished")
 | |
| 1659 | def report(kind: String, id: Long): Report = | |
| 1660 | Report(kind, id, finished + Path.make(List(kind, id.toString))) | |
| 1661 | ||
| 1662 | def open_cluster_ssh(): SSH.Session = | |
| 1663 | SSH.open_session(options, | |
| 1664 |         host = options.string("build_manager_cluster_ssh_host"),
 | |
| 1665 |         port = options.int("build_manager_cluster_ssh_port"),
 | |
| 1666 |         user = options.string("build_manager_cluster_ssh_user"))
 | |
| 1667 | ||
| 1668 | ||
| 1669 | /* client */ | |
| 1670 | ||
| 1671 | def open_ssh(): SSH.Session = | |
| 1672 | SSH.open_session(options, | |
| 1673 |         host = options.string("build_manager_ssh_host"),
 | |
| 1674 |         port = options.int("build_manager_ssh_port"),
 | |
| 1675 |         user = options.string("build_manager_ssh_user"))
 | |
| 1676 | ||
| 80246 | 1677 | def open_postgresql_server(): SSH.Server = | 
| 1678 | PostgreSQL.open_server(options, | |
| 1679 |         host = options.string("build_manager_database_host"),
 | |
| 1680 |         port = options.int("build_manager_database_port"),
 | |
| 1681 |         ssh_host = options.string("build_manager_ssh_host"),
 | |
| 1682 |         ssh_port = options.int("build_manager_ssh_port"),
 | |
| 1683 |         ssh_user = options.string("build_manager_ssh_user"))
 | |
| 1684 | } | |
| 1685 | ||
| 1686 | ||
| 80344 | 1687 | /** build manager server **/ | 
| 1688 | ||
| 80246 | 1689 | /* build manager */ | 
| 1690 | ||
| 1691 | def build_manager( | |
| 1692 | build_hosts: List[Build_Cluster.Host], | |
| 1693 | options: Options, | |
| 1694 | port: Int, | |
| 1695 | sync_dirs: List[Sync.Dir] = Nil, | |
| 1696 | progress: Progress = new Progress | |
| 1697 |   ): Unit = {
 | |
| 1698 | val store = Store(options) | |
| 1699 | val isabelle_repository = Mercurial.self_repository() | |
| 80412 
a7f8249533e9
moved ci_build module to build_ci;
 Fabian Huch <huch@in.tum.de> parents: 
80411diff
changeset | 1700 |     val ci_jobs = space_explode(',', options.string("build_manager_ci_jobs")).map(Build_CI.the_job)
 | 
| 80246 | 1701 | |
| 80349 | 1702 | progress.echo_if(ci_jobs.nonEmpty, "Managing ci jobs: " + commas_quote(ci_jobs.map(_.name))) | 
| 80246 | 1703 | |
| 1704 | using(store.open_database())(db => | |
| 1705 | Build_Manager.private_data.transaction_lock(db, | |
| 80252 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1706 |         create = true, label = "Build_Manager.build_manager") { store.init_dirs() })
 | 
| 80246 | 1707 | |
| 1708 | val processes = List( | |
| 1709 | new Runner(store, build_hosts, isabelle_repository, sync_dirs, progress), | |
| 1710 | new Poller(ci_jobs, store, isabelle_repository, sync_dirs, progress), | |
| 80647 | 1711 | new Timer(ci_jobs, store, progress), | 
| 80649 
f5ae78dd49d1
build_manager: display more info;
 Fabian Huch <huch@in.tum.de> parents: 
80647diff
changeset | 1712 | new Web_Server(port, store, build_hosts, progress)) | 
| 80246 | 1713 | |
| 1714 | val threads = processes.map(Isabelle_Thread.create(_)) | |
| 1715 |     POSIX_Interrupt.handler {
 | |
| 1716 | progress.stop() | |
| 1717 | processes.foreach(_.interrupt()) | |
| 1718 |     } {
 | |
| 1719 | threads.foreach(_.start()) | |
| 1720 | threads.foreach(_.join()) | |
| 1721 | } | |
| 1722 | } | |
| 1723 | ||
| 80334 | 1724 | |
| 1725 | /* Isabelle tool wrapper */ | |
| 1726 | ||
| 1727 |   val isabelle_tool = Isabelle_Tool("build_manager", "run build manager", Scala_Project.here,
 | |
| 1728 |     { args =>
 | |
| 1729 | var afp_root: Option[Path] = None | |
| 1730 | val dirs = new mutable.ListBuffer[Path] | |
| 1731 | val build_hosts = new mutable.ListBuffer[Build_Cluster.Host] | |
| 1732 | var options = Options.init() | |
| 82038 | 1733 | var port = 0 | 
| 80334 | 1734 | |
| 1735 |       val getopts = Getopts("""
 | |
| 1736 | Usage: isabelle build_manager [OPTIONS] | |
| 1737 | ||
| 1738 | Options are: | |
| 1739 |     -A ROOT      include AFP with given root directory (":" for """ + AFP.BASE.implode + """)
 | |
| 1740 | -D DIR include extra component in given directory | |
| 1741 | -H HOSTS host specifications for all available hosts of the form | |
| 1742 | NAMES:PARAMETERS (separated by commas) | |
| 1743 | -o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) | |
| 1744 | -p PORT explicit web server port | |
| 1745 | ||
| 82039 | 1746 | Run Isabelle build manager. | 
| 1747 | """, | |
| 80334 | 1748 | "A:" -> (arg => afp_root = Some(if (arg == ":") AFP.BASE else Path.explode(arg))), | 
| 1749 | "D:" -> (arg => dirs += Path.explode(arg)), | |
| 1750 | "H:" -> (arg => build_hosts ++= Build_Cluster.Host.parse(Registry.global, arg)), | |
| 1751 | "o:" -> (arg => options = options + arg), | |
| 1752 | "p:" -> (arg => port = Value.Int.parse(arg))) | |
| 1753 | ||
| 1754 | val more_args = getopts(args) | |
| 1755 | if (more_args.nonEmpty) getopts.usage() | |
| 1756 | ||
| 1757 | val progress = new Console_Progress() | |
| 1758 | val sync_dirs = | |
| 1759 | Sync.afp_dirs(afp_root) ::: dirs.toList.map(dir => Sync.Dir(dir.file_name, dir)) | |
| 1760 | ||
| 1761 | sync_dirs.foreach(_.check()) | |
| 1762 | ||
| 1763 | build_manager(build_hosts = build_hosts.toList, options = options, port = port, | |
| 1764 | sync_dirs = sync_dirs, progress = progress) | |
| 1765 | }) | |
| 1766 | ||
| 1767 | ||
| 80344 | 1768 | /** restore build manager database **/ | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1769 | |
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1770 | def build_manager_database( | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1771 | options: Options, | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1772 | sync_dirs: List[Sync.Dir] = Sync.afp_dirs(), | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1773 | update_reports: Boolean = false, | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1774 | progress: Progress = new Progress | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1775 |   ): Unit = {
 | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1776 | val store = Store(options) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1777 |     using(store.open_database()) { db =>
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1778 |       db.transaction {
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1779 | val tables0 = Build_Manager.private_data.tables.list | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1780 | val tables = tables0.filter(t => db.exists_table(t.name)) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1781 |         if (tables.nonEmpty) {
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1782 |           progress.echo("Removing tables " + commas_quote(tables.map(_.name)) + " ...")
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1783 | db.execute_statement(SQL.MULTI(tables.map(db.destroy))) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1784 | } | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1785 | } | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1786 | |
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1787 | val reports = | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1788 |         for {
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1789 | kind <- File.read_dir(store.finished) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1790 | entry <- File.read_dir(store.finished + Path.basic(kind)) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1791 | id <- Value.Long.unapply(entry) | 
| 80497 | 1792 | report = store.report(kind, id) | 
| 1793 | if report.ok | |
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1794 | } yield report | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1795 | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1796 | val results = reports.map(report => report -> report.result()) | 
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1797 | |
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1798 |       if (update_reports) {
 | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1799 | val isabelle_repository = Mercurial.self_repository() | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1800 | val afp_repository = | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1801 |           sync_dirs.find(_.name == Component.AFP).getOrElse(error("Missing AFP for udpate")).hg
 | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1802 | |
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1803 | isabelle_repository.pull() | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1804 | afp_repository.pull() | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1805 | |
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1806 |         for ((kind, results0) <- results.groupBy(_._1.kind) if kind != User_Build.name) {
 | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1807 | val results1 = results0.sortBy(_._1.id) | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1808 |           results1.foldLeft(("", "")) {
 | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1809 | case ((isabelle_rev0, afp_rev0), (report, result)) => | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1810 |               val isabelle_rev = result.isabelle_version.getOrElse("")
 | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1811 |               val afp_rev = result.afp_version.getOrElse("")
 | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1812 | |
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1813 | report.write_log(Component.Isabelle, isabelle_repository, isabelle_rev0, isabelle_rev) | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1814 | report.write_log(Component.AFP, afp_repository, afp_rev0, afp_rev) | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1815 | report.write_diff( | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1816 | Component.Isabelle, isabelle_repository, isabelle_rev0, isabelle_rev) | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1817 | report.write_diff(Component.AFP, afp_repository, afp_rev0, afp_rev) | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1818 | |
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1819 | (isabelle_rev, afp_rev) | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1820 | } | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1821 | } | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1822 | } | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1823 | |
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1824 | val state = State(finished = results.map((_, result) => result.name -> result).toMap) | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1825 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1826 | Build_Manager.private_data.transaction_lock(db, | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1827 |         create = true, label = "Build_Manager.build_manager_database") {
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1828 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1829 |         progress.echo("Writing " + results.length + " results ...")
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1830 | Build_Manager.private_data.push_state(db, State(), state) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1831 | } | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1832 | } | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1833 | } | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1834 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1835 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1836 | /* Isabelle tool wrapper */ | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1837 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1838 |   val isabelle_tool1 = Isabelle_Tool("build_manager_database",
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1839 | "restore build_manager database from log files", | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1840 | Scala_Project.here, | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1841 |     { args =>
 | 
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1842 | var afp_root: Option[Path] = None | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1843 | var options = Options.init() | 
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1844 | var update_reports = false | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1845 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1846 |       val getopts = Getopts("""
 | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1847 | Usage: isabelle build_manager_database [OPTIONS] | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1848 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1849 | Options are: | 
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1850 |     -A ROOT      include AFP with given root directory (":" for """ + AFP.BASE.implode + """)
 | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1851 | -o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) | 
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1852 | -u update reports | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1853 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1854 | Restore build_manager database from log files. | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1855 | """, | 
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1856 | "A:" -> (arg => afp_root = Some(if (arg == ":") AFP.BASE else Path.explode(arg))), | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1857 | "o:" -> (arg => options = options + arg), | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1858 | "u" -> (_ => update_reports = true)) | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1859 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1860 | val more_args = getopts(args) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1861 | if (more_args.nonEmpty) getopts.usage() | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1862 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1863 | val progress = new Console_Progress() | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1864 | |
| 80545 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1865 | build_manager_database(options, sync_dirs = Sync.afp_dirs(afp_root), | 
| 
17786f08b93e
allow updating reports via build_manager_database tool, e.g. to generate hg logs/diffs;
 Fabian Huch <huch@in.tum.de> parents: 
80544diff
changeset | 1866 | update_reports = update_reports, progress = progress) | 
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1867 | }) | 
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1868 | |
| 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1869 | |
| 80344 | 1870 | /** build manager client */ | 
| 1871 | ||
| 80334 | 1872 | /* build task */ | 
| 1873 | ||
| 80246 | 1874 | def build_task( | 
| 1875 | options: Options, | |
| 1876 | store: Store, | |
| 1877 | afp_root: Option[Path] = None, | |
| 1878 | base_sessions: List[String] = Nil, | |
| 1879 | presentation: Boolean = false, | |
| 1880 | requirements: Boolean = false, | |
| 1881 | exclude_session_groups: List[String] = Nil, | |
| 1882 | all_sessions: Boolean = false, | |
| 1883 | build_heap: Boolean = false, | |
| 1884 | clean_build: Boolean = false, | |
| 1885 | export_files: Boolean = false, | |
| 1886 | fresh_build: Boolean = false, | |
| 1887 | session_groups: List[String] = Nil, | |
| 1888 | sessions: List[String] = Nil, | |
| 1889 | prefs: List[Options.Spec] = Nil, | |
| 1890 | exclude_sessions: List[String] = Nil, | |
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 1891 | verbose: Boolean = false, | 
| 80250 
8ae6f4e8cc2a
allow explicit Isabelle rev in build task (e.g., for older Isabelle versions);
 Fabian Huch <huch@in.tum.de> parents: 
80246diff
changeset | 1892 | rev: String = "", | 
| 80246 | 1893 | progress: Progress = new Progress | 
| 1894 |   ): UUID.T = {
 | |
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1895 | val uuid = UUID.random() | 
| 80246 | 1896 |     val afp_rev = if (afp_root.nonEmpty) Some("") else None
 | 
| 1897 | ||
| 80281 
17d2f775907a
add cluster/hosts configurations to build manager: allows running jobs in parallel on distinct hardware;
 Fabian Huch <huch@in.tum.de> parents: 
80280diff
changeset | 1898 |     val hosts_spec = options.string("build_manager_cluster")
 | 
| 80469 
a3bae6dd7344
add timeout to build manager tasks/jobs (e.g. for cluster builds that don't terminate after error on host);
 Fabian Huch <huch@in.tum.de> parents: 
80468diff
changeset | 1899 |     val timeout = options.seconds("build_manager_timeout")
 | 
| 80348 | 1900 | val paths = Web_Server.paths(store) | 
| 80338 | 1901 | |
| 80246 | 1902 |     progress.interrupt_handler {
 | 
| 1903 |       using(store.open_ssh()) { ssh =>
 | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1904 |         val user = ssh.execute("whoami").check.out
 | 
| 81881 | 1905 | |
| 80646 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1906 | val build_config = User_Build(user, afp_rev, prefs, requirements, all_sessions, | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1907 | base_sessions, exclude_session_groups, exclude_sessions, session_groups, sessions, | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1908 | build_heap, clean_build, export_files, fresh_build, presentation, verbose) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1909 | val task = Task(build_config, hosts_spec, timeout, uuid = uuid, priority = Priority.high) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1910 | |
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1911 | val dir = store.task_dir(task) | 
| 
b4e116523cb6
build_manager: store submitting user;
 Fabian Huch <huch@in.tum.de> parents: 
80645diff
changeset | 1912 | |
| 80252 
96543177ab7e
build manager: manage directories/permissions, to minimize local administration;
 Fabian Huch <huch@in.tum.de> parents: 
80251diff
changeset | 1913 | val rsync_context = Rsync.Context(ssh = ssh) | 
| 80518 
d3b96e19ccc7
tuned messages: whitespace following usual Isabelle conventions;
 wenzelm parents: 
80502diff
changeset | 1914 |         progress.echo("Transferring repositories ...")
 | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1915 | Sync.sync(store.options, rsync_context, dir, preserve_jars = true, | 
| 80250 
8ae6f4e8cc2a
allow explicit Isabelle rev in build task (e.g., for older Isabelle versions);
 Fabian Huch <huch@in.tum.de> parents: 
80246diff
changeset | 1916 | dirs = Sync.afp_dirs(afp_root), rev = rev) | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1917 | store.sync_permissions(dir, ssh) | 
| 80246 | 1918 | |
| 1919 |         if (progress.stopped) {
 | |
| 80518 
d3b96e19ccc7
tuned messages: whitespace following usual Isabelle conventions;
 wenzelm parents: 
80502diff
changeset | 1920 |           progress.echo("Cancelling submission ...")
 | 
| 80280 
7987b33fb6c5
clarified context: operations now in build process;
 Fabian Huch <huch@in.tum.de> parents: 
80279diff
changeset | 1921 | ssh.rm_tree(dir) | 
| 80246 | 1922 |         } else {
 | 
| 1923 |           using(store.open_postgresql_server()) { server =>
 | |
| 1924 |             using(store.open_database(server = server)) { db =>
 | |
| 1925 |               Build_Manager.private_data.transaction_lock(db, label = "Build_Manager.build_task") {
 | |
| 1926 | val old_state = Build_Manager.private_data.pull_state(db, State()) | |
| 1927 | val state = old_state.add_pending(task) | |
| 1928 | Build_Manager.private_data.push_state(db, old_state, state) | |
| 1929 | } | |
| 1930 | } | |
| 1931 | } | |
| 80338 | 1932 | |
| 1933 | val address = paths.frontend_url(Web_Server.Page.BUILD, Web_Server.Id(task.uuid.toString)) | |
| 80246 | 1934 |           progress.echo("Submitted task. Private url: " + address)
 | 
| 1935 | } | |
| 1936 | } | |
| 1937 | } | |
| 1938 | ||
| 80337 
02f8a35ed8e2
clarified names: more canonical;
 Fabian Huch <huch@in.tum.de> parents: 
80336diff
changeset | 1939 | uuid | 
| 80246 | 1940 | } | 
| 1941 | ||
| 1942 | ||
| 1943 | /* Isabelle tool wrapper */ | |
| 1944 | ||
| 82915 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1945 | private val build_manager_ssh_options = | 
| 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1946 |     List("build_manager_ssh_user", "build_manager_ssh_host", "build_manager_ssh_port")
 | 
| 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1947 | |
| 80343 
595b362ab851
add build_manager_database tool to restore db from log files;
 Fabian Huch <huch@in.tum.de> parents: 
80342diff
changeset | 1948 |   val isabelle_tool2 = Isabelle_Tool("build_task", "submit build task for build manager",
 | 
| 80246 | 1949 | Scala_Project.here, | 
| 1950 |     { args =>
 | |
| 1951 | var afp_root: Option[Path] = None | |
| 1952 | val base_sessions = new mutable.ListBuffer[String] | |
| 1953 | var presentation = false | |
| 1954 | var requirements = false | |
| 1955 | val exclude_session_groups = new mutable.ListBuffer[String] | |
| 1956 | var all_sessions = false | |
| 1957 | var build_heap = false | |
| 1958 | var clean_build = false | |
| 1959 | var export_files = false | |
| 1960 | var fresh_build = false | |
| 1961 | val session_groups = new mutable.ListBuffer[String] | |
| 1962 | var options = Options.init(specs = Options.Spec.ISABELLE_BUILD_OPTIONS) | |
| 80423 | 1963 | val prefs = new mutable.ListBuffer[Options.Spec] | 
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 1964 | var verbose = false | 
| 80250 
8ae6f4e8cc2a
allow explicit Isabelle rev in build task (e.g., for older Isabelle versions);
 Fabian Huch <huch@in.tum.de> parents: 
80246diff
changeset | 1965 | var rev = "" | 
| 80246 | 1966 | val exclude_sessions = new mutable.ListBuffer[String] | 
| 1967 | ||
| 82915 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1968 | def show_options: String = | 
| 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1969 | cat_lines(build_manager_ssh_options.flatMap(options.get).map(_.print)) | 
| 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1970 | |
| 80246 | 1971 |       val getopts = Getopts("""
 | 
| 1972 | Usage: isabelle build_task [OPTIONS] [SESSIONS ...] | |
| 1973 | ||
| 1974 | Options are: | |
| 1975 |     -A ROOT      include AFP with given root directory (":" for """ + AFP.BASE.implode + """)
 | |
| 1976 | -B NAME include session NAME and all descendants | |
| 1977 | -P enable HTML/PDF presentation | |
| 1978 | -R refer to requirements of selected sessions | |
| 1979 | -X NAME exclude sessions from group NAME and all descendants | |
| 1980 | -a select all sessions | |
| 1981 | -b build heap images | |
| 1982 | -c clean build | |
| 1983 | -e export files from session specification into file-system | |
| 1984 | -f fresh build | |
| 1985 | -g NAME select session group NAME | |
| 1986 | -o OPTION override Isabelle system OPTION (via NAME=VAL or NAME) | |
| 82915 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1987 | -p OPTION override Isabelle system OPTION for build process | 
| 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1988 | (via NAME=VAL or NAME) | 
| 80250 
8ae6f4e8cc2a
allow explicit Isabelle rev in build task (e.g., for older Isabelle versions);
 Fabian Huch <huch@in.tum.de> parents: 
80246diff
changeset | 1989 | -r REV explicit revision (default: state of working directory) | 
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 1990 | -v verbose | 
| 80246 | 1991 | -x NAME exclude session NAME and all descendants | 
| 1992 | ||
| 82915 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1993 | Submit build task on managed server. | 
| 80246 | 1994 | |
| 82915 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1995 | Requires SSH access to known host according to system options: | 
| 
b7422567c507
tuned doc: display build manager SSH options;
 Fabian Huch <huch@in.tum.de> parents: 
82466diff
changeset | 1996 | """ + Library.indent_lines(4, show_options) + "\n", | 
| 80246 | 1997 | "A:" -> (arg => afp_root = Some(if (arg == ":") AFP.BASE else Path.explode(arg))), | 
| 1998 | "B:" -> (arg => base_sessions += arg), | |
| 1999 | "P" -> (_ => presentation = true), | |
| 2000 | "R" -> (_ => requirements = true), | |
| 2001 | "X:" -> (arg => exclude_session_groups += arg), | |
| 2002 | "a" -> (_ => all_sessions = true), | |
| 2003 | "b" -> (_ => build_heap = true), | |
| 2004 | "c" -> (_ => clean_build = true), | |
| 2005 | "e" -> (_ => export_files = true), | |
| 2006 | "f" -> (_ => fresh_build = true), | |
| 2007 | "g:" -> (arg => session_groups += arg), | |
| 2008 | "o:" -> (arg => options = options + arg), | |
| 80423 | 2009 | "p:" -> (arg => prefs += Options.Spec.make(arg)), | 
| 80250 
8ae6f4e8cc2a
allow explicit Isabelle rev in build task (e.g., for older Isabelle versions);
 Fabian Huch <huch@in.tum.de> parents: 
80246diff
changeset | 2010 | "r:" -> (arg => rev = arg), | 
| 80254 
6b3374d208b8
add verbose option to build_task;
 Fabian Huch <huch@in.tum.de> parents: 
80252diff
changeset | 2011 | "v" -> (_ => verbose = true), | 
| 80246 | 2012 | "x:" -> (arg => exclude_sessions += arg)) | 
| 2013 | ||
| 2014 | val sessions = getopts(args) | |
| 2015 | val store = Store(options) | |
| 2016 | val progress = new Console_Progress() | |
| 2017 | ||
| 80470 | 2018 | build_task(options, store, afp_root = afp_root, base_sessions = base_sessions.toList, | 
| 2019 | presentation = presentation, requirements = requirements, exclude_session_groups = | |
| 2020 | exclude_session_groups.toList, all_sessions = all_sessions, build_heap = build_heap, | |
| 2021 | clean_build = clean_build, export_files = export_files, fresh_build = fresh_build, | |
| 2022 | session_groups = session_groups.toList, sessions = sessions, prefs = prefs.toList, verbose = | |
| 2023 | verbose, rev = rev, exclude_sessions = exclude_sessions.toList, progress = progress) | |
| 80246 | 2024 | }) | 
| 2025 | } |