summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kyoshida@novell.com>2011-07-25 22:41:01 -0400
committerKohei Yoshida <kyoshida@novell.com>2011-07-25 22:41:47 -0400
commit20d3758189a41abdb88ca463f4ad755b547f2027 (patch)
tree613343e57eedf692183a51c003d7e4a64d36ac8b
parent183e9062e423ea2289645295cc5c48c3618ad348 (diff)
Build analysis scripts moved to contrib/dev-tools.
-rwxr-xr-xscratch/build-analysis-tools/check-deps.py387
-rwxr-xr-xscratch/build-analysis-tools/parse-scp2.py855
2 files changed, 0 insertions, 1242 deletions
diff --git a/scratch/build-analysis-tools/check-deps.py b/scratch/build-analysis-tools/check-deps.py
deleted file mode 100755
index c4256d60e..000000000
--- a/scratch/build-analysis-tools/check-deps.py
+++ /dev/null
@@ -1,387 +0,0 @@
-#!/usr/bin/env python
-########################################################################
-#
-# Copyright (c) 2010 Kohei Yoshida
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation
-# files (the "Software"), to deal in the Software without
-# restriction, including without limitation the rights to use,
-# copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following
-# conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-#
-########################################################################
-
-import sys, os, os.path, optparse, subprocess
-
-class ParseError(Exception): pass
-
-class SingleModeError(Exception): pass
-
-class ViewerError(Exception): pass
-
-arg_desc = "module1 module2 ..."
-
-desc = """
-Execute this script at the root directory of your OOo build tree. It parses
-all build.lst files found in the modules and outputs module dependency data
-in the dot compatible format.
-
-When no arguments are given, it prints dependencies of all discovered
-modules. When module names are given as arguments, it only traces
-dependencies of those modules.
-
-Sometimes modules are referenced in the build.lst but are absent from the
-source tree. Those missing modules are displayed red in the dependency graph."""
-
-err_missing_modules = """
-The following modules are mentioned but not present in the source tree:"""
-
-class Module(object):
-
- def __init__ (self, name):
- self.name = name
- self.deps = {} # dependents
- self.precs = {} # precedents
-
-# Store all unique dependency set, with no duplicates.
-class DependSet(object):
-
- def __init__ (self):
- self.modules = {}
-
- def insert_depend (self, prec, dep):
- if not self.modules.has_key(prec):
- self.modules[prec] = {}
- if dep != None:
- self.modules[prec][dep] = True
-
-class DepsCheker(object):
-
- def __init__ (self):
- self.modules = {} # all mentioned modules, whether present or not.
- self.modules_present = {} # modules actually present in the source tree.
- self.modules_used = {} # modules displayed in the graph.
- self.selected = [] # selected modules from the command line args.
-
- self.modules_missing = None
-
- def __normalize_name (self, name):
- # Replace prohibited characters with someone sane.
- name = name.replace('-', '_')
- return name
-
- def __insert_depend (self, mod, dep):
-
- # precedent to dependent
- if not self.modules.has_key(mod):
- self.modules[mod] = Module(mod)
- obj = self.modules[mod]
- obj.deps[dep] = True
-
- # dependent to precedent
- if not self.modules.has_key(dep):
- self.modules[dep] = Module(dep)
- obj = self.modules[dep]
- obj.precs[mod] = True
-
- def __parse_build_lst (self, build_lst):
-
- # Read only the first line
- file = open(build_lst, 'r')
- while True:
- line = file.readline().strip()
- if line[0] != '#':
- break
- file.close()
-
- words = line.split()
- n = len(words)
-
- # Check line format to make sure it's formatted as expected.
- if n < 4:
- raise ParseError()
- if words[2] != ':' and words[2] != '::':
- raise ParseError()
- if words[-1] != 'NULL':
- raise ParseError()
-
- mod_name = self.__normalize_name(words[1])
- depends = words[3:]
- for dep in depends:
- if dep == 'NULL':
- break
-
- names = dep.split(':')
- if len(names) > 2:
- raise ParseError()
- elif len(names) == 2:
- dep = names[1]
-
- dep = self.__normalize_name(dep)
- self.__insert_depend(mod_name, dep)
-
- def run (self, selected):
-
- # modules we want to print dependency on.
- self.selected = selected
-
- # Find all build.lst files.
- for mod in os.listdir(os.getcwd()):
- if not os.path.isdir(mod):
- # not a directory
- continue
-
- build_lst = mod + '/prj/build.lst'
- if not os.path.isfile(build_lst):
- # no build.lst found
- continue
-
- self.modules_present[self.__normalize_name(mod)] = True
- self.__parse_build_lst(build_lst)
-
- def __build_depset_all (self):
- self.dep_set = DependSet() # reset
- if len(self.selected) == 0:
- mods = self.modules.keys()
- for mod in mods:
- deps = self.modules[mod].deps.keys()
- for dep in deps:
- self.dep_set.insert_depend(mod, dep)
- else:
- # determine involved modules.
- self.__processed_mods = {}
- for selected in self.selected:
- if not self.modules.has_key(selected):
- raise ParseError()
-
- if len(self.modules[selected].deps) > 0:
- self.__trace_deps(self.modules[selected])
-
- def __build_depset_single (self, mods):
- self.dep_set = DependSet() # reset
- for mod in mods:
-
- if not self.modules.has_key(mod):
- continue
-
- obj = self.modules[mod]
- if len(obj.precs) == 0 and len(obj.deps) == 0:
- # No dependencies. Just print the module.
- self.dep_set.insert_depend(mod, None)
- continue
-
- for prec in obj.precs.keys():
- self.dep_set.insert_depend(prec, obj.name)
- for dep in obj.deps.keys():
- self.dep_set.insert_depend(obj.name, dep)
-
- def print_dot_all (self):
- self.__build_depset_all()
- s = "digraph modules {\n"
- s += self.__print_dot_depset()
- s += self.__print_dot_selected()
- s += self.__print_dot_missing_modules()
- s += "}\n"
- return s
-
- def print_dot_single (self, mods):
- self.__build_depset_single(mods)
- s = "digraph modules {\n"
- s += self.__print_dot_depset()
- s += self.__print_dot_selected()
- s += self.__print_dot_missing_modules()
- s += "}\n"
- return s
-
- def print_flat_all (self):
- self.__build_depset_all()
- return self.__print_flat_depset()
-
- def print_flat_single (self, mods):
- self.__build_depset_single(mods)
- return self.__print_flat_depset()
-
- def __calc_missing_modules (self):
- if self.modules_missing != None:
- # already calculated.
- return
-
- present = self.modules_present.keys()
- self.modules_missing = {}
- for mod in self.modules.keys():
- if not self.modules_present.has_key(mod):
- self.modules_missing[mod] = True
-
- def print_missing_modules (self):
- self.__calc_missing_modules()
-
- if len(self.modules_missing) == 0:
- return
-
- sys.stderr.write(err_missing_modules + "\n")
- keys = self.modules_missing.keys()
- keys.sort()
- for mod in keys:
- sys.stderr.write(" " + mod + "\n")
-
- def __trace_deps (self, obj):
- if self.__processed_mods.has_key(obj.name):
- return
-
- self.__processed_mods[obj.name] = True
-
- for dep_name in obj.deps.keys():
- if not self.modules.has_key(dep_name):
- raise ParseError()
- self.dep_set.insert_depend(obj.name, dep_name)
- self.__trace_deps(self.modules[dep_name])
-
- def __print_flat_depset (self):
- s = ''
- mods = self.dep_set.modules.keys()
- mods.sort()
- for mod in mods:
- deps = self.dep_set.modules[mod].keys()
- if len(deps) == 0:
- # this module has no dependency.
- s += "%s\n"%mod
- else:
- deps.sort()
- for dep in deps:
- s += "%s:%s\n"%(mod, dep)
- return s
-
- def __print_dot_depset (self):
- s = ''
- mods = self.dep_set.modules.keys()
- for mod in mods:
- deps = self.dep_set.modules[mod].keys()
- if len(deps) == 0:
- # this module has no dependency.
- s += self.__print_dot_dep_line(mod, None)
- else:
- for dep in deps:
- s += self.__print_dot_dep_line(mod, dep)
- return s
-
- def __print_dot_selected (self):
- s = ''
- for mod in self.selected:
- if not self.modules_used.has_key(mod):
- continue
- s += " %s [color=lightblue,style=filled];\n"%mod
- return s
-
-
- def __print_dot_missing_modules (self):
- self.__calc_missing_modules()
- s = ''
- for mod in self.modules_missing.keys():
- if not self.modules_used.has_key(mod):
- continue
- s += " %s [color=red,style=filled];\n"%mod
-
- return s
-
-
- def __print_dot_dep_line (self, prec, dep):
- if prec == None:
- raise ParseError()
-
- self.modules_used[prec] = True
- if dep == None:
- # this module has no dependency. I still need to mention the module name.
- return " %s;\n"%prec
- self.modules_used[dep] = True
- return " %s -> %s;\n"%(prec, dep)
-
-def exec_exists (cmd):
- retcode = subprocess.call("which %s >/dev/null 2>/dev/null"%cmd, shell=True)
- return retcode == 0
-
-def error (msg):
- sys.stderr.write(msg + "\n")
- sys.exit(1)
-
-def launch_viewer (code):
- tmpfile = '/tmp/check-deps.tmp'
- tmpimage = '/tmp/check-deps-image.png'
- file = open(tmpfile, 'w')
- file.write(code)
- file.close()
- retcode = subprocess.call("dot -Tpng %s -o %s"%(tmpfile, tmpimage), shell=True)
- if retcode != 0:
- raise ViewerError()
-
- retcode = subprocess.call("eog %s"%tmpimage, shell=True)
- if retcode != 0:
- raise ViewerError()
-
-
-if __name__ == '__main__':
-
- # Process commnad line arguments.
- parser = optparse.OptionParser()
- parser.usage += " " + arg_desc + "\n" + desc
- parser.add_option("-m", "--outout-mode", dest="output_mode", default="dot", metavar="MODE",
- help="Specify output format mode. Supported modes are 'dot' and 'flat'.")
- parser.add_option("-s", "--single", action="store_true", dest="single", default=False,
- help="Print only immediate dependencies of specified modules.")
- parser.add_option("-g", "--gui", action="store_true", dest="gui", default=False,
- help="Display dependency graph in image viewer.")
- options, args = parser.parse_args()
-
- if options.gui:
- # Check to make sure 'dot' and 'eog' are present.
- if not exec_exists('dot'):
- error("'dot' not found. Make sure you have 'dot' in your path.")
- if not exec_exists('eog'):
- error("'eog' not found. Make sure you have 'eog' in your path.")
-
- # GUI mode requires dot-compatible output.
- options.output_mode = 'dot'
-
- if options.output_mode != 'dot' and options.output_mode != 'flat':
- error("Unrecognized output mode: %s"%options.output_mode)
-
- checker = DepsCheker()
- s = ''
- if options.single:
- if len(args) == 0:
- # single mode requires module names.
- raise SingleModeError()
- checker.run(args)
- if options.output_mode == 'dot':
- s = checker.print_dot_single(args)
- else:
- s = checker.print_flat_single(args)
-
- else:
- checker.run(args)
- if options.output_mode == 'dot':
- s = checker.print_dot_all()
- else:
- s = checker.print_flat_all()
-
- checker.print_missing_modules()
-
- if options.gui:
- launch_viewer(s)
- else:
- print (s)
-
diff --git a/scratch/build-analysis-tools/parse-scp2.py b/scratch/build-analysis-tools/parse-scp2.py
deleted file mode 100755
index 98b1b9c49..000000000
--- a/scratch/build-analysis-tools/parse-scp2.py
+++ /dev/null
@@ -1,855 +0,0 @@
-#!/usr/bin/env python
-########################################################################
-#
-# Copyright (c) 2010 Kohei Yoshida
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation
-# files (the "Software"), to deal in the Software without
-# restriction, including without limitation the rights to use,
-# copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following
-# conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-#
-########################################################################
-
-import sys, os, os.path, optparse, subprocess
-
-arg_desc = ""
-
-desc = """
-Run this script at the root of OOo source tree."""
-
-# taken from setup_native/source/packinfo/packinfo_office.txt
-top_modules = [
- 'gid_Module_Optional_Gnome',
- 'gid_Module_Optional_Kde',
- 'gid_Module_Root',
- 'gid_Module_Prg_Wrt_Bin',
- 'gid_Module_Prg_Calc_Bin',
- 'gid_Module_Prg_Draw_Bin',
- 'gid_Module_Prg_Impress_Bin',
- 'gid_Module_Prg_Base_Bin',
- 'gid_Module_Prg_Math_Bin',
- 'gid_Module_Optional_Binfilter',
- 'gid_Module_Optional_Grfflt',
- 'gid_Module_Oooimprovement',
- 'gid_Module_Optional_Testtool',
- 'gid_Module_Optional_Oo_English',
- 'gid_Module_Optional_Xsltfiltersamples',
- 'gid_Module_Optional_Javafilter',
- 'gid_Module_Optional_Activexcontrol',
- 'gid_Module_Optional_Onlineupdate',
- 'gid_Module_Optional_Pyuno',
- 'gid_Module_Optional_Pymailmerge',
- 'gid_Module_Optional_Headless',
- 'gid_Module_Root_Files_Images',
- 'gid_Module_Root_Fonts_OOo_Hidden',
- 'gid_Module_Oo_Linguistic',
- 'gid_Module_Root_Files_2',
- 'gid_Module_Root_Files_3',
- 'gid_Module_Root_Files_4',
- 'gid_Module_Root_Files_5',
- 'gid_Module_Root_Files_6',
- 'gid_Module_Root_Files_7',
- 'gid_Module_Root_Extension_Oooimprovement',
- 'gid_Module_Root_Extension_Dictionary_Af',
- 'gid_Module_Root_Extension_Dictionary_Ca',
- 'gid_Module_Root_Extension_Dictionary_Cs',
- 'gid_Module_Root_Extension_Dictionary_Da',
- 'gid_Module_Root_Extension_Dictionary_De_AT',
- 'gid_Module_Root_Extension_Dictionary_De_CH',
- 'gid_Module_Root_Extension_Dictionary_De_DE',
- 'gid_Module_Root_Extension_Dictionary_En',
- 'gid_Module_Root_Extension_Dictionary_Es',
- 'gid_Module_Root_Extension_Dictionary_Et',
- 'gid_Module_Root_Extension_Dictionary_Fr',
- 'gid_Module_Root_Extension_Dictionary_Gl',
- 'gid_Module_Root_Extension_Dictionary_He',
- 'gid_Module_Root_Extension_Dictionary_Hu',
- 'gid_Module_Root_Extension_Dictionary_It',
- 'gid_Module_Root_Extension_Dictionary_Ku_Tr',
- 'gid_Module_Root_Extension_Dictionary_Lt',
- 'gid_Module_Root_Extension_Dictionary_Ne',
- 'gid_Module_Root_Extension_Dictionary_Nl',
- 'gid_Module_Root_Extension_Dictionary_No',
- 'gid_Module_Root_Extension_Dictionary_Pl',
- 'gid_Module_Root_Extension_Dictionary_Pt',
- 'gid_Module_Root_Extension_Dictionary_Ro',
- 'gid_Module_Root_Extension_Dictionary_Ru',
- 'gid_Module_Root_Extension_Dictionary_Sk',
- 'gid_Module_Root_Extension_Dictionary_Sl',
- 'gid_Module_Root_Extension_Dictionary_Sr',
- 'gid_Module_Root_Extension_Dictionary_Sv',
- 'gid_Module_Root_Extension_Dictionary_Sw',
- 'gid_Module_Root_Extension_Dictionary_Th',
- 'gid_Module_Root_Extension_Dictionary_Vi',
- 'gid_Module_Root_Extension_Dictionary_Zu',
- 'gid_Module_Optional_OGLTrans'
-]
-
-class ErrorBase(Exception):
-
- def __init__ (self, name, msg, sev):
- self.value = "%s: %s"%(name, msg)
- self.sev = sev # error severity, 0 = least severe
-
- def __str__ (self):
- return repr(self.value)
-
-class ParseError(ErrorBase):
-
- def __init__ (self, msg, sev = 0):
- ErrorBase.__init__(self, "ParseError", msg, sev)
-
-class DirError(ErrorBase):
- def __init__ (self, msg):
- ErrorBase.__init__(self, "DirError", msg, 0)
-
-class ModuleError(ErrorBase):
- def __init__ (self, msg):
- ErrorBase.__init__(self, "ModuleError", msg, 0)
-
-class LinkedNode(object):
- def __init__ (self, name):
- self.name = name
- self.parent = None
- self.children = []
-
-# ----------------------------------------------------------------------------
-
-def error (msg):
- sys.stderr.write(msg + "\n")
-
-def get_attr_or_fail (name, key, attrs):
- if not attrs.has_key(key):
- raise ParseError("%s doesn't have %s attribute, but expected."%(name, key), 1)
- return attrs[key]
-
-# ----------------------------------------------------------------------------
-
-class Scp2Tokenizer(object):
- """Tokenizer for scp files."""
-
- def __init__ (self, content):
- self.content = content
- self.tokens = []
-
- def flush_buffer (self):
- if len(self.buf) > 0:
- self.tokens.append(self.buf)
- self.buf = ''
-
- def run (self):
- self.tokens = []
- i = 0
- n = len(self.content)
- self.buf = ''
- while i < n:
- c = self.content[i]
- if c in '\t\n':
- c = ' '
-
- if c in ' ;':
- self.flush_buffer()
- if c == ';':
- self.tokens.append(c)
- elif c == '"':
- # String literal. Parse until reaching the closing quote.
- self.flush_buffer()
- i += 1
- c = self.content[i]
- while c != '"':
- self.buf += c
- i += 1
- c = self.content[i]
- self.flush_buffer()
- else:
- self.buf += c
- i += 1
-
-# ----------------------------------------------------------------------------
-
-class Scp2Parser(object):
- """Parser for scp files."""
-
- class Type:
- File = 0
- Directory = 1
- FolderItem = 2
-
- NodeTypes = [
- 'DataCarrier', # ignored
- 'Directory', # ignored, referenced directly from File
- 'File', # done, linked from within Module
- 'Folder', # ignored
- 'FolderItem', # ignored for now. windows specific?
- 'Installation', # ignored. I don't know what this is for.
- 'Module', # done
- 'Profile', # ignored
- 'ProfileItem', # ignored
- 'RegistryItem', # done
- 'ScpAction', # ignored
- 'Shortcut', # linked to File? Treat this as a child of File for now.
- 'StarRegistry', # ignored, probably for StarOffice only
- 'Unixlink', # done, linked from within Module
- 'WindowsCustomAction' # ignored
- ]
-
- def __init__ (self, content, filename):
- self.content = content
- self.filename = filename
- self.nodedata = {}
-
- def tokenize (self):
- tokenizer = Scp2Tokenizer(self.content)
- tokenizer.run()
- self.tokens = tokenizer.tokens
-
- def next (self):
- self.i += 1
-
- def token (self):
- return self.tokens[self.i]
-
- def parse (self):
- if len(self.tokens) == 0:
- # No tokens to parse. Bail out.
- return
-
- self.i = 0
- self.n = len(self.tokens)
- while self.i < self.n:
- t = self.token()
- if t in Scp2Parser.NodeTypes:
- name, attrs, values = self.__parseEntity()
- attrs['__node_type__'] = t # type of node
- attrs['__node_location__'] = self.filename # file where the node is defined
- attrs['__node_values__'] = values # list of values that are not attributes (i.e. not associated with names)
- if self.nodedata.has_key(name):
- raise ParseError("node named %s already exists"%name, 1)
- self.nodedata[name] = attrs
- else:
- raise ParseError("Unknown node type: %s"%t)
-
- self.next()
-
- def append_nodes (self, nodedata, nodetree):
-
- for key in self.nodedata.keys():
-
- if nodedata.has_key(key):
- raise ParseError("node named %s already exists"%key, 1)
-
- # Transfer all the node attributes to the caller instance.
- nodedata[key] = self.nodedata[key]
-
- # Now, add linkage data to the parent tree instance.
-
- if not nodetree.has_key(key):
- # Create a new linked node instance.
- nodetree[key] = LinkedNode(key)
-
- attrs = self.nodedata[key]
-
- node_type = attrs['__node_type__']
- if node_type == 'Module':
- self.__link_module_node(key, attrs, nodetree)
- elif node_type == 'RegistryItem':
- # RegistryItem entries have ModuleID to link back to a module.
- self.__link_simple(key, attrs, nodetree, 'ModuleID')
- elif node_type == 'Shortcut':
- self.__link_simple(key, attrs, nodetree, 'FileID')
- elif node_type == 'Profile':
- self.__link_simple(key, attrs, nodetree, 'ModuleID')
- elif node_type == 'ProfileItem':
- self.__link_simple(key, attrs, nodetree, 'ProfileID')
-
-
- def __link_simple (self, name, attrs, nodetree, pid_attr):
- parentID = get_attr_or_fail(name, pid_attr, attrs)
- if not nodetree.has_key(parentID):
- nodetree[parentID] = LinkedNode(parentID)
- if not nodetree.has_key(name):
- nodetree[name] = LinkedNode(name)
-
- nodetree[parentID].children.append(nodetree[name])
- if nodetree[name].parent != None:
- raise ParseError("parent node instance already exists for '%s'"%name, 1)
- nodetree[name].parent = nodetree[parentID]
-
-
- def __link_files (self, name, files, nodetree):
-
- # file list strings are formatted like this '(file1,file2,file3,....)'
- if files[0] != '(' or files[-1] != ')':
- raise ParseError("file list string is not formatted correctly: %s"%files)
- files = files[1:-1]
- list = files.split(',')
- for file in list:
- if not nodetree.has_key(file):
- nodetree[file] = LinkedNode(file)
- nodetree[name].children.append(nodetree[file])
-
-
- def __link_module_node (self, name, attrs, nodetree):
-
- if attrs.has_key('ParentID'):
- parentID = attrs['ParentID']
-
- if not nodetree.has_key(parentID):
- nodetree[parentID] = LinkedNode(parentID)
-
- nodetree[parentID].children.append(nodetree[name])
- if nodetree[name].parent != None:
- raise ParseError("parent node instance already exists for '%s'"%name, 1)
- nodetree[name].parent = nodetree[parentID]
-
- if attrs.has_key('Files'):
- self.__link_files(name, attrs['Files'], nodetree)
-
- if attrs.has_key('Unixlinks'):
- self.__link_files(name, attrs['Unixlinks'], nodetree)
-
-
- def __parseEntity (self):
- self.next()
- name = self.token()
- if len(name) == 0:
- raise ParseError("empty name", 1)
- left = True
- attr_name = ''
- attr_value = ''
- attrs = {}
- values = []
- self.next()
- while self.token() != 'End':
- if self.token() == '=':
- if not left:
- raise ParseError("multiple '='s in a single line")
-
- if len(attr_name) == 0:
- raise ParseError("empty attribute name")
-
- left = False
-
- elif left:
- if self.token() == ';':
- # Not a valid attribute. Store it as a 'value'.
- values.append(attr_name)
- attr_name = ''
- else:
- attr_name += self.token()
- else:
- # Parse all the way up to ';'
- attr_value = ''
- while self.token() != ';':
- attr_value += self.token()
- self.next()
- attrs[attr_name] = attr_value
- left = True
- attr_name = ''
-
- self.next()
-
- return name, attrs, values
-
-# ----------------------------------------------------------------------------
-
-class XMLFunc:
-
- @staticmethod
- def resolve_vars (s, vars):
- """Replace all ${...}s with their respective values."""
-
- ret = ''
-
- while True:
- start = s.find('${')
- if start == -1:
- ret += s
- break
-
- end = s.find('}', start+2)
- if end == -1:
- ret += s
- break
-
- key = s[start+2:end]
- if vars.has_key(key):
- ret += s[:start] + vars[key]
- s = s[end+1:]
-
- return ret
-
- @staticmethod
- def to_xml_name (name):
- """CamelCase to camel-case"""
- s = ''
- n = len(name)
- for i in xrange(0, n):
- c = name[i]
- if 'A' <= c and c <= 'Z':
- if i > 0:
- s += '-'
- s += c.lower()
- else:
- s += c
- return s
-
- @staticmethod
- def add_attr (attrs, key):
- s = ''
- if attrs.has_key(key):
- s = " %s=\"%s\""%(XMLFunc.to_xml_name(key), attrs[key])
- return s
-
- @staticmethod
- def add_attr_localized (attrs, key, locale):
- if attrs.has_key(key):
- # Try non-localized name first.
- return " %s=\"%s\""%(XMLFunc.to_xml_name(key), attrs[key])
-
- key_localized = key + "(%s)"%locale
- if attrs.has_key(key_localized):
- # Try non-localized name first.
- return " %s=\"%s\" locale=\"%s\""%(XMLFunc.to_xml_name(key), attrs[key_localized], locale)
-
- return ''
-
- @staticmethod
- def add_attr_vars (attrs, key, vars):
- if not attrs.has_key(key):
- return ''
-
- s = " %s=\"%s\""%(XMLFunc.to_xml_name(key), XMLFunc.resolve_vars(attrs[key], vars))
- return s
-
-
- @staticmethod
- def add_attr_array (attrs, key):
-
- if not attrs.has_key(key):
- return ''
-
- raw_str = attrs[key]
- if len(raw_str) == 0 or raw_str[0] != '(' or raw_str[-1] != ')':
- raise ParseError("%s attribute is not formatted properly: '%s'"%(key, raw_str), 1)
-
- if raw_str == '()':
- return ''
-
- val = raw_str[1:-1].lower().replace('_', '-')
- s = " %s=\"%s\""%(XMLFunc.to_xml_name(key), val)
- return s
-
-
-
-class Scp2Processor(object):
- """Collect all .scp files in scp2 directory, and run preprocessor."""
-
- tmpin = "/tmp/parse-scp2.py.cpp"
- tmpout = "/tmp/parse-scp2.py.out"
-
- SkipList = {
- 'scp2/source/ooo/ure_standalone.scp': True,
- 'scp2/source/sdkoo/sdkoo.scp': True,
- 'scp2/source/ooo/starregistry_ooo.scp': True
- }
-
- def __init__ (self, cur_dir, mod_output_dir, vars):
- self.cur_dir = cur_dir
- self.mod_output_dir = mod_output_dir
- self.vars = vars
- self.scp_files = []
- self.nodedata = {}
- self.nodetree = {}
- self.locale = 'en-US'
-
- # Check file paths first.
- if not os.path.isfile("%s/scp2/inc/macros.inc"%self.cur_dir):
- raise ParseError("You don't appear to be at the root of OOo's source tree.")
- if not os.path.isdir("%s/scp2/%s/inc"%(self.cur_dir, self.mod_output_dir)):
- raise ParseError("You don't appear to be at the root of OOo's source tree.")
-
- def to_relative (self, fullpath):
- i = fullpath.find("/scp2/")
- if i < 0:
- return fullpath
- i += 1 # skip '/' before 'scp2'
- return fullpath[i:]
-
- def run (self):
- # Collect all .scp files under scp2.
- os.path.walk(self.cur_dir + "/scp2", Scp2Processor.visit, self)
-
- # Process each .scp file.
- for scp in self.scp_files:
- relpath = self.to_relative(scp)
- if Scp2Processor.SkipList.has_key(relpath):
- error("skipping %s"%scp)
- continue
-
- self.process_scp(scp)
-
- def process_scp (self, scp):
- ret = subprocess.call("cp %s %s"%(scp, Scp2Processor.tmpin), shell=True)
- if ret > 0:
- raise ParseError("failed to copy scp file to a temporary location.")
-
- subprocess.call("gcc -E -I./scp2/inc -I./scp2/%s/inc -DUNX %s 2>/dev/null | grep -v -E \"^\#\" > %s"%
- (self.mod_output_dir, Scp2Processor.tmpin, Scp2Processor.tmpout), shell=True)
-
- file = open(Scp2Processor.tmpout, 'r')
- content = file.read()
- file.close()
- parser = Scp2Parser(content, self.to_relative(scp))
- parser.tokenize()
- try:
- parser.parse()
- parser.append_nodes(self.nodedata, self.nodetree)
- except ParseError as e:
- # Skip mal-formed files, instead of exit with error.
- error (e.value)
- error ("Error parsing %s"%scp)
- if e.sev > 0:
- # This is a severe error. Exit right away.
- sys.exit(1)
-
- def print_summary_flat (self):
- names = self.nodedata.keys()
- names.sort()
- for name in names:
- attrs = self.nodedata[name]
- node_type = attrs['__node_type__']
- print ('-'*70)
- print ("%s (%s)"%(name, node_type))
- print ("[node location: %s]"%attrs['__node_location__'])
-
- # Print values first.
- values = attrs['__node_values__']
- for value in values:
- print(" %s"%value)
-
- # Print all attributes.
- attr_names = attrs.keys()
- attr_names.sort()
- for attr_name in attr_names:
- if attr_name in ['__node_type__', '__node_location__', '__node_values__']:
- # Skip special attributes.
- continue
- print (" %s = %s"%(attr_name, attrs[attr_name]))
-
- def print_summary_tree (self, root):
-
- if not self.nodetree.has_key(root):
- raise ModuleError("module %s not found."%root)
-
- node = self.nodetree[root]
- self.__print_summary_tree_node(node, 0)
-
- def __get_fullpath (self, fileID, locale):
- """Given a file identifier, construct the absolute path for that file."""
-
- nodedata = self.nodedata[fileID]
- filename = None
- localized = False
- key_localized = "Name(%s)"%locale
- if nodedata.has_key('Name'):
- filename = nodedata['Name']
- elif nodedata.has_key(key_localized):
- filename = nodedata[key_localized]
- localized = True
- else:
- raise DirError("%s doesn't have a name attribute."%fileID)
-
- if not nodedata.has_key('Dir'):
- raise DirError("file %s doesn't have Dir attribute."%fileID)
-
- parent_dir_name = nodedata['Dir']
-
- while parent_dir_name != None:
-
- if parent_dir_name == 'PREDEFINED_PROGDIR':
- # special directory name
- filename = parent_dir_name + '/' + filename
- break
-
- if not self.nodedata.has_key(parent_dir_name):
- # directory is referenced but not defined. Skip it for now.
- raise DirError("directory '%s' is referenced but not defined."%parent_dir_name)
-
- nodedata = self.nodedata[parent_dir_name]
- if nodedata.has_key('DosName'):
- filename = nodedata['DosName'] + "/" + filename
- elif nodedata.has_key('DosName(en-US)'):
- filename = nodedata['DosName(en-US)'] + "/" + filename
- elif nodedata.has_key('HostName'):
- filename = nodedata['HostName'] + "/" + filename
- else:
- raise DirError("directory '%s' does not have either DosName or HostName attribute."%parent_dir_name)
-
- if nodedata.has_key('ParentID'):
- parent_dir_name = nodedata['ParentID']
- else:
- parent_dir_name = None
-
- return filename, localized
-
- def __print_summary_tree_node (self, node, level):
-
- indent = ' '*level
-
- if node == None:
- return
-
- if not self.nodedata.has_key(node.name):
- # This node is referenced but is not defined. Skip it.
- return
-
- nodedata = self.nodedata[node.name]
- if not self.nodedata.has_key(node.name):
- raise ParseError("there is no associated node data for '%s'"%node.name)
-
- node_type = nodedata['__node_type__']
-
- name = ''
- localized = False
- if node_type in ['File', 'Unixlink', 'Shortcut', 'Profile']:
- try:
- name, localized = self.__get_fullpath(node.name, self.locale)
- name = XMLFunc.resolve_vars(name, self.vars)
- except DirError as e:
- error(e.value)
- return
-
- s = indent + "<%s id=\"%s\""%(XMLFunc.to_xml_name(node_type), node.name)
-
- if len(name) > 0:
- s += " name=\"%s\""%name
-
- if node_type == 'Module':
- s += XMLFunc.add_attr_array(nodedata, 'Styles')
-
- elif node_type == 'File':
- s += XMLFunc.add_attr(nodedata, 'UnixRights')
- s += XMLFunc.add_attr_array(nodedata, 'Styles')
-
- elif node_type == 'Profile':
- s += XMLFunc.add_attr_array(nodedata, 'Styles')
-
- elif node_type == 'ProfileItem':
- s += XMLFunc.add_attr(nodedata, 'Section')
- s += XMLFunc.add_attr(nodedata, 'Key')
- s += XMLFunc.add_attr_vars(nodedata, 'Value', self.vars)
-
- elif node_type == 'Unixlink':
- s += XMLFunc.add_attr_vars(nodedata, 'Target', self.vars)
-
- elif node_type == 'RegistryItem':
- val_path = get_attr_or_fail(node.name, 'ParentID', nodedata)
- val_path += '\\' + get_attr_or_fail(node.name, 'Subkey', nodedata)
- s += " path=\"%s\""%val_path
- s += XMLFunc.add_attr_localized(nodedata, 'Value', self.locale)
-
- if localized:
- s += " locale=\"%s\""%self.locale
-
- if len(node.children) > 0:
- s += ">"
- print (s)
-
- children = node.children
- children.sort()
- for child in children:
- self.__print_summary_tree_node(child, level+1)
-
- print (indent + "</%s>"%XMLFunc.to_xml_name(node_type))
- else:
- s += "/>"
- print (s)
-
- @staticmethod
- def visit (arg, dirname, names):
- instance = arg
- for name in names:
- filepath = dirname + "/" + name
- if os.path.splitext(filepath)[1] == '.scp':
- instance.scp_files.append(filepath)
-
-# ----------------------------------------------------------------------------
-
-class OOLstParser(object):
- """Parser for openoffice.lst file."""
-
- def __init__ (self):
- self.vars = {}
-
- def __repr__ (self):
- s = ''
- scope_names = self.vars.keys()
- scope_names.sort()
- for scope in scope_names:
- s += "%s\n"%scope
- attrs = self.vars[scope]
- keys = attrs.keys()
- keys.sort()
- for key in keys:
- s += " %s"%key
- if attrs[key] != None:
- s += " = %s"%attrs[key]
- else:
- s += " ="
- s += "\n"
-
- return s
-
- def get_vars (self, scopes):
- vars = {}
- for scope in scopes:
- for key in self.vars[scope].keys():
- vars[key] = self.vars[scope][key]
- return vars
-
- def parse_openoffice_lst (self, lines):
-
- class _Error(ParseError):
- def __init__ (self, msg, sev=0):
- ParseError.__init__(self, "(openoffice.lst) " + msg, sev)
-
- self.ns = [] # namespace stack
- n = len(lines)
- self.last = None
- for i in xrange(0, n):
- words = lines[i].split()
- if len(words) == 0:
- # empty line
- continue
-
- if words[0] == '{':
- # new scope begins
- if len(words) != 1:
- raise _Error("{ is followed by a token.", 1)
- if self.last == None:
- raise _Error("fail to find a namespace token in the previous line.", 1)
- if len(self.last) != 1:
- raise _Error("line contains multiple tokens when only one token is expected.", 1)
- t = self.last[0]
- self.ns.append(t)
-
- elif words[0] == '}':
- # current scope ends
- self.__check_last_line()
-
- if len(words) != 1:
- raise _Error("} is followed by a token.", 1)
- self.ns.pop()
-
- else:
- # check the last line
- self.__check_last_line()
-
- self.last = words
-
- def __check_last_line (self):
- if self.last == None or len(self.last) == 0:
- return
-
- if self.last[0] in '{}':
- return
-
- key = self.last[0]
- val = None
- if len(self.last) > 1:
- sep = ' '
- val = sep.join(self.last[1:])
- self.__insert_attr(self.ns, key, val)
-
-
- def __insert_attr (self, ns, key, val):
- ns_str = '' # aggregate namespaces, separated by '::'s.
- for name in ns:
- if len(ns_str) == 0:
- ns_str = name
- else:
- ns_str += '::' + name
-
- if not self.vars.has_key(ns_str):
- # Create this namespace entry.
- self.vars[ns_str] = {}
- self.vars[ns_str][key] = val
-
-
-# ----------------------------------------------------------------------------
-
-if __name__ == '__main__':
-
- parser = optparse.OptionParser()
- parser.usage += " " + arg_desc + "\n" + desc
- parser.add_option("", "--module-output-dir", dest="mod_output_dir", default="unxlngi6.pro", metavar="DIR",
- help="Specify the name of module output directory. The default value is 'unxlngi6.pro'.")
- parser.add_option("-m", "--output-mode", dest="mode", default='tree', metavar="MODE",
- help="Specify output mode. Allowed values are 'tree' and 'flat. The default mode is 'tree'.")
- parser.add_option("", "--openoffice-lst", dest="openoffice_lst", default="instsetoo_native/util/openoffice.lst", metavar="FILE",
- help="Specify the location of openoffice.lst file which contains variables used by the scp files. The default value is 'instsetoo_native/util/openoffice.lst'.")
-
- options, args = parser.parse_args()
-
- if not options.mode in ['tree', 'flat']:
- error("unknown output mode '%s'"%options.mode)
- sys.exit(1)
-
- cur_dir = os.getcwd()
- oo_lst_path = cur_dir + '/' + options.openoffice_lst
- if not os.path.isfile(oo_lst_path):
- error("failed to find the openoffice.lst file at (%s)."%oo_lst_path)
- sys.exit(1)
-
- oolst_parser = OOLstParser()
- try:
- file = open(oo_lst_path, 'r')
- oolst_parser.parse_openoffice_lst(file.readlines())
- file.close()
- except ParseError as e:
- error(e.value)
- if e.sev > 0:
- sys.exit(1)
-
- # For now, just pull variables from these two namespaces.
- scopes_to_use = ['Globals::Settings::variables', 'OpenOffice::Settings::variables']
- vars = oolst_parser.get_vars(scopes_to_use)
- if vars.has_key('PRODUCTNAME'):
- # Special variable
- vars['UNIXPRODUCTNAME'] = vars['PRODUCTNAME'].lower()
-
- try:
- processor = Scp2Processor(cur_dir, options.mod_output_dir, vars)
- processor.run()
- if options.mode == 'tree':
- for module in top_modules:
- try:
- processor.print_summary_tree(module)
- except ModuleError as e:
- error(e.value)
-
- elif options.mode == 'flat':
- processor.print_summary_flat()
- else:
- raise ParseError("unknown output mode '%s'"%options.mode)
-
- except ParseError as e:
- error (e.value)
- sys.exit(1)