2 # -*- coding: utf-8 -*-
4 # Copyright (C) 2016 and later: Unicode, Inc. and others.
5 # License & terms of use: http://www.unicode.org/copyright.html
6 # Copyright (C) 2011-2014, International Business Machines
7 # Corporation and others. All Rights Reserved.
9 # file name: dependencies.py
11 # created on: 2011may26
13 """Reader module for dependency data for the ICU dependency tester.
15 Reads dependencies.txt and makes the data available.
18 files: Set of "library/filename.o" files mentioned in the dependencies file.
19 items: Map from library or group names to item maps.
20 Each item has a "type" ("library" or "group" or "system_symbols").
21 A library or group item can have an optional set of "files" (as in the files attribute).
22 Each item can have an optional set of "deps" (libraries & groups).
23 A group item also has a "library" name unless it is a group of system symbols.
24 The one "system_symbols" item and its groups have sets of "system_symbols"
25 with standard-library system symbol names.
26 libraries: Set of library names mentioned in the dependencies file.
27 file_to_item: Map from a symbol (ushoe.o) to library or group (shoesize)
29 __author__
= "Markus W. Scherer"
31 # TODO: Support binary items.
32 # .txt syntax: binary: tools/genrb
33 # item contents: {"type": "binary"} with optional files & deps
34 # A binary must not be used as a dependency for anything else.
44 _groups_to_be_defined
= set()
46 def _CheckLibraryName(name
):
49 sys
.exit("Error:%d: \"library: \" without name" % _line_number
)
50 if name
.endswith(".o"):
51 sys
.exit("Error:%d: invalid library name %s" % (_line_number
, name
))
53 def _CheckGroupName(name
):
56 sys
.exit("Error:%d: \"group: \" without name" % _line_number
)
57 if "/" in name
or name
.endswith(".o"):
58 sys
.exit("Error:%d: invalid group name %s" % (_line_number
, name
))
60 def _CheckFileName(name
):
62 if "/" in name
or not name
.endswith(".o"):
63 sys
.exit("Error:%d: invalid file name %s" % (_line_number
, name
))
65 def _RemoveComment(line
):
67 _line_number
= _line_number
+ 1
68 index
= line
.find("#") # Remove trailing comment.
69 if index
>= 0: line
= line
[:index
]
70 return line
.rstrip() # Remove trailing newlines etc.
74 line
= _RemoveComment(f
.next())
77 def _ReadFiles(deps_file
, item
, library_name
):
79 item_files
= item
.get("files")
81 line
= _ReadLine(deps_file
)
83 if not line
.startswith(" "): return line
84 if item_files
== None: item_files
= item
["files"] = set()
85 for file_name
in line
.split():
86 _CheckFileName(file_name
)
87 file_name
= library_name
+ "/" + file_name
88 if file_name
in files
:
89 sys
.exit("Error:%d: file %s listed in multiple groups" % (_line_number
, file_name
))
91 item_files
.add(file_name
)
92 file_to_item
[file_name
] = item
["name"]
94 def _IsLibrary(item
): return item
and item
["type"] == "library"
96 def _IsLibraryGroup(item
): return item
and "library" in item
98 def _ReadDeps(deps_file
, item
, library_name
):
99 global items
, _line_number
, _groups_to_be_defined
100 item_deps
= item
.get("deps")
102 line
= _ReadLine(deps_file
)
103 if not line
: continue
104 if not line
.startswith(" "): return line
105 if item_deps
== None: item_deps
= item
["deps"] = set()
106 for dep
in line
.split():
108 dep_item
= items
.get(dep
)
109 if item
["type"] == "system_symbols" and (_IsLibraryGroup(dep_item
) or _IsLibrary(dep_item
)):
110 sys
.exit(("Error:%d: system_symbols depend on previously defined " +
111 "library or library group %s") % (_line_number
, dep
))
113 # Add this dependency as a new group.
114 items
[dep
] = {"type": "group"}
115 if library_name
: items
[dep
]["library"] = library_name
116 _groups_to_be_defined
.add(dep
)
119 def _AddSystemSymbol(item
, symbol
):
120 exports
= item
.get("system_symbols")
121 if exports
== None: exports
= item
["system_symbols"] = set()
124 def _ReadSystemSymbols(deps_file
, item
):
127 line
= _ReadLine(deps_file
)
128 if not line
: continue
129 if not line
.startswith(" "): return line
132 # One double-quote-enclosed symbol on the line, allows spaces in a symbol name.
134 if line
.startswith('"') and line
.endswith('"') and '"' not in symbol
:
135 _AddSystemSymbol(item
, symbol
)
137 sys
.exit("Error:%d: invalid quoted symbol name %s" % (_line_number
, line
))
139 # One or more space-separate symbols.
140 for symbol
in line
.split(): _AddSystemSymbol(item
, symbol
)
143 """Reads "dependencies.txt" and populates the module attributes."""
144 global items
, libraries
, _line_number
, _groups_to_be_defined
145 deps_file
= open("dependencies.txt")
150 while not line
: line
= _RemoveComment(deps_file
.next())
152 if line
.startswith("library: "):
153 current_type
= "library"
154 name
= line
[9:].lstrip()
155 _CheckLibraryName(name
)
157 sys
.exit("Error:%d: library definition using duplicate name %s" % (_line_number
, name
))
159 item
= items
[name
] = {"type": "library", "name": name}
160 line
= _ReadFiles(deps_file
, item
, name
)
161 elif line
.startswith("group: "):
162 current_type
= "group"
163 name
= line
[7:].lstrip()
164 _CheckGroupName(name
)
165 if name
not in items
:
166 sys
.exit("Error:%d: group %s defined before mentioned as a dependency" %
167 (_line_number
, name
))
168 if name
not in _groups_to_be_defined
:
169 sys
.exit("Error:%d: group definition using duplicate name %s" % (_line_number
, name
))
170 _groups_to_be_defined
.remove(name
)
173 library_name
= item
.get("library")
175 line
= _ReadFiles(deps_file
, item
, library_name
)
177 line
= _ReadSystemSymbols(deps_file
, item
)
178 elif line
== " deps":
179 if current_type
== "library":
180 line
= _ReadDeps(deps_file
, items
[name
], name
)
181 elif current_type
== "group":
183 line
= _ReadDeps(deps_file
, item
, item
.get("library"))
184 elif current_type
== "system_symbols":
185 item
= items
[current_type
]
186 line
= _ReadDeps(deps_file
, item
, None)
188 sys
.exit("Error:%d: deps before any library or group" % _line_number
)
189 elif line
== "system_symbols:":
190 current_type
= "system_symbols"
191 if current_type
in items
:
192 sys
.exit("Error:%d: duplicate entry for system_symbols" % _line_number
)
193 item
= items
[current_type
] = {"type": current_type, "name": current_type}
194 line
= _ReadSystemSymbols(deps_file
, item
)
196 sys
.exit("Syntax error:%d: %s" % (_line_number
, line
))
197 except StopIteration:
199 if _groups_to_be_defined
:
200 sys
.exit("Error: some groups mentioned in dependencies are undefined: %s" % _groups_to_be_defined
)