From 9c1d7d90122e1ea49eab32ac855598d3ebce4a7d Mon Sep 17 00:00:00 2001 From: Orion Poplawski Date: Oct 31 2012 22:10:14 +0000 Subject: Updated createmodule.sh and added createmodule.py --- diff --git a/createmodule.py b/createmodule.py new file mode 100755 index 0000000..60c6ba7 --- /dev/null +++ b/createmodule.py @@ -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 +# +# 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 . + +from optparse import OptionParser +import os,sys +from subprocess import * + +# Handle options +usage = "Usage: %prog [-p prefix] [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) diff --git a/createmodule.sh b/createmodule.sh index 8b82b34..b44cf05 100755 --- a/createmodule.sh +++ b/createmodule.sh @@ -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 # # 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 . -if [ -z "$1" ] -then - echo "usage: $0 [args]" 1>&2 +usage="Usage: $0 [-p prefix] [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 ] - 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]}" ] + if [ "${env1[$key]}" != "${env2[$key]}" ] + then + #Working directory change + if [ "$key" = PWD ] + then + if [ -n "$prefix" ] 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