Updated createmodule.sh and added createmodule.py

This commit is contained in:
Orion Poplawski 2012-10-31 16:10:14 -06:00
parent 2ccfc854ef
commit 9c1d7d9012
2 changed files with 293 additions and 42 deletions

186
createmodule.py Executable file
View File

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

View File

@ -3,7 +3,7 @@
# createmodule.sh - Takes the name of a environment init script and
# produces a modulefile that duplicates the changes made by the init script
#
# Copyright (C) 2010 by Orion E. Poplawski
# Copyright (C) 2010-2012 by Orion E. Poplawski <orion@cora.nwra.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
@ -18,10 +18,29 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
if [ -z "$1" ]
then
echo "usage: $0 <initscript> [args]" 1>&2
usage="Usage: $0 [-p prefix] <initscript> [args]"
usage() {
echo $usage 1>&2
exit 1
}
while getopts "p:" opt
do
case $opt in
p) prefix=$OPTARG; shift 2;;
*) usage;;
esac
done
# Need a script name
[ -z "$1" ] && usage
# Need to be a readable script
if [ ! -r "$1" ]
then
echo "ERROR: Cannot read $1" 1>&2
exit 1
fi
#Will print out array assignment list
@ -49,53 +68,99 @@ eval env2=(`printenvarray`)
#Print out the modulefile
echo "#%Module 1.0"
#Prefix
[ -n "$prefix" ] && echo -e "\nset prefix $prefix\n"
#Subshell so we can sort the output
(
dedup() {
list=`mktemp`
echo $1 | sed -r -e 's,[^/]+/\.\./,,g' -e 's,[^/]+/\.\./,,g' -e 's/:/\n/g' |
while read x
do
grep -Fx ${x} $list && continue
if [ -n "$prefix" ]
then
echo $x | sed -e s,$prefix,\$prefix,
else
echo $x
fi
echo $x >> $list
done | tr '\n' : | sed -e 's/:$//'
rm $list
}
#Keys that changed
for key in "${!env1[@]}"
do
if [ "${env1[$key]}" != "${env2[$key]}" ]
then
#Working directory change
if [ "$key" = PWD ]
if [ "${env1[$key]}" != "${env2[$key]}" ]
then
#Working directory change
if [ "$key" = PWD ]
then
if [ -n "$prefix" ]
then
echo -e "chdir\t\t${env2[PWD]}"
#Test for delete
elif [ -z "${env2[$key]}" ]
then
echo -e "unsetenv\t${key}\t${env2[$key]}"
#Test for prepend
elif [ "${env2[$key]%${env1[$key]}}" != "${env2[$key]}" ]
then
added="${env2[$key]%${env1[$key]}}"
echo -e "prepend-path\t$key\t${added%:}"
#Test for append
elif [ "${env2[$key]#${env1[$key]}}" != "${env2[$key]}" ]
then
added="${env2[$key]#${env1[$key]}}"
echo -e "append-path\t$key\t${added#:}"
echo -e "chdir\t\t${env2[PWD]}" | sed -e s,$prefix,\$prefix,g
else
#Unhandled
echo "Unhandled change of $key" 1>&2
echo "Before <${env1[$key]}>" 1>&2
echo "After <${env2[$key]}>" 1>&2
echo -e "chdir\t\t${env2[PWD]}"
fi
fi
#Delete keys we've handled
unset env1[$key]
unset env2[$key]
#Test for delete
elif [ -z "${env2[$key]}" ]
then
echo -e "unsetenv\t${key}\t${env2[$key]}"
#Test for prepend
elif [ "${env2[$key]%${env1[$key]}}" != "${env2[$key]}" ]
then
added=$(dedup ${env2[$key]%:${env1[$key]}})
echo -e "prepend-path\t$key\t${added}"
#Test for prepend plus : added at end (MANPATH)
elif [ "${env2[$key]%${env1[$key]}:}" != "${env2[$key]}" ]
then
added=$(dedup ${env2[$key]%${env1[$key]}:})
echo -e "prepend-path\t$key\t${added}"
#Test for append
elif [ "${env2[$key]#${env1[$key]}}" != "${env2[$key]}" ]
then
added=$(dedup ${env2[$key]#:${env1[$key]}})
echo -e "append-path\t$key\t${added}"
#Test for prepend plus append
elif [ "${env2[$key]%${env1[$key]}:*}" != "${env2[$key]}" ]
then
added=$(dedup ${env2[$key]%:${env1[$key]}*})
echo -e "prepend-path\t$key\t${added}"
added=$(dedup ${env2[$key]#*${env1[$key]}:})
echo -e "append-path\t$key\t${added}"
else
#Unhandled
echo "Unhandled change of $key" 1>&2
echo "Before <${env1[$key]}>" 1>&2
echo "After <${env2[$key]}>" 1>&2
fi
fi
#Delete keys we've handled
unset env1[$key]
unset env2[$key]
done
#New keys
for key in "${!env2[@]}"
do
if [ "$key" = OLDPWD ]
then
continue
fi
#Use prepend-path for new paths
if [ "${key/PATH/}" != "$key" ]
then
echo -e "prepend-path\t${key}\t${env2[$key]}"
else
echo -e "setenv\t\t${key}\t${env2[$key]}"
fi
if [ "$key" = OLDPWD ]
then
continue
fi
#Use prepend-path for new paths
if [ "${key/PATH/}" != "$key" ]
then
# TODO - Need to handle stripping of default MANPATH
echo -e "prepend-path\t${key}\t"$(dedup ${env2[$key]})
else
if [ -n "$prefix" ]
then
echo -e "setenv\t\t${key}\t${env2[$key]}" | sed -e s,$prefix,\$prefix,g
else
echo -e "setenv\t\t${key}\t${env2[$key]}"
fi
fi
done
) | sort