Home | History | Annotate | Download | only in depstest
      1 #! /usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 #
      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.
      8 #
      9 # file name: dependencies.py
     10 #
     11 # created on: 2011may26
     12 
     13 """Reader module for dependency data for the ICU dependency tester.
     14 
     15 Reads dependencies.txt and makes the data available.
     16 
     17 Attributes:
     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)
     28 """
     29 __author__ = "Markus W. Scherer"
     30 
     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.
     35 
     36 import sys
     37 
     38 files = set()
     39 items = {}
     40 libraries = set()
     41 file_to_item = {}
     42 
     43 _line_number = 0
     44 _groups_to_be_defined = set()
     45 
     46 def _CheckLibraryName(name):
     47   global _line_number
     48   if not 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))
     52 
     53 def _CheckGroupName(name):
     54   global _line_number
     55   if not 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))
     59 
     60 def _CheckFileName(name):
     61   global _line_number
     62   if "/" in name or not name.endswith(".o"):
     63     sys.exit("Error:%d: invalid file name %s"  % (_line_number, name))
     64 
     65 def _RemoveComment(line):
     66   global _line_number
     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.
     71 
     72 def _ReadLine(f):
     73   while True:
     74     line = _RemoveComment(f.next())
     75     if line: return line
     76 
     77 def _ReadFiles(deps_file, item, library_name):
     78   global files
     79   item_files = item.get("files")
     80   while True:
     81     line = _ReadLine(deps_file)
     82     if not line: continue
     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))
     90       files.add(file_name)
     91       item_files.add(file_name)
     92       file_to_item[file_name] = item["name"]
     93 
     94 def _IsLibrary(item): return item and item["type"] == "library"
     95 
     96 def _IsLibraryGroup(item): return item and "library" in item
     97 
     98 def _ReadDeps(deps_file, item, library_name):
     99   global items, _line_number, _groups_to_be_defined
    100   item_deps = item.get("deps")
    101   while True:
    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():
    107       _CheckGroupName(dep)
    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))
    112       if dep_item == None:
    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)
    117       item_deps.add(dep)
    118 
    119 def _AddSystemSymbol(item, symbol):
    120   exports = item.get("system_symbols")
    121   if exports == None: exports = item["system_symbols"] = set()
    122   exports.add(symbol)
    123 
    124 def _ReadSystemSymbols(deps_file, item):
    125   global _line_number
    126   while True:
    127     line = _ReadLine(deps_file)
    128     if not line: continue
    129     if not line.startswith("    "): return line
    130     line = line.lstrip()
    131     if '"' in line:
    132       # One double-quote-enclosed symbol on the line, allows spaces in a symbol name.
    133       symbol = line[1:-1]
    134       if line.startswith('"') and line.endswith('"') and '"' not in symbol:
    135         _AddSystemSymbol(item, symbol)
    136       else:
    137         sys.exit("Error:%d: invalid quoted symbol name %s" % (_line_number, line))
    138     else:
    139       # One or more space-separate symbols.
    140       for symbol in line.split(): _AddSystemSymbol(item, symbol)
    141 
    142 def Load():
    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")
    146   try:
    147     line = None
    148     current_type = None
    149     while True:
    150       while not line: line = _RemoveComment(deps_file.next())
    151 
    152       if line.startswith("library: "):
    153         current_type = "library"
    154         name = line[9:].lstrip()
    155         _CheckLibraryName(name)
    156         if name in items:
    157           sys.exit("Error:%d: library definition using duplicate name %s" % (_line_number, name))
    158         libraries.add(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)
    171         item = items[name]
    172         item["name"] = name
    173         library_name = item.get("library")
    174         if library_name:
    175           line = _ReadFiles(deps_file, item, library_name)
    176         else:
    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":
    182           item = items[name]
    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)
    187         else:
    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)
    195       else:
    196         sys.exit("Syntax error:%d: %s" % (_line_number, line))
    197   except StopIteration:
    198     pass
    199   if _groups_to_be_defined:
    200     sys.exit("Error: some groups mentioned in dependencies are undefined: %s" % _groups_to_be_defined)
    201