1214 def render_cancel(uuid: UUID.T): XML.Body = |
1216 def render_cancel(uuid: UUID.T): XML.Body = |
1215 render_if(!public, List( |
1217 render_if(!public, List( |
1216 submit_form("", List(hidden(ID, uuid.toString), |
1218 submit_form("", List(hidden(ID, uuid.toString), |
1217 api_button(paths.api_route(API.BUILD_CANCEL), "cancel build"))))) |
1219 api_button(paths.api_route(API.BUILD_CANCEL), "cancel build"))))) |
1218 |
1220 |
1219 def render_diff(diff: String): XML.Body = { |
1221 def non_local(components: List[Component]): List[Component] = |
1220 val Colored = "\u001b\\[([0-9;]+)m(.*)\u001b\\[0m".r |
1222 for (component <- components if !component.is_local) yield component |
1221 val colors = List("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white") |
1223 |
1222 |
1224 def render_rev(components: List[Component], data: Report.Data): XML.Body = { |
1223 val lines = split_lines(diff).map { |
1225 val relevant = non_local(components) |
1224 case Colored(code, s) => |
1226 val hg_info = data.component_logs.map(_._1) ++ data.component_diffs.map(_._1) |
1225 val codes = space_explode(';', code.stripSuffix(";1")).map(Value.Int.parse) |
1227 val s = relevant.mkString(", ") |
1226 val fg = codes match { case 0 :: i :: Nil => colors.unapply(i - 30) case _ => None } |
1228 |
1227 |
1229 if (!relevant.map(_.name).exists(hg_info.toSet)) text(s) |
1228 val sp = span(if (code.endsWith(";1")) List(bold(text(s))) else text(s)) |
1230 else List(page_link(Page.DIFF, s, Markup.Name(build.name))) |
1229 List(fg.map(color => sp + ("style" -> ("color:" + color))).getOrElse(sp)) |
|
1230 case line => text(Library.strip_ansi_color(line)) |
|
1231 } |
|
1232 |
|
1233 List(source(Library.separate(nl, lines).flatten)) |
|
1234 } |
1231 } |
1235 |
|
1236 def render_rev(components: List[Component], diffs: Map[String, String]): XML.Body = |
|
1237 for (component <- components if !component.is_local) |
|
1238 yield par(text(component.toString) ++ diffs.get(component.name).flatMap(render_diff)) |
|
1239 |
1232 |
1240 build match { |
1233 build match { |
1241 case task: Task => |
1234 case task: Task => |
1242 par(text("Task from " + Build_Log.print_date(task.submit_date) + ". ")) :: |
1235 par(text("Task from " + Build_Log.print_date(task.submit_date) + ". ")) :: |
1243 render_rev(task.components, Map.empty) ::: |
1236 par(text(non_local(task.components).mkString(", "))) :: |
1244 render_cancel(task.uuid) |
1237 render_cancel(task.uuid) |
1245 |
1238 |
1246 case job: Job => |
1239 case job: Job => |
1247 val report_data = cache.lookup(store.report(job.kind, job.id)) |
1240 val report_data = cache.lookup(store.report(job.kind, job.id)) |
1248 |
1241 |
1249 par(text("Start: " + Build_Log.print_date(job.start_date))) :: |
1242 par(text("Start: " + Build_Log.print_date(job.start_date))) :: |
1250 par( |
1243 par( |
1251 if (job.cancelled) text("Cancelling ...") |
1244 if (job.cancelled) text("Cancelling ...") |
1252 else text("Running ...") ::: render_cancel(job.uuid)) :: |
1245 else text("Running ...") ::: render_cancel(job.uuid)) :: |
1253 render_rev(job.components, report_data.component_diffs.toMap) ::: |
1246 par(render_rev(job.components, report_data)) :: |
1254 par(text("Log") :+ source(report_data.build_log)) :: Nil |
1247 par(List(source(report_data.build_log))) :: Nil |
1255 |
1248 |
1256 case result: Result => |
1249 case result: Result => |
1257 val report_data = cache.lookup(store.report(result.kind, result.id)) |
1250 val report_data = cache.lookup(store.report(result.kind, result.id)) |
1258 |
1251 |
1259 par(text("Start: " + Build_Log.print_date(result.start_date) + |
1252 par(text("Start: " + Build_Log.print_date(result.start_date) + |
1260 if_proper(result.end_date, |
1253 if_proper(result.end_date, |
1261 ", took " + (result.end_date.get - result.start_date).message_hms))) :: |
1254 ", took " + (result.end_date.get - result.start_date).message_hms))) :: |
1262 par(text("Status: " + result.status)) :: |
1255 par(text("Status: " + result.status)) :: |
1263 render_rev(result.components, report_data.component_diffs.toMap) ::: |
1256 par(render_rev(result.components, report_data)) :: |
1264 par(text("Log") :+ source(report_data.build_log)) :: Nil |
1257 par(List(source(report_data.build_log))) :: Nil |
1265 } |
1258 } |
1266 } |
1259 } |
|
1260 |
|
1261 def render_diff(build: Build, state: State): XML.Body = render_page("Diff: " + build.name) { |
|
1262 def colored(s: String): XML.Body = { |
|
1263 val Colored = "([^\u001b]*)\u001b\\[([0-9;]+)m(.*)\u001b\\[0m([^\u001b]*)".r |
|
1264 val colors = List("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white") |
|
1265 |
|
1266 val lines = split_lines(s).map { |
|
1267 case Colored(pre, code, s, post) => |
|
1268 val codes = space_explode(';', code.stripSuffix(";1")).map(Value.Int.parse) |
|
1269 val fg = codes match { case 0 :: i :: Nil => colors.unapply(i - 30) case _ => None } |
|
1270 |
|
1271 val sp = span(if (code.endsWith(";1")) List(bold(text(s))) else text(s)) |
|
1272 val sp1 = fg.map(color => sp + ("style" -> ("color:" + color))).getOrElse(sp) |
|
1273 List(span(text(pre)), sp1, span(text(post))) |
|
1274 case line => text(Library.strip_ansi_color(line)) |
|
1275 } |
|
1276 |
|
1277 List(source(Library.separate(nl, lines).flatten)) |
|
1278 } |
|
1279 |
|
1280 def render_diff(data: Report.Data, components: List[Component]): XML.Body = |
|
1281 par(List(page_link(Page.BUILD, "back to build", Markup.Name(build.name)))) :: |
|
1282 (for (component <- components if !component.is_local) yield { |
|
1283 par( |
|
1284 text(component.name) ::: |
|
1285 data.component_logs.toMap.get(component.name).toList.flatMap(colored) ::: |
|
1286 data.component_diffs.toMap.get(component.name).toList.flatMap(colored)) |
|
1287 }) |
|
1288 |
|
1289 build match { |
|
1290 case job: Job => |
|
1291 render_diff(cache.lookup(store.report(job.kind, job.id)), job.components) |
|
1292 case result: Result => |
|
1293 render_diff(cache.lookup(store.report(result.kind, result.id)), result.components) |
|
1294 case _ => Nil |
|
1295 } |
|
1296 } |
1267 |
1297 |
1268 def render_cancelled: XML.Body = |
1298 def render_cancelled: XML.Body = |
1269 render_page("Build cancelled")(List(page_link(Page.HOME, "Home"))) |
1299 render_page("Build cancelled")(List(page_link(Page.HOME, "Home"))) |
1270 |
1300 |
1271 def parse_uuid(params: Params.Data): Option[UUID.T] = |
1301 def parse_uuid(params: Params.Data): Option[UUID.T] = |
1319 model match { |
1357 model match { |
1320 case Model.Error => HTML.text("invalid request") |
1358 case Model.Error => HTML.text("invalid request") |
1321 case Model.Home(state) => View.render_home(state) |
1359 case Model.Home(state) => View.render_home(state) |
1322 case Model.Overview(kind, state) => View.render_overview(kind, state) |
1360 case Model.Overview(kind, state) => View.render_overview(kind, state) |
1323 case Model.Details(build, state, public) => View.render_details(build, state, public) |
1361 case Model.Details(build, state, public) => View.render_details(build, state, public) |
|
1362 case Model.Diff(build, state) => View.render_diff(build, state) |
1324 case Model.Cancelled => View.render_cancelled |
1363 case Model.Cancelled => View.render_cancelled |
1325 }) |
1364 }) |
1326 |
1365 |
1327 val error_model: Model = Model.Error |
1366 val error_model: Model = Model.Error |
1328 val endpoints = List( |
1367 val endpoints = List( |
1329 Get(Page.HOME, "home", _ => overview), |
1368 Get(Page.HOME, "home", _ => overview), |
1330 Get(Page.OVERVIEW, "overview", get_overview), |
1369 Get(Page.OVERVIEW, "overview", get_overview), |
1331 Get(Page.BUILD, "build", get_build), |
1370 Get(Page.BUILD, "build", get_build), |
|
1371 Get(Page.DIFF, "diff", get_diff), |
1332 Post(API.BUILD_CANCEL, "cancel build", cancel_build)) |
1372 Post(API.BUILD_CANCEL, "cancel build", cancel_build)) |
1333 val logo = Bytes.read(Path.explode("$ISABELLE_HOME/lib/logo/isabelle_transparent-48.gif")) |
1373 val logo = Bytes.read(Path.explode("$ISABELLE_HOME/lib/logo/isabelle_transparent-48.gif")) |
1334 val head = |
1374 val head = |
1335 List( |
1375 List( |
1336 HTML.title("Isabelle Build Manager"), |
1376 HTML.title("Isabelle Build Manager"), |