From 44f60b6a2db1cbe5d989dd2406ef3a6d04c35b1f Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Mon, 29 Apr 2013 14:48:23 -0400
Subject: [PATCH] Added upgrade scriptlet to add JNI_JAR_DIR.

A new upgrade scriptlet has been added to add JNI_JAR_DIR into
pki.conf. The code to manipulate property files has been refactored
from PKIUpgradeTracker into a separate PropertyFile class to allow
reuse.

The pki-base package has been modified to deliver a default pki.conf
in /usr/share/pki/etc and copy it into /etc/pki if it doesn't exist.
---
 base/common/CMakeLists.txt                 |  11 +-
 base/common/python/pki/__init__.py         | 117 ++++++++++++++++++++
 base/common/python/pki/upgrade.py          | 169 +++++++++++------------------
 base/common/{ => share}/etc/pki.conf       |   3 +-
 base/common/upgrade/10.0.1/.gitignore      |   4 -
 base/common/upgrade/10.0.1/01-AddJniJarDir |  66 +++++++++++
 base/server/python/pki/server/__init__.py  |   2 +-
 base/server/python/pki/server/upgrade.py   |   2 -
 specs/pki-core.spec                        |  18 ++-
 9 files changed, 269 insertions(+), 123 deletions(-)
 rename base/common/{ => share}/etc/pki.conf (74%)
 delete mode 100644 base/common/upgrade/10.0.1/.gitignore
 create mode 100755 base/common/upgrade/10.0.1/01-AddJniJarDir

diff --git a/base/common/CMakeLists.txt b/base/common/CMakeLists.txt
index fb3ed75d5ce8d31d189a4cbb9c0c7dd473b3e7e2..e23e5c5f409fb392d8ae965a9f6151fa9f69aa66 100644
--- a/base/common/CMakeLists.txt
+++ b/base/common/CMakeLists.txt
@@ -2,15 +2,15 @@ project(common NONE)
 
 # install common configuration files
 configure_file(
-    ${CMAKE_CURRENT_SOURCE_DIR}/etc/pki.conf
-    ${CMAKE_CURRENT_BINARY_DIR}/etc/pki.conf
+    ${CMAKE_CURRENT_SOURCE_DIR}/share/etc/pki.conf
+    ${CMAKE_CURRENT_BINARY_DIR}/share/etc/pki.conf
 )
 
 install(
     FILES
-        ${CMAKE_CURRENT_BINARY_DIR}/etc/pki.conf
+        ${CMAKE_CURRENT_BINARY_DIR}/share/etc/pki.conf
     DESTINATION
-        ${SYSCONF_INSTALL_DIR}/pki/
+        ${DATA_INSTALL_DIR}/etc/
 )
 
 # install Python libraries
@@ -59,7 +59,8 @@ install(
         WORLD_EXECUTE WORLD_READ
 )
 
-# install directories
+# install server files
+# TODO: move into base/server
 install(
     DIRECTORY
         shared/
diff --git a/base/common/python/pki/__init__.py b/base/common/python/pki/__init__.py
index f9822dde904820e9817e5d07ac2fd549c3d6ce63..95f3a73353db1aa0345883db80837e555490df35 100644
--- a/base/common/python/pki/__init__.py
+++ b/base/common/python/pki/__init__.py
@@ -97,3 +97,120 @@ class PKIException(Exception):
         Exception.__init__(self, message)
 
         self.exception = exception
+
+
+class PropertyFile(object):
+
+    def __init__(self, filename, delimiter='='):
+
+        self.filename = filename
+        self.delimiter = delimiter
+
+        self.lines = []
+
+    def read(self):
+
+        self.lines = []
+
+        if not os.path.exists(self.filename):
+            return
+
+        # read all lines and preserve the original order
+        with open(self.filename, 'r') as f:
+            for line in f:
+                line = line.strip('\n')
+                self.lines.append(line)
+
+    def write(self):
+
+        # write all lines in the original order
+        with open(self.filename, 'w') as f:
+            for line in self.lines:
+                f.write(line + '\n')
+
+    def show(self):
+
+        for line in self.lines:
+            print line
+
+    def insert_line(self, index, line):
+
+        self.lines.insert(index, line)
+
+    def index(self, name):
+
+        for i, line in enumerate(self.lines):
+
+            # parse <key> <delimiter> <value>
+            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
+
+            if not match:
+                continue
+
+            key = match.group(1)
+
+            if key.lower() == name.lower():
+                return i
+
+        return -1
+
+    def get(self, name):
+
+        result = None
+
+        for line in self.lines:
+
+            # parse <key> <delimiter> <value>
+            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
+
+            if not match:
+                continue
+
+            key = match.group(1)
+            value = match.group(2)
+
+            if key.lower() == name.lower():
+                return value
+
+        return result
+
+    def set(self, name, value, index=None):
+
+        for i, line in enumerate(self.lines):
+
+            # parse <key> <delimiter> <value>
+            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
+
+            if not match:
+                continue
+
+            key = match.group(1)
+
+            if key.lower() == name.lower():
+                self.lines[i] = key + self.delimiter + value
+                return
+
+        if index is None:
+            self.lines.append(name + self.delimiter + value)
+
+        else:
+            self.insert_line(index, name + self.delimiter + value)
+
+    def remove(self, name):
+
+        for i, line in enumerate(self.lines):
+
+            # parse <key> <delimiter> <value>
+            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
+
+            if not match:
+                continue
+
+            key = match.group(1)
+            value = match.group(2)
+
+            if key.lower() == name.lower():
+                self.lines.pop(i)
+                return value
+
+        return None
diff --git a/base/common/python/pki/upgrade.py b/base/common/python/pki/upgrade.py
index 66f07ff66a8e24c2a43a288628a7bd2281a775b5..dd4ffe8a2af218f4aadb1e2812795a1fdf58578e 100644
--- a/base/common/python/pki/upgrade.py
+++ b/base/common/python/pki/upgrade.py
@@ -108,36 +108,14 @@ class PKIUpgradeTracker(object):
         index_key='PKI_UPGRADE_INDEX'):
 
         self.name = name
-        self.filename = filename
 
-        self.delimiter = delimiter
         self.version_key = version_key
         self.index_key = index_key
 
-        self.read()
-
-
-    def read(self):
-
-        self.lines = []
-
-        if not os.path.exists(self.filename):
-            return
-
-        # read all lines and preserve the original order
-        with open(self.filename, 'r') as f:
-            for line in f:
-                line = line.strip('\n')
-                self.lines.append(line)
-
-
-    def write(self):
-
-        # write all lines in the original order
-        with open(self.filename, 'w') as f:
-            for line in self.lines:
-                f.write(line + '\n')
+        # properties must be read and written immediately to avoid
+        # interfering with scriptlets that update the same file
 
+        self.properties = pki.PropertyFile(filename, delimiter)
 
     def remove(self):
 
@@ -145,8 +123,6 @@ class PKIUpgradeTracker(object):
 
         self.remove_version()
         self.remove_index()
-        self.write()
-
 
     def set(self, version):
 
@@ -154,8 +130,6 @@ class PKIUpgradeTracker(object):
 
         self.set_version(version)
         self.remove_index()
-        self.write()
-
 
     def show(self):
 
@@ -170,106 +144,93 @@ class PKIUpgradeTracker(object):
 
         print
 
-
-    def get_property(self, name):
-
-        result = None
-
-        for line in self.lines:
-
-            # parse <key> <delimiter> <value>
-            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
-
-            if not match:
-                continue
-
-            key = match.group(1)
-            value = match.group(2)
-
-            if key.lower() == name.lower():
-                result = value
-                break
-
-        return result
-
-
-    def set_property(self, name, value):
-
-        found = False
-
-        for index, line in enumerate(self.lines):
-
-            # parse <key> <delimiter> <value>
-            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
-
-            if not match:
-                continue
-
-            key = match.group(1)
-
-            if key.lower() != name.lower():
-                continue
-
-            self.lines[index] = key + self.delimiter + value
-            found = True
-            break
-
-        if not found:
-            self.lines.append(name + self.delimiter + value)
-
-
-    def remove_property(self, name):
-
-        for index, line in enumerate(self.lines):
-
-            # parse <key> <delimiter> <value>
-            match = re.match('^\s*(\S*)\s*%s\s*(.*)\s*$' % self.delimiter, line)
-
-            if not match:
-                continue
-
-            key = match.group(1)
-
-            if key.lower() != name.lower():
-                continue
-
-            self.lines.pop(index)
-
-
     def get_index(self):
 
-        index = self.get_property(self.index_key)
+        self.properties.read()
+
+        index = self.properties.get(self.index_key)
 
         if index:
             return int(index)
 
         return 0
 
-
     def set_index(self, index):
-        self.set_property(self.index_key, str(index))
 
+        self.properties.read()
+
+        # find index
+        i = self.properties.index(self.index_key)
+        if i >= 0:
+            # if already exists, update index
+            self.properties.set(self.index_key, str(index))
+
+        else:
+            # find version
+            i = self.properties.index(self.version_key)
+            if i >= 0:
+                # if version exists, add index after version
+                self.properties.set(self.index_key, str(index), index=i+1)
+
+            else:
+                # otherwise, add index at the end separated by a blank line
+
+                # if last line is not empty, append empty line
+                length = len(self.properties.lines)
+                if length > 0 and self.properties.lines[length-1] != '':
+                    self.properties.insert_line(length, '')
+                    length = length + 1
+
+                # add index
+                self.properties.set(self.index_key, str(index), index=length)
+
+        self.properties.write()
 
     def remove_index(self):
-        self.remove_property(self.index_key)
 
+        self.properties.read()
+        self.properties.remove(self.index_key)
+        self.properties.write()
 
     def get_version(self):
 
-        version = self.get_property(self.version_key)
+        self.properties.read()
 
+        version = self.properties.get(self.version_key)
         if version:
             return Version(version)
 
         return Version(DEFAULT_VERSION)
 
-
     def set_version(self, version):
-        self.set_property(self.version_key, str(version))
 
+        self.properties.read()
+
+        # find version
+        i = self.properties.index(self.version_key)
+        if i >= 0:
+            # if already exists, update version
+            self.properties.set(self.version_key, str(version))
+
+        else:
+            # otherwise, add version at the end separated by a blank line
+
+            # if last line is not empty, append empty line
+            length = len(self.properties.lines)
+            if length > 0 and self.properties.lines[length-1] != '':
+                self.properties.insert_line(length, '')
+                length = length + 1
+
+            # add version
+            self.properties.set(self.version_key, str(version), index=length)
+
+        self.properties.write()
 
     def remove_version(self):
-        self.remove_property(self.version_key)
+
+        self.properties.read()
+        self.properties.remove(self.version_key)
+        self.properties.write()
 
 
 @functools.total_ordering
@@ -309,8 +270,6 @@ class PKIUpgradeScriptlet(object):
             tracker.remove_index()
             tracker.set_version(self.version.next)
 
-        tracker.write()
-
     def upgrade_system(self):
         # Callback method to upgrade the system.
         pass
diff --git a/base/common/etc/pki.conf b/base/common/share/etc/pki.conf
similarity index 74%
rename from base/common/etc/pki.conf
rename to base/common/share/etc/pki.conf
index c7f4f8470e7efe81d61d4714445e0db035f0909e..8b16efd4b898289beb8fac097bf5ef37288a8010 100644
--- a/base/common/etc/pki.conf
+++ b/base/common/share/etc/pki.conf
@@ -1,6 +1,5 @@
 # RESTEasy library
 RESTEASY_LIB=${RESTEASY_LIB}
+
 # JNI jar file location
 JNI_JAR_DIR=${JNI_JAR_DIR}
-
-PKI_VERSION=${APPLICATION_VERSION}
diff --git a/base/common/upgrade/10.0.1/.gitignore b/base/common/upgrade/10.0.1/.gitignore
deleted file mode 100644
index 5e7d2734cfc60289debf74293817c0a8f572ff32..0000000000000000000000000000000000000000
--- a/base/common/upgrade/10.0.1/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-# Ignore everything in this directory
-*
-# Except this file
-!.gitignore
diff --git a/base/common/upgrade/10.0.1/01-AddJniJarDir b/base/common/upgrade/10.0.1/01-AddJniJarDir
new file mode 100755
index 0000000000000000000000000000000000000000..ea92640b5692264b838781f3376ae06244aa18a9
--- /dev/null
+++ b/base/common/upgrade/10.0.1/01-AddJniJarDir
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# Authors:
+#     Endi S. Dewata <edewata@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Copyright (C) 2013 Red Hat, Inc.
+# All rights reserved.
+#
+
+import os
+
+import pki
+import pki.upgrade
+
+
+class AddJniJarDir(pki.upgrade.PKIUpgradeScriptlet):
+
+    def __init__(self):
+
+        self.message = 'Add JNI_JAR_DIR into pki.conf'
+
+    def upgrade_system(self):
+
+        # read pki.conf.default
+        default_conf = pki.PropertyFile(
+            os.path.join(pki.SHARE_DIR, 'etc', 'pki.conf'))
+        default_conf.read()
+
+        default_path = default_conf.get('JNI_JAR_DIR')
+
+        # read pki.conf
+        conf = pki.PropertyFile(os.path.join(pki.CONF_DIR, 'pki.conf'))
+        conf.read()
+
+        # find JNI_JAR_DIR
+        if conf.index('JNI_JAR_DIR') >= 0:
+            # already exists
+            return
+
+        # find RESTEASY_LIB
+        index = conf.index('RESTEASY_LIB')
+
+        # insert JNI_JAR_DIR after RESTEASY_LIB
+        index = index + 1
+        conf.insert_line(index, '')
+
+        index = index + 1
+        conf.insert_line(index, '# JNI jar file location')
+
+        index = index + 1
+        conf.set('JNI_JAR_DIR', default_path, index=index)
+
+        # update pki.conf
+        conf.write()
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index 62dee2febf37a6fa1202d405d93445fb2fd14e81..aaf10bd08112daa26caca9037ccf997cc2d40772 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -87,7 +87,7 @@ class PKIServerException(pki.PKIException):
     def __init__(self, message, exception=None,\
                  instance=None, subsystem=None):
 
-        pki.upgrade.PKIException.__init__(self, message, exception)
+        pki.PKIException.__init__(self, message, exception)
 
         self.instance = instance
         self.subsystem = subsystem
diff --git a/base/server/python/pki/server/upgrade.py b/base/server/python/pki/server/upgrade.py
index e7ce4115a2be4435141d05b7744e166362520970..84e05127eb1dfa19dd86d408fdbdc8b437827fac 100644
--- a/base/server/python/pki/server/upgrade.py
+++ b/base/server/python/pki/server/upgrade.py
@@ -64,8 +64,6 @@ class PKIServerUpgradeScriptlet(pki.upgrade.PKIUpgradeScriptlet):
             tracker.remove_index()
             tracker.set_version(self.version.next)
 
-        tracker.write()
-
     def upgrade(self):
 
         for instance in self.upgrader.instances():
diff --git a/specs/pki-core.spec b/specs/pki-core.spec
index 2d333a505bf4586b96088108190a875564dc8171..dec34a4c7bcd20837157e4c77103cbfb8bfd8efa 100644
--- a/specs/pki-core.spec
+++ b/specs/pki-core.spec
@@ -5,7 +5,7 @@ distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
 
 Name:             pki-core
 Version:          10.0.2
-Release:          1%{?dist}
+Release:          2%{?dist}
 Summary:          Certificate System - PKI Core Components
 URL:              http://pki.fedoraproject.org/
 License:          GPLv2
@@ -615,6 +615,12 @@ end
 
 %post -n pki-base
 
+# Generate pki.conf if it doesn't exist
+if [ ! -e /etc/pki/pki.conf ]
+then
+    cp /usr/share/pki/etc/pki.conf /etc/pki/pki.conf
+fi
+
 echo "Upgrading base at `/bin/date`." >> /var/log/pki/pki-upgrade-%{version}.log 2>&1
 /sbin/pki-upgrade --silent >> /var/log/pki/pki-upgrade-%{version}.log 2>&1
 echo >> /var/log/pki/pki-upgrade-%{version}.log 2>&1
@@ -853,8 +859,9 @@ fi
 %doc base/common/LICENSE
 %dir %{_datadir}/pki
 %{_datadir}/pki/VERSION
+%{_datadir}/pki/etc/pki.conf
+%{_datadir}/pki/upgrade/
 %dir %{_sysconfdir}/pki
-%config(noreplace) %{_sysconfdir}/pki/pki.conf
 %dir %{_javadir}/pki
 %{_javadir}/pki/pki-cmsutil.jar
 %{_javadir}/pki/pki-nsutil.jar
@@ -865,7 +872,6 @@ fi
 %{python_sitelib}/pki/*.pyo
 %dir %{_localstatedir}/log/pki
 %{_sbindir}/pki-upgrade
-%{_datadir}/pki/upgrade/
 
 %files -n pki-tools
 %defattr(-,root,root,-)
@@ -1055,6 +1061,10 @@ fi
 
 
 %changelog
+* Mon Apr 29 2013 Endi S. Dewata <edewata@redhat.com> 10.0.2-2
+- Moved /etc/pki/pki.conf into /usr/share/pki/etc
+- Generate /etc/pki/pki.conf from the default on post install
+
 * Fri Apr 26 2013 Ade Lee <alee@redhat.com> 10.0.2-1
 - Change release number for official release.
 
@@ -1062,7 +1072,7 @@ fi
 - Added %pretrans script for f19
 - Added java-atk-wrapper dependency
 
-* Tue Apr 24 2013 Endi S. Dewata <edewata@redhat.com> 10.0.2-0.7
+* Wed Apr 24 2013 Endi S. Dewata <edewata@redhat.com> 10.0.2-0.7
 - Added pki-server-upgrade script and pki.server module.
 - Call upgrade scripts in %post for pki-base and pki-server.
 
-- 
1.8.1.4

