1/*  Title:      Pure/Admin/build_doc.scala
2    Author:     Makarius
3
4Build Isabelle documentation.
5*/
6
7package isabelle
8
9
10import java.io.{File => JFile}
11
12
13object Build_Doc
14{
15  /* build_doc */
16
17  def build_doc(
18    options: Options,
19    progress: Progress = No_Progress,
20    all_docs: Boolean = false,
21    max_jobs: Int = 1,
22    system_mode: Boolean = false,
23    docs: List[String] = Nil): Int =
24  {
25    val sessions_structure = Sessions.load_structure(options)
26    val selection =
27      for {
28        name <- sessions_structure.build_topological_order
29        info = sessions_structure(name)
30        if info.groups.contains("doc")
31        doc = info.options.string("document_variants")
32        if all_docs || docs.contains(doc)
33      } yield (doc, name)
34
35    val selected_docs = selection.map(_._1)
36    val sessions = selection.map(_._2)
37
38    docs.filter(doc => !selected_docs.contains(doc)) match {
39      case Nil =>
40      case bad => error("No documentation session for " + commas_quote(bad))
41    }
42
43    progress.echo("Build started for documentation " + commas_quote(selected_docs))
44
45    val res1 =
46      Build.build(options, progress, requirements = true, build_heap = true,
47        max_jobs = max_jobs, system_mode = system_mode, sessions = sessions)
48    if (res1.ok) {
49      Isabelle_System.with_tmp_dir("document_output")(output =>
50        {
51          val res2 =
52            Build.build(
53              options.bool.update("browser_info", false).
54                string.update("document", "pdf").
55                string.update("document_output", output.implode),
56              progress, clean_build = true, max_jobs = max_jobs, system_mode = system_mode,
57              sessions = sessions)
58          if (res2.ok) {
59            val doc_dir = Path.explode("~~/doc")
60            for (doc <- selected_docs) {
61              val name = Path.explode(doc + ".pdf")
62              File.copy(output + name, doc_dir + name)
63            }
64          }
65          res2.rc
66        })
67    }
68    else res1.rc
69  }
70
71
72  /* Isabelle tool wrapper */
73
74  val isabelle_tool =
75    Isabelle_Tool("build_doc", "build Isabelle documentation", args =>
76    {
77      var all_docs = false
78      var max_jobs = 1
79      var system_mode = false
80
81      val getopts =
82        Getopts("""
83Usage: isabelle build_doc [OPTIONS] [DOCS ...]
84
85  Options are:
86    -a           select all documentation sessions
87    -j INT       maximum number of parallel jobs (default 1)
88    -s           system build mode
89
90  Build Isabelle documentation from documentation sessions with
91  suitable document_variants entry.
92""",
93          "a" -> (_ => all_docs = true),
94          "j:" -> (arg => max_jobs = Value.Int.parse(arg)),
95          "s" -> (_ => system_mode = true))
96
97      val docs = getopts(args)
98
99      if (!all_docs && docs.isEmpty) getopts.usage()
100
101      val options = Options.init()
102      val progress = new Console_Progress()
103      val rc =
104        progress.interrupt_handler {
105          build_doc(options, progress, all_docs, max_jobs, system_mode, docs)
106        }
107      sys.exit(rc)
108    }, admin = true)
109}
110