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