Newer
Older
Markus Blatt
committed
###############################################
###
### Configuration
###
# name of the "control" files
CONTROL="dune.module"
###############################################
Markus Blatt
committed
# 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"
Markus Blatt
committed
#
# read paramters from a $CONTROL file
#
# paramters:
# $1 file to read
#
PARSER_TRIM="awk '{gsub(/^[[:space:]]+| +$/,\"\");printf(\"%s\", \$0);}'"
Markus Blatt
committed
parse_control() {
# check file existence
if test ! -f "$1" -o "$(basename $1)" != "$CONTROL"; then
echo "ERROR: '$1' is no $CONTROL file" >&2
Markus Blatt
committed
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)"
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"
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 eval test x\$INST_$module = "xyes"; 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
;;
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
return
;;
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"
Christian Engwer
committed
for name in $deps; do
mod=$(fix_variable_name $name)
Christian Engwer
committed
done
Christian Engwer
committed
for name in $sugs; do
mod=$(fix_variable_name $name)
Christian Engwer
committed
done
# update list of modules
if test "$module_inst" = "yes"; then
export INSTMODULES="$INSTMODULES$module "
else
export LOCALMODULES="$LOCALMODULES$module "
fi
Markus Blatt
committed
}
#
# 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() {
if test -z "$FOUND_MODULES"; then
# foreach dir in $@
while read dir; do
if test -d "$dir"; then
while read m; do
$(find -H "$dir" -name $CONTROL | $GREP -v 'dune-[-_a-zA-Z]/dune-[-a-zA-Z_]*-[0-9]\{1,\}.[0-9]\{1,\}/')
$(echo $DUNE_CONTROL_PATH | sed -e 's/:\+/:/g' | tr ':' '\n')
EOF
export MODULES="$LOCALMODULES$INSTMODULES"
export FOUND_MODULES="$MODULES"
Markus Blatt
committed
fi
}
#
# sort $MODULES according to the dependencies
#
sort_modules() {
Christian Engwer
committed
export SORTEDMODULES=""
export REVERSEMODULES=""
export SORTEDMODULES_SUB=""
Christian Engwer
committed
# handle each modules passed as parameter
Markus Blatt
committed
for m in "$@"; do
# did we find a module file for this module?
echo "ERROR: could not find module $(eval echo \$NAME_$m)" >&2
Markus Blatt
committed
done
# save result
export MODULES="$SORTEDMODULES"
# setup list of SUGS/DEPS and the INFO list
export SORTEDMODULES_INFO=""
export SORTEDMODULES_DEPS=""
export SORTEDMODULES_MAIN=""
export SORTEDMODULES_SUGS=""
local mode
for m in $MODULES; do
eval mode=\$MODE_$m
SORTEDMODULES_INFO="$SORTEDMODULES_INFO $m[$mode]"
eval SORTEDMODULES_$mode=\"\$SORTEDMODULES_$mode $m\"
done
export SORTEDMODULES_INFO
export SORTEDMODULES_DEPS
export SORTEDMODULES_SUGS
export SORTEDMODULES_MAIN
# clean up temporary variables
for m in $MODULES; do
export MODE_$m=""
export SORT_DONE_$m=""
export SORT_DEPS_DONE_$m=""
export SORT_SUGS_DONE_$m=""
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
_check_deps()
{
local module="$1"
local mode="$2"
local depmode="$3"
local report="ERROR"
local requires="requires"
local required="required"
if test "x$mode" = "xSUGS"; then
report="WARNING"
requires="suggests"
required="suggested"
fi
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 eval test x\$HAVE_$dep != "x"; then
eval ver=\$VERS_$dep
if test "$SKIPVERSIONCHECK" != "yes" && ! check_version "$ver" "$depver"; then
echo "$report: version mismatch." >&2
echo " $modname $requires $name $depver," >&2
echo " but only $name = $ver is available." >&2
if test "x$mode" = "xDEPS"; then
exit 1
else
echo "Skipping $name!" >&2
continue
fi
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 "$report: 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
if test "x$mode" = "xDEPS"; then
exit 1
else
echo "Skipping $name!" >&2
continue
fi
else
eval ver=$(pkg-config $name --modversion)
if test "$SKIPVERSIONCHECK" != "yes" && ! check_version "$ver" "$depver"; then
echo "$report: version mismatch." >&2
echo " $modname $requires $name $depver," >&2
echo " but only $name = $ver is installed." >&2
if test "x$mode" = "xDEPS"; then
exit 1
else
echo "Skipping $name!" >&2
continue
fi
fi
# update module list
parse_control $(pkg-config $name --variable=prefix)/lib/dunecontrol/$name/dune.module
_sort_module $dep $depmode
fi
fi
done
Markus Blatt
committed
#
# recursive part of sort_modules
# evaluate dependencies of one module
#
# paramters:
# $1 name of the modules
# $2 parser mode:
# DEPS: search for dependencies
# SUSG: search for suggestions (DEPS of SUGS are handled as SUGS)
# MAIN: primary invocation of a DEPS search,
# MAIN modules are not added to the list of DEPS/SUGS
Markus Blatt
committed
#
_sort_module() {
local modname=""
eval modname=\$NAME_$module
local deps=""
local name=""
local dep=""
local ver=""
local depver=""
Markus Blatt
committed
shift 1
if ! check_modname $module; then
echo "ERROR: invalid module name $module" >&2
exit 1
fi
depmode=$(test $mode = SUGS && echo SUGS || echo DEPS)
if eval test "x\$SORT_${depmode}_DONE_$module" != "xyes"; then
# stop any recursion
export SORT_${depmode}_DONE_$module=yes
Markus Blatt
committed
# resolve dependencies
_check_deps $module DEPS $depmode # it might happen that the DEPS are actually SUGS
Markus Blatt
committed
# resolve suggestions
_check_deps $module SUGS SUGS
# remember mode of the module
if eval test "x\$MODE_$module" = xSUGS -o "x\$MODE_$module" = x; then
export MODE_$module=$mode
fi
# topological list of the module and its dependencies/suggestions
if eval test "x\$SORT_DONE_$module" != "xyes"; then
export SORT_DONE_$module=yes
export REVERSEMODULES="$module $REVERSEMODULES"
Markus Blatt
committed
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() {
Markus Blatt
committed
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)"
Markus Blatt
committed
# execute $command
$command
) || false
else
echo "ERROR: could not find $file" >&2
Markus Blatt
committed
exit 1
fi
}
# fix a value such that it is suitable for a variable name
fix_variable_name() {
}
#
# fix a value such that it is suitable for a variable name and assign it
#
# parameters:
# $1 name of variable
# $2 value
#
echo "ERROR: error in assignment. $name is not a valid variabel name." >&2
export $name=$(fix_variable_name $@)
Markus Blatt
committed
#
# make sure the module name fits the naming convention
# (we try to assign the name and report upon failure)
Markus Blatt
committed
#
# 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_]*}" ]
Markus Blatt
committed
}
#
# 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/'
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
#
# 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
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
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