src/Pure/Admin/afp.scala
changeset 69973 a3e3be17dca5
parent 69787 60b5a4731695
child 69974 916726680a66
equal deleted inserted replaced
69972:5e82015fa879 69973:a3e3be17dca5
    19   def groups_bulky: List[String] = List("large", "slow")
    19   def groups_bulky: List[String] = List("large", "slow")
    20 
    20 
    21   def init(options: Options, base_dir: Path = Path.explode("$AFP_BASE")): AFP =
    21   def init(options: Options, base_dir: Path = Path.explode("$AFP_BASE")): AFP =
    22     new AFP(options, base_dir)
    22     new AFP(options, base_dir)
    23 
    23 
    24   sealed case class Entry(name: String, sessions: List[String])
    24 
       
    25   /* metadata */
       
    26 
       
    27   object Metadata
       
    28   {
       
    29     private val Section = """^\[(\S+)\]\s*$""".r
       
    30     private val Property = """^(\S+)\s*=(.*)$""".r
       
    31     private val Extra_Line = """^\s+(.*)$""".r
       
    32     private val Blank_Line = """^\s*$""".r
       
    33 
       
    34     def read(metadata_file: Path): Map[String, Metadata] =
       
    35     {
       
    36       var result = Map.empty[String, Metadata]
       
    37       var section = ""
       
    38       var props = List.empty[Properties.Entry]
       
    39 
       
    40       def flush()
       
    41       {
       
    42         if (section != "") result += (section -> new Metadata(props.reverse))
       
    43         section = ""
       
    44         props = Nil
       
    45       }
       
    46 
       
    47       for ((line, i) <- split_lines(File.read(metadata_file)).zipWithIndex)
       
    48       {
       
    49         def err(msg: String): Nothing =
       
    50           error(msg + Position.here(Position.Line_File(i + 1, metadata_file.expand.implode)))
       
    51 
       
    52         line match {
       
    53           case Section(name) => flush(); section = name
       
    54           case Property(a, b) =>
       
    55             if (section == "") err("Property without a section")
       
    56             props = (a -> b.trim) :: props
       
    57           case Extra_Line(line) =>
       
    58             props match {
       
    59               case Nil => err("Extra line without a property")
       
    60               case (a, b) :: rest => props = (a, b + "\n" + line.trim) :: rest
       
    61             }
       
    62           case Blank_Line() =>
       
    63           case _ => err("Bad input")
       
    64         }
       
    65       }
       
    66 
       
    67       flush()
       
    68       result
       
    69     }
       
    70   }
       
    71 
       
    72   class Metadata private[AFP](properties: Properties.T)
       
    73   {
       
    74     override def toString: String =
       
    75       properties.map({ case (a, b) => a + "=" + b }).mkString("Metadata(", ", ", ")")
       
    76 
       
    77     def is_empty: Boolean = properties.isEmpty
       
    78   }
       
    79 
       
    80 
       
    81   /* entries */
       
    82 
       
    83   sealed case class Entry(name: String, metadata: Metadata, sessions: List[String])
    25 }
    84 }
    26 
    85 
    27 class AFP private(options: Options, val base_dir: Path)
    86 class AFP private(options: Options, val base_dir: Path)
    28 {
    87 {
    29   override def toString: String = base_dir.expand.toString
    88   override def toString: String = base_dir.expand.toString
    30 
    89 
    31   val main_dir: Path = base_dir + Path.explode("thys")
    90   val main_dir: Path = base_dir + Path.explode("thys")
    32 
    91 
    33 
    92 
    34   /* entries and sessions */
    93   /* entries with metadata and sessions */
    35 
    94 
    36   val entries: List[AFP.Entry] =
    95   val entries: List[AFP.Entry] =
    37     (for (name <- Sessions.parse_roots(main_dir + Sessions.ROOTS)) yield {
    96   {
    38       val sessions =
    97     val entry_metadata = AFP.Metadata.read(base_dir + Path.explode("metadata/metadata"))
    39         Sessions.parse_root_entries(main_dir + Path.explode(name) + Sessions.ROOT).map(_.name)
    98 
    40       AFP.Entry(name, sessions)
    99     val entries =
    41     }).sortBy(_.name)
   100       (for (name <- Sessions.parse_roots(main_dir + Sessions.ROOTS)) yield {
       
   101         val metadata =
       
   102           entry_metadata.getOrElse(name, error("Entry without metadata: " + quote(name)))
       
   103         val sessions =
       
   104           Sessions.parse_root_entries(main_dir + Path.explode(name) + Sessions.ROOT).map(_.name)
       
   105         AFP.Entry(name, metadata, sessions)
       
   106       }).sortBy(_.name)
       
   107 
       
   108     val entry_set = entries.iterator.map(_.name).toSet
       
   109     val extra_metadata =
       
   110       (for ((name, _) <- entry_metadata.iterator if !entry_set(name)) yield name).toList.sorted
       
   111     if (extra_metadata.nonEmpty) error("Meta data without entry: " + commas_quote(extra_metadata))
       
   112 
       
   113     entries
       
   114   }
    42 
   115 
    43   val sessions: List[String] = entries.flatMap(_.sessions)
   116   val sessions: List[String] = entries.flatMap(_.sessions)
    44 
   117 
    45   val sessions_structure: Sessions.Structure =
   118   val sessions_structure: Sessions.Structure =
    46     Sessions.load_structure(options, dirs = List(main_dir)).
   119     Sessions.load_structure(options, dirs = List(main_dir)).