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)). |