src/Pure/Build/build_manager.scala
changeset 80260 ed9b1598d293
parent 80259 06a473ad2777
child 80261 e3f472221f8f
--- a/src/Pure/Build/build_manager.scala	Thu Jun 06 09:04:01 2024 +0200
+++ b/src/Pure/Build/build_manager.scala	Thu Jun 06 13:37:27 2024 +0200
@@ -720,11 +720,12 @@
   /* repository poller */
 
   object Poller {
-    case class State(ids: List[String], next: Future[List[String]])
+    case class Versions(isabelle: String, components: List[Component])
+    case class State(current: Versions, next: Future[Versions])
   }
 
   class Poller(
-    ci_jobs: List[String],
+    ci_jobs: List[isabelle.CI_Build.Job],
     store: Store,
     isabelle_repository: Mercurial.Repository,
     sync_dirs: List[Sync.Dir],
@@ -733,25 +734,35 @@
 
     override def delay = options.seconds("build_manager_poll_delay")
 
-    private def ids: List[String] =
-      isabelle_repository.id("default") :: sync_dirs.map(_.hg.id("default"))
+    private def current: Poller.Versions =
+      Poller.Versions(isabelle_repository.id("default"), sync_dirs.map(dir =>
+        Component(dir.name, dir.hg.id("default"))))
 
-    private def poll: Future[List[String]] = Future.fork {
+    private def poll: Future[Poller.Versions] = Future.fork {
       Par_List.map((repo: Mercurial.Repository) => repo.pull(),
         isabelle_repository :: sync_dirs.map(_.hg))
 
-      ids
+      current
+    }
+
+    val init: Poller.State = Poller.State(current, poll)
+
+    def ci_task(ci_job: isabelle.CI_Build.Job): Task = {
+      val ci_build = CI_Build(ci_job.name, ci_job.components.map(Component(_, "default")))
+      Task(ci_build, priority = Priority.low, isabelle_rev = "default")
     }
 
-    val init: Poller.State = Poller.State(ids, poll)
+    private def add_tasks(current: Poller.Versions, next: Poller.Versions): Unit = {
+      val isabelle_updated = current.isabelle != next.isabelle
+      val updated_components =
+        next.components.zip(current.components).filter(_ != _).map(_._1.name).toSet
 
-    def ci_task(name: String): Task =
-      Task(CI_Build(name, sync_dirs.map(dir => Component(dir.name, "default"))),
-        priority = Priority.low, isabelle_rev = "default")
-
-    private def add_task(): Unit = synchronized_database("add_task") {
-      for (name <- ci_jobs if !_state.pending.values.exists(_.kind == name)) {
-        _state = _state.add_pending(ci_task(name))
+      synchronized_database("add_tasks") {
+        for {
+          ci_job <- ci_jobs
+          if isabelle_updated || ci_job.components.exists(updated_components.contains)
+          if !_state.pending.values.exists(_.kind == ci_job.name)
+        } _state = _state.add_pending(ci_task(ci_job))
       }
     }
 
@@ -761,13 +772,13 @@
         state.next.join_result match {
           case Exn.Exn(exn) =>
             echo_error_message("Could not reach repository: " + exn.getMessage)
-            Poller.State(state.ids, poll)
-          case Exn.Res(ids1) =>
-            if (state.ids != ids1) {
-              echo("Found new revisions: " + ids1)
-              add_task()
+            Poller.State(state.current, poll)
+          case Exn.Res(next) =>
+            if (state.current != next) {
+              echo("Found new revisions: " + next)
+              add_tasks(state.current, next)
             }
-            Poller.State(ids1, poll)
+            Poller.State(next, poll)
         }
       }
   }
@@ -1153,7 +1164,8 @@
   ): Unit = {
     val store = Store(options)
     val isabelle_repository = Mercurial.self_repository()
-    val ci_jobs = space_explode(',', options.string("build_manager_ci_jobs"))
+    val ci_jobs =
+      space_explode(',', options.string("build_manager_ci_jobs")).map(isabelle.CI_Build.the_job)
     val url = Url(options.string("build_manager_address"))
     val paths = Web_App.Paths(url, Path.current, true, Web_Server.Page.HOME)