# -*-sh-*- ############################################### ### ### Configuration ### # name of the "control" files CONTROL="dune.module" ############################################### ### ### check for environment variables ### if test -z $GREP; then GREP=grep fi # SunOS [e]grep does not seem to comprehend character classes. Set up # some variables to spell them out UPPER=ABCDEFGHIJKLMNOPQRSTUVWXYZ LOWER=abcdefghijklmnopqrstuvwxyz ALPHA="$UPPER$LOWER" DIGIT=0123456789 ALNUM="$ALPHA$DIGIT" space=" " formfeed="" newline=" " cr=" " tab=" " vtab="" # $SPACE will unfortunately not work since grep will not accept an # embedded newline. Instead one can often get away with using $BLANK SPACE="$space$formfeed$newline$cr$tab$vtab" BLANK="$space$tab" # # read paramters from a $CONTROL file # # paramters: # $1 file to read # PARSER_TRIM="awk '{gsub(/^[[:space:]]+| +$/,\"\");printf(\"%s\", \$0);}'" parse_control() { # check file existence if test ! -f "$1" -o "$(basename $1)" != "$CONTROL"; then echo "ERROR: '$1' is no $CONTROL file" >&2 exit 1 fi # reset information handling module="" module_inst="no" # read parameters from control file local name="$($GREP Module: "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" if test "x$name" = "x"; then echo "ERROR: $CONTROL files $1 does not contain a Module entry" >&2 exit 1 fi # create and check variable name from module name export module=$(fix_variable_name $name) if ! check_modname "$module"; then echo "ERROR: $CONTROL files $1 contains an invalid Module entry" >&2 exit 1 fi # read dune.module file local deps="$($GREP "^[$BLANK]*Depends:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" local sugs="$($GREP "^[$BLANK]*Suggests:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" local vers="$($GREP "^[$BLANK]*Version:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" local main="$($GREP "^[$BLANK]*Maintainer:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" # check whether the module is installed. # - installed modules can be found via pkg-config # - pkg-config --var=prefix should be the same as $path # # the path contains a different sub structure # for installed and source modules # - installed module: ${path}/lib/dunecontrol/${name}/dune.module # and there is a file ${path}/lib/pkgconfig/${name}.pc # - source module: ${path}/dune.module # and there is a file ${path}/${name}.pc.in local path="$(canonicalpath "$1")" if pkg-config $name; then local prefix="$(pkg-config --variable=prefix $name)" local pkgpath=$(canonicalname "$prefix/lib/dunecontrol/$name") if test x"$pkgpath" = x"$path"; then path="$prefix" module_inst="yes" fi fi # avoid multiple definition of the same module if eval test "x\$HAVE_$module" != "x"; then # make sure we don't stumble over the same module twice if eval test "\$PATH_$module" = "$path"; then return fi local old_mod_inst eval old_mod_inst=\$INST_$module case "$old_mod_inst$module_inst" in # multiple local modules are an error # multiple installed modules are an error nono|yesyes) echo "ERROR: multiple definition of module $name" >&2 echo "previous defined in:" >&2 if test "$(eval echo \$INST_$module)" = "yes"; then echo " $(eval echo \$PATH_$module)/lib/dunecontrol/$name/$CONTROL" >&2 else echo " $(eval echo \$PATH_$module)/$CONTROL" >&2 fi echo "redefined in:" >&2 if test "$module_inst" = "yes"; then echo " $path/lib/dunecontrol/$name/$CONTROL" >&2 else echo " $path/$CONTROL" >&2 fi exit 1 ;; # installed modules are superseded by locally built modules noyes) echo "WARNING: ignoring installed module file" >&2 echo " $path/lib/dunecontrol/$name/$CONTROL" >&2 echo "using previously found locally built module" >&2 echo " $(eval echo \$PATH_$module)/$CONTROL" >&2 module_inst="no" return ;; # local modules supersede installed modules yesno) echo "WARNING: not using installed module file" >&2 echo " $(eval echo \$PATH_$module)/lib/dunecontrol/$name/$CONTROL" >&2 echo "using locally built module" >&2 echo " $path/$CONTROL" >&2 true # do nothing, ignore the previously found module ;; esac fi # set status variables export HAVE_$module=yes export PATH_$module="$path" export VERS_$module="$vers" export NAME_$module="$name" export MAIN_$module="$main" export DEPS_$module="$deps" export INST_$module="$module_inst" for name in $deps; do mod=$(fix_variable_name $name) export NAME_$mod="$name" done export SUGS_$module="$sugs" for name in $sugs; do mod=$(fix_variable_name $name) export NAME_$mod="$name" done # update list of modules if test "$module_inst" = "yes"; then export INSTMODULES="$INSTMODULES$module " else export LOCALMODULES="$LOCALMODULES$module " fi } # # try to setup the control path # setup_control_path() { if test -z $DUNE_CONTROL_PATH; then DUNE_CONTROL_PATH=. # try pkg-config locations if pkg-config dune-common; then # try usual locations of installed modules for i in /usr/local/lib/dunecontrol/ /usr/lib/dunecontrol/; do if test -d $i; then DUNE_CONTROL_PATH=$DUNE_CONTROL_PATH:"$i" fi done for i in `echo $PKG_CONFIG_PATH | tr ':' ' '`; do if test -d "$i/../dunecontrol"; then DUNE_CONTROL_PATH=$DUNE_CONTROL_PATH:"$i/../dunecontrol" fi done fi fi # try to read DUNE_CONTROL_PATH from OPTS file if test -n "$DUNE_OPTS_FILE"; then DUNE_CONTROL_PATH="$(. $DUNE_OPTS_FILE; eval echo $DUNE_CONTROL_PATH)" fi # canonicalize path local TMP="" # foreach dir in $@ while read dir; do TMP=$TMP:"$(canonicalname $dir)" done <<EOF $(echo $DUNE_CONTROL_PATH | sed -e 's/:\+/:/g' | tr ':' '\n') EOF # sort+uniq path DUNE_CONTROL_PATH="$(echo $TMP | tr ':' '\n' | sort -u | tr '\n' ':' | sed -e 's/^://' -e 's/:$//')" # safe result export DUNE_CONTROL_PATH } # # search for modules in each directory in DUNE_CONTROL_PATH # find_modules_in_path() { setup_control_path if test -z "$FOUND_MODULES"; then # foreach dir in $@ while read dir; do if test -d "$dir"; then while read m; do test -n "$m" && parse_control "$m" done <<EOFM $(find -H "$dir" -name $CONTROL | $GREP -v 'dune-[-_a-zA-Z]/dune-[-a-zA-Z_]*-[0-9]\{1,\}.[0-9]\{1,\}/') EOFM else parse_control "$dir" fi done <<EOF $(echo $DUNE_CONTROL_PATH | sed -e 's/:\+/:/g' | tr ':' '\n') EOF export MODULES="$LOCALMODULES$INSTMODULES" export FOUND_MODULES="$MODULES" else export MODULES="$FOUND_MODULES" fi } # # sort $MODULES according to the dependencies # sort_modules() { # reset lists export SORTEDMODULES="" export SORTEDMODULES_INFO="" export SORTEDMODULES_DEPS="" export SORTEDMODULES_SUGS="" # handle each modules passed as parameter for m in "$@"; do # did we find a module file for this module? if test "x$(eval echo \$HAVE_$m)" != "x"; then _sort_module $m MAIN else echo "ERROR: could not find module $(eval echo \$NAME_$m)" >&2 exit 1 fi done # save result export MODULES="$SORTEDMODULES" # clean up temporary variables for m in $MODULES; do export SORT_DEPS_DONE_$m="" export SORT_SUGS_DONE_$m="" export SORT_MAIN_DONE_$m="" done } _check_deps() { local module="$1" local mode="$2" local depmode="$3" eval deps=\$${mode}_$module #initially remove leading space deps=`echo ${deps//^[, ]}` while test -n "$deps"; do #the end of the name is marked either by space, opening parenthesis, #or comma name="${deps%%[ (,]*}" #remove the name and adjacent whitespace deps=`echo "$deps" | sed 's/^[^ (,]* *//'` #check whether there is a dependency version case "$deps" in '('*) deps="${deps#(}" depver="${deps%%)*}" deps="${deps#*)}" ;; *) depver= ;; esac #remove any leading whitespace or commas for the next iteration deps=`echo ${deps//^[, ]}` dep=$(fix_variable_name $name) if ! check_modname $dep; then echo "ERROR: invalid module name $name" >&2 exit 1 fi if test "x$(eval echo \$HAVE_$dep)" != "x"; then eval ver=\$VERS_$dep if test "$SKIPVERSIONCHECK" != "yes" && ! check_version "$ver" "$depver"; then echo "ERROR: version mismatch." >&2 echo " $modname requires $name $depver," >&2 echo " but only $name = $ver is available." >&2 exit 1 fi _sort_module $dep $depmode else # perhaps this module is installed, # then it should be handled via pkg-config if ! pkg-config $name; then echo "ERROR: could not find module $name," >&2 echo " module is also unknown to pkg-config." >&2 echo " Maybe you need to adjust PKG_CONFIG_PATH!" >&2 echo " $name is required by $modname" >&2 exit 1 else eval ver=$(pkg-config $name --modversion) if test "$SKIPVERSIONCHECK" != "yes" && ! check_version "$ver" "$depver"; then echo "ERROR: version mismatch." >&2 echo " $modname requires $name $depver," >&2 echo " but only $name = $ver is installed." >&2 exit 1 fi # update module list parse_control $(pkg-config $name --variable=prefix)/lib/dunecontrol/$name/dune.module _sort_module $dep $depmode fi fi done } # # recursive part of sort_modules # evaluate dependencies of one module # # paramters: # $1 name of the modules # _sort_module() { local module="$1" local mode="$2" test -n "$mode" local modname="" eval modname=\$NAME_$module local deps="" local name="" local dep="" local ver="" local depver="" shift 1 if ! check_modname $module; then echo "ERROR: invalid module name $module" >&2 exit 1 fi if test "x$(eval echo \$SORT_${mode}_DONE_$module)" != "xyes"; then # resolve dependencies depmode=$(test $mode = SUGS && echo SUGS || echo DEPS) _check_deps $module DEPS $depmode # it might happen that the DEPS are actually SUGS # resolve suggestions _check_deps $module SUGS SUGS # insert this module into the list export SORTEDMODULES_$mode="$(eval echo \$SORTEDMODULES_$mode) $module" export SORT_${mode}_DONE_$module=yes if test $mode = DEPS -o $mode = MAIN; then # it is sufficient to check that the module hasn't been handled yet, # as dependencies are handled before suggestions export SORTEDMODULES="$SORTEDMODULES $module" export SORTEDMODULES_INFO="$SORTEDMODULES_INFO $module[$mode]" fi fi } # # load the $CONTROL file, skip all control variables # and run a command # # parameters: # $1 command to execute # $2 full path of the $CONTROL file # eval_control() { local command="$1" local file="$2" shift 2 if test -f "$file"; then # open subshell ( set -e # load functions defined in $file # if $command is not defined in $file, # then the default implementation will be executed eval "$($GREP -v "^[-$ALNUM]\{1,\}:" $file)" # execute $command $command ) || false else echo "ERROR: could not find $file" >&2 exit 1 fi } # # fix a value such that it is suitable for a variable name # # parameters: # $1 value # fix_variable_name() { echo ${@//[[:punct:]]/_} } # # fix a value such that it is suitable for a variable name and assign it # # parameters: # $1 name of variable # $2 value # fix_and_assign() { local name="$1" if ! check_modname $name; then echo "ERROR: error in assignment. $name is not a valid variabel name." >&2 fi shift 1 export $name=$(fix_variable_name $@) } # # make sure the module name fits the naming convention # (we try to assign the name and report upon failure) # # parameters: # $1 module name # check_modname() { # magic pattern match, see http://www.linuxmisc.com/9-unix-questions/67d307ca51f16ed4.htm [ -n "${1##*[!A-Za-z0-9_]*}" ] && [ -n "${1##[!A-Za-z_]*}" ] } # # compare a sub part of the version string # # parameters: # $1 version # $2 part # # parts: # 1: major # 2: minor # 3: revision # get_sub_version() { #it would be nice to give the part to awk via a "-v FIELD=$2" #command line argument. Unfortunatly, SunOS does not support this. #Worse, we cannot use awks int() function here, since under SunOS it #will always return 0 for string input. echo $1 | cut -d. -f"$2" | sed 's/[^0-9].*$//;s/^$/0/' } # # compare two versions # # parameters: # $1 version1 # $2 version1 # # return: # 0: equal # 1: v1 > v2 # 2: v1 < v2 # compare_versions() { local v1="$1" local v2="$2" for i in 1 2 3; do compare_sub_version $v1 $v2 $i || return 0 done echo "eq" } compare_sub_version() { # compare sub version number local sub1=`get_sub_version $1 $3` local sub2=`get_sub_version $2 $3` if test $sub1 -gt $sub2; then echo "gt" return 1 fi if test $sub1 -lt $sub2; then echo "lt" return 1 fi return 0 } check_version() { if test -z "$2"; then # if no constraint is given, check_version is true return 0 fi local v=$1 local PATTERN="^ *\([<>=]*\) *\([0-9.]*\)\(.*\)$" if test x != `echo "$2" | sed -e "s/$PATTERN/x/"`; then echo "ERROR: invalid version constraint $2" >&2 exit 1 fi local op=`echo "$2" | sed -e "s/$PATTERN/\1/"` local v2=`echo "$2" | sed -e "s/$PATTERN/\2/"` local rest=`echo "$2" | sed -e "s/$PATTERN/\3/" -e 's/ //g'` local result=1 local rel=`compare_versions $v $v2` case $rel$op in "eq<="|"eq="|"eq>="|\ "gt>="|"gt>"|\ "lt<="|"lt<") result=0 ;; esac if test -z "$rest"; then return $result fi PATTERN="\([|&]\{2\}\)\(.*\)$" if test xx != x`echo "$rest" | sed -e "s/$PATTERN/x/"`; then echo "ERROR: invalid version constraint '$rest'" >&2 exit 1 fi op=`echo "$rest" | sed -e "s/$PATTERN/\1/"` v2=`echo "$rest" | sed -e "s/$PATTERN/\2/"` if eval "test $result -eq 0" $op "check_version \"$v\" \"$v2\""; then return 0 fi return 1 }