diff --git a/maintainer/gen-versions.sh b/maintainer/gen-versions.sh index c13abd27..af58b8b4 100755 --- a/maintainer/gen-versions.sh +++ b/maintainer/gen-versions.sh @@ -1,293 +1,316 @@ #!/bin/bash -# Where the version configs are generated -config_dir=config/versions -defaults=packages/default.desc +######################################## +# Common meta-language implementation -declare -A forks +declare -A info debug() { - if [ -n "${DEBUG}" ]; then - echo ":: $@" >&2 - fi + if [ -n "${DEBUG}" ]; then + echo "DEBUG :: $@" >&2 + fi } -read_files() +warn() { - local f l - - for f in ${defaults} "$@"; do - [ -r "${f}" ] || continue - while read l; do - case "${l}" in - "#*") continue;; - *) echo "[${l%%=*}]=${l#*=}";; - esac - done < "${f}" - done + echo "WARN :: $@" >&2 } -derived_package() +error() { - info[name]=${p} - info[forks]=${forks[${p}]} - info[master]=${info[master]:-${p}} - # Various kconfig-ized prefixes - tmp=${p^^} - info[pfx]=${tmp//[^0-9A-Z_]/_} - tmp=${info[origin]^^} - info[originpfx]=${tmp//[^0-9A-Z_/_} - tmp=${info[master]^^} - info[masterpfx]=${tmp//[^0-9A-Z_/_} + echo "ERROR :: $@" >&2 + exit 1 +} + +find_end() +{ + local token="${1}" + local count=1 + + # Skip first line, we know it has the proper '#!' command on it + endline=$[l + 1] + while [ "${endline}" -le "${end}" ]; do + case "${tlines[${endline}]}" in + "#!${token} "*) + count=$[count + 1] + ;; + "#!end-${token}") + count=$[count - 1] + ;; + esac + if [ "${count}" = 0 ]; then + return + fi + endline=$[endline + 1] + done + error "line ${l}: '${token}' token is unpaired" +} + +set_iter() +{ + local name="${1}" + + if [ "${info[iter_${name}]+set}" = "set" ]; then + error "Iterator over '${name}' is already set up" + fi + shift + debug "Setting iterator over '${name}' to '$*'" + info[iter_${name}]="$*" +} + +run_if() +{ + local cond="${1}" + local endline + + find_end "if" + if eval "${cond}"; then + debug "True conditional '${cond}' at lines ${l}..${endline}" + run_lines $[l + 1] $[endline - 1] + else + debug "False conditional '${cond}' at lines ${l}..${endline}" + fi + lnext=$[endline + 1] + debug "Continue at line ${lnext}" +} + +do_foreach() +{ + local var="${1}" + local v saveinfo + + shift + if [ "`type -t enter_${var}`" != "function" ]; then + error "No parameter setup routine for iterator over '${var}'" + fi + for v in ${info[iter_${var}]}; do + saveinfo=`declare -p info` + eval "enter_${var} ${v}" + eval "$@" + eval "${saveinfo#declare -A }" + done +} + +run_foreach() +{ + local var="${1}" + local endline + + if [ "${info[iter_${var}]+set}" != "set" ]; then + error "line ${l}: iterator over '${var}' is not defined" + fi + find_end "foreach" + debug "Loop over '${var}', lines ${l}..${endline}" + do_foreach ${var} run_lines $[l + 1] $[endline - 1] + lnext=$[endline + 1] + debug "Continue at line ${lnext}" +} + +run_lines() +{ + local start="${1}" + local end="${2}" + local l lnext s v + + debug "Running lines ${start}..${end}" + l=${start} + while [ "${l}" -le "${end}" ]; do + lnext=$[l+1] + s="${tlines[${l}]}" + # Expand @@foo@@ to ${info[foo]}. First escape quotes/backslashes. + s="${s//\\/\\\\}" + s="${s//\$/\\\$}" + while [ -n "${s}" ]; do + case "${s}" in + *@@*@@*) + v="${s#*@@}" + v="${v%%@@*}" + if [ "${info[${v}]+set}" != "set" ]; then + error "line ${l}: reference to undefined variable '${v}'" + fi + s="${s%%@@*}\${info[${v}]}${s#*@@*@@}" + ;; + *@@*) + error "line ${l}: non-paired @@ markers" + ;; + *) + break + ;; + esac + done + + debug "Evaluate: ${s}" + case "${s}" in + "#!if "*) + run_if "${s#* }" + ;; + "#!foreach "*) + run_foreach "${s#* }" + ;; + "#!"*) + error "line ${l}: unrecognized command" + ;; + *) + # Not a special command + eval "echo \"${s//\"/\\\"}\"" + ;; + esac + l=${lnext} + done +} + +run_template() +{ + local -a tlines + local src="${1}" + + debug "Running template ${src}" + mapfile -O 1 -t tlines < "${src}" + run_lines 1 ${#tlines[@]} +} + +######################################## + +# Where the version configs are generated +config_dir=config/versions +template=maintainer/kconfig-versions.template + +declare -A pkg_forks +declare -a pkg_masters pkg_nforks pkg_all + +kconfigize() +{ + local v="${1}" + + v=${v//[^0-9A-Za-z_]/_} + echo "${v^^}" +} + +read_file() +{ + local l + + while read l; do + case "${l}" in + "#*") continue;; + *) echo "info[${l%%=*}]=${l#*=}";; + esac + done < "${1}" } read_package_desc() { - read_files "packages/${1}/package.desc" + read_file "packages/${1}/package.desc" } read_version_desc() { - read_files "packages/${1}/package.desc" "packages/${1}/${2}/version.desc" + read_file "packages/${1}/${2}/version.desc" } -for_each_package() -{ - local list="${1}" - local -A info - local p tmp - - debug "Entering: for_each_package $@" - - shift - for p in ${list}; do - eval "info=( `read_package_desc ${p}` )" - derived_package ${p} - debug "Evaluate for ${p}: $@" - eval "$@" - done -} - -for_each_version() -{ - local pkg="${1}" - local -A info prev - local -a versions - local v tmp - - debug "Entering: for_each_version $@" - - shift - versions=( `cd packages/${pkg} && ls */version.desc 2>/dev/null | sed 's,/version.desc$,,' | sort -rV` ) - tmp= - for v in "${versions[@]}"; do - if [ -n "${tmp}" ]; then - prev["${tmp}"]=${v} - fi - tmp="${v}" - done - - if [ -n "${tmp}" ]; then - prev["${tmp}"]= - fi - - for v in "${versions[@]}"; do - eval "info=( `read_version_desc "${pkg}" "${v}"` )" - debug "INFO [[ `read_version_desc "${pkg}" "${v}"` ]]" - derived_package ${pkg} - info[ver]="${v}" - info[kcfg]="${v//[^0-9A-Za-z_]/_}" - info[prev]="${prev[${v}]//[^0-9A-Za-z_]/_}" - debug "Evaluate for ${pkg}/${v}: $@" - eval "$@" - done -} - -# Setup: find master-fork relationships between packages find_forks() { - [ "${info[master]}" != "${info[name]}" ] && forks[${info[master]}]+=" ${info[name]}" + local -A info + + eval `read_package_desc ${1}` + + if [ -n "${info[master]}" ]; then + pkg_nforks[${info[master]}]=$[pkg_nforks[${info[master]}]+1] + pkg_forks[${info[master]}]+=" ${1}" + else + pkg_nforks[${1}]=$[pkg_nforks[${1}]+1] + pkg_forks[${1}]="${1}${pkg_forks[${1}]}" + pkg_masters+=( "${1}" ) + fi } -gen_versions() +check_obsolete_experimental() { - local cond=$1 - - debug "Entering: gen_versions $@" - - if [ -n "${cond}" ]; then - cat <"${config_dir}/${info[name]}.in" - cat </dev/null | sed 's,/package.desc$,,' | xargs echo` +pkg_all=( `cd packages && \ + ls */package.desc 2>/dev/null | \ + while read f; do [ -r "${f}" ] && echo "${f%/package.desc}"; done | \ + xargs echo` ) debug "Generating package version descriptions" -debug "Packages: ${all_packages}" -for_each_package "${all_packages}" find_forks -for_each_package "${all_packages}" gen_one_component -debug "Done!" +debug "Packages: ${pkg_all[@]}" + +# We need to group forks of the same package into the same +# config file. Discover such relationships and only iterate +# over "master" packages at the top. +for p in "${pkg_all[@]}"; do + find_forks "${p}" +done +debug "Master packages: ${pkg_masters[@]}" + +# Now for each master, create its kconfig file with version +# definitions. +for p in "${pkg_masters[@]}"; do + debug "Generating '${config_dir}/${p}.in'" + exec >"${config_dir}/${p}.in" + # Base definitions for the whole config file + info=( \ + [master]=${p} \ + [masterpfx]=`kconfigize ${p}` \ + [nforks]=${pkg_nforks[${p}]} \ + ) + set_iter fork ${pkg_forks[${p}]} + run_template "${template}" +done diff --git a/maintainer/kconfig-versions.template b/maintainer/kconfig-versions.template new file mode 100644 index 00000000..7aa0de17 --- /dev/null +++ b/maintainer/kconfig-versions.template @@ -0,0 +1,129 @@ +# +# DO NOT EDIT! This file is automatically generated. +# + +#!if [ "@@nforks@@" -ge 2 ] +choice + bool "Show @@master@@ versions from" + +#!foreach fork +config @@masterpfx@@_USE_@@originpfx@@ + bool "@@origin@@" +#!if [ -n "@@only_obsolete@@" ] + depends on OBSOLETE +#!end-if +#!if [ -n "@@only_experimental@@" ] + depends on EXPERIMENTAL +#!end-if + help +@@originhelp@@ + +#!end-foreach +endchoice + +config @@masterpfx@@_USE + string +#!foreach fork + default "@@pfx@@" if @@masterpfx@@_USE_@@originpfx@@ +#!end-foreach + +#!end-if + +#!foreach fork +#!if [ "@@nforks@@" -ge 2 ] +if @@masterpfx@@_USE_@@originpfx@@ +#!end-if + +if EXPERIMENTAL +choice + bool "Source of @@name@@" + +config @@pfx@@_SRC_RELEASE + bool "Released tarball" + help + Download a released tarball. + +#!if [ -n "@@repository@@" ] +config @@pfx@@_SRC_DEVEL + bool "Vendor repository" + help + Check out from vendor repository at: + @@repository@@ +#!end-if + +config @@pfx@@_SRC_CUSTOM + bool "Custom location" + help + Custom directory or tarball. + +endchoice +endif + +#!if [ -n "@@repository@@" ] +if @@pfx@@_SRC_DEVEL + +config @@pfx@@_DEVEL_VCS + string + default "@@vcs@@" + +config @@pfx@@_DEVEL_URL + string + default "@@repository_url@@" + +config @@pfx@@_DEVEL_BRANCH + string "Branch to check out" + default "@@repository_dflt_branch@@" + help + Git: branch to be checked out + Subversion: directories to append to the repository URL. + +config @@pfx@@_DEVEL_REVISION + string "Revision/changeset" + default "HEAD" + help + Commit ID or revision ID to check out. + +endif +#!end-if + +if @@pfx@@_SRC_CUSTOM + +config @@pfx@@_CUSTOM_LOCATION + string "Custom source location" + help + Path to the directory or tarball with the sources. + +endif + +choice + bool "Version of @@name@@" + +#!foreach version +config @@pfx@@_V_@@kcfg@@ + bool "@@ver@@" + select @@pfx@@_V_@@kcfg@@_or_later + +#!end-foreach +endchoice + +#!if [ "@@nforks@@" -ge 2 ] +endif +#!end-if + +config @@pfx@@_VERSION + string +#!foreach version + default "@@ver@@" if @@pfx@@_V_@@kcfg@@ +#!end-foreach + default "unknown" + +#!foreach version +config @@pfx@@_V_@@kcfg@@_or_later + bool +#!if [ -n "@@prev@@" ] + select @@pfx@@_V_@@prev@@_or_later +#!end-if + +#!end-foreach + +#!end-foreach