| #!/usr/bin/env python |
| #_____________________________________________ |
| # Caolan McNamara caolanm@redhat.com |
| # converted from original java written by Andreas Schluens so we can continue |
| # to build 680 OpenOffice.org series without java |
| # this is not really a replacement for the existing java tool, just the |
| # minimum required to make it work for now, the existing tool is still |
| # the canonical base, changes to it will have to be mirrored here until |
| # there is a java which is available for use by all |
| #_____________________________________________ |
| |
| import sys, string, os.path |
| |
| CFGFILE = os.environ["SOLARVER"] + "/" + os.environ["INPATH"] + "/inc/l10ntools/FCFGMerge.cfg" |
| |
| PROP_XMLVERSION = "xmlversion" # // <= global cfg file |
| PROP_XMLENCODING = "xmlencoding" # // <= global cfg file |
| PROP_XMLPATH = "xmlpath" # // <= global cfg file |
| PROP_XMLPACKAGE = "xmlpackage" # // <= global cfg file |
| PROP_SETNAME_TYPES = "setname_types" # // <= global cfg file |
| PROP_SETNAME_FILTERS = "setname_filters" # // <= global cfg file |
| PROP_SETNAME_LOADERS = "setname_frameloaders" # // <= global cfg file |
| PROP_SETNAME_HANDLERS = "setname_contenthandlers" # // <= global cfg file |
| PROP_SUBDIR_TYPES = "subdir_types" # // <= global cfg file |
| PROP_SUBDIR_FILTERS = "subdir_filters" # // <= global cfg file |
| PROP_SUBDIR_LOADERS = "subdir_frameloaders" # // <= global cfg file |
| PROP_SUBDIR_HANDLERS = "subdir_contenthandlers" # // <= global cfg file |
| PROP_EXTENSION_XCU = "extension_xcu" # // <= global cfg file |
| PROP_EXTENSION_PKG = "extension_pkg" # // <= global cfg file |
| PROP_DELIMITER = "delimiter" # // <= global cfg file |
| PROP_TRIM = "trim" # // <= global cfg file |
| PROP_DECODE = "decode" # // <= global cfg file |
| PROP_FRAGMENTSDIR = "fragmentsdir" # // <= cmdline |
| PROP_TEMPDIR = "tempdir" # // <= cmdline |
| PROP_OUTDIR = "outdir" # // <= cmdline |
| PROP_PKG = "pkg" # // <= cmdline |
| PROP_TCFG = "tcfg" # // <= cmdline |
| PROP_FCFG = "fcfg" # // <= cmdline |
| PROP_LCFG = "lcfg" # // <= cmdline |
| PROP_CCFG = "ccfg" # // <= cmdline |
| PROP_LANGUAGEPACK = "languagepack" # // <= cmdline |
| PROP_ITEMS = "items" # // <= pkg cfg files! |
| |
| #---begin java.util.Properties copy---# |
| """ |
| |
| An incomplete clean room implementation of |
| java.util.Properties written in Python. |
| |
| Copyright (C) 2002,2004 - Ollie Rutherfurd <oliver@rutherfurd.net> |
| |
| Based on: |
| |
| http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html |
| |
| Missing: |
| |
| - Currently, u\XXXX sequences are escaped when saving, but not unescaped |
| when read.. |
| |
| License: Python License |
| |
| Example Usage: |
| |
| >>> from properties import Properties |
| >>> props = Properties() |
| >>> props['one'] = '1' |
| >>> props['your name'] = "I don't know" |
| >>> print '\n'.join(props.keys()) |
| your name |
| one |
| >>> from StringIO import StringIO |
| >>> buff = StringIO() |
| >>> props.store(buff, "a little example...") |
| >>> buff.seek(0) |
| >>> print buff.read() |
| # a little example... |
| your\ name=I\ don\'t\ know |
| one=1 |
| >>> print props['your name'] |
| I don't know |
| |
| $Id: pyAltFCFGMerge,v 1.3 2007-12-07 10:57:44 vg Exp $ |
| |
| """ |
| |
| __all__ = ['Properties'] |
| |
| |
| def dec2hex(n): |
| |
| h = hex(n)[2:].upper() |
| return '\\u' + '0' * (4 - len(h)) + h |
| |
| |
| def escapestr(s): |
| |
| buff = [] |
| # QUESTION: escape leading or trailing spaces? |
| for c in s: |
| if c == '\\': |
| buff.append('\\\\') |
| elif c == '\t': |
| buff.append('\\t') |
| elif c == '\n': |
| buff.append('\\n') |
| elif c == '\r': |
| buff.append('\\r') |
| elif c == ' ': |
| buff.append('\\ ') |
| elif c == "'": |
| buff.append("\\'") |
| elif c == '"': |
| buff.append('\\"') |
| elif c == '#': |
| buff.append('\\#') |
| elif c == '!': |
| buff.append('\\!') |
| elif c == '=': |
| buff.append('\\=') |
| elif 32 <= ord(c) <= 126: |
| buff.append(c) |
| else: |
| buff.append(dec2hex(c)) |
| |
| return ''.join(buff) |
| |
| |
| # TODO: add support for \uXXXX? |
| def unescapestr(line): |
| |
| buff = [] |
| escape = 0 |
| for i in range(len(line)): |
| c = line[i] |
| if c == '\\': |
| if escape: |
| escape = 0 |
| buff.append('\\') |
| continue |
| else: |
| # this is to deal with '\' |
| # acting as a line continuation |
| # character |
| if i == len(line) - 1: |
| buff.append('\\') |
| break |
| else: |
| escape = 1 |
| continue |
| elif c == 'n': |
| if escape: |
| escape = 0 |
| buff.append('\n') |
| continue |
| elif c == 'r': |
| if escape: |
| escape = 0 |
| buff.append('\r') |
| continue |
| elif c == 't': |
| if escape: |
| escape = 0 |
| buff.append('\t') |
| continue |
| |
| buff.append(c) |
| |
| # make sure escape doesn't stay one |
| # all expected escape sequences either break |
| # or continue, so this should be safe |
| if escape: |
| escape = 0 |
| |
| return ''.join(buff) |
| |
| |
| |
| class Properties(dict): |
| |
| def __init__(self, defaults={}): |
| dict.__init__(self) |
| for n,v in defaults.items(): |
| self[n] = v |
| |
| def __getittem__(self,key): |
| try: |
| return dict.__getittem__(self,key) |
| except KeyError: |
| return None |
| |
| def read(self,filename): |
| """ |
| Reads properties from a file (java Property class |
| reads from an input stream -- see load()). |
| """ |
| f = None |
| try: |
| f = open(filename) |
| self.load(f) |
| finally: |
| if f: |
| f.close() |
| |
| def load(self, buff): |
| """ |
| Reads properties from a stream (StringIO, file, etc...) |
| """ |
| props = readprops(buff) |
| #for n,v in props.iteritems(): |
| for n in props.keys(): |
| self[n] = props[n] |
| |
| def readprops(buff): |
| |
| name,value = None,'' |
| props = {} |
| continued = 0 |
| |
| while 1: |
| line = buff.readline() |
| if not line: |
| break |
| line = line.strip() |
| |
| # empty line |
| if not line: |
| continue |
| |
| # comment |
| if line[0] in ('#','!'): |
| continue |
| |
| # find name |
| i,escaped = 0,0 |
| while i < len(line): |
| c = line[i] |
| |
| if c == '\\': |
| if escaped: |
| escaped = 0 |
| else: |
| escaped = 1 |
| i += 1 |
| continue |
| |
| elif c in (' ', '\t', ':', '=') and not escaped: |
| name = unescapestr(line[:i]) |
| break |
| |
| # make sure escaped doesn't stay on |
| if escaped: |
| escaped = 0 |
| |
| i += 1 |
| |
| # no dlimiter was found, name is entire line, there is no value |
| if name == None: |
| name = unescapestr(line.lstrip()) |
| |
| # skip delimiter |
| while line[i:i+1] in ('\t', ' ', ':', '='): |
| i += 1 |
| |
| value = unescapestr(line[i:].strip()) |
| while value[-1:] == '\\': |
| value = value[:-1] # remove \ |
| line = buff.readline() |
| if not line: |
| break |
| value += unescapestr(line.strip()) |
| |
| #print 'value:',value ## |
| props[name] = value |
| |
| return props |
| #---end java.util.Properties copy---# |
| |
| # Its a simple command line tool, which can merge different XML fragments |
| # together. Such fragments must exist as files on disk, will be moved into |
| # one file together on disk. |
| # |
| # @author Andreas Schluens |
| # |
| def run(sCmdLine): |
| printCopyright() |
| |
| aCfg = ConfigHelper(CFGFILE, sCmdLine) |
| |
| # help requested? |
| if aCfg.isHelp(): |
| printHelp() |
| sys.exit(-1) |
| |
| #create new merge object and start operation |
| aMerger = Merger(aCfg) |
| aMerger.merge() |
| |
| sys.exit(0) |
| |
| #prints out a copyright message on stdout. |
| def printCopyright(): |
| print("FCFGMerge") |
| print("Copyright: 2003 by Red Hat, Inc., based on FCFGMerge.java` by Sun") |
| print("All Rights Reserved.") |
| |
| #prints out a help message on stdout. |
| def printHelp(): |
| print("____________________________________________________________") |
| print("usage: FCFGMerge cfg=<file name>") |
| print("parameters:") |
| print("\tcfg=<file name>") |
| print("\t\tmust point to a system file, which contains") |
| print("\t\tall neccessary configuration data for the merge process.") |
| print("\tFurther cou can specify every parameter allowed in the") |
| print("\tconfig file as command line parameter too, to overwrite") |
| print("\tthe value from the file.") |
| |
| def StringTokenizer(mstring, separators, isSepIncluded=0): |
| #Return a list of tokens given a base string and a string of |
| #separators, optionally including the separators if asked for""" |
| token='' |
| tokenList=[] |
| for c in mstring: |
| if c in separators: |
| if token != '': |
| tokenList.append(token) |
| token='' |
| if isSepIncluded: |
| tokenList.append(c) |
| else: |
| token+=c |
| if token: |
| tokenList.append(token) |
| return tokenList |
| |
| # can be used to analyze command line parameters |
| # and merge it together with might existing config |
| # files. That provides the possibility to overwrite |
| # config values via command line parameter. |
| # |
| # @author Andreas Schluens |
| class ConfigHelper: |
| def __init__(self, sPropFile, lCommandLineArgs): |
| self.m_bEmpty = 1 |
| # first load prop file, so its values can be overwritten |
| # by command line args later |
| # Do it only, if a valid file name was given. |
| # But in case this file name is wrong, throw an exception. |
| # So the outside code can react! |
| if sPropFile != None and len(sPropFile) > 0: |
| self.props = Properties() |
| self.props.read(sPropFile) |
| |
| count = 0 |
| if lCommandLineArgs != None: |
| count = len(lCommandLineArgs) |
| print("Count is {c}".format(c=count)) |
| self.m_bEmpty = (count < 1) |
| |
| #print( lCommandLineArgs, "and len is", count ) |
| for arg in range(count): |
| # is it a named-value argument? |
| # Note: We ignores double "=" signs! => search from left to right |
| pos = lCommandLineArgs[arg].find('=') |
| if pos != -1: |
| sArg = lCommandLineArgs[arg][0:pos] |
| sValue = lCommandLineArgs[arg][pos+1:] |
| self.props[sArg] = sValue |
| continue |
| |
| # is it a boolean argument? |
| # Note: Because "--" and "-" will be interpreted as the same |
| # we search from right to left! |
| pos = lCommandLineArgs[arg].rfind('-') |
| if pos == -1: |
| pos = lCommandLineArgs[arg].rfind('/') |
| if pos != -1: |
| sArg = lCommandLineArgs[arg][pos+1:] |
| self.props[sArg] = 1 |
| continue |
| |
| raise Exception("Invalid command line detected. The argument \""+lCommandLineArgs[arg]+"\" use an unsupported format.") |
| |
| # for item in self.props: |
| # print item, '->', self.props[item] |
| |
| def isHelp(self): |
| return ( |
| ("help" in self.props) or |
| ("?" in self.props ) or |
| ("h" in self.props ) |
| ) |
| |
| def getValue(self, sProp): |
| if not sProp in self.props: |
| raise Exception("The requested config value \""+sProp+"\" "\ |
| "does not exists!"); |
| return self.props[sProp]; |
| |
| def getValueWithDefault(self, sProp, default): |
| if not sProp in self.props: |
| return default; |
| return self.props[sProp]; |
| |
| def getStringList(self, sProp, sDelimiter, bTrim, bDecode): |
| if not sProp in self.props: |
| raise Exception("The requested config value \""+sProp+"\" does "\ |
| "not exists!"); |
| sValue = self.props[sProp] |
| |
| lValue = [] |
| lTokens = StringTokenizer(sValue, sDelimiter) |
| for sToken in lTokens: |
| if bTrim: |
| sToken = sToken.strip() |
| |
| # remove "" |
| if ((bDecode) and (sToken.find("\"") == 0) and \ |
| (sToken.rfind("\"") == len(sToken)-1)): |
| sToken = sToken[1, len(sToken)-1] |
| lValue.append(sToken) |
| |
| return lValue |
| |
| def generateHeader(sVersion, sEncoding, sPath, sPackage, bLanguagePack): |
| sHeader = "<?xml version=\"" |
| sHeader += sVersion |
| sHeader += "\" encoding=\"" |
| sHeader += sEncoding |
| sHeader += "\"?>\n" |
| |
| if bLanguagePack: |
| sHeader += "<oor:component-data oor:package=\"" |
| sHeader += sPath |
| sHeader += "\" oor:name=\"" |
| sHeader += sPackage |
| sHeader += "\" xmlns:install=\"http://openoffice.org/2004/installation\"" |
| sHeader += " xmlns:oor=\"http://openoffice.org/2001/registry\"" |
| sHeader += " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"" |
| sHeader += " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" |
| else: |
| sHeader += "<oor:component-data xmlns:oor=\"http://openoffice.org/2001/registry\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" oor:package=\"" |
| sHeader += sPath |
| sHeader += "\" oor:name=\"" |
| sHeader += sPackage |
| sHeader += "\">\n" |
| return sHeader |
| |
| def generateFooter(): |
| return "</oor:component-data>\n" |
| |
| # can merge different xml fragments together. |
| # |
| # @author Caolan McNamara converted from the original java by Andreas Schluens |
| # |
| class Merger: |
| def __init__(self, aCfg): |
| self.m_aCfg = aCfg |
| |
| self.m_aFragmentsDir = self.m_aCfg.getValue(PROP_FRAGMENTSDIR) |
| |
| sDelimiter = self.m_aCfg.getValue(PROP_DELIMITER) |
| bTrim = self.m_aCfg.getValue(PROP_TRIM) |
| bDecode = self.m_aCfg.getValue(PROP_DECODE) |
| |
| try: |
| aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_TCFG), None) |
| self.m_lTypes = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) |
| except: |
| self.m_lTypes = [] |
| |
| try: |
| aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_FCFG), None) |
| self.m_lFilters = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) |
| except: |
| print( "Filters are empty" ) |
| self.m_lFilters = [] |
| |
| try: |
| aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_LCFG), None) |
| self.m_lLoaders = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) |
| except: |
| self.m_lLoaders = [] |
| |
| try: |
| aFcfg = ConfigHelper(self.m_aCfg.getValue(PROP_CCFG), None) |
| self.m_lHandlers = aFcfg.getStringList(PROP_ITEMS, sDelimiter, bTrim, bDecode) |
| except: |
| self.m_lHandlers = [] |
| |
| def merge(self): |
| sPackage = self.m_aCfg.getValue(PROP_PKG) |
| |
| print("create package \""+sPackage+"\" ...") |
| print("generate package header ... ") |
| |
| sBuffer = generateHeader(\ |
| self.m_aCfg.getValue(PROP_XMLVERSION ),\ |
| self.m_aCfg.getValue(PROP_XMLENCODING),\ |
| self.m_aCfg.getValue(PROP_XMLPATH ),\ |
| self.m_aCfg.getValue(PROP_XMLPACKAGE ),\ |
| self.m_aCfg.getValueWithDefault(PROP_LANGUAGEPACK, False)) |
| |
| # counts all transfered fragments |
| # Can be used later to decide, if a generated package file |
| # contains "nothing"! |
| nItemCount = 0 |
| |
| for i in range(4): |
| sSetName = None |
| sSubDir = None |
| lFragments = None |
| |
| try: |
| if i == 0: #types |
| print("generate set for types ... ") |
| sSetName = self.m_aCfg.getValue(PROP_SETNAME_TYPES) |
| sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_TYPES ) |
| lFragments = self.m_lTypes |
| elif i == 1: # filters |
| print("generate set for filter ... ") |
| sSetName = self.m_aCfg.getValue(PROP_SETNAME_FILTERS) |
| sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_FILTERS ) |
| lFragments = self.m_lFilters |
| elif i == 2: # loaders |
| print("generate set for frame loader ... ") |
| sSetName = self.m_aCfg.getValue(PROP_SETNAME_LOADERS) |
| sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_LOADERS ) |
| lFragments = self.m_lLoaders |
| elif i == 3: # handlers |
| print("generate set for content handler ... ") |
| sSetName = self.m_aCfg.getValue(PROP_SETNAME_HANDLERS) |
| sSubDir = self.m_aCfg.getValue(PROP_SUBDIR_HANDLERS ) |
| lFragments = self.m_lHandlers |
| except: |
| continue |
| |
| print("Length of Fragments: {f} Set Name {setname} Subdir {subdir}". |
| format(f=len(lFragments),setname=sSetName,subdir=sSubDir)) |
| #sys.stdin.readline() |
| nItemCount = nItemCount + len(lFragments) |
| |
| sBuffer = sBuffer + self.getFragments(\ |
| os.path.join(self.m_aFragmentsDir, sSubDir), \ |
| sSetName, lFragments, 1) |
| |
| print("generate package footer ... ") |
| sBuffer = sBuffer + generateFooter() |
| |
| # Attention! |
| # If the package seems to be empty, it make no sense to generate a |
| # corresponding xml file. We should suppress writing of this file on |
| # disk completely ... |
| if nItemCount < 1: |
| print("Package is empty and will not result into an xml file on disk!? Please check configuration file.") |
| return |
| print("package contains "+str(nItemCount)+" items") |
| |
| aPackage = open(sPackage, mode="w") |
| print("write temp package {pkg}".format(pkg=sPackage)) |
| aPackage.write(sBuffer) |
| |
| def getFragments(self, aDir, sSetName, lFragments, nPrettyTabs): |
| sBuffer = '' |
| sExtXcu = self.m_aCfg.getValue(PROP_EXTENSION_XCU); |
| |
| if len(lFragments) < 1: |
| return sBuffer |
| |
| for tabs in range(nPrettyTabs): |
| sBuffer = sBuffer + "\t" |
| sBuffer = sBuffer + "<node oor:name=\""+sSetName+"\">\n" |
| nPrettyTabs = nPrettyTabs + 1 |
| |
| for sFragment in lFragments: |
| sFragPath = os.path.join(aDir, sFragment+"."+sExtXcu) |
| try: |
| aFragmentFile = open(sFragPath) |
| except: |
| # handle simple files only and check for existence! |
| raise Exception("fragment \""+sFragPath+"\" does not exists.") |
| |
| print("merge fragment \""+sFragPath+"\" ...") |
| sBuffer = sBuffer + aFragmentFile.read() |
| |
| sBuffer = sBuffer + "\n" |
| |
| nPrettyTabs = nPrettyTabs - 1 |
| for tabs in range(nPrettyTabs): |
| sBuffer = sBuffer + "\t" |
| sBuffer = sBuffer + "</node>\n" |
| return sBuffer |
| |
| run(sys.argv) |