--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Admin/build_doc.scala Wed Oct 12 10:22:34 2016 +0200
@@ -0,0 +1,107 @@
+/* Title: Pure/Admin/build_doc.scala
+ Author: Makarius
+
+Build Isabelle documentation.
+*/
+
+package isabelle
+
+
+import java.io.{File => JFile}
+
+
+object Build_Doc
+{
+ /* build_doc */
+
+ def build_doc(
+ options: Options,
+ progress: Progress = Ignore_Progress,
+ all_docs: Boolean = false,
+ max_jobs: Int = 1,
+ system_mode: Boolean = false,
+ docs: List[String] = Nil): Int =
+ {
+ val selection =
+ for {
+ (name, info) <- Sessions.load(options).topological_order
+ if info.groups.contains("doc")
+ doc = info.options.string("document_variants")
+ if all_docs || docs.contains(doc)
+ } yield (doc, name)
+
+ val selected_docs = selection.map(_._1)
+ val sessions = selection.map(_._2)
+
+ docs.filter(doc => !selected_docs.contains(doc)) match {
+ case Nil =>
+ case bad => error("No documentation session for " + commas_quote(bad))
+ }
+
+ progress.echo("Build started for documentation " + commas_quote(selected_docs))
+
+ val res1 =
+ Build.build(options, progress, requirements = true, build_heap = true,
+ max_jobs = max_jobs, system_mode = system_mode, sessions = sessions)
+ if (res1.ok) {
+ Isabelle_System.with_tmp_dir("document_output")(output =>
+ {
+ val res2 =
+ Build.build(
+ options.bool.update("browser_info", false).
+ string.update("document", "pdf").
+ string.update("document_output", File.standard_path(output)),
+ progress, clean_build = true, max_jobs = max_jobs, system_mode = system_mode,
+ sessions = sessions)
+ if (res2.ok) {
+ val doc_dir = Path.explode("$ISABELLE_HOME/doc").file
+ for (doc <- selected_docs) {
+ val name = doc + ".pdf"
+ File.copy(new JFile(output, name), new JFile(doc_dir, name))
+ }
+ }
+ res2.rc
+ })
+ }
+ else res1.rc
+ }
+
+
+ /* Isabelle tool wrapper */
+
+ val isabelle_tool =
+ Isabelle_Tool("build_doc", "build Isabelle documentation", args =>
+ {
+ var all_docs = false
+ var max_jobs = 1
+ var system_mode = false
+
+ val getopts =
+ Getopts("""
+Usage: isabelle build_doc [OPTIONS] [DOCS ...]"
+
+ Options are:
+ -a select all documentation sessions
+ -j INT maximum number of parallel jobs (default 1)
+ -s system build mode
+
+ Build Isabelle documentation from documentation sessions with
+ suitable document_variants entry.
+""",
+ "a" -> (_ => all_docs = true),
+ "j:" -> (arg => max_jobs = Value.Int.parse(arg)),
+ "s" -> (_ => system_mode = true))
+
+ val docs = getopts(args)
+
+ if (!all_docs && docs.isEmpty) getopts.usage()
+
+ val options = Options.init()
+ val progress = new Console_Progress()
+ val rc =
+ progress.interrupt_handler {
+ build_doc(options, progress, all_docs, max_jobs, system_mode, docs)
+ }
+ sys.exit(rc)
+ }, admin = true)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Admin/build_stats.scala Wed Oct 12 10:22:34 2016 +0200
@@ -0,0 +1,191 @@
+/* Title: Pure/Admin/build_stats.scala
+ Author: Makarius
+
+Statistics from session build output.
+*/
+
+package isabelle
+
+
+object Build_Stats
+{
+ /* presentation */
+
+ private val default_history_length = 100
+ private val default_size = (800, 600)
+ private val default_only_sessions = Set.empty[String]
+ private val default_elapsed_threshold = Time.zero
+ private val default_ml_timing: Option[Boolean] = None
+
+ def present_job(job: String, dir: Path,
+ history_length: Int = default_history_length,
+ size: (Int, Int) = default_size,
+ only_sessions: Set[String] = default_only_sessions,
+ elapsed_threshold: Time = default_elapsed_threshold,
+ ml_timing: Option[Boolean] = default_ml_timing): List[String] =
+ {
+ val job_infos = CI_API.build_job_builds(job).sortBy(_.timestamp).reverse.take(history_length)
+ if (job_infos.isEmpty) error("No build infos for job " + quote(job))
+
+ val all_infos =
+ Par_List.map((job_info: CI_API.Job_Info) =>
+ (job_info.timestamp / 1000, job_info.read_main_log.parse_build_info), job_infos)
+ val all_sessions =
+ (Set.empty[String] /: all_infos)(
+ { case (s, (_, info)) => s ++ info.sessions.keySet })
+
+ def check_threshold(info: Build_Log.Build_Info, session: String): Boolean =
+ {
+ val t = info.timing(session)
+ !t.is_zero && t.elapsed >= elapsed_threshold
+ }
+
+ val sessions =
+ for {
+ session <- (if (only_sessions.isEmpty) all_sessions else all_sessions & only_sessions)
+ if all_infos.filter({ case (_, info) => check_threshold(info, session) }).length >= 3
+ } yield session
+
+ Isabelle_System.mkdirs(dir)
+ for (session <- sessions) {
+ Isabelle_System.with_tmp_file(session, "png") { data_file =>
+ Isabelle_System.with_tmp_file(session, "gnuplot") { plot_file =>
+ val data =
+ for { (t, info) <- all_infos if info.finished(session) }
+ yield {
+ val timing1 = info.timing(session)
+ val timing2 = info.ml_timing(session)
+ List(t.toString,
+ timing1.elapsed.minutes,
+ timing1.cpu.minutes,
+ timing2.elapsed.minutes,
+ timing2.cpu.minutes,
+ timing2.gc.minutes).mkString(" ")
+ }
+ File.write(data_file, cat_lines(data))
+
+ val plots1 =
+ List(
+ """ using 1:3 smooth sbezier title "cpu time (smooth)" """,
+ """ using 1:3 smooth csplines title "cpu time" """,
+ """ using 1:2 smooth sbezier title "elapsed time (smooth)" """,
+ """ using 1:2 smooth csplines title "elapsed time" """)
+ val plots2 =
+ List(
+ """ using 1:5 smooth sbezier title "ML cpu time (smooth)" """,
+ """ using 1:5 smooth csplines title "ML cpu time" """,
+ """ using 1:4 smooth sbezier title "ML elapsed time (smooth)" """,
+ """ using 1:4 smooth csplines title "ML elapsed time" """,
+ """ using 1:6 smooth sbezier title "ML gc time (smooth)" """,
+ """ using 1:6 smooth csplines title "ML gc time" """)
+ val plots =
+ ml_timing match {
+ case None => plots1
+ case Some(false) => plots1 ::: plots2
+ case Some(true) => plots2
+ }
+
+ val data_file_name = File.standard_path(data_file.getAbsolutePath)
+ File.write(plot_file, """
+set terminal png size """ + size._1 + "," + size._2 + """
+set output """ + quote(File.standard_path(dir + Path.basic(session + ".png"))) + """
+set xdata time
+set timefmt "%s"
+set format x "%d-%b"
+set xlabel """ + quote(session) + """ noenhanced
+set key left top
+plot [] [0:] """ + plots.map(s => quote(data_file_name) + " " + s).mkString(", ") + "\n")
+ val result = Isabelle_System.bash("\"$ISABELLE_GNUPLOT\" " + File.bash_path(plot_file))
+ if (result.rc != 0) {
+ Output.error_message("Session " + session + ": gnuplot error")
+ result.print
+ }
+ }
+ }
+ }
+
+ sessions.toList.sorted
+ }
+
+
+ /* Isabelle tool wrapper */
+
+ private val html_header = """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head><title>Performance statistics from session build output</title></head>
+<body>
+"""
+ private val html_footer = """
+</body>
+</html>
+"""
+
+ val isabelle_tool =
+ Isabelle_Tool("build_stats", "present statistics from session build output", args =>
+ {
+ var target_dir = Path.explode("stats")
+ var ml_timing = default_ml_timing
+ var only_sessions = default_only_sessions
+ var elapsed_threshold = default_elapsed_threshold
+ var history_length = default_history_length
+ var size = default_size
+
+ val getopts = Getopts("""
+Usage: isabelle build_stats [OPTIONS] [JOBS ...]
+
+ Options are:
+ -D DIR target directory (default "stats")
+ -M only ML timing
+ -S SESSIONS only given SESSIONS (comma separated)
+ -T THRESHOLD only sessions with elapsed time >= THRESHOLD (minutes)
+ -l LENGTH length of history (default 100)
+ -m include ML timing
+ -s WxH size of PNG image (default 800x600)
+
+ Present statistics from session build output of the given JOBS, from Jenkins
+ continuous build service specified as URL via ISABELLE_JENKINS_ROOT.
+""",
+ "D:" -> (arg => target_dir = Path.explode(arg)),
+ "M" -> (_ => ml_timing = Some(true)),
+ "S:" -> (arg => only_sessions = space_explode(',', arg).toSet),
+ "T:" -> (arg => elapsed_threshold = Time.minutes(Value.Double.parse(arg))),
+ "l:" -> (arg => history_length = Value.Int.parse(arg)),
+ "m" -> (_ => ml_timing = Some(false)),
+ "s:" -> (arg =>
+ space_explode('x', arg).map(Value.Int.parse(_)) match {
+ case List(w, h) if w > 0 && h > 0 => size = (w, h)
+ case _ => error("Error bad PNG image size: " + quote(arg))
+ }))
+
+ val jobs = getopts(args)
+ val all_jobs = CI_API.build_jobs()
+ val bad_jobs = jobs.filterNot(all_jobs.contains(_)).sorted
+
+ if (jobs.isEmpty)
+ error("No build jobs given. Available jobs: " + all_jobs.sorted.mkString(" "))
+
+ if (bad_jobs.nonEmpty)
+ error("Unknown build jobs: " + bad_jobs.mkString(" ") +
+ "\nAvailable jobs: " + all_jobs.sorted.mkString(" "))
+
+ for (job <- jobs) {
+ val dir = target_dir + Path.basic(job)
+ Output.writeln(dir.implode)
+ val sessions =
+ present_job(job, dir, history_length, size, only_sessions, elapsed_threshold, ml_timing)
+ File.write(dir + Path.basic("index.html"),
+ html_header + "\n<h1>" + HTML.output(job) + "</h1>\n" +
+ cat_lines(
+ sessions.map(session =>
+ """<br/><img src=""" + quote(HTML.output(session + ".png")) + """><br/>""")) +
+ "\n" + html_footer)
+ }
+
+ File.write(target_dir + Path.basic("index.html"),
+ html_header + "\n<ul>\n" +
+ cat_lines(
+ jobs.map(job => """<li> <a href=""" + quote(HTML.output(job + "/index.html")) + """>""" +
+ HTML.output(job) + """</a> </li>""")) +
+ "\n</ul>\n" + html_footer)
+ }, admin = true)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Admin/check_sources.scala Wed Oct 12 10:22:34 2016 +0200
@@ -0,0 +1,72 @@
+/* Title: Pure/Admin/check_sources.scala
+ Author: Makarius
+
+Some sanity checks for Isabelle sources.
+*/
+
+package isabelle
+
+
+object Check_Sources
+{
+ def check_file(path: Path)
+ {
+ val file_name = path.implode
+ val file_pos = path.position
+ def line_pos(i: Int) = Position.Line_File(i + 1, file_name)
+
+ val content = File.read(path)
+
+ for { (line, i) <- split_lines(content).iterator.zipWithIndex }
+ {
+ try {
+ Symbol.decode_strict(line)
+
+ for { c <- Word.codepoint_iterator(line); if c > 128 && !Character.isAlphabetic(c) }
+ {
+ Output.warning("Suspicious Unicode character " + quote(Word.codepoint(c)) +
+ Position.here(line_pos(i)))
+ }
+ }
+ catch { case ERROR(msg) => Output.warning(msg + Position.here(line_pos(i))) }
+
+ if (line.contains('\t'))
+ Output.warning("TAB character" + Position.here(line_pos(i)))
+ }
+
+ if (content.contains('\r'))
+ Output.warning("CR character" + Position.here(file_pos))
+
+ if (Word.bidi_detect(content))
+ Output.warning("Bidirectional Unicode text " + Position.here(file_pos))
+ }
+
+ def check_hg(root: Path)
+ {
+ Output.writeln("Checking " + root + " ...")
+ using(Mercurial.open_repository(root)) { hg =>
+ for {
+ file <- hg.manifest()
+ if file.endsWith(".thy") || file.endsWith(".ML") || file.endsWith("/ROOT")
+ } check_file(root + Path.explode(file))
+ }
+ }
+
+
+ /* Isabelle tool wrapper */
+
+ val isabelle_tool =
+ Isabelle_Tool("check_sources", "some sanity checks for Isabelle sources", args =>
+ {
+ val getopts = Getopts("""
+Usage: isabelle check_sources [ROOT_DIRS...]
+
+ Check .thy, .ML, ROOT files from manifest of Mercurial ROOT_DIRS.
+""")
+
+ val specs = getopts(args)
+ if (specs.isEmpty) getopts.usage()
+
+ for (root <- specs) check_hg(Path.explode(root))
+ }, admin = true)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/Admin/remote_dmg.scala Wed Oct 12 10:22:34 2016 +0200
@@ -0,0 +1,65 @@
+/* Title: Pure/Admin/remote_dmg.scala
+ Author: Makarius
+
+Build dmg on remote Mac OS X system.
+*/
+
+package isabelle
+
+
+object Remote_DMG
+{
+ def remote_dmg(session: SSH.Session, tar_gz_file: Path, dmg_file: Path, volume_name: String = "")
+ {
+ session.with_tmp_dir(remote_dir =>
+ using(session.sftp())(sftp =>
+ {
+ val cd = "cd " + File.bash_string(remote_dir) + "; "
+
+ sftp.write_file(remote_dir + "/dmg.tar.gz", tar_gz_file)
+ session.execute(cd + "mkdir root && tar -C root -xzf dmg.tar.gz").check
+ session.execute(
+ cd + "hdiutil create -srcfolder root" +
+ (if (volume_name == "") "" else " -volname " + File.bash_string(volume_name)) +
+ " dmg.dmg").check
+ sftp.read_file(remote_dir + "/dmg.dmg", dmg_file)
+ }))
+ }
+
+
+ /* Isabelle tool wrapper */
+
+ val isabelle_tool =
+ Isabelle_Tool("remote_dmg", "build dmg on remote Mac OS X system", args =>
+ {
+ Command_Line.tool0 {
+ var port = SSH.default_port
+ var volume_name = ""
+
+ val getopts = Getopts("""
+Usage: isabelle remote_dmg [OPTIONS] USER@HOST TAR_GZ_FILE DMG_FILE
+
+ Options are:
+ -p PORT alternative SSH port (default: """ + SSH.default_port + """)
+ -V NAME specify volume name
+
+ Turn the contents of a tar.gz file into a dmg file -- produced on a remote
+ Mac OS X system.
+""",
+ "p:" -> (arg => port = Value.Int.parse(arg)),
+ "V:" -> (arg => volume_name = arg))
+
+ val more_args = getopts(args)
+ val (user, host, tar_gz_file, dmg_file) =
+ more_args match {
+ case List(SSH.User_Host(user, host), tar_gz_file, dmg_file) =>
+ (user, host, Path.explode(tar_gz_file), Path.explode(dmg_file))
+ case _ => getopts.usage()
+ }
+
+ val ssh = SSH.init(Options.init)
+ using(ssh.open_session(user = user, host = host, port = port))(
+ remote_dmg(_, tar_gz_file, dmg_file, volume_name))
+ }
+ }, admin = true)
+}
--- a/src/Pure/System/isabelle_system.scala Wed Oct 12 09:38:20 2016 +0200
+++ b/src/Pure/System/isabelle_system.scala Wed Oct 12 10:22:34 2016 +0200
@@ -324,6 +324,11 @@
/** Isabelle resources **/
+ /* repository clone with Admin */
+
+ def admin(): Boolean = Path.explode("~~/Admin").is_dir
+
+
/* components */
def components(): List[Path] =
--- a/src/Pure/System/isabelle_tool.scala Wed Oct 12 09:38:20 2016 +0200
+++ b/src/Pure/System/isabelle_tool.scala Wed Oct 12 10:22:34 2016 +0200
@@ -113,11 +113,12 @@
Update_Theorems.isabelle_tool)
private def list_internal(): List[(String, String)] =
- for (tool <- internal_tools.toList) yield (tool.name, tool.description)
+ for (tool <- internal_tools.toList if tool.accessible)
+ yield (tool.name, tool.description)
private def find_internal(name: String): Option[List[String] => Unit] =
internal_tools.collectFirst({
- case tool if tool.name == name =>
+ case tool if tool.name == name && tool.accessible =>
args => Command_Line.tool0 { tool.body(args) }
})
@@ -148,4 +149,8 @@
}
}
-sealed case class Isabelle_Tool(name: String, description: String, body: List[String] => Unit)
+sealed case class Isabelle_Tool(
+ name: String, description: String, body: List[String] => Unit, admin: Boolean = false)
+{
+ def accessible: Boolean = !admin || Isabelle_System.admin()
+}
--- a/src/Pure/Tools/build_doc.scala Wed Oct 12 09:38:20 2016 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/* Title: Pure/Tools/build_doc.scala
- Author: Makarius
-
-Build Isabelle documentation.
-*/
-
-package isabelle
-
-
-import java.io.{File => JFile}
-
-
-object Build_Doc
-{
- /* build_doc */
-
- def build_doc(
- options: Options,
- progress: Progress = Ignore_Progress,
- all_docs: Boolean = false,
- max_jobs: Int = 1,
- system_mode: Boolean = false,
- docs: List[String] = Nil): Int =
- {
- val selection =
- for {
- (name, info) <- Sessions.load(options).topological_order
- if info.groups.contains("doc")
- doc = info.options.string("document_variants")
- if all_docs || docs.contains(doc)
- } yield (doc, name)
-
- val selected_docs = selection.map(_._1)
- val sessions = selection.map(_._2)
-
- docs.filter(doc => !selected_docs.contains(doc)) match {
- case Nil =>
- case bad => error("No documentation session for " + commas_quote(bad))
- }
-
- progress.echo("Build started for documentation " + commas_quote(selected_docs))
-
- val res1 =
- Build.build(options, progress, requirements = true, build_heap = true,
- max_jobs = max_jobs, system_mode = system_mode, sessions = sessions)
- if (res1.ok) {
- Isabelle_System.with_tmp_dir("document_output")(output =>
- {
- val res2 =
- Build.build(
- options.bool.update("browser_info", false).
- string.update("document", "pdf").
- string.update("document_output", File.standard_path(output)),
- progress, clean_build = true, max_jobs = max_jobs, system_mode = system_mode,
- sessions = sessions)
- if (res2.ok) {
- val doc_dir = Path.explode("$ISABELLE_HOME/doc").file
- for (doc <- selected_docs) {
- val name = doc + ".pdf"
- File.copy(new JFile(output, name), new JFile(doc_dir, name))
- }
- }
- res2.rc
- })
- }
- else res1.rc
- }
-
-
- /* Isabelle tool wrapper */
-
- val isabelle_tool = Isabelle_Tool("build_doc", "build Isabelle documentation", args =>
- {
- var all_docs = false
- var max_jobs = 1
- var system_mode = false
-
- val getopts =
- Getopts("""
-Usage: isabelle build_doc [OPTIONS] [DOCS ...]"
-
- Options are:
- -a select all documentation sessions
- -j INT maximum number of parallel jobs (default 1)
- -s system build mode
-
- Build Isabelle documentation from documentation sessions with
- suitable document_variants entry.
-""",
- "a" -> (_ => all_docs = true),
- "j:" -> (arg => max_jobs = Value.Int.parse(arg)),
- "s" -> (_ => system_mode = true))
-
- val docs = getopts(args)
-
- if (!all_docs && docs.isEmpty) getopts.usage()
-
- val options = Options.init()
- val progress = new Console_Progress()
- val rc =
- progress.interrupt_handler {
- build_doc(options, progress, all_docs, max_jobs, system_mode, docs)
- }
- sys.exit(rc)
- })
-}
--- a/src/Pure/Tools/build_stats.scala Wed Oct 12 09:38:20 2016 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/* Title: Pure/Tools/build_stats.scala
- Author: Makarius
-
-Statistics from session build output.
-*/
-
-package isabelle
-
-
-object Build_Stats
-{
- /* presentation */
-
- private val default_history_length = 100
- private val default_size = (800, 600)
- private val default_only_sessions = Set.empty[String]
- private val default_elapsed_threshold = Time.zero
- private val default_ml_timing: Option[Boolean] = None
-
- def present_job(job: String, dir: Path,
- history_length: Int = default_history_length,
- size: (Int, Int) = default_size,
- only_sessions: Set[String] = default_only_sessions,
- elapsed_threshold: Time = default_elapsed_threshold,
- ml_timing: Option[Boolean] = default_ml_timing): List[String] =
- {
- val job_infos = CI_API.build_job_builds(job).sortBy(_.timestamp).reverse.take(history_length)
- if (job_infos.isEmpty) error("No build infos for job " + quote(job))
-
- val all_infos =
- Par_List.map((job_info: CI_API.Job_Info) =>
- (job_info.timestamp / 1000, job_info.read_main_log.parse_build_info), job_infos)
- val all_sessions =
- (Set.empty[String] /: all_infos)(
- { case (s, (_, info)) => s ++ info.sessions.keySet })
-
- def check_threshold(info: Build_Log.Build_Info, session: String): Boolean =
- {
- val t = info.timing(session)
- !t.is_zero && t.elapsed >= elapsed_threshold
- }
-
- val sessions =
- for {
- session <- (if (only_sessions.isEmpty) all_sessions else all_sessions & only_sessions)
- if all_infos.filter({ case (_, info) => check_threshold(info, session) }).length >= 3
- } yield session
-
- Isabelle_System.mkdirs(dir)
- for (session <- sessions) {
- Isabelle_System.with_tmp_file(session, "png") { data_file =>
- Isabelle_System.with_tmp_file(session, "gnuplot") { plot_file =>
- val data =
- for { (t, info) <- all_infos if info.finished(session) }
- yield {
- val timing1 = info.timing(session)
- val timing2 = info.ml_timing(session)
- List(t.toString,
- timing1.elapsed.minutes,
- timing1.cpu.minutes,
- timing2.elapsed.minutes,
- timing2.cpu.minutes,
- timing2.gc.minutes).mkString(" ")
- }
- File.write(data_file, cat_lines(data))
-
- val plots1 =
- List(
- """ using 1:3 smooth sbezier title "cpu time (smooth)" """,
- """ using 1:3 smooth csplines title "cpu time" """,
- """ using 1:2 smooth sbezier title "elapsed time (smooth)" """,
- """ using 1:2 smooth csplines title "elapsed time" """)
- val plots2 =
- List(
- """ using 1:5 smooth sbezier title "ML cpu time (smooth)" """,
- """ using 1:5 smooth csplines title "ML cpu time" """,
- """ using 1:4 smooth sbezier title "ML elapsed time (smooth)" """,
- """ using 1:4 smooth csplines title "ML elapsed time" """,
- """ using 1:6 smooth sbezier title "ML gc time (smooth)" """,
- """ using 1:6 smooth csplines title "ML gc time" """)
- val plots =
- ml_timing match {
- case None => plots1
- case Some(false) => plots1 ::: plots2
- case Some(true) => plots2
- }
-
- val data_file_name = File.standard_path(data_file.getAbsolutePath)
- File.write(plot_file, """
-set terminal png size """ + size._1 + "," + size._2 + """
-set output """ + quote(File.standard_path(dir + Path.basic(session + ".png"))) + """
-set xdata time
-set timefmt "%s"
-set format x "%d-%b"
-set xlabel """ + quote(session) + """ noenhanced
-set key left top
-plot [] [0:] """ + plots.map(s => quote(data_file_name) + " " + s).mkString(", ") + "\n")
- val result = Isabelle_System.bash("\"$ISABELLE_GNUPLOT\" " + File.bash_path(plot_file))
- if (result.rc != 0) {
- Output.error_message("Session " + session + ": gnuplot error")
- result.print
- }
- }
- }
- }
-
- sessions.toList.sorted
- }
-
-
- /* Isabelle tool wrapper */
-
- private val html_header = """<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head><title>Performance statistics from session build output</title></head>
-<body>
-"""
- private val html_footer = """
-</body>
-</html>
-"""
-
- val isabelle_tool =
- Isabelle_Tool("build_stats", "present statistics from session build output", args =>
- {
- var target_dir = Path.explode("stats")
- var ml_timing = default_ml_timing
- var only_sessions = default_only_sessions
- var elapsed_threshold = default_elapsed_threshold
- var history_length = default_history_length
- var size = default_size
-
- val getopts = Getopts("""
-Usage: isabelle build_stats [OPTIONS] [JOBS ...]
-
- Options are:
- -D DIR target directory (default "stats")
- -M only ML timing
- -S SESSIONS only given SESSIONS (comma separated)
- -T THRESHOLD only sessions with elapsed time >= THRESHOLD (minutes)
- -l LENGTH length of history (default 100)
- -m include ML timing
- -s WxH size of PNG image (default 800x600)
-
- Present statistics from session build output of the given JOBS, from Jenkins
- continuous build service specified as URL via ISABELLE_JENKINS_ROOT.
-""",
- "D:" -> (arg => target_dir = Path.explode(arg)),
- "M" -> (_ => ml_timing = Some(true)),
- "S:" -> (arg => only_sessions = space_explode(',', arg).toSet),
- "T:" -> (arg => elapsed_threshold = Time.minutes(Value.Double.parse(arg))),
- "l:" -> (arg => history_length = Value.Int.parse(arg)),
- "m" -> (_ => ml_timing = Some(false)),
- "s:" -> (arg =>
- space_explode('x', arg).map(Value.Int.parse(_)) match {
- case List(w, h) if w > 0 && h > 0 => size = (w, h)
- case _ => error("Error bad PNG image size: " + quote(arg))
- }))
-
- val jobs = getopts(args)
- val all_jobs = CI_API.build_jobs()
- val bad_jobs = jobs.filterNot(all_jobs.contains(_)).sorted
-
- if (jobs.isEmpty)
- error("No build jobs given. Available jobs: " + all_jobs.sorted.mkString(" "))
-
- if (bad_jobs.nonEmpty)
- error("Unknown build jobs: " + bad_jobs.mkString(" ") +
- "\nAvailable jobs: " + all_jobs.sorted.mkString(" "))
-
- for (job <- jobs) {
- val dir = target_dir + Path.basic(job)
- Output.writeln(dir.implode)
- val sessions =
- present_job(job, dir, history_length, size, only_sessions, elapsed_threshold, ml_timing)
- File.write(dir + Path.basic("index.html"),
- html_header + "\n<h1>" + HTML.output(job) + "</h1>\n" +
- cat_lines(
- sessions.map(session =>
- """<br/><img src=""" + quote(HTML.output(session + ".png")) + """><br/>""")) +
- "\n" + html_footer)
- }
-
- File.write(target_dir + Path.basic("index.html"),
- html_header + "\n<ul>\n" +
- cat_lines(
- jobs.map(job => """<li> <a href=""" + quote(HTML.output(job + "/index.html")) + """>""" +
- HTML.output(job) + """</a> </li>""")) +
- "\n</ul>\n" + html_footer)
- })
-}
--- a/src/Pure/Tools/check_sources.scala Wed Oct 12 09:38:20 2016 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/* Title: Pure/Tools/check_sources.scala
- Author: Makarius
-
-Some sanity checks for Isabelle sources.
-*/
-
-package isabelle
-
-
-object Check_Sources
-{
- def check_file(path: Path)
- {
- val file_name = path.implode
- val file_pos = path.position
- def line_pos(i: Int) = Position.Line_File(i + 1, file_name)
-
- val content = File.read(path)
-
- for { (line, i) <- split_lines(content).iterator.zipWithIndex }
- {
- try {
- Symbol.decode_strict(line)
-
- for { c <- Word.codepoint_iterator(line); if c > 128 && !Character.isAlphabetic(c) }
- {
- Output.warning("Suspicious Unicode character " + quote(Word.codepoint(c)) +
- Position.here(line_pos(i)))
- }
- }
- catch { case ERROR(msg) => Output.warning(msg + Position.here(line_pos(i))) }
-
- if (line.contains('\t'))
- Output.warning("TAB character" + Position.here(line_pos(i)))
- }
-
- if (content.contains('\r'))
- Output.warning("CR character" + Position.here(file_pos))
-
- if (Word.bidi_detect(content))
- Output.warning("Bidirectional Unicode text " + Position.here(file_pos))
- }
-
- def check_hg(root: Path)
- {
- Output.writeln("Checking " + root + " ...")
- using(Mercurial.open_repository(root)) { hg =>
- for {
- file <- hg.manifest()
- if file.endsWith(".thy") || file.endsWith(".ML") || file.endsWith("/ROOT")
- } check_file(root + Path.explode(file))
- }
- }
-
-
- /* Isabelle tool wrapper */
-
- val isabelle_tool =
- Isabelle_Tool("check_sources", "some sanity checks for Isabelle sources", args =>
- {
- val getopts = Getopts("""
-Usage: isabelle check_sources [ROOT_DIRS...]
-
- Check .thy, .ML, ROOT files from manifest of Mercurial ROOT_DIRS.
-""")
-
- val specs = getopts(args)
- if (specs.isEmpty) getopts.usage()
-
- for (root <- specs) check_hg(Path.explode(root))
- })
-}
--- a/src/Pure/Tools/remote_dmg.scala Wed Oct 12 09:38:20 2016 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/* Title: Pure/Tools/remote_dmg.scala
- Author: Makarius
-
-Build dmg on remote Mac OS X system.
-*/
-
-package isabelle
-
-
-object Remote_DMG
-{
- def remote_dmg(session: SSH.Session, tar_gz_file: Path, dmg_file: Path, volume_name: String = "")
- {
- session.with_tmp_dir(remote_dir =>
- using(session.sftp())(sftp =>
- {
- val cd = "cd " + File.bash_string(remote_dir) + "; "
-
- sftp.write_file(remote_dir + "/dmg.tar.gz", tar_gz_file)
- session.execute(cd + "mkdir root && tar -C root -xzf dmg.tar.gz").check
- session.execute(
- cd + "hdiutil create -srcfolder root" +
- (if (volume_name == "") "" else " -volname " + File.bash_string(volume_name)) +
- " dmg.dmg").check
- sftp.read_file(remote_dir + "/dmg.dmg", dmg_file)
- }))
- }
-
-
- /* Isabelle tool wrapper */
-
- val isabelle_tool = Isabelle_Tool("remote_dmg", "build dmg on remote Mac OS X system", args =>
- {
- Command_Line.tool0 {
- var port = SSH.default_port
- var volume_name = ""
-
- val getopts = Getopts("""
-Usage: isabelle remote_dmg [OPTIONS] USER@HOST TAR_GZ_FILE DMG_FILE
-
- Options are:
- -p PORT alternative SSH port (default: """ + SSH.default_port + """)
- -V NAME specify volume name
-
- Turn the contents of a tar.gz file into a dmg file -- produced on a remote
- Mac OS X system.
-""",
- "p:" -> (arg => port = Value.Int.parse(arg)),
- "V:" -> (arg => volume_name = arg))
-
- val more_args = getopts(args)
- val (user, host, tar_gz_file, dmg_file) =
- more_args match {
- case List(SSH.User_Host(user, host), tar_gz_file, dmg_file) =>
- (user, host, Path.explode(tar_gz_file), Path.explode(dmg_file))
- case _ => getopts.usage()
- }
-
- val ssh = SSH.init(Options.init)
- using(ssh.open_session(user = user, host = host, port = port))(
- remote_dmg(_, tar_gz_file, dmg_file, volume_name))
- }
- })
-}
--- a/src/Pure/build-jars Wed Oct 12 09:38:20 2016 +0200
+++ b/src/Pure/build-jars Wed Oct 12 10:22:34 2016 +0200
@@ -9,11 +9,15 @@
## sources
declare -a SOURCES=(
+ Admin/build_doc.scala
Admin/build_history.scala
Admin/build_log.scala
+ Admin/build_stats.scala
+ Admin/check_sources.scala
Admin/ci_api.scala
Admin/ci_profile.scala
Admin/isabelle_cronjob.scala
+ Admin/remote_dmg.scala
Concurrent/consumer_thread.scala
Concurrent/counter.scala
Concurrent/event_timer.scala
@@ -113,10 +117,7 @@
Thy/thy_syntax.scala
Tools/bibtex.scala
Tools/build.scala
- Tools/build_doc.scala
- Tools/build_stats.scala
Tools/check_keywords.scala
- Tools/check_sources.scala
Tools/debugger.scala
Tools/doc.scala
Tools/main.scala
@@ -125,7 +126,6 @@
Tools/ml_statistics.scala
Tools/news.scala
Tools/print_operation.scala
- Tools/remote_dmg.scala
Tools/simplifier_trace.scala
Tools/task_statistics.scala
Tools/update_cartouches.scala