|
|
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)
|