| author | wenzelm | 
| Thu, 24 Oct 2024 22:05:57 +0200 | |
| changeset 81253 | bbed9f218158 | 
| parent 80886 | 5d562dd387ae | 
| child 81551 | a296642fa0a5 | 
| permissions | -rw-r--r-- | 
| 79502 | 1 | /* Title: Pure/Build/sessions.scala | 
| 62631 | 2 | Author: Makarius | 
| 3 | ||
| 65430 | 4 | Cumulative session information. | 
| 62631 | 5 | */ | 
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 65461 
b6c2e30dc018
support for known theories files (according to multiple uses);
 wenzelm parents: 
65457diff
changeset | 9 | import java.io.{File => JFile}
 | 
| 62631 | 10 | |
| 73364 | 11 | import scala.collection.immutable.{SortedSet, SortedMap}
 | 
| 62631 | 12 | import scala.collection.mutable | 
| 13 | ||
| 14 | ||
| 75393 | 15 | object Sessions {
 | 
| 77562 | 16 | /* main operations */ | 
| 17 | ||
| 18 | def background0(session: String): Background = Background.empty(session) | |
| 19 | ||
| 20 | def background(options: Options, | |
| 21 | session: String, | |
| 22 | progress: Progress = new Progress, | |
| 23 | dirs: List[Path] = Nil, | |
| 24 | include_sessions: List[String] = Nil, | |
| 25 | session_ancestor: Option[String] = None, | |
| 26 | session_requirements: Boolean = false | |
| 27 |   ): Background = {
 | |
| 28 | Background.load(options, session, progress = progress, dirs = dirs, | |
| 29 | include_sessions = include_sessions, session_ancestor = session_ancestor, | |
| 30 | session_requirements = session_requirements) | |
| 31 | } | |
| 32 | ||
| 33 | def load_structure( | |
| 34 | options: Options, | |
| 35 | dirs: List[Path] = Nil, | |
| 36 | select_dirs: List[Path] = Nil, | |
| 37 | infos: List[Info] = Nil, | |
| 38 | augment_options: String => List[Options.Spec] = _ => Nil | |
| 39 |   ): Structure = {
 | |
| 40 | val roots = load_root_files(dirs = dirs, select_dirs = select_dirs) | |
| 41 | Structure.make(options, augment_options, roots = roots, infos = infos) | |
| 42 | } | |
| 43 | ||
| 44 | def deps(sessions_structure: Structure, | |
| 45 | progress: Progress = new Progress, | |
| 46 | inlined_files: Boolean = false, | |
| 80886 
5d562dd387ae
discontinued "isabelle build -k": superseded by admin-tool "isabelle check_keywords";
 wenzelm parents: 
80194diff
changeset | 47 | list_files: Boolean = false | 
| 77562 | 48 |   ): Deps = {
 | 
| 49 | Deps.load(sessions_structure, progress = progress, inlined_files = inlined_files, | |
| 80886 
5d562dd387ae
discontinued "isabelle build -k": superseded by admin-tool "isabelle check_keywords";
 wenzelm parents: 
80194diff
changeset | 50 | list_files = list_files) | 
| 77562 | 51 | } | 
| 52 | ||
| 53 | ||
| 67284 | 54 | /* session and theory names */ | 
| 62883 | 55 | |
| 72837 | 56 |   val ROOTS: Path = Path.explode("ROOTS")
 | 
| 72832 | 57 |   val ROOT: Path = Path.explode("ROOT")
 | 
| 58 | ||
| 72837 | 59 | val roots_name: String = "ROOTS" | 
| 67215 | 60 | val root_name: String = "ROOT" | 
| 75406 | 61 | val theory_import: String = "Pure.Sessions" | 
| 67215 | 62 | |
| 69762 
58fb0d779583
support for session information via virtual file-system;
 wenzelm parents: 
69671diff
changeset | 63 | val UNSORTED = "Unsorted" | 
| 65445 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 64 | val DRAFT = "Draft" | 
| 
e9e7f5f5794c
more qualifier treatment, but in the end it is still ignored;
 wenzelm parents: 
65441diff
changeset | 65 | |
| 65360 | 66 | def is_pure(name: String): Boolean = name == Thy_Header.PURE | 
| 64856 | 67 | |
| 75922 | 68 | def illegal_session(name: String): Boolean = name == "" || name == DRAFT | 
| 76849 
d431a9340163
more systematic Sessions.illegal_theory, based on File_Format.theory_excluded;
 wenzelm parents: 
76829diff
changeset | 69 | def illegal_theory(name: String): Boolean = | 
| 76850 | 70 | name == root_name || File_Format.registry.theory_excluded(name) | 
| 67284 | 71 | |
| 72 | ||
| 72837 | 73 | /* ROOTS file format */ | 
| 74 | ||
| 76850 | 75 |   class ROOTS_File_Format extends File_Format {
 | 
| 72837 | 76 | val format_name: String = roots_name | 
| 77 | val file_ext = "" | |
| 72839 
a597300290de
clarified File_Format.detect: needs to operate on full node name;
 wenzelm parents: 
72837diff
changeset | 78 | |
| 
a597300290de
clarified File_Format.detect: needs to operate on full node name;
 wenzelm parents: 
72837diff
changeset | 79 | override def detect(name: String): Boolean = | 
| 76828 | 80 |       Url.get_base_name(name) match {
 | 
| 81 | case Some(base_name) => base_name == roots_name | |
| 72839 
a597300290de
clarified File_Format.detect: needs to operate on full node name;
 wenzelm parents: 
72837diff
changeset | 82 | case None => false | 
| 
a597300290de
clarified File_Format.detect: needs to operate on full node name;
 wenzelm parents: 
72837diff
changeset | 83 | } | 
| 72837 | 84 | |
| 85 | override def theory_suffix: String = "ROOTS_file" | |
| 86 | override def theory_content(name: String): String = | |
| 76859 | 87 | """theory "ROOTS" imports Pure begin ROOTS_file "." end""" | 
| 76849 
d431a9340163
more systematic Sessions.illegal_theory, based on File_Format.theory_excluded;
 wenzelm parents: 
76829diff
changeset | 88 | override def theory_excluded(name: String): Boolean = name == "ROOTS" | 
| 72837 | 89 | } | 
| 90 | ||
| 91 | ||
| 76597 | 92 | /* base info */ | 
| 67284 | 93 | |
| 76654 | 94 |   object Base {
 | 
| 95 | val bootstrap: Base = Base(overall_syntax = Thy_Header.bootstrap_syntax) | |
| 96 | } | |
| 97 | ||
| 65495 | 98 | sealed case class Base( | 
| 75750 
2eee2fdfb6e2
clarified signature: proper session_name for Sessions.Base (like Sessions.Info);
 wenzelm parents: 
75749diff
changeset | 99 | session_name: String = "", | 
| 75749 | 100 | session_pos: Position.T = Position.none, | 
| 75748 | 101 | proper_session_theories: List[Document.Node.Name] = Nil, | 
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 102 | document_theories: List[Document.Node.Name] = Nil, | 
| 75740 | 103 | loaded_theories: Graph[String, Outer_Syntax] = Graph.string, // cumulative imports | 
| 104 | used_theories: List[(Document.Node.Name, Options)] = Nil, // new imports | |
| 76872 | 105 | theory_load_commands: Map[String, List[Command_Span.Span]] = Map.empty, | 
| 70740 | 106 | known_theories: Map[String, Document.Node.Entry] = Map.empty, | 
| 107 | known_loaded_files: Map[String, List[Path]] = Map.empty, | |
| 66720 | 108 | overall_syntax: Outer_Syntax = Outer_Syntax.empty, | 
| 66744 | 109 | imported_sources: List[(Path, SHA1.Digest)] = Nil, | 
| 75741 | 110 | session_sources: List[(Path, SHA1.Digest)] = Nil, | 
| 66822 | 111 | session_graph_display: Graph_Display.Graph = Graph_Display.empty_graph, | 
| 75393 | 112 | errors: List[String] = Nil | 
| 113 |   ) {
 | |
| 75885 
8342cba8eae8
clarified signature: avoid constants from Sessions.Structure within Session.Base;
 wenzelm parents: 
75884diff
changeset | 114 | def session_entry: (String, Base) = session_name -> this | 
| 
8342cba8eae8
clarified signature: avoid constants from Sessions.Structure within Session.Base;
 wenzelm parents: 
75884diff
changeset | 115 | |
| 76661 | 116 |     override def toString: String = "Sessions.Base(" + print_body + ")"
 | 
| 117 | def print_body: String = | |
| 118 | "session_name = " + quote(session_name) + | |
| 119 | ", loaded_theories = " + loaded_theories.size + | |
| 120 | ", used_theories = " + used_theories.length | |
| 69102 
4b06a20b13b5
tuned output -- avoid bombing of Scala toplevel, e.g. for AFP deps;
 wenzelm parents: 
69080diff
changeset | 121 | |
| 77204 | 122 | def all_sources: List[(Path, SHA1.Digest)] = imported_sources ::: session_sources | 
| 123 | ||
| 76628 | 124 | def all_document_theories: List[Document.Node.Name] = | 
| 125 | proper_session_theories ::: document_theories | |
| 126 | ||
| 66717 
67dbf5cdc056
more informative loaded_theories: dependencies and syntax;
 wenzelm parents: 
66716diff
changeset | 127 | def loaded_theory(name: String): Boolean = loaded_theories.defined(name) | 
| 66712 | 128 | def loaded_theory(name: Document.Node.Name): Boolean = loaded_theory(name.theory) | 
| 65432 | 129 | |
| 66717 
67dbf5cdc056
more informative loaded_theories: dependencies and syntax;
 wenzelm parents: 
66716diff
changeset | 130 | def loaded_theory_syntax(name: String): Option[Outer_Syntax] = | 
| 
67dbf5cdc056
more informative loaded_theories: dependencies and syntax;
 wenzelm parents: 
66716diff
changeset | 131 | if (loaded_theory(name)) Some(loaded_theories.get_node(name)) else None | 
| 
67dbf5cdc056
more informative loaded_theories: dependencies and syntax;
 wenzelm parents: 
66716diff
changeset | 132 | def loaded_theory_syntax(name: Document.Node.Name): Option[Outer_Syntax] = | 
| 
67dbf5cdc056
more informative loaded_theories: dependencies and syntax;
 wenzelm parents: 
66716diff
changeset | 133 | loaded_theory_syntax(name.theory) | 
| 
67dbf5cdc056
more informative loaded_theories: dependencies and syntax;
 wenzelm parents: 
66716diff
changeset | 134 | |
| 72669 | 135 | def theory_syntax(name: Document.Node.Name): Outer_Syntax = | 
| 136 | loaded_theory_syntax(name) getOrElse overall_syntax | |
| 137 | ||
| 66770 
122df1fde073
clarified node_syntax (amending ae38b8c0fdd9): default to overall_syntax, e.g. relevant for command spans wrt. bad header;
 wenzelm parents: 
66764diff
changeset | 138 | def node_syntax(nodes: Document.Nodes, name: Document.Node.Name): Outer_Syntax = | 
| 
122df1fde073
clarified node_syntax (amending ae38b8c0fdd9): default to overall_syntax, e.g. relevant for command spans wrt. bad header;
 wenzelm parents: 
66764diff
changeset | 139 | nodes(name).syntax orElse loaded_theory_syntax(name) getOrElse overall_syntax | 
| 65355 | 140 | } | 
| 64856 | 141 | |
| 76677 | 142 | |
| 143 | /* background context */ | |
| 144 | ||
| 77562 | 145 |   object Background {
 | 
| 146 | def empty(session: String): Background = | |
| 147 | Background(Base(session_name = session)) | |
| 148 | ||
| 149 | def load(options: Options, | |
| 150 | session: String, | |
| 151 | progress: Progress = new Progress, | |
| 152 | dirs: List[Path] = Nil, | |
| 153 | include_sessions: List[String] = Nil, | |
| 154 | session_ancestor: Option[String] = None, | |
| 155 | session_requirements: Boolean = false | |
| 156 |     ): Background = {
 | |
| 157 | val full_sessions = load_structure(options, dirs = dirs) | |
| 158 | ||
| 159 | val selected_sessions = | |
| 160 | full_sessions.selection(Selection(sessions = session :: session_ancestor.toList)) | |
| 161 | val info = selected_sessions(session) | |
| 162 | val ancestor = session_ancestor orElse info.parent | |
| 163 | ||
| 164 | val (session1, infos1) = | |
| 165 |         if (session_requirements && ancestor.isDefined) {
 | |
| 166 | val deps = Sessions.deps(selected_sessions, progress = progress) | |
| 167 | val base = deps(session) | |
| 168 | ||
| 169 | val ancestor_loaded = | |
| 170 |             deps.get(ancestor.get) match {
 | |
| 171 | case Some(ancestor_base) | |
| 172 | if !selected_sessions.imports_requirements(List(ancestor.get)).contains(session) => | |
| 173 | ancestor_base.loaded_theories.defined _ | |
| 174 | case _ => | |
| 175 |                 error("Bad ancestor " + quote(ancestor.get) + " for session " + quote(session))
 | |
| 176 | } | |
| 177 | ||
| 178 | val required_theories = | |
| 179 |             for {
 | |
| 180 | thy <- base.loaded_theories.keys | |
| 181 | if !ancestor_loaded(thy) && selected_sessions.theory_qualifier(thy) != session | |
| 182 | } | |
| 183 | yield thy | |
| 184 | ||
| 185 | if (required_theories.isEmpty) (ancestor.get, Nil) | |
| 186 |           else {
 | |
| 187 |             val other_name = info.name + "_requirements(" + ancestor.get + ")"
 | |
| 188 | Isabelle_System.isabelle_tmp_prefix() | |
| 189 | ||
| 190 | (other_name, | |
| 191 | List( | |
| 192 | Info.make( | |
| 193 | Chapter_Defs.empty, | |
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 194 | Options.init0(), | 
| 77562 | 195 | info.options, | 
| 196 | augment_options = _ => Nil, | |
| 197 | dir_selected = false, | |
| 198 |                   dir = Path.explode("$ISABELLE_TMP_PREFIX"),
 | |
| 199 | chapter = info.chapter, | |
| 200 | Session_Entry( | |
| 201 | pos = info.pos, | |
| 202 | name = other_name, | |
| 203 | groups = info.groups, | |
| 204 | path = ".", | |
| 205 | parent = ancestor, | |
| 206 | description = "Required theory imports from other sessions", | |
| 207 | options = Nil, | |
| 208 | imports = info.deps, | |
| 209 | directories = Nil, | |
| 210 | theories = List((Nil, required_theories.map(thy => ((thy, Position.none), false)))), | |
| 211 | document_theories = Nil, | |
| 212 | document_files = Nil, | |
| 213 | export_files = Nil, | |
| 214 | export_classpath = Nil)))) | |
| 215 | } | |
| 216 | } | |
| 217 | else (session, Nil) | |
| 218 | ||
| 219 | val full_sessions1 = | |
| 220 | if (infos1.isEmpty) full_sessions | |
| 221 | else load_structure(options, dirs = dirs, infos = infos1) | |
| 222 | ||
| 223 | val selected_sessions1 = | |
| 224 | full_sessions1.selection(Selection(sessions = session1 :: session :: include_sessions)) | |
| 225 | ||
| 226 | val deps1 = Sessions.deps(selected_sessions1, progress = progress) | |
| 227 | ||
| 228 | Background(deps1(session1), sessions_structure = full_sessions1, | |
| 229 | errors = deps1.errors, infos = infos1) | |
| 230 | } | |
| 231 | } | |
| 232 | ||
| 76656 | 233 | sealed case class Background( | 
| 76597 | 234 | base: Base, | 
| 235 | sessions_structure: Structure = Structure.empty, | |
| 236 | errors: List[String] = Nil, | |
| 237 | infos: List[Info] = Nil | |
| 238 |   ) {
 | |
| 239 | def session_name: String = base.session_name | |
| 76732 | 240 | def info: Info = sessions_structure(session_name) | 
| 76597 | 241 | |
| 76656 | 242 | def check_errors: Background = | 
| 76597 | 243 | if (errors.isEmpty) this | 
| 244 | else error(cat_lines(errors)) | |
| 245 | } | |
| 246 | ||
| 247 | ||
| 77562 | 248 | /* source dependencies */ | 
| 76597 | 249 | |
| 77562 | 250 |   object Deps {
 | 
| 251 | def load(sessions_structure: Structure, | |
| 252 | progress: Progress = new Progress, | |
| 253 | inlined_files: Boolean = false, | |
| 80886 
5d562dd387ae
discontinued "isabelle build -k": superseded by admin-tool "isabelle check_keywords";
 wenzelm parents: 
80194diff
changeset | 254 | list_files: Boolean = false | 
| 77562 | 255 |     ): Deps = {
 | 
| 256 | var cache_sources = Map.empty[JFile, SHA1.Digest] | |
| 257 |       def check_sources(paths: List[Path]): List[(Path, SHA1.Digest)] = {
 | |
| 258 |         for {
 | |
| 259 | path <- paths | |
| 260 | file = path.file | |
| 261 | if cache_sources.isDefinedAt(file) || file.isFile | |
| 262 | } | |
| 263 |         yield {
 | |
| 264 |           cache_sources.get(file) match {
 | |
| 265 | case Some(digest) => (path, digest) | |
| 266 | case None => | |
| 267 | val digest = SHA1.digest(file) | |
| 268 | cache_sources = cache_sources + (file -> digest) | |
| 269 | (path, digest) | |
| 76597 | 270 | } | 
| 271 | } | |
| 272 | } | |
| 77562 | 273 | |
| 274 | val session_bases = | |
| 275 |         sessions_structure.imports_topological_order.foldLeft(Map(Base.bootstrap.session_entry)) {
 | |
| 276 | case (session_bases, session_name) => | |
| 277 | progress.expose_interrupt() | |
| 278 | ||
| 279 | val info = sessions_structure(session_name) | |
| 280 |             try {
 | |
| 281 | val deps_base = info.deps_base(session_bases) | |
| 282 | val session_background = | |
| 283 | Background(base = deps_base, sessions_structure = sessions_structure) | |
| 284 | val resources = new Resources(session_background) | |
| 285 | ||
| 286 | progress.echo( | |
| 287 | "Session " + info.chapter + "/" + session_name + | |
| 288 |                   if_proper(info.groups, info.groups.mkString(" (", " ", ")")),
 | |
| 289 | verbose = !list_files) | |
| 290 | ||
| 291 | val dependencies = resources.session_dependencies(info) | |
| 292 | ||
| 293 | val proper_session_theories = | |
| 294 | dependencies.theories.filter(name => | |
| 295 | sessions_structure.theory_qualifier(name) == session_name) | |
| 296 | ||
| 297 | val theory_files = dependencies.theories.map(_.path) | |
| 298 | ||
| 299 | val (load_commands, load_commands_errors) = | |
| 300 |                 try { if (inlined_files) (dependencies.load_commands, Nil) else (Nil, Nil) }
 | |
| 301 |                 catch { case ERROR(msg) => (Nil, List(msg)) }
 | |
| 302 | ||
| 303 | val theory_load_commands = | |
| 304 | (for ((name, span) <- load_commands.iterator) yield name.theory -> span).toMap | |
| 305 | ||
| 306 | val loaded_files: List[(String, List[Path])] = | |
| 307 |                 for ((name, spans) <- load_commands) yield {
 | |
| 308 | val (theory, files) = dependencies.loaded_files(name, spans) | |
| 309 | theory -> files.map(file => Path.explode(file.node)) | |
| 310 | } | |
| 311 | ||
| 312 | val document_files = | |
| 313 | for ((path1, path2) <- info.document_files) | |
| 314 | yield info.dir + path1 + path2 | |
| 315 | ||
| 316 | val session_files = | |
| 317 | (theory_files ::: loaded_files.flatMap(_._2) ::: document_files).map(_.expand) | |
| 318 | ||
| 319 | val imported_files = if (inlined_files) dependencies.imported_files else Nil | |
| 76597 | 320 | |
| 77562 | 321 |               if (list_files) {
 | 
| 322 |                 progress.echo(cat_lines(session_files.map(_.implode).sorted.map("  " + _)))
 | |
| 323 | } | |
| 324 | ||
| 325 |               val session_graph_display: Graph_Display.Graph = {
 | |
| 326 | def session_node(name: String): Graph_Display.Node = | |
| 327 |                   Graph_Display.Node("[" + name + "]", "session." + name)
 | |
| 328 | ||
| 329 |                 def node(name: Document.Node.Name): Graph_Display.Node = {
 | |
| 330 | val qualifier = sessions_structure.theory_qualifier(name) | |
| 331 |                   if (qualifier == info.name) {
 | |
| 332 | Graph_Display.Node(name.theory_base_name, "theory." + name.theory) | |
| 333 | } | |
| 334 | else session_node(qualifier) | |
| 335 | } | |
| 336 | ||
| 337 | val required_sessions = | |
| 338 | dependencies.loaded_theories.all_preds(dependencies.theories.map(_.theory)) | |
| 339 | .map(theory => sessions_structure.theory_qualifier(theory)) | |
| 340 | .filter(name => name != info.name && sessions_structure.defined(name)) | |
| 76597 | 341 | |
| 77562 | 342 | val required_subgraph = | 
| 343 | sessions_structure.imports_graph | |
| 344 | .restrict(sessions_structure.imports_graph.all_preds(required_sessions).toSet) | |
| 345 | .transitive_closure | |
| 346 | .restrict(required_sessions.toSet) | |
| 347 | .transitive_reduction_acyclic | |
| 348 | ||
| 349 | val graph0 = | |
| 350 |                   required_subgraph.topological_order.foldLeft(Graph_Display.empty_graph) {
 | |
| 351 | case (g, session) => | |
| 352 | val a = session_node(session) | |
| 353 | val bs = required_subgraph.imm_preds(session).toList.map(session_node) | |
| 354 | bs.foldLeft((a :: bs).foldLeft(g)(_.default_node(_, Nil)))(_.add_edge(_, a)) | |
| 355 | } | |
| 356 | ||
| 357 |                 dependencies.entries.foldLeft(graph0) {
 | |
| 358 | case (g, entry) => | |
| 359 | val a = node(entry.name) | |
| 360 | val bs = entry.header.imports.map(node).filterNot(_ == a) | |
| 361 | bs.foldLeft((a :: bs).foldLeft(g)(_.default_node(_, Nil)))(_.add_edge(_, a)) | |
| 362 | } | |
| 363 | } | |
| 364 | ||
| 365 | val known_theories = | |
| 366 | dependencies.entries.iterator.map(entry => entry.name.theory -> entry). | |
| 367 | foldLeft(deps_base.known_theories)(_ + _) | |
| 368 | ||
| 369 | val known_loaded_files = deps_base.known_loaded_files ++ loaded_files | |
| 76597 | 370 | |
| 77562 | 371 |               val import_errors = {
 | 
| 372 | val known_sessions = | |
| 373 | sessions_structure.imports_requirements(List(session_name)).toSet | |
| 374 |                 for {
 | |
| 375 | name <- dependencies.theories | |
| 376 | qualifier = sessions_structure.theory_qualifier(name) | |
| 377 | if !known_sessions(qualifier) | |
| 378 | } yield "Bad import of theory " + quote(name.toString) + | |
| 379 | ": need to include sessions " + quote(qualifier) + " in ROOT" | |
| 380 | } | |
| 381 | ||
| 382 | val document_errors = | |
| 383 | info.document_theories.flatMap( | |
| 384 |                 {
 | |
| 385 | case (thy, pos) => | |
| 386 | val build_hierarchy = | |
| 387 |                       if (sessions_structure.build_graph.defined(session_name)) {
 | |
| 388 | sessions_structure.build_hierarchy(session_name) | |
| 389 | } | |
| 390 | else Nil | |
| 391 | ||
| 392 | def err(msg: String): Option[String] = | |
| 393 | Some(msg + " " + quote(thy) + Position.here(pos)) | |
| 394 | ||
| 395 |                     known_theories.get(thy).map(_.name) match {
 | |
| 396 |                       case None => err("Unknown document theory")
 | |
| 397 | case Some(name) => | |
| 398 | val qualifier = sessions_structure.theory_qualifier(name) | |
| 399 |                         if (proper_session_theories.contains(name)) {
 | |
| 400 |                           err("Redundant document theory from this session:")
 | |
| 401 | } | |
| 402 | else if ( | |
| 403 | !build_hierarchy.contains(qualifier) && | |
| 404 | !dependencies.theories.contains(name) | |
| 405 |                         ) {
 | |
| 406 |                           err("Document theory from other session not imported properly:")
 | |
| 407 | } | |
| 408 | else None | |
| 409 | } | |
| 410 | }) | |
| 411 | val document_theories = | |
| 412 |                 info.document_theories.map({ case (thy, _) => known_theories(thy).name })
 | |
| 413 | ||
| 414 |               val dir_errors = {
 | |
| 415 | val ok = info.dirs.map(_.canonical_file).toSet | |
| 416 | val bad = | |
| 417 |                   (for {
 | |
| 418 | name <- proper_session_theories.iterator | |
| 419 | path = Path.explode(name.master_dir) | |
| 420 | if !ok(path.canonical_file) | |
| 421 | path1 = File.relative_path(info.dir.canonical, path).getOrElse(path) | |
| 422 | } yield (path1, name)).toList | |
| 423 |                 val bad_dirs = (for { (path1, _) <- bad } yield path1.toString).distinct.sorted
 | |
| 76597 | 424 | |
| 77562 | 425 | val errs1 = | 
| 426 |                   for { (path1, name) <- bad }
 | |
| 427 | yield "Implicit use of directory " + path1 + " for theory " + quote(name.toString) | |
| 428 | val errs2 = | |
| 429 | if (bad_dirs.isEmpty) Nil | |
| 430 |                   else List("Implicit use of session directories: " + commas(bad_dirs))
 | |
| 431 | val errs3 = for (p <- info.dirs if !p.is_dir) yield "No such directory: " + p | |
| 432 | val errs4 = | |
| 433 |                   (for {
 | |
| 434 | name <- proper_session_theories.iterator | |
| 435 | name1 <- resources.find_theory_node(name.theory) | |
| 436 | if name.node != name1.node | |
| 437 |                   } yield {
 | |
| 438 | "Incoherent theory file import:\n " + quote(name.node) + | |
| 439 | " vs. \n " + quote(name1.node) | |
| 440 | }).toList | |
| 441 | ||
| 442 | errs1 ::: errs2 ::: errs3 ::: errs4 | |
| 443 | } | |
| 444 | ||
| 445 | val sources_errors = | |
| 446 | for (p <- session_files if !p.is_file) yield "No such file: " + p | |
| 447 | ||
| 448 | val path_errors = | |
| 449 |                 try { Path.check_case_insensitive(session_files ::: imported_files); Nil }
 | |
| 450 |                 catch { case ERROR(msg) => List(msg) }
 | |
| 451 | ||
| 452 | val bibtex_errors = info.bibtex_entries.errors | |
| 453 | ||
| 454 | val base = | |
| 455 | Base( | |
| 456 | session_name = info.name, | |
| 457 | session_pos = info.pos, | |
| 458 | proper_session_theories = proper_session_theories, | |
| 459 | document_theories = document_theories, | |
| 460 | loaded_theories = dependencies.loaded_theories, | |
| 461 | used_theories = dependencies.theories_adjunct, | |
| 462 | theory_load_commands = theory_load_commands, | |
| 463 | known_theories = known_theories, | |
| 464 | known_loaded_files = known_loaded_files, | |
| 80886 
5d562dd387ae
discontinued "isabelle build -k": superseded by admin-tool "isabelle check_keywords";
 wenzelm parents: 
80194diff
changeset | 465 | overall_syntax = dependencies.overall_syntax, | 
| 77562 | 466 | imported_sources = check_sources(imported_files), | 
| 467 | session_sources = check_sources(session_files), | |
| 468 | session_graph_display = session_graph_display, | |
| 469 | errors = dependencies.errors ::: load_commands_errors ::: import_errors ::: | |
| 470 | document_errors ::: dir_errors ::: sources_errors ::: path_errors ::: | |
| 471 | bibtex_errors) | |
| 472 | ||
| 473 | session_bases + base.session_entry | |
| 474 | } | |
| 475 |             catch {
 | |
| 476 | case ERROR(msg) => | |
| 477 | cat_error(msg, "The error(s) above occurred in session " + | |
| 478 | quote(info.name) + Position.here(info.pos)) | |
| 479 | } | |
| 480 | } | |
| 481 | ||
| 482 | new Deps(sessions_structure, session_bases) | |
| 483 | } | |
| 76597 | 484 | } | 
| 485 | ||
| 77560 | 486 | final class Deps private[Sessions]( | 
| 487 | val sessions_structure: Structure, | |
| 488 | val session_bases: Map[String, Base] | |
| 489 |   ) {
 | |
| 76656 | 490 | def background(session: String): Background = | 
| 491 | Background(base = apply(session), sessions_structure = sessions_structure, errors = errors) | |
| 69102 
4b06a20b13b5
tuned output -- avoid bombing of Scala toplevel, e.g. for AFP deps;
 wenzelm parents: 
69080diff
changeset | 492 | |
| 76279 
2d4ff8c166d2
proper Deps.is_empty (amending 77327455b00d), e.g. relevant for warning "Nothing to build";
 wenzelm parents: 
76107diff
changeset | 493 | def is_empty: Boolean = session_bases.keysIterator.forall(_.isEmpty) | 
| 65463 
104502de757c
more informative known_files: known_theories within the local session directory come first;
 wenzelm parents: 
65461diff
changeset | 494 | def apply(name: String): Base = session_bases(name) | 
| 66988 | 495 | def get(name: String): Option[Base] = session_bases.get(name) | 
| 66744 | 496 | |
| 77207 
d98a99e4eea9
proper Shasum.digest, to emulate old form from build_history database;
 wenzelm parents: 
77206diff
changeset | 497 |     def sources_shasum(name: String): SHA1.Shasum = {
 | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 498 | val meta_info = sessions_structure(name).meta_info | 
| 77204 | 499 | val sources = | 
| 77211 | 500 | SHA1.shasum_sorted( | 
| 501 | for ((path, digest) <- apply(name).all_sources) | |
| 502 | yield digest -> File.symbolic_path(path)) | |
| 77214 
df8d71edbc79
clarified signature, using right-associative operation;
 wenzelm parents: 
77211diff
changeset | 503 | meta_info ::: sources | 
| 77204 | 504 | } | 
| 66571 | 505 | |
| 506 | def errors: List[String] = | |
| 507 |       (for {
 | |
| 508 | (name, base) <- session_bases.iterator | |
| 509 | if base.errors.nonEmpty | |
| 510 | } yield cat_lines(base.errors) + | |
| 75749 | 511 | "\nThe error(s) above occurred in session " + quote(name) + Position.here(base.session_pos) | 
| 66571 | 512 | ).toList | 
| 513 | ||
| 514 | def check_errors: Deps = | |
| 515 |       errors match {
 | |
| 516 | case Nil => this | |
| 517 | case errs => error(cat_lines(errs)) | |
| 518 | } | |
| 75774 
efc25bf4b795
discontinued Export.Provider in favour of Export.Context and its derivatives;
 wenzelm parents: 
75773diff
changeset | 519 | |
| 76597 | 520 |     override def toString: String = "Sessions.Deps(" + sessions_structure + ")"
 | 
| 65251 | 521 | } | 
| 64856 | 522 | |
| 66963 | 523 | |
| 80055 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 524 | /* notable groups */ | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 525 | |
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 526 | sealed case class Group_Info( | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 527 | name: String, | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 528 | description: String, | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 529 | bulky: Boolean = false, | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 530 | afp: Boolean = false | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 531 |   ) {
 | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 532 | override def toString: String = name | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 533 | } | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 534 | |
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 535 | lazy val notable_groups: List[Group_Info] = | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 536 | List( | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 537 |       Group_Info("large", "full 64-bit memory model or word arithmetic required",
 | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 538 | bulky = true, afp = true), | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 539 |       Group_Info("slow", "CPU time much higher than 60min (on mid-range hardware)",
 | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 540 | bulky = true, afp = true), | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 541 |       Group_Info("very_slow", "elapsed time of many hours (on high-end hardware)",
 | 
| 80062 
1478c6d52864
clarified "bulky" sessions (again, see also 06153e2e0cdb), but note that "very_slow" is normally used together with "slow";
 wenzelm parents: 
80055diff
changeset | 542 | bulky = true, afp = true), | 
| 80055 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 543 |       Group_Info("AFP", "entry within AFP", afp = true),
 | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 544 |       Group_Info("doc", "Isabelle documentation"),
 | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 545 |       Group_Info("no_doc", "suppressed Isabelle documentation")
 | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 546 | ) | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 547 | |
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 548 | lazy val bulky_groups: Set[String] = | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 549 | Set.from(notable_groups.flatMap(g => if (g.bulky) Some(g.name) else None)) | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 550 | |
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 551 | lazy val afp_groups: Set[String] = | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 552 | Set.from(notable_groups.flatMap(g => if (g.afp) Some(g.name) else None)) | 
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 553 | |
| 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 554 | |
| 65415 
8cd54b18b68b
clarified signature: tree structure is not essential;
 wenzelm parents: 
65410diff
changeset | 555 | /* cumulative session info */ | 
| 62631 | 556 | |
| 78502 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 557 | private val BUILD_PREFS_BG = "<build_prefs:" | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 558 | private val BUILD_PREFS_EN = ">" | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 559 | |
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 560 | def make_build_prefs(name: String): String = | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 561 | BUILD_PREFS_BG + name + BUILD_PREFS_EN | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 562 | |
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 563 |   def is_build_prefs(s: String): Boolean = {
 | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 564 |     val i = s.indexOf('<')
 | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 565 |     i >= 0 && {
 | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 566 | val s1 = s.substring(i) | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 567 | s1.startsWith(BUILD_PREFS_BG) && s1.endsWith(BUILD_PREFS_EN) | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 568 | } | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 569 | } | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 570 | |
| 80128 | 571 | def eq_sources(thorough: Boolean, shasum1: SHA1.Shasum, shasum2: SHA1.Shasum): Boolean = | 
| 572 | if (thorough) shasum1 == shasum2 | |
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 573 |     else {
 | 
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 574 | def trim(shasum: SHA1.Shasum): SHA1.Shasum = | 
| 78502 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 575 | shasum.filter(s => !is_build_prefs(s)) | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 576 | |
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 577 | trim(shasum1) == trim(shasum2) | 
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 578 | } | 
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 579 | |
| 75999 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 580 | sealed case class Chapter_Info( | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 581 | name: String, | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 582 | pos: Position.T, | 
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 583 | groups: List[String], | 
| 75999 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 584 | description: String, | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 585 | sessions: List[String] | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 586 | ) | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 587 | |
| 76632 | 588 |   object Info {
 | 
| 589 | def make( | |
| 590 | chapter_defs: Chapter_Defs, | |
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 591 | options0: Options, | 
| 76632 | 592 | options: Options, | 
| 76927 
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
 wenzelm parents: 
76907diff
changeset | 593 | augment_options: String => List[Options.Spec], | 
| 76632 | 594 | dir_selected: Boolean, | 
| 595 | dir: Path, | |
| 596 | chapter: String, | |
| 597 | entry: Session_Entry | |
| 598 |     ): Info = {
 | |
| 599 |       try {
 | |
| 600 | val name = entry.name | |
| 601 | ||
| 602 |         if (illegal_session(name)) error("Illegal session name " + quote(name))
 | |
| 603 |         if (is_pure(name) && entry.parent.isDefined) error("Illegal parent session")
 | |
| 604 |         if (!is_pure(name) && !entry.parent.isDefined) error("Missing parent session")
 | |
| 605 | ||
| 606 | val session_path = dir + Path.explode(entry.path) | |
| 607 | val directories = entry.directories.map(dir => session_path + Path.explode(dir)) | |
| 608 | ||
| 77627 
582a7db1da37
more accurate Sessions.Info.session_prefs: cover relative changes wrt. statically declared options;
 wenzelm parents: 
77624diff
changeset | 609 | val session_options0 = options ++ entry.options | 
| 
582a7db1da37
more accurate Sessions.Info.session_prefs: cover relative changes wrt. statically declared options;
 wenzelm parents: 
77624diff
changeset | 610 | val session_options = session_options0 ++ augment_options(name) | 
| 
582a7db1da37
more accurate Sessions.Info.session_prefs: cover relative changes wrt. statically declared options;
 wenzelm parents: 
77624diff
changeset | 611 | val session_prefs = | 
| 
582a7db1da37
more accurate Sessions.Info.session_prefs: cover relative changes wrt. statically declared options;
 wenzelm parents: 
77624diff
changeset | 612 | session_options.make_prefs(defaults = session_options0, filter = _.session_content) | 
| 76632 | 613 | |
| 78502 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 614 | val build_prefs_digests = | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 615 | session_options.changed(defaults = options0, filter = _.session_content) | 
| 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 616 | .map(ch => SHA1.digest(ch.print_prefs) -> make_build_prefs(ch.name)) | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 617 | |
| 76632 | 618 | val theories = | 
| 619 |           entry.theories.map({ case (opts, thys) =>
 | |
| 620 | (session_options ++ opts, | |
| 621 |               thys.map({ case ((thy, pos), _) =>
 | |
| 622 | val thy_name = Thy_Header.import_name(thy) | |
| 623 |                 if (illegal_theory(thy_name)) {
 | |
| 624 |                   error("Illegal theory name " + quote(thy_name) + Position.here(pos))
 | |
| 625 | } | |
| 626 | else (thy, pos) })) }) | |
| 627 | ||
| 628 | val global_theories = | |
| 629 |           for { (_, thys) <- entry.theories; ((thy, pos), global) <- thys if global }
 | |
| 630 |           yield {
 | |
| 631 | val thy_name = Path.explode(thy).file_name | |
| 632 |             if (Long_Name.is_qualified(thy_name)) {
 | |
| 633 |               error("Bad qualified name for global theory " +
 | |
| 634 | quote(thy_name) + Position.here(pos)) | |
| 635 | } | |
| 636 | else thy_name | |
| 637 | } | |
| 638 | ||
| 639 | val conditions = | |
| 640 |           theories.flatMap(thys => space_explode(',', thys._1.string("condition"))).distinct.sorted.
 | |
| 641 | map(x => (x, Isabelle_System.getenv(x) != "")) | |
| 642 | ||
| 643 | val document_files = | |
| 644 |           entry.document_files.map({ case (s1, s2) => (Path.explode(s1), Path.explode(s2)) })
 | |
| 645 | ||
| 646 | val export_files = | |
| 647 |           entry.export_files.map({ case (dir, prune, pats) => (Path.explode(dir), prune, pats) })
 | |
| 648 | ||
| 649 | val meta_digest = | |
| 650 | SHA1.digest( | |
| 77627 
582a7db1da37
more accurate Sessions.Info.session_prefs: cover relative changes wrt. statically declared options;
 wenzelm parents: 
77624diff
changeset | 651 | (name, chapter, entry.parent, entry.directories, entry.options, entry.imports, | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 652 | entry.theories_no_position, conditions, entry.document_theories_no_position).toString) | 
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 653 | |
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 654 | val meta_info = | 
| 78502 
5e59f6a46b2f
more informative shasum: show differences explicitly;
 wenzelm parents: 
78407diff
changeset | 655 | SHA1.shasum_meta_info(meta_digest) ::: SHA1.shasum_sorted(build_prefs_digests) | 
| 76632 | 656 | |
| 657 | val chapter_groups = chapter_defs(chapter).groups | |
| 658 | val groups = chapter_groups ::: entry.groups.filterNot(chapter_groups.contains) | |
| 659 | ||
| 660 | Info(name, chapter, dir_selected, entry.pos, groups, session_path, | |
| 77610 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 661 | entry.parent, entry.description, directories, session_options, session_prefs, | 
| 76632 | 662 | entry.imports, theories, global_theories, entry.document_theories, document_files, | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 663 | export_files, entry.export_classpath, meta_info) | 
| 76632 | 664 | } | 
| 665 |       catch {
 | |
| 666 | case ERROR(msg) => | |
| 667 | error(msg + "\nThe error(s) above occurred in session entry " + | |
| 668 | quote(entry.name) + Position.here(entry.pos)) | |
| 669 | } | |
| 670 | } | |
| 671 | } | |
| 672 | ||
| 62631 | 673 | sealed case class Info( | 
| 65519 | 674 | name: String, | 
| 62631 | 675 | chapter: String, | 
| 66829 | 676 | dir_selected: Boolean, | 
| 62631 | 677 | pos: Position.T, | 
| 678 | groups: List[String], | |
| 679 | dir: Path, | |
| 680 | parent: Option[String], | |
| 681 | description: String, | |
| 70681 | 682 | directories: List[Path], | 
| 62631 | 683 | options: Options, | 
| 77610 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 684 | session_prefs: String, | 
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 685 | imports: List[String], | 
| 65517 | 686 | theories: List[(Options, List[(String, Position.T)])], | 
| 65374 | 687 | global_theories: List[String], | 
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 688 | document_theories: List[(String, Position.T)], | 
| 62631 | 689 | document_files: List[(Path, Path)], | 
| 69671 | 690 | export_files: List[(Path, Int, List[String])], | 
| 75679 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 691 | export_classpath: List[String], | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 692 | meta_info: SHA1.Shasum | 
| 75393 | 693 |   ) {
 | 
| 66828 | 694 | def deps: List[String] = parent.toList ::: imports | 
| 695 | ||
| 75393 | 696 |     def deps_base(session_bases: String => Base): Base = {
 | 
| 72066 | 697 |       val parent_base = session_bases(parent.getOrElse(""))
 | 
| 698 | val imports_bases = imports.map(session_bases) | |
| 699 | parent_base.copy( | |
| 700 | known_theories = | |
| 73359 | 701 |           (for {
 | 
| 702 | base <- imports_bases.iterator | |
| 703 | (_, entry) <- base.known_theories.iterator | |
| 704 | } yield (entry.name.theory -> entry)).foldLeft(parent_base.known_theories)(_ + _), | |
| 72066 | 705 | known_loaded_files = | 
| 73359 | 706 | imports_bases.iterator.map(_.known_loaded_files). | 
| 707 | foldLeft(parent_base.known_loaded_files)(_ ++ _)) | |
| 72066 | 708 | } | 
| 709 | ||
| 70681 | 710 | def dirs: List[Path] = dir :: directories | 
| 70668 | 711 | |
| 76492 
e228be7cd375
clarified GUI.Selector, with support for separator as pseudo-entry;
 wenzelm parents: 
76351diff
changeset | 712 |     def main_group: Boolean = groups.contains("main")
 | 
| 
e228be7cd375
clarified GUI.Selector, with support for separator as pseudo-entry;
 wenzelm parents: 
76351diff
changeset | 713 |     def doc_group: Boolean = groups.contains("doc")
 | 
| 
e228be7cd375
clarified GUI.Selector, with support for separator as pseudo-entry;
 wenzelm parents: 
76351diff
changeset | 714 | |
| 80128 | 715 |     def build_thorough: Boolean = options.bool("build_thorough")
 | 
| 716 | ||
| 73701 | 717 | def timeout_ignored: Boolean = | 
| 718 |       !options.bool("timeout_build") || Time.seconds(options.real("timeout")) < Time.ms(1)
 | |
| 719 | ||
| 62631 | 720 |     def timeout: Time = Time.seconds(options.real("timeout") * options.real("timeout_scale"))
 | 
| 67297 
86a099f896fc
formal check of @{cite} bibtex entries -- only in batch-mode session builds;
 wenzelm parents: 
67290diff
changeset | 721 | |
| 72574 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 722 | def document_enabled: Boolean = | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 723 |       options.string("document") match {
 | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 724 | case "" | "false" => false | 
| 73826 
72900f34dbb3
allow system option short form NAME for NAME=true for type string, not just bool;
 wenzelm parents: 
73815diff
changeset | 725 | case "pdf" | "true" => true | 
| 72574 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 726 |         case doc => error("Bad document specification " + quote(doc))
 | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 727 | } | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 728 | |
| 75393 | 729 |     def document_variants: List[Document_Build.Document_Variant] = {
 | 
| 72574 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 730 | val variants = | 
| 77218 | 731 |         space_explode(':', options.string("document_variants")).
 | 
| 73718 | 732 | map(Document_Build.Document_Variant.parse) | 
| 72649 | 733 | |
| 734 | val dups = Library.duplicates(variants.map(_.name)) | |
| 72574 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 735 |       if (dups.nonEmpty) error("Duplicate document variants: " + commas_quote(dups))
 | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 736 | |
| 72649 | 737 | variants | 
| 738 | } | |
| 739 | ||
| 75902 | 740 |     def document_echo: Boolean = options.bool("document_echo")
 | 
| 741 | ||
| 75393 | 742 |     def documents: List[Document_Build.Document_Variant] = {
 | 
| 72672 | 743 | val variants = document_variants | 
| 72574 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 744 | if (!document_enabled || document_files.isEmpty) Nil else variants | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 745 | } | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 746 | |
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 747 | def document_output: Option[Path] = | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 748 |       options.string("document_output") match {
 | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 749 | case "" => None | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 750 | case s => Some(dir + Path.explode(s)) | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 751 | } | 
| 
d892f6d66402
build documents in Isabelle/Scala, based on generated tex files as session exports;
 wenzelm parents: 
72571diff
changeset | 752 | |
| 72648 | 753 |     def browser_info: Boolean = options.bool("browser_info")
 | 
| 754 | ||
| 76776 | 755 | lazy val bibtex_entries: Bibtex.Entries = | 
| 76778 
4086a0e4723b
clarified signature: internalize errors (but: the parser rarely fails);
 wenzelm parents: 
76776diff
changeset | 756 |       (for {
 | 
| 
4086a0e4723b
clarified signature: internalize errors (but: the parser rarely fails);
 wenzelm parents: 
76776diff
changeset | 757 | (document_dir, file) <- document_files.iterator | 
| 
4086a0e4723b
clarified signature: internalize errors (but: the parser rarely fails);
 wenzelm parents: 
76776diff
changeset | 758 | if File.is_bib(file.file_name) | 
| 
4086a0e4723b
clarified signature: internalize errors (but: the parser rarely fails);
 wenzelm parents: 
76776diff
changeset | 759 |       } yield {
 | 
| 
4086a0e4723b
clarified signature: internalize errors (but: the parser rarely fails);
 wenzelm parents: 
76776diff
changeset | 760 | val path = dir + document_dir + file | 
| 77030 
d7dc5b1e4381
proper positions for Isabelle/ML, instead of Isabelle/Scala;
 wenzelm parents: 
77029diff
changeset | 761 | Bibtex.Entries.parse(File.read(path), start = Token.Pos.file(File.standard_path(path))) | 
| 76778 
4086a0e4723b
clarified signature: internalize errors (but: the parser rarely fails);
 wenzelm parents: 
76776diff
changeset | 762 | }).foldRight(Bibtex.Entries.empty)(_ ::: _) | 
| 70859 
6e6254bbce1f
split into standard partitions, for improved scalability;
 wenzelm parents: 
70796diff
changeset | 763 | |
| 70869 | 764 |     def record_proofs: Boolean = options.int("record_proofs") >= 2
 | 
| 765 | ||
| 70859 
6e6254bbce1f
split into standard partitions, for improved scalability;
 wenzelm parents: 
70796diff
changeset | 766 | def is_afp: Boolean = chapter == AFP.chapter | 
| 80055 
42bc8ab751c1
clarified modules: more official Sessions.notable_groups;
 wenzelm parents: 
79502diff
changeset | 767 | def is_afp_bulky: Boolean = is_afp && groups.exists(bulky_groups) | 
| 62631 | 768 | } | 
| 769 | ||
| 75393 | 770 |   object Selection {
 | 
| 65422 | 771 | val empty: Selection = Selection() | 
| 65525 | 772 | val all: Selection = Selection(all_sessions = true) | 
| 70788 | 773 | def session(session: String): Selection = Selection(sessions = List(session)) | 
| 65419 | 774 | } | 
| 775 | ||
| 776 | sealed case class Selection( | |
| 777 | requirements: Boolean = false, | |
| 778 | all_sessions: Boolean = false, | |
| 66737 
2edc0c42c883
option -B for "isabelle build" and "isabelle imports";
 wenzelm parents: 
66736diff
changeset | 779 | base_sessions: List[String] = Nil, | 
| 65419 | 780 | exclude_session_groups: List[String] = Nil, | 
| 781 | exclude_sessions: List[String] = Nil, | |
| 782 | session_groups: List[String] = Nil, | |
| 75393 | 783 | sessions: List[String] = Nil | 
| 784 |   ) {
 | |
| 66736 | 785 | def ++ (other: Selection): Selection = | 
| 65422 | 786 | Selection( | 
| 787 | requirements = requirements || other.requirements, | |
| 788 | all_sessions = all_sessions || other.all_sessions, | |
| 66737 
2edc0c42c883
option -B for "isabelle build" and "isabelle imports";
 wenzelm parents: 
66736diff
changeset | 789 | base_sessions = Library.merge(base_sessions, other.base_sessions), | 
| 66736 | 790 | exclude_session_groups = Library.merge(exclude_session_groups, other.exclude_session_groups), | 
| 791 | exclude_sessions = Library.merge(exclude_sessions, other.exclude_sessions), | |
| 792 | session_groups = Library.merge(session_groups, other.session_groups), | |
| 793 | sessions = Library.merge(sessions, other.sessions)) | |
| 65419 | 794 | } | 
| 795 | ||
| 75393 | 796 |   object Structure {
 | 
| 76631 | 797 | val empty: Structure = make(Options.empty) | 
| 798 | ||
| 799 | def make( | |
| 800 | options: Options, | |
| 76927 
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
 wenzelm parents: 
76907diff
changeset | 801 | augment_options: String => List[Options.Spec] = _ => Nil, | 
| 76631 | 802 | roots: List[Root_File] = Nil, | 
| 803 | infos: List[Info] = Nil | |
| 804 |     ): Structure = {
 | |
| 805 | val chapter_defs: Chapter_Defs = | |
| 806 |         roots.foldLeft(Chapter_Defs.empty) {
 | |
| 807 | case (defs1, root) => | |
| 808 |             root.entries.foldLeft(defs1) {
 | |
| 809 | case (defs2, entry: Chapter_Def) => defs2 + entry | |
| 810 | case (defs2, _) => defs2 | |
| 811 | } | |
| 812 | } | |
| 72858 
cb0c407fbc6e
added "isabelle log": print messages from build database;
 wenzelm parents: 
72855diff
changeset | 813 | |
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 814 | val options0 = Options.init0() | 
| 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 815 | val session_prefs = options.make_prefs(defaults = options0, filter = _.session_content) | 
| 77610 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 816 | |
| 76631 | 817 |       val root_infos = {
 | 
| 818 | var chapter = UNSORTED | |
| 76635 | 819 | val root_infos = new mutable.ListBuffer[Info] | 
| 76631 | 820 |         for (root <- roots) {
 | 
| 821 |           root.entries.foreach {
 | |
| 822 | case entry: Chapter_Entry => chapter = entry.name | |
| 823 | case entry: Session_Entry => | |
| 76927 
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
 wenzelm parents: 
76907diff
changeset | 824 | root_infos += | 
| 77675 
9e5f8f6e58a0
more thorough treatment of build prefs, guarded by system option "build_through": avoid accidental rebuild of HOL etc.;
 wenzelm parents: 
77629diff
changeset | 825 | Info.make(chapter_defs, options0, options, augment_options, | 
| 76927 
da13da82f6f9
treat update_options as part of Sessions.Info meta_digest, for proper re-build of updated sessions;
 wenzelm parents: 
76907diff
changeset | 826 | root.select, root.dir, chapter, entry) | 
| 76631 | 827 | case _ => | 
| 828 | } | |
| 829 | chapter = UNSORTED | |
| 830 | } | |
| 76635 | 831 | root_infos.toList | 
| 76631 | 832 | } | 
| 833 | ||
| 834 | val info_graph = | |
| 835 |         (root_infos ::: infos).foldLeft(Graph.string[Info]) {
 | |
| 836 | case (graph, info) => | |
| 837 |             if (graph.defined(info.name)) {
 | |
| 838 |               error("Duplicate session " + quote(info.name) + Position.here(info.pos) +
 | |
| 839 | Position.here(graph.get_node(info.name).pos)) | |
| 840 | } | |
| 841 | else graph.new_node(info.name, info) | |
| 842 | } | |
| 843 | ||
| 76630 | 844 | def augment_graph( | 
| 75393 | 845 | graph: Graph[String, Info], | 
| 846 | kind: String, | |
| 847 | edges: Info => Iterable[String] | |
| 848 |       ) : Graph[String, Info] = {
 | |
| 849 |         def add_edge(pos: Position.T, name: String, g: Graph[String, Info], parent: String) = {
 | |
| 76048 | 850 |           if (!g.defined(parent)) {
 | 
| 72855 | 851 |             error("Bad " + kind + " session " + quote(parent) + " for " +
 | 
| 852 | quote(name) + Position.here(pos)) | |
| 76048 | 853 | } | 
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 854 | |
| 72855 | 855 |           try { g.add_edge_acyclic(parent, name) }
 | 
| 856 |           catch {
 | |
| 857 | case exn: Graph.Cycles[_] => | |
| 858 | error(cat_lines(exn.cycles.map(cycle => | |
| 859 | "Cyclic session dependency of " + | |
| 860 |                   cycle.map(c => quote(c.toString)).mkString(" via "))) + Position.here(pos))
 | |
| 861 | } | |
| 862 | } | |
| 73359 | 863 |         graph.iterator.foldLeft(graph) {
 | 
| 864 | case (g, (name, (info, _))) => | |
| 865 | edges(info).foldLeft(g)(add_edge(info.pos, name, _, _)) | |
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 866 | } | 
| 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 867 | } | 
| 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 868 | |
| 76630 | 869 | val build_graph = augment_graph(info_graph, "parent", _.parent) | 
| 870 | val imports_graph = augment_graph(build_graph, "imports", _.imports) | |
| 62631 | 871 | |
| 72855 | 872 | val session_positions: List[(String, Position.T)] = | 
| 873 | (for ((name, (info, _)) <- info_graph.iterator) yield (name, info.pos)).toList | |
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70681diff
changeset | 874 | |
| 72855 | 875 | val session_directories: Map[JFile, String] = | 
| 73359 | 876 |         (for {
 | 
| 877 | session <- imports_graph.topological_order.iterator | |
| 878 | info = info_graph.get_node(session) | |
| 879 | dir <- info.dirs.iterator | |
| 880 |         } yield (info, dir)).foldLeft(Map.empty[JFile, String]) {
 | |
| 881 | case (dirs, (info, dir)) => | |
| 72855 | 882 | val session = info.name | 
| 883 | val canonical_dir = dir.canonical_file | |
| 884 |               dirs.get(canonical_dir) match {
 | |
| 885 | case Some(session1) => | |
| 886 | val info1 = info_graph.get_node(session1) | |
| 887 |                   error("Duplicate use of directory " + dir +
 | |
| 888 | "\n for session " + quote(session1) + Position.here(info1.pos) + | |
| 889 | "\n vs. session " + quote(session) + Position.here(info.pos)) | |
| 890 | case None => dirs + (canonical_dir -> session) | |
| 891 | } | |
| 73359 | 892 | } | 
| 70671 
cb1776c8e216
clarified signature: retain global session information, unaffected by later restriction;
 wenzelm parents: 
70668diff
changeset | 893 | |
| 72855 | 894 | val global_theories: Map[String, String] = | 
| 73359 | 895 |         (for {
 | 
| 896 | session <- imports_graph.topological_order.iterator | |
| 897 | info = info_graph.get_node(session) | |
| 898 | thy <- info.global_theories.iterator } | |
| 76630 | 899 | yield (info, thy) | 
| 900 |         ).foldLeft(Thy_Header.bootstrap_global_theories.toMap) {
 | |
| 73359 | 901 | case (global, (info, thy)) => | 
| 72855 | 902 | val qualifier = info.name | 
| 903 |               global.get(thy) match {
 | |
| 904 | case Some(qualifier1) if qualifier != qualifier1 => | |
| 905 |                   error("Duplicate global theory " + quote(thy) + Position.here(info.pos))
 | |
| 906 | case _ => global + (thy -> qualifier) | |
| 907 | } | |
| 73359 | 908 | } | 
| 70671 
cb1776c8e216
clarified signature: retain global session information, unaffected by later restriction;
 wenzelm parents: 
70668diff
changeset | 909 | |
| 77610 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 910 | new Structure(chapter_defs, session_prefs, session_positions, session_directories, | 
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 911 | global_theories, build_graph, imports_graph) | 
| 72855 | 912 | } | 
| 62631 | 913 | } | 
| 914 | ||
| 67052 | 915 | final class Structure private[Sessions]( | 
| 75999 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 916 | chapter_defs: Chapter_Defs, | 
| 77610 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 917 | val session_prefs: String, | 
| 75393 | 918 | val session_positions: List[(String, Position.T)], | 
| 919 | val session_directories: Map[JFile, String], | |
| 920 | val global_theories: Map[String, String], | |
| 921 | val build_graph: Graph[String, Info], | |
| 922 | val imports_graph: Graph[String, Info] | |
| 923 |   ) {
 | |
| 69524 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 924 | sessions_structure => | 
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 925 | |
| 70683 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70681diff
changeset | 926 | def dest_session_directories: List[(String, String)] = | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70681diff
changeset | 927 | for ((file, session) <- session_directories.toList) | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70681diff
changeset | 928 | yield (File.standard_path(file), session) | 
| 
8c7706b053c7
find theory files via session structure: much faster Prover IDE startup;
 wenzelm parents: 
70681diff
changeset | 929 | |
| 75999 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 930 |     lazy val known_chapters: List[Chapter_Info] = {
 | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 931 | val chapter_sessions = | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 932 | Multi_Map.from( | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 933 | for ((_, (info, _)) <- build_graph.iterator) | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 934 | yield info.chapter -> info.name) | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 935 | val chapters1 = | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 936 |         (for (entry <- chapter_defs.list.iterator) yield {
 | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 937 | val sessions = chapter_sessions.get_list(entry.name) | 
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 938 | Chapter_Info(entry.name, entry.pos, entry.groups, entry.description, sessions.sorted) | 
| 75999 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 939 | }).toList | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 940 | val chapters2 = | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 941 |         (for {
 | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 942 | (name, sessions) <- chapter_sessions.iterator_list | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 943 | if !chapters1.exists(_.name == name) | 
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 944 | } yield Chapter_Info(name, Position.none, Nil, "", sessions.sorted)).toList.sortBy(_.name) | 
| 75999 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 945 | chapters1 ::: chapters2 | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 946 | } | 
| 
b831a0bdd751
clarified signature of Sessions.Session: chapter_defs: vs. known_chapters (in declaration order) vs. chapters (covered by visible sessions);
 wenzelm parents: 
75998diff
changeset | 947 | |
| 76002 | 948 | def relevant_chapters: List[Chapter_Info] = known_chapters.filter(_.sessions.nonEmpty) | 
| 69762 
58fb0d779583
support for session information via virtual file-system;
 wenzelm parents: 
69671diff
changeset | 949 | |
| 66823 | 950 | def build_graph_display: Graph_Display.Graph = Graph_Display.make_graph(build_graph) | 
| 951 | def imports_graph_display: Graph_Display.Graph = Graph_Display.make_graph(imports_graph) | |
| 952 | ||
| 67025 
961285f581e6
clarifified selection: always wrt. build_graph structure;
 wenzelm parents: 
67024diff
changeset | 953 | def defined(name: String): Boolean = imports_graph.defined(name) | 
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 954 | def apply(name: String): Info = imports_graph.get_node(name) | 
| 67025 
961285f581e6
clarifified selection: always wrt. build_graph structure;
 wenzelm parents: 
67024diff
changeset | 955 | def get(name: String): Option[Info] = if (defined(name)) Some(apply(name)) else None | 
| 62631 | 956 | |
| 70859 
6e6254bbce1f
split into standard partitions, for improved scalability;
 wenzelm parents: 
70796diff
changeset | 957 | def theory_qualifier(name: String): String = | 
| 
6e6254bbce1f
split into standard partitions, for improved scalability;
 wenzelm parents: 
70796diff
changeset | 958 | global_theories.getOrElse(name, Long_Name.qualifier(name)) | 
| 75884 
3d8b37b1d798
clarified signature: avoid object-oriented HTML_Context;
 wenzelm parents: 
75791diff
changeset | 959 | def theory_qualifier(name: Document.Node.Name): String = theory_qualifier(name.theory) | 
| 70859 
6e6254bbce1f
split into standard partitions, for improved scalability;
 wenzelm parents: 
70796diff
changeset | 960 | |
| 75393 | 961 |     def check_sessions(names: List[String]): Unit = {
 | 
| 71601 | 962 | val bad_sessions = SortedSet(names.filterNot(defined): _*).toList | 
| 76048 | 963 |       if (bad_sessions.nonEmpty) {
 | 
| 68542 | 964 |         error("Undefined session(s): " + commas_quote(bad_sessions))
 | 
| 76048 | 965 | } | 
| 68542 | 966 | } | 
| 967 | ||
| 68733 | 968 | def check_sessions(sel: Selection): Unit = | 
| 969 | check_sessions(sel.base_sessions ::: sel.exclude_sessions ::: sel.sessions) | |
| 970 | ||
| 75393 | 971 |     private def selected(graph: Graph[String, Info], sel: Selection): List[String] = {
 | 
| 68733 | 972 | check_sessions(sel) | 
| 973 | ||
| 68732 | 974 | val select_group = sel.session_groups.toSet | 
| 68734 
c14a2cc9b5ef
isabelle build options -c -x -B refer to imports_graph;
 wenzelm parents: 
68733diff
changeset | 975 | val select_session = sel.sessions.toSet ++ imports_graph.all_succs(sel.base_sessions) | 
| 68732 | 976 | |
| 977 | val selected0 = | |
| 978 | if (sel.all_sessions) graph.keys | |
| 979 |         else {
 | |
| 980 |           (for {
 | |
| 981 | (name, (info, _)) <- graph.iterator | |
| 74810 | 982 | if info.dir_selected || select_session(name) || info.groups.exists(select_group) | 
| 68732 | 983 | } yield name).toList | 
| 984 | } | |
| 985 | ||
| 986 | if (sel.requirements) (graph.all_preds(selected0).toSet -- selected0).toList | |
| 987 | else selected0 | |
| 988 | } | |
| 989 | ||
| 75393 | 990 |     def selection(sel: Selection): Structure = {
 | 
| 68733 | 991 | check_sessions(sel) | 
| 67025 
961285f581e6
clarifified selection: always wrt. build_graph structure;
 wenzelm parents: 
67024diff
changeset | 992 | |
| 75393 | 993 |       val excluded = {
 | 
| 68732 | 994 | val exclude_group = sel.exclude_session_groups.toSet | 
| 995 | val exclude_group_sessions = | |
| 996 |           (for {
 | |
| 68734 
c14a2cc9b5ef
isabelle build options -c -x -B refer to imports_graph;
 wenzelm parents: 
68733diff
changeset | 997 | (name, (info, _)) <- imports_graph.iterator | 
| 76599 | 998 | if info.groups.exists(exclude_group) | 
| 68732 | 999 | } yield name).toList | 
| 68734 
c14a2cc9b5ef
isabelle build options -c -x -B refer to imports_graph;
 wenzelm parents: 
68733diff
changeset | 1000 | imports_graph.all_succs(exclude_group_sessions ::: sel.exclude_sessions).toSet | 
| 68732 | 1001 | } | 
| 67027 | 1002 | |
| 75393 | 1003 |       def restrict(graph: Graph[String, Info]): Graph[String, Info] = {
 | 
| 68732 | 1004 | val sessions = graph.all_preds(selected(graph, sel)).filterNot(excluded) | 
| 67029 | 1005 | graph.restrict(graph.all_preds(sessions).toSet) | 
| 67025 
961285f581e6
clarifified selection: always wrt. build_graph structure;
 wenzelm parents: 
67024diff
changeset | 1006 | } | 
| 
961285f581e6
clarifified selection: always wrt. build_graph structure;
 wenzelm parents: 
67024diff
changeset | 1007 | |
| 77610 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 1008 | new Structure(chapter_defs, session_prefs, session_positions, session_directories, | 
| 
3b09ae9e40cb
clarified session prefs (or "options" within the database);
 wenzelm parents: 
77599diff
changeset | 1009 | global_theories, restrict(build_graph), restrict(imports_graph)) | 
| 62631 | 1010 | } | 
| 1011 | ||
| 72571 | 1012 | def selection(session: String): Structure = selection(Selection.session(session)) | 
| 1013 | ||
| 69524 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1014 | def selection_deps( | 
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1015 | selection: Selection, | 
| 71726 
a5fda30edae2
clarified signature: more uniform treatment of stopped/interrupted state;
 wenzelm parents: 
71642diff
changeset | 1016 | progress: Progress = new Progress, | 
| 69524 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1017 | loading_sessions: Boolean = false, | 
| 77521 
5642de4d225d
clarified signature: manage "verbose" flag via "progress";
 wenzelm parents: 
77516diff
changeset | 1018 | inlined_files: Boolean = false | 
| 75393 | 1019 |     ): Deps = {
 | 
| 69524 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1020 | val deps = | 
| 70869 | 1021 | Sessions.deps(sessions_structure.selection(selection), | 
| 77521 
5642de4d225d
clarified signature: manage "verbose" flag via "progress";
 wenzelm parents: 
77516diff
changeset | 1022 | progress = progress, inlined_files = inlined_files) | 
| 69524 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1023 | |
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1024 |       if (loading_sessions) {
 | 
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1025 | val selection_size = deps.sessions_structure.build_graph.size | 
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1026 |         if (selection_size > 1) progress.echo("Loading " + selection_size + " sessions ...")
 | 
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1027 | } | 
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1028 | |
| 
fa94f2b2a877
clarified sessions_deps, according to Isabelle/MMT usage;
 wenzelm parents: 
69393diff
changeset | 1029 | deps | 
| 68304 | 1030 | } | 
| 1031 | ||
| 75760 
f8be63d2ec6f
more robust build_hierarchy: support Resources.empty / Sessions.Structure.empty (required for Build_Job.print_log);
 wenzelm parents: 
75759diff
changeset | 1032 | def build_hierarchy(session: String): List[String] = | 
| 
f8be63d2ec6f
more robust build_hierarchy: support Resources.empty / Sessions.Structure.empty (required for Build_Job.print_log);
 wenzelm parents: 
75759diff
changeset | 1033 | if (build_graph.defined(session)) build_graph.all_preds(List(session)) | 
| 
f8be63d2ec6f
more robust build_hierarchy: support Resources.empty / Sessions.Structure.empty (required for Build_Job.print_log);
 wenzelm parents: 
75759diff
changeset | 1034 | else List(session) | 
| 
f8be63d2ec6f
more robust build_hierarchy: support Resources.empty / Sessions.Structure.empty (required for Build_Job.print_log);
 wenzelm parents: 
75759diff
changeset | 1035 | |
| 68732 | 1036 | def build_selection(sel: Selection): List[String] = selected(build_graph, sel) | 
| 67029 | 1037 | def build_descendants(ss: List[String]): List[String] = build_graph.all_succs(ss) | 
| 72065 
11dc8929832d
clarified order --- proper sorting of requirements;
 wenzelm parents: 
72064diff
changeset | 1038 | def build_requirements(ss: List[String]): List[String] = build_graph.all_preds_rev(ss) | 
| 67029 | 1039 | def build_topological_order: List[String] = build_graph.topological_order | 
| 62631 | 1040 | |
| 68732 | 1041 | def imports_selection(sel: Selection): List[String] = selected(imports_graph, sel) | 
| 67029 | 1042 | def imports_descendants(ss: List[String]): List[String] = imports_graph.all_succs(ss) | 
| 72065 
11dc8929832d
clarified order --- proper sorting of requirements;
 wenzelm parents: 
72064diff
changeset | 1043 | def imports_requirements(ss: List[String]): List[String] = imports_graph.all_preds_rev(ss) | 
| 67029 | 1044 | def imports_topological_order: List[String] = imports_graph.topological_order | 
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 1045 | |
| 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 1046 | override def toString: String = | 
| 67052 | 1047 |       imports_graph.keys_iterator.mkString("Sessions.Structure(", ", ", ")")
 | 
| 62631 | 1048 | } | 
| 1049 | ||
| 1050 | ||
| 1051 | /* parser */ | |
| 1052 | ||
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1053 | private val CHAPTER_DEFINITION = "chapter_definition" | 
| 62631 | 1054 | private val CHAPTER = "chapter" | 
| 1055 | private val SESSION = "session" | |
| 1056 | private val DESCRIPTION = "description" | |
| 70668 | 1057 | private val DIRECTORIES = "directories" | 
| 62631 | 1058 | private val OPTIONS = "options" | 
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 1059 | private val SESSIONS = "sessions" | 
| 62631 | 1060 | private val THEORIES = "theories" | 
| 65374 | 1061 | private val GLOBAL = "global" | 
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1062 | private val DOCUMENT_THEORIES = "document_theories" | 
| 62631 | 1063 | private val DOCUMENT_FILES = "document_files" | 
| 68292 | 1064 | private val EXPORT_FILES = "export_files" | 
| 75679 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1065 | private val EXPORT_CLASSPATH = "export_classpath" | 
| 62631 | 1066 | |
| 71601 | 1067 | val root_syntax: Outer_Syntax = | 
| 76614 | 1068 |     Outer_Syntax.empty + "(" + ")" + "+" + "," + "=" + "[" + "]" + "in" +
 | 
| 1069 | GLOBAL + | |
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1070 | (CHAPTER_DEFINITION, Keyword.THY_DECL) + | 
| 63443 | 1071 | (CHAPTER, Keyword.THY_DECL) + | 
| 1072 | (SESSION, Keyword.THY_DECL) + | |
| 1073 | (DESCRIPTION, Keyword.QUASI_COMMAND) + | |
| 70668 | 1074 | (DIRECTORIES, Keyword.QUASI_COMMAND) + | 
| 63443 | 1075 | (OPTIONS, Keyword.QUASI_COMMAND) + | 
| 65420 
695d4e22345a
support for static session imports, without affect build hierarchy;
 wenzelm parents: 
65419diff
changeset | 1076 | (SESSIONS, Keyword.QUASI_COMMAND) + | 
| 63443 | 1077 | (THEORIES, Keyword.QUASI_COMMAND) + | 
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1078 | (DOCUMENT_THEORIES, Keyword.QUASI_COMMAND) + | 
| 68292 | 1079 | (DOCUMENT_FILES, Keyword.QUASI_COMMAND) + | 
| 75679 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1080 | (EXPORT_FILES, Keyword.QUASI_COMMAND) + | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1081 | (EXPORT_CLASSPATH, Keyword.QUASI_COMMAND) | 
| 62631 | 1082 | |
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1083 | abstract class Entry | 
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1084 |   object Chapter_Def {
 | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1085 | def empty(chapter: String): Chapter_Def = Chapter_Def(Position.none, chapter, Nil, "") | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1086 | } | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1087 | sealed case class Chapter_Def( | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1088 | pos: Position.T, | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1089 | name: String, | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1090 | groups: List[String], | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1091 | description: String | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1092 | ) extends Entry | 
| 75984 | 1093 | sealed case class Chapter_Entry(name: String) extends Entry | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1094 | sealed case class Session_Entry( | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1095 | pos: Position.T, | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1096 | name: String, | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1097 | groups: List[String], | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1098 | path: String, | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1099 | parent: Option[String], | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1100 | description: String, | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1101 | options: List[Options.Spec], | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1102 | imports: List[String], | 
| 70681 | 1103 | directories: List[String], | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1104 | theories: List[(List[Options.Spec], List[((String, Position.T), Boolean)])], | 
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1105 | document_theories: List[(String, Position.T)], | 
| 68292 | 1106 | document_files: List[(String, String)], | 
| 75679 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1107 | export_files: List[(String, Int, List[String])], | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1108 | export_classpath: List[String] | 
| 75393 | 1109 |   ) extends Entry {
 | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1110 | def theories_no_position: List[(List[Options.Spec], List[(String, Boolean)])] = | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1111 |       theories.map({ case (a, b) => (a, b.map({ case ((c, _), d) => (c, d) })) })
 | 
| 72666 
945cee776e79
proper meta_digest: avoid non-portable position information;
 wenzelm parents: 
72653diff
changeset | 1112 | def document_theories_no_position: List[String] = | 
| 
945cee776e79
proper meta_digest: avoid non-portable position information;
 wenzelm parents: 
72653diff
changeset | 1113 | document_theories.map(_._1) | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1114 | } | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1115 | |
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1116 |   object Chapter_Defs {
 | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1117 | val empty: Chapter_Defs = new Chapter_Defs(Nil) | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1118 | } | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1119 | |
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1120 |   class Chapter_Defs private(rev_list: List[Chapter_Def]) {
 | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1121 | def list: List[Chapter_Def] = rev_list.reverse | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1122 | |
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1123 | override def toString: String = | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1124 |       list.map(_.name).mkString("Chapter_Defs(", ", ", ")")
 | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1125 | |
| 75996 | 1126 | def get(chapter: String): Option[Chapter_Def] = | 
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1127 | rev_list.find(_.name == chapter) | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1128 | |
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1129 | def apply(chapter: String): Chapter_Def = | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1130 | get(chapter) getOrElse Chapter_Def.empty(chapter) | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1131 | |
| 75996 | 1132 | def + (entry: Chapter_Def): Chapter_Defs = | 
| 75997 | 1133 |       get(entry.name) match {
 | 
| 1134 | case None => new Chapter_Defs(entry :: rev_list) | |
| 1135 | case Some(old_entry) => | |
| 1136 |           error("Duplicate chapter definition " + quote(entry.name) +
 | |
| 1137 | Position.here(old_entry.pos) + Position.here(entry.pos)) | |
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1138 | } | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1139 | } | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1140 | |
| 75405 | 1141 |   private object Parsers extends Options.Parsers {
 | 
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1142 | private val groups: Parser[List[String]] = | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1143 |       ($$$("(") ~! (rep1(name) <~ $$$(")")) ^^ { case _ ~ x => x }) | success(Nil)
 | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1144 | |
| 75998 | 1145 | private val description: Parser[String] = | 
| 1146 |       ($$$(DESCRIPTION) ~! text ^^ { case _ ~ x => x }) | success("")
 | |
| 1147 | ||
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1148 | private val chapter_def: Parser[Chapter_Def] = | 
| 76005 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1149 | command(CHAPTER_DEFINITION) ~! (position(chapter_name) ~ groups ~ description) ^^ | 
| 
a9bbf075f431
include groups from 'chapter_definition' in session info, based on the state of chapter_defs after processing all ROOT files (thus the declaration order does not matter);
 wenzelm parents: 
76002diff
changeset | 1150 |         { case _ ~ ((a, pos) ~ b ~ c) => Chapter_Def(pos, a, b, c) }
 | 
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1151 | |
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1152 | private val chapter_entry: Parser[Chapter_Entry] = | 
| 75984 | 1153 |       command(CHAPTER) ~! chapter_name ^^ { case _ ~ a => Chapter_Entry(a) }
 | 
| 62631 | 1154 | |
| 75393 | 1155 |     private val session_entry: Parser[Session_Entry] = {
 | 
| 78407 
b262ecc98319
more operations for independent "inline" options;
 wenzelm parents: 
78178diff
changeset | 1156 |       val options = $$$("[") ~> rep1sep(option_spec, $$$(",")) <~ $$$("]")
 | 
| 62631 | 1157 | |
| 65374 | 1158 | val theory_entry = | 
| 70668 | 1159 |         position(theory_name) ~ opt_keyword(GLOBAL) ^^ { case x ~ y => (x, y) }
 | 
| 65374 | 1160 | |
| 62631 | 1161 | val theories = | 
| 65374 | 1162 | $$$(THEORIES) ~! | 
| 66970 
13857f49d215
clarified ROOT syntax: 'sessions' and 'theories' are optional, but need to be non-empty;
 wenzelm parents: 
66969diff
changeset | 1163 | ((options | success(Nil)) ~ rep1(theory_entry)) ^^ | 
| 65374 | 1164 |           { case _ ~ (x ~ y) => (x, y) }
 | 
| 62631 | 1165 | |
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1166 | val document_theories = | 
| 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1167 |         $$$(DOCUMENT_THEORIES) ~! rep1(position(name)) ^^ { case _ ~ x => x }
 | 
| 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1168 | |
| 62631 | 1169 | val document_files = | 
| 76614 | 1170 |         $$$(DOCUMENT_FILES) ~! (in_path_parens("document") ~ rep1(path)) ^^
 | 
| 1171 |           { case _ ~ (x ~ y) => y.map((x, _)) }
 | |
| 68292 | 1172 | |
| 69671 | 1173 |       val prune = $$$("[") ~! (nat ~ $$$("]")) ^^ { case _ ~ (x ~ _) => x } | success(0)
 | 
| 1174 | ||
| 68292 | 1175 | val export_files = | 
| 76614 | 1176 |         $$$(EXPORT_FILES) ~! (in_path_parens("export") ~ prune ~ rep1(embedded)) ^^
 | 
| 69671 | 1177 |           { case _ ~ (x ~ y ~ z) => (x, y, z) }
 | 
| 62631 | 1178 | |
| 75679 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1179 | val export_classpath = | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1180 |         $$$(EXPORT_CLASSPATH) ~! (rep1(embedded) | success(List("*:classpath/*.jar"))) ^^
 | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1181 |           { case _ ~ x => x }
 | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1182 | |
| 62631 | 1183 | command(SESSION) ~! | 
| 76614 | 1184 |         (position(session_name) ~ groups ~ in_path(".") ~
 | 
| 62631 | 1185 |           ($$$("=") ~!
 | 
| 75998 | 1186 |             (opt(session_name ~! $$$("+") ^^ { case x ~ _ => x }) ~ description ~
 | 
| 62631 | 1187 |               (($$$(OPTIONS) ~! options ^^ { case _ ~ x => x }) | success(Nil)) ~
 | 
| 66970 
13857f49d215
clarified ROOT syntax: 'sessions' and 'theories' are optional, but need to be non-empty;
 wenzelm parents: 
66969diff
changeset | 1188 |               (($$$(SESSIONS) ~! rep1(session_name)  ^^ { case _ ~ x => x }) | success(Nil)) ~
 | 
| 70681 | 1189 |               (($$$(DIRECTORIES) ~! rep1(path) ^^ { case _ ~ x => x }) | success(Nil)) ~
 | 
| 66970 
13857f49d215
clarified ROOT syntax: 'sessions' and 'theories' are optional, but need to be non-empty;
 wenzelm parents: 
66969diff
changeset | 1190 | rep(theories) ~ | 
| 72600 
2fa4f25d9d07
official support for document theories from other sessions;
 wenzelm parents: 
72574diff
changeset | 1191 | (opt(document_theories) ^^ (x => x.getOrElse(Nil))) ~ | 
| 68292 | 1192 | (rep(document_files) ^^ (x => x.flatten)) ~ | 
| 75679 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1193 | rep(export_files) ~ | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1194 | opt(export_classpath)))) ^^ | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1195 |         { case _ ~ ((a, pos) ~ b ~ c ~ (_ ~ (d ~ e ~ f ~ g ~ h ~ i ~ j ~ k ~ l ~ m))) =>
 | 
| 
aa89255b704c
support for classpath artifacts within session structure:
 wenzelm parents: 
75672diff
changeset | 1196 | Session_Entry(pos, a, b, c, d, e, f, g, h, i, j, k, l, m.getOrElse(Nil)) } | 
| 62631 | 1197 | } | 
| 1198 | ||
| 75393 | 1199 |     def parse_root(path: Path): List[Entry] = {
 | 
| 66764 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1200 | val toks = Token.explode(root_syntax.keywords, File.read(path)) | 
| 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1201 | val start = Token.Pos.file(path.implode) | 
| 75986 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1202 | val parser: Parser[Entry] = chapter_def | chapter_entry | session_entry | 
| 
27d98da31985
support 'chapter_definition' with description for presentation purposes;
 wenzelm parents: 
75984diff
changeset | 1203 |       parse_all(rep(parser), Token.reader(toks, start)) match {
 | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1204 | case Success(result, _) => result | 
| 66764 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1205 | case bad => error(bad.toString) | 
| 62631 | 1206 | } | 
| 1207 | } | |
| 1208 | } | |
| 1209 | ||
| 75405 | 1210 | def parse_root(path: Path): List[Entry] = Parsers.parse_root(path) | 
| 66819 | 1211 | |
| 1212 | def parse_root_entries(path: Path): List[Session_Entry] = | |
| 76789 | 1213 | Parsers.parse_root(path).flatMap(Library.as_subclass(classOf[Session_Entry])) | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1214 | |
| 75393 | 1215 |   def parse_roots(roots: Path): List[String] = {
 | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1216 |     for {
 | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1217 | line <- split_lines(File.read(roots)) | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1218 |       if !(line == "" || line.startsWith("#"))
 | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1219 | } yield line | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1220 | } | 
| 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1221 | |
| 62631 | 1222 | |
| 62635 | 1223 | /* load sessions from certain directories */ | 
| 62631 | 1224 | |
| 77760 | 1225 | def is_session_dir(dir: Path, ssh: SSH.System = SSH.Local): Boolean = | 
| 1226 | ssh.is_file(dir + ROOT) || ssh.is_file(dir + ROOTS) | |
| 62631 | 1227 | |
| 75297 
fc4d07587695
more robust errors -- on foreground process instead of background server;
 wenzelm parents: 
74812diff
changeset | 1228 | def check_session_dir(dir: Path): Path = | 
| 80194 
79655411a32d
clarified signature (see also be0ab4b94c62 and c41791ad75c3);
 wenzelm parents: 
80128diff
changeset | 1229 | if (is_session_dir(dir)) dir.absolute | 
| 76549 | 1230 |     else {
 | 
| 1231 |       error("Bad session root directory: " + dir.expand.toString +
 | |
| 1232 | "\n (missing \"ROOT\" or \"ROOTS\")") | |
| 1233 | } | |
| 62631 | 1234 | |
| 75393 | 1235 |   def directories(dirs: List[Path], select_dirs: List[Path]): List[(Boolean, Path)] = {
 | 
| 77760 | 1236 | val default_dirs = Components.directories().filter(is_session_dir(_)) | 
| 68746 
f95e2f145ea5
canonical session directories in correspondence to Known.files;
 wenzelm parents: 
68734diff
changeset | 1237 |     for { (select, dir) <- (default_dirs ::: dirs).map((false, _)) ::: select_dirs.map((true, _)) }
 | 
| 
f95e2f145ea5
canonical session directories in correspondence to Known.files;
 wenzelm parents: 
68734diff
changeset | 1238 | yield (select, dir.canonical) | 
| 65561 | 1239 | } | 
| 1240 | ||
| 76629 | 1241 |   sealed case class Root_File(path: Path, select: Boolean) {
 | 
| 1242 | val key: JFile = path.canonical_file | |
| 1243 | def dir: Path = path.dir | |
| 1244 | ||
| 1245 | lazy val entries: List[Entry] = Parsers.parse_root(path) | |
| 1246 | } | |
| 1247 | ||
| 1248 | def load_root_files( | |
| 66968 
9991671c98aa
allow to augment session context via explicit session infos;
 wenzelm parents: 
66967diff
changeset | 1249 | dirs: List[Path] = Nil, | 
| 76629 | 1250 | select_dirs: List[Path] = Nil | 
| 1251 |   ): List[Root_File] = {
 | |
| 1252 | def load_dir(select: Boolean, dir: Path): List[Root_File] = | |
| 62635 | 1253 | load_root(select, dir) ::: load_roots(select, dir) | 
| 62631 | 1254 | |
| 76629 | 1255 |     def load_root(select: Boolean, dir: Path): List[Root_File] = {
 | 
| 66764 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1256 | val root = dir + ROOT | 
| 76629 | 1257 | if (root.is_file) List(Root_File(root, select)) else Nil | 
| 66764 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1258 | } | 
| 62631 | 1259 | |
| 76629 | 1260 |     def load_roots(select: Boolean, dir: Path): List[Root_File] = {
 | 
| 62631 | 1261 | val roots = dir + ROOTS | 
| 1262 |       if (roots.is_file) {
 | |
| 1263 |         for {
 | |
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1264 | entry <- parse_roots(roots) | 
| 62631 | 1265 | dir1 = | 
| 66818 
5bc903a60932
clarified signature: public access to ROOT file syntax;
 wenzelm parents: 
66780diff
changeset | 1266 |             try { check_session_dir(dir + Path.explode(entry)) }
 | 
| 62631 | 1267 |             catch {
 | 
| 1268 | case ERROR(msg) => | |
| 1269 | error(msg + "\nThe error(s) above occurred in session catalog " + roots.toString) | |
| 1270 | } | |
| 66764 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1271 | res <- load_dir(select, dir1) | 
| 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1272 | } yield res | 
| 62631 | 1273 | } | 
| 1274 | else Nil | |
| 1275 | } | |
| 1276 | ||
| 76629 | 1277 | val raw_roots: List[Root_File] = | 
| 62631 | 1278 |       for {
 | 
| 65561 | 1279 | (select, dir) <- directories(dirs, select_dirs) | 
| 76629 | 1280 | root <- load_dir(select, check_session_dir(dir)) | 
| 1281 | } yield root | |
| 66764 
006deaf5c3dc
process ROOT files only once, which allows duplicate (or overlapping) session root directories;
 wenzelm parents: 
66759diff
changeset | 1282 | |
| 76629 | 1283 | var next_root = 0 | 
| 1284 | var seen_roots = Map.empty[JFile, (Root_File, Int)] | |
| 1285 |     for (root <- raw_roots) {
 | |
| 1286 |       seen_roots.get(root.key) match {
 | |
| 1287 | case None => | |
| 1288 | seen_roots += (root.key -> (root, next_root)) | |
| 1289 | next_root += 1 | |
| 76633 
95c258c0753c
clarified order: accumulate strictly from left to right;
 wenzelm parents: 
76632diff
changeset | 1290 | case Some((root0, next0)) => | 
| 76634 | 1291 | val root1 = root0.copy(select = root0.select || root.select) | 
| 1292 | seen_roots += (root0.key -> (root1, next0)) | |
| 76629 | 1293 | } | 
| 1294 | } | |
| 1295 | seen_roots.valuesIterator.toList.sortBy(_._2).map(_._1) | |
| 1296 | } | |
| 75995 | 1297 | |
| 62632 | 1298 | |
| 71808 | 1299 | /* Isabelle tool wrapper */ | 
| 1300 | ||
| 72763 | 1301 |   val isabelle_tool = Isabelle_Tool("sessions", "explore structure of Isabelle sessions",
 | 
| 75394 | 1302 | Scala_Project.here, | 
| 1303 |     { args =>
 | |
| 1304 | var base_sessions: List[String] = Nil | |
| 1305 | var select_dirs: List[Path] = Nil | |
| 1306 | var requirements = false | |
| 1307 | var exclude_session_groups: List[String] = Nil | |
| 1308 | var all_sessions = false | |
| 76107 | 1309 | var build_graph = false | 
| 75394 | 1310 | var dirs: List[Path] = Nil | 
| 1311 | var session_groups: List[String] = Nil | |
| 1312 | var exclude_sessions: List[String] = Nil | |
| 71808 | 1313 | |
| 75394 | 1314 |       val getopts = Getopts("""
 | 
| 71808 | 1315 | Usage: isabelle sessions [OPTIONS] [SESSIONS ...] | 
| 1316 | ||
| 1317 | Options are: | |
| 1318 | -B NAME include session NAME and all descendants | |
| 1319 | -D DIR include session directory and select its sessions | |
| 1320 | -R refer to requirements of selected sessions | |
| 1321 | -X NAME exclude sessions from group NAME and all descendants | |
| 1322 | -a select all sessions | |
| 76107 | 1323 | -b follow session build dependencies (default: source imports) | 
| 71808 | 1324 | -d DIR include session directory | 
| 1325 | -g NAME select session group NAME | |
| 1326 | -x NAME exclude session NAME and all descendants | |
| 1327 | ||
| 1328 | Explore the structure of Isabelle sessions and print result names in | |
| 1329 | topological order (on stdout). | |
| 1330 | """, | |
| 75394 | 1331 | "B:" -> (arg => base_sessions = base_sessions ::: List(arg)), | 
| 1332 | "D:" -> (arg => select_dirs = select_dirs ::: List(Path.explode(arg))), | |
| 1333 | "R" -> (_ => requirements = true), | |
| 1334 | "X:" -> (arg => exclude_session_groups = exclude_session_groups ::: List(arg)), | |
| 1335 | "a" -> (_ => all_sessions = true), | |
| 76107 | 1336 | "b" -> (_ => build_graph = true), | 
| 75394 | 1337 | "d:" -> (arg => dirs = dirs ::: List(Path.explode(arg))), | 
| 1338 | "g:" -> (arg => session_groups = session_groups ::: List(arg)), | |
| 1339 | "x:" -> (arg => exclude_sessions = exclude_sessions ::: List(arg))) | |
| 71808 | 1340 | |
| 75394 | 1341 | val sessions = getopts(args) | 
| 71808 | 1342 | |
| 75394 | 1343 | val options = Options.init() | 
| 71808 | 1344 | |
| 75394 | 1345 | val selection = | 
| 1346 | Selection(requirements = requirements, all_sessions = all_sessions, base_sessions = base_sessions, | |
| 1347 | exclude_session_groups = exclude_session_groups, exclude_sessions = exclude_sessions, | |
| 1348 | session_groups = session_groups, sessions = sessions) | |
| 1349 | val sessions_structure = | |
| 1350 | load_structure(options, dirs = dirs, select_dirs = select_dirs).selection(selection) | |
| 71808 | 1351 | |
| 76107 | 1352 | val order = | 
| 1353 | if (build_graph) sessions_structure.build_topological_order | |
| 1354 | else sessions_structure.imports_topological_order | |
| 1355 | for (name <- order) Output.writeln(name, stdout = true) | |
| 75394 | 1356 | }) | 
| 62631 | 1357 | } |