Blame SOURCES/createmodule.py

1a066f
#!/usr/bin/python
1a066f
#
1a066f
# createmodule.py - Takes the name of a environment init script and 
1a066f
# produces a modulefile that duplicates the changes made by the init script
1a066f
#
1a066f
# Copyright (C) 2012 by Orion E. Poplawski <orion@cora.nwra.com>
1a066f
#
1a066f
# This program is free software: you can redistribute it and/or modify
1a066f
# it under the terms of the GNU General Public License as published by
1a066f
# the Free Software Foundation, either version 2 of the License, or
1a066f
# (at your option) any later version.
1a066f
1a066f
# This program is distributed in the hope that it will be useful,
1a066f
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1a066f
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1a066f
# GNU General Public License for more details.
1a066f
1a066f
# You should have received a copy of the GNU General Public License
1a066f
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1a066f
1a066f
from optparse import OptionParser
1a066f
import os,sys
1a066f
from subprocess import *
1a066f
1a066f
# Handle options
1a066f
usage = "Usage: %prog [-p prefix] <initscript> [args]"
1a066f
parser = OptionParser()
1a066f
parser.set_usage(usage)
1a066f
parser.add_option('-p', '--prefix', dest='prefix', help='Specify path prefix')
1a066f
(options, args) = parser.parse_args()
1a066f
1a066f
# Need a script name
1a066f
if not args:
1a066f
    parser.print_usage()
1a066f
    exit(1)
1a066f
1a066f
# Return environment after a command
1a066f
def getenv(cmd = ':'):
1a066f
    env = {}
1a066f
    p = Popen(cmd + ";env", shell=True, stdout=PIPE, stderr=PIPE)
1a066f
    (stdout, stderr) = p.communicate()
1a066f
    if p.returncode != 0:
1a066f
        print "EROR: Could not execute initscript:"
1a066f
        print "%s returned exit code %d" % (cmd, p.returncode)
1a066f
        print stderr
1a066f
        exit(1)
1a066f
    if stderr != '':
1a066f
        print "WARNING: initscript sent the following to stderr:"
1a066f
        print stderr
1a066f
    # Parse the output key=value pairs
1a066f
    for line in stdout.splitlines():
1a066f
        try:
1a066f
            (var,value) = line.split('=',1)
1a066f
        except ValueError:
1a066f
            print "ERROR: Could not parse output:"
1a066f
            print stdout
1a066f
            exit(1)
1a066f
        env[var] = value
1a066f
    return env
1a066f
1a066f
#Record initial environment
1a066f
env1=getenv()
1a066f
1a066f
#Record environment after sourcing the initscript
1a066f
env2=getenv(". " + " ".join(args))
1a066f
1a066f
# Initialize our variables for storing modifications
1a066f
chdir = None
1a066f
appendpath = {}
1a066f
prependpath = {}
1a066f
setenv = {}
1a066f
unsetenv = []
1a066f
pathnames = []
1a066f
1a066f
# Function to nomalize all paths in a list of paths and remove duplicate items
1a066f
def normpaths(paths):
1a066f
    newpaths = []
1a066f
    for path in paths:
1a066f
        normpath = os.path.normpath(path)
1a066f
        if normpath not in newpaths:
1a066f
             newpaths.append(os.path.normpath(path))
1a066f
    return newpaths
1a066f
1a066f
# Start with existing keys and look for changes
1a066f
for key in env1.keys():
1a066f
    # Test for delete
1a066f
    if key not in env2:
1a066f
        unsetenv.append(key)
1a066f
        continue
1a066f
    # No change
1a066f
    if env1[key] == env2[key]:
1a066f
        del env2[key]
1a066f
        continue
1a066f
    #Working directory change
1a066f
    if key == 'PWD':
1a066f
	chdir=os.path.normpath(env2[key])
1a066f
        pathnames.append(chdir)
1a066f
        del env2[key]
1a066f
        continue
1a066f
    # Determine modifcations to beginning and end of the string
1a066f
    (prepend,append) = env2[key].split(env1[key])
1a066f
    if prepend:
1a066f
        prependpaths = prepend.strip(':').split(':')
1a066f
        # LICENSE variables often include paths outside install directory
1a066f
        if 'LICENSE' not in key:
1a066f
            pathnames += prependpaths
1a066f
        prependpath[key] = ':'.join(normpaths(prependpaths))
1a066f
    if append:
1a066f
        appendpaths = append.strip(':').split(':')
1a066f
        # LICENSE variables often include paths outside install directory
1a066f
        if 'LICENSE' not in key:
1a066f
            pathnames += appendpaths
1a066f
        appendpath[key] = ':'.join(normpaths(appendpaths))
1a066f
    del env2[key]
1a066f
      
1a066f
# We're left with new keys in env2
1a066f
for key in env2.keys():
1a066f
    # Use prepend-path for new paths
1a066f
    if ('PATH' in key) or (':' in env2[key]):
1a066f
        prependpaths = env2[key].strip(':').split(':')
1a066f
        # MANPATH can have system defaults added it it wasn't previously set
1a066f
        # LICENSE variables often include paths outside install directory
1a066f
        if key != 'MANPATH' and 'LICENSE' not in key:
1a066f
            pathnames += prependpaths
1a066f
        prependpath[key] = ':'.join(normpaths(prependpaths))
1a066f
        continue
1a066f
    # Set new variables
1a066f
    setenv[key] = os.path.normpath(env2[key])
1a066f
    if 'LICENSE' not in key:
1a066f
        pathnames.append(setenv[key])
1a066f
1a066f
# Determine a prefix
1a066f
prefix = None
1a066f
if options.prefix:
1a066f
    prefix = options.prefix
1a066f
else:
1a066f
    prefix = os.path.commonprefix(pathnames).rstrip('/')
1a066f
    if prefix == '':
1a066f
          prefix = None
1a066f
1a066f
# Print out the modulefile
1a066f
print "#%Module 1.0"
1a066f
1a066f
# Prefix
1a066f
if prefix is not None:
1a066f
    print "\nset prefix " + prefix + "\n"
1a066f
1a066f
# Chdir
1a066f
if chdir is not None:
1a066f
    print "chdir\t" + chdir
1a066f
1a066f
# Function to format output line with tabs and substituting prefix
1a066f
def formatline(item, key, value=None):
1a066f
    print item,
1a066f
    print "\t"*(2-(len(item)+1)/8),
1a066f
    print key,
1a066f
    if value is not None:
1a066f
        print "\t"*(3-(len(key)+1)/8),
1a066f
        if prefix is not None:
1a066f
            print value.replace(prefix,'$prefix')
1a066f
        else:
1a066f
            print value
1a066f
1a066f
# Paths first, grouped by variable name
1a066f
pathkeys = appendpath.keys() + prependpath.keys()
1a066f
pathkeys.sort()
1a066f
for key in pathkeys:
1a066f
    if key in prependpath:
1a066f
        formatline("prepend-path",key,prependpath[key])
1a066f
    if key in appendpath:
1a066f
        formatline("append-path",key,appendpath[key])
1a066f
1a066f
# Setenv
1a066f
setenvkeys = setenv.keys()
1a066f
setenvkeys.sort()
1a066f
if setenvkeys:
1a066f
    print
1a066f
for key in setenvkeys:
1a066f
    formatline("setenv",key,setenv[key])
1a066f
1a066f
# Unsetenv
1a066f
unsetenv.sort()
1a066f
if unsetenv:
1a066f
    print
1a066f
for key in unsetenv:
1a066f
    formatline("unsetenv",key)