]>
Commit | Line | Data |
---|---|---|
1 | #! /usr/bin/python | |
2 | # -*- coding: utf-8 -*- | |
3 | # | |
4 | # Copyright (C) 2011, International Business Machines | |
5 | # Corporation and others. All Rights Reserved. | |
6 | # | |
7 | # file name: dependencies.py | |
8 | # | |
9 | # created on: 2011may26 | |
10 | ||
11 | """Reader module for dependency data for the ICU dependency tester. | |
12 | ||
13 | Reads dependencies.txt and makes the data available. | |
14 | ||
15 | Attributes: | |
16 | files: Set of "library/filename.o" files mentioned in the dependencies file. | |
17 | items: Map from library or group names to item maps. | |
18 | Each item has a "type" ("library" or "group" or "system_symbols"). | |
19 | A library or group item can have an optional set of "files" (as in the files attribute). | |
20 | Each item can have an optional set of "deps" (libraries & groups). | |
21 | A group item also has a "library" name unless it is a group of system symbols. | |
22 | The one "system_symbols" item and its groups have sets of "system_symbols" | |
23 | with standard-library system symbol names. | |
24 | libraries: Set of library names mentioned in the dependencies file. | |
25 | """ | |
26 | __author__ = "Markus W. Scherer" | |
27 | ||
28 | # TODO: Support binary items. | |
29 | # .txt syntax: binary: tools/genrb | |
30 | # item contents: {"type": "binary"} with optional files & deps | |
31 | # A binary must not be used as a dependency for anything else. | |
32 | ||
33 | import sys | |
34 | ||
35 | files = set() | |
36 | items = {} | |
37 | libraries = set() | |
38 | ||
39 | _line_number = 0 | |
40 | _groups_to_be_defined = set() | |
41 | ||
42 | def _CheckLibraryName(name): | |
43 | global _line_number | |
44 | if not name: | |
45 | sys.exit("Error:%d: \"library: \" without name" % _line_number) | |
46 | if name.endswith(".o"): | |
47 | sys.exit("Error:%d: invalid library name %s" % (_line_number, name)) | |
48 | ||
49 | def _CheckGroupName(name): | |
50 | global _line_number | |
51 | if not name: | |
52 | sys.exit("Error:%d: \"group: \" without name" % _line_number) | |
53 | if "/" in name or name.endswith(".o"): | |
54 | sys.exit("Error:%d: invalid group name %s" % (_line_number, name)) | |
55 | ||
56 | def _CheckFileName(name): | |
57 | global _line_number | |
58 | if "/" in name or not name.endswith(".o"): | |
59 | sys.exit("Error:%d: invalid file name %s" % (_line_number, name)) | |
60 | ||
61 | def _RemoveComment(line): | |
62 | global _line_number | |
63 | _line_number = _line_number + 1 | |
64 | index = line.find("#") # Remove trailing comment. | |
65 | if index >= 0: line = line[:index] | |
66 | return line.rstrip() # Remove trailing newlines etc. | |
67 | ||
68 | def _ReadLine(f): | |
69 | while True: | |
70 | line = _RemoveComment(f.next()) | |
71 | if line: return line | |
72 | ||
73 | def _ReadFiles(deps_file, item, library_name): | |
74 | global files | |
75 | item_files = item.get("files") | |
76 | while True: | |
77 | line = _ReadLine(deps_file) | |
78 | if not line: continue | |
79 | if not line.startswith(" "): return line | |
80 | if item_files == None: item_files = item["files"] = set() | |
81 | for file_name in line.split(): | |
82 | _CheckFileName(file_name) | |
83 | file_name = library_name + "/" + file_name | |
84 | if file_name in files: | |
85 | sys.exit("Error:%d: file %s listed in multiple groups" % (_line_number, file_name)) | |
86 | files.add(file_name) | |
87 | item_files.add(file_name) | |
88 | ||
89 | def _IsLibrary(item): return item and item["type"] == "library" | |
90 | ||
91 | def _IsLibraryGroup(item): return item and "library" in item | |
92 | ||
93 | def _ReadDeps(deps_file, item, library_name): | |
94 | global items, _line_number, _groups_to_be_defined | |
95 | item_deps = item.get("deps") | |
96 | while True: | |
97 | line = _ReadLine(deps_file) | |
98 | if not line: continue | |
99 | if not line.startswith(" "): return line | |
100 | if item_deps == None: item_deps = item["deps"] = set() | |
101 | for dep in line.split(): | |
102 | _CheckGroupName(dep) | |
103 | dep_item = items.get(dep) | |
104 | if item["type"] == "system_symbols" and (_IsLibraryGroup(dep_item) or _IsLibrary(dep_item)): | |
105 | sys.exit(("Error:%d: system_symbols depend on previously defined " + | |
106 | "library or library group %s") % (_line_number, dep)) | |
107 | if dep_item == None: | |
108 | # Add this dependency as a new group. | |
109 | items[dep] = {"type": "group"} | |
110 | if library_name: items[dep]["library"] = library_name | |
111 | _groups_to_be_defined.add(dep) | |
112 | item_deps.add(dep) | |
113 | ||
114 | def _AddSystemSymbol(item, symbol): | |
115 | exports = item.get("system_symbols") | |
116 | if exports == None: exports = item["system_symbols"] = set() | |
117 | exports.add(symbol) | |
118 | ||
119 | def _ReadSystemSymbols(deps_file, item): | |
120 | global _line_number | |
121 | while True: | |
122 | line = _ReadLine(deps_file) | |
123 | if not line: continue | |
124 | if not line.startswith(" "): return line | |
125 | line = line.lstrip() | |
126 | if '"' in line: | |
127 | # One double-quote-enclosed symbol on the line, allows spaces in a symbol name. | |
128 | symbol = line[1:-1] | |
129 | if line.startswith('"') and line.endswith('"') and '"' not in symbol: | |
130 | _AddSystemSymbol(item, symbol) | |
131 | else: | |
132 | sys.exit("Error:%d: invalid quoted symbol name %s" % (_line_number, line)) | |
133 | else: | |
134 | # One or more space-separate symbols. | |
135 | for symbol in line.split(): _AddSystemSymbol(item, symbol) | |
136 | ||
137 | def Load(): | |
138 | """Reads "dependencies.txt" and populates the module attributes.""" | |
139 | global items, libraries, _line_number, _groups_to_be_defined | |
140 | deps_file = open("dependencies.txt") | |
141 | try: | |
142 | line = None | |
143 | current_type = None | |
144 | while True: | |
145 | while not line: line = _RemoveComment(deps_file.next()) | |
146 | ||
147 | if line.startswith("library: "): | |
148 | current_type = "library" | |
149 | name = line[9:].lstrip() | |
150 | _CheckLibraryName(name) | |
151 | if name in items: | |
152 | sys.exit("Error:%d: library definition using duplicate name %s" % (_line_number, name)) | |
153 | libraries.add(name) | |
154 | item = items[name] = {"type": "library"} | |
155 | line = _ReadFiles(deps_file, item, name) | |
156 | elif line.startswith("group: "): | |
157 | current_type = "group" | |
158 | name = line[7:].lstrip() | |
159 | _CheckGroupName(name) | |
160 | if name not in items: | |
161 | sys.exit("Error:%d: group %s defined before mentioned as a dependency" % | |
162 | (_line_number, name)) | |
163 | if name not in _groups_to_be_defined: | |
164 | sys.exit("Error:%d: group definition using duplicate name %s" % (_line_number, name)) | |
165 | _groups_to_be_defined.remove(name) | |
166 | item = items[name] | |
167 | library_name = item.get("library") | |
168 | if library_name: | |
169 | line = _ReadFiles(deps_file, item, library_name) | |
170 | else: | |
171 | line = _ReadSystemSymbols(deps_file, item) | |
172 | elif line == " deps": | |
173 | if current_type == "library": | |
174 | line = _ReadDeps(deps_file, items[name], name) | |
175 | elif current_type == "group": | |
176 | item = items[name] | |
177 | line = _ReadDeps(deps_file, item, item.get("library")) | |
178 | elif current_type == "system_symbols": | |
179 | item = items[current_type] | |
180 | line = _ReadDeps(deps_file, item, None) | |
181 | else: | |
182 | sys.exit("Error:%d: deps before any library or group" % _line_number) | |
183 | elif line == "system_symbols:": | |
184 | current_type = "system_symbols" | |
185 | if current_type in items: | |
186 | sys.exit("Error:%d: duplicate entry for system_symbols" % _line_number) | |
187 | item = items[current_type] = {"type": current_type} | |
188 | line = _ReadSystemSymbols(deps_file, item) | |
189 | else: | |
190 | sys.exit("Syntax error:%d: %s" % (_line_number, line)) | |
191 | except StopIteration: | |
192 | pass | |
193 | if _groups_to_be_defined: | |
194 | sys.exit("Error: some groups mentioned in dependencies are undefined: %s" % _groups_to_be_defined) |