blob: 65bfffbf65cfac8c3100cec5ad49725412438378 [file] [log] [blame]
#!/usr/bin/python
import os
import re
import platform
import string
# -----------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# -----------------------------------------------------------------------
class PropertiesException(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
class Property:
def __init__(self, k, v, c):
self.k = k # key
self.v = v # value
self.c = c # comments
self.orig_v = v
def reset(self):
self.v = self.orig_v
def __str__(self):
return str(self.k) + '=' + str(self.v)
class Properties:
def __init__(self):
self.props = {}
self.builtin = {}
self.keys = []
self.comments = []
#
# Create builtins corresponding to some of the java properties.
#
# We allow expansion on java system properties. It's obviously not possible to
# do most of them but these guys may have a use e.g. to put ducc_ling into
# architecture-specific places.
#
(system, node, release, version, machine, processor) = platform.uname()
if ( system == 'Darwin' ):
self.builtin['os.arch'] = 'x86_64'
self.builtin['os.name'] = 'Mac OS X'
elif ( system == 'Linux' ):
if ( machine == 'ppc64' ):
self.builtin['os.arch'] = 'ppc64'
self.builtin['os.name'] = 'Linux'
elif ( machine == 'x86_64' ):
self.builtin['os.arch'] = 'amd64'
self.builtin['os.name'] = 'Linux'
elif ( machine == 'ppc64le' ):
self.builtin['os.arch'] = 'ppc64le'
self.builtin['os.name'] = 'Linux'
#
# Expand all ${} values. The search order is:
# 1 look in this properties file
# 2 look in the environment
# 3 look in a subset of the Java system properties (os.name & os.arch)
#
def do_subst(self, st):
key = None
p = re.compile("\\$\\{[a-zA-Z0-9_\\.\\-]+\\}")
ndx = 0
response = st.strip()
m = p.search(response, ndx)
while ( m != None ):
key = m.group()[2:-1]
val = None
if ( self.has_key(key) ):
val = self.get(key)
elif ( os.environ.has_key(key) ):
val = os.environ[key]
elif (self.builtin.has_key(key) ):
val = self.builtin[key]
if ( val != None ):
response = string.replace(response, m.group() , val)
ndx = m.start()+1
m = p.search(response, ndx)
return response
def mkitem(self, line):
#
# First deal with line comments so we can preserve them on write
#
if ( line.startswith('#') ):
self.comments.append(line)
return False
if ( line.startswith('//') ):
self.comments.append(line)
return False
if ( line == '' ):
return False
#
# Now strip off embedded comments, these are lost, but they're not valid
# for java props anyway.
#
ndx = line.find('#') # remove comments - like the java DuccProperties
if ( ndx >= 0 ):
line = line[0:ndx] # strip the comment
ndx = line.find('//') # remove comments - like the java DuccProperties
if ( ndx >= 0 ):
line = line[0:ndx] # strip the comment
line = line.strip() # clear leading and trailing whitespace
if ( line == '' ):
return
mobj = re.search('[ =:]+', line)
if ( mobj ):
key = line[:mobj.start()].strip()
val = line[mobj.end():].strip()
# print 'NEXT', mobj.start(), 'END', mobj.end(), 'KEY', key, 'VAL', val
# val = self.do_subst(val) # we'll do lazy subst on get instead
self.props[key] = Property(key, val, self.comments)
if ( key in self.keys ):
self.keys.remove(key)
self.keys.append(key)
self.comments = []
else:
self.props[line] = Property(line, '', self.comments)
self.keys.append(line)
self.comments = []
#
# Load reads a properties file and adds it contents to the
# hash. It may be called several times; each call updates
# the internal has, thus building it up. The input file is
# in the form of a java-like properties file.
#
def load(self, propsfile):
if ( not os.path.exists(propsfile) ):
raise PropertiesException(propsfile + ' does not exist and cannot be loaded.')
f = open(propsfile);
for line in f:
self.mkitem(line.strip())
f.close()
# read a jar manifest into a properties entity
def load_from_manifest(self, jarfile):
z = zipfile.ZipFile(jarfile)
items = z.read('META-INF/MANIFEST.MF').split('\n')
for item in items:
self.mkitem(item)
#
# Try to load a properties file. Just be silent if it doesn't exist.
#
def load_if_exists(self, propsfile):
if ( os.path.exists(propsfile) ):
return self.load(propsfile)
#
# Put something into the hash with an optional comment
#
def put(self, key, value, comment=[]):
self.props[key] = Property(key, value, comment)
self.keys.append(key)
#
# Put a Property object into the map
#
def put_property(self, p):
self.props[p.k] = p
self.keys.append(p.k)
#
# Get a value from the hash
#
def get(self, key):
if ( self.props.has_key(key) ):
return self.do_subst(self.props[key].v) # we'll do lazy subst on get instead
return None
#
# Get a Property object for manipulation (k, v, comment)
#
def get_property(self, key):
if ( self.props.has_key(key) ):
return self.props[key] # note no expansion.
return None
#
# Remove an item if it exists
#
def delete(self, key):
if ( self.props.has_key(key) ):
del self.props[key]
self.keys.remove(key)
#
# Write the has as a Java-like properties file
#
def write(self, propsfile):
f = open(propsfile, 'w')
for k in self.keys:
p = self.props[k]
v = p.v
c = p.c
for cc in c:
f.write(cc + '\n')
f.write(k + ' = ' + str(v) + '\n\n')
f.close()
#
# return a shallow copy of the dictionary
#
def copy_dictionary(self):
return self.props.copy()
#
# Return the entries (Property list) in the dictionary
#
def items(self):
return self.props.items()
#
# The keys, in the order as defined in the input file
#
def get_keys(self):
return self.keys
#
# check to see if the key exists in the dictionary
#
def has_key(self, key):
return self.props.has_key(key)
#
# Return the length of the dictionary
#
def __len__(self):
return len(self.props)