Home | History | Annotate | Download | only in depstest
      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)
    195