diff --git a/CHANGES b/CHANGES index 5857165c8d..7ca6b08d03 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,17 @@ --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ---------- ------------------------------------------------------------------------------ +Build System +------------------ + * The res_digium_phone, codec_g729a, codec_silk, codec_siren7 and + codec_siren14 binary modules hosted at downloads.digium.com can now be + automatically downloaded and installed during the Asterisk install + process. If selected in menuselect, when 'make install' is run, the + script will check the downloads site for a new version and download + and install it if needed. The '--with-externals-cache' option to + ./configure can be used to specify a location to cache the latest + tarballs so they don't have to be re-downloaded for every install. + app_voicemail ------------------ * Added "tps_queue_high" and "tps_queue_low" options. diff --git a/Makefile b/Makefile index bf8f0f89a1..992e1d3019 100644 --- a/Makefile +++ b/Makefile @@ -618,9 +618,10 @@ $(SUBDIRS_INSTALL): NEWMODS:=$(foreach d,$(MOD_SUBDIRS),$(notdir $(wildcard $(d)/*.so))) OLDMODS=$(filter-out $(NEWMODS) $(notdir $(DESTDIR)$(ASTMODDIR)),$(notdir $(wildcard $(DESTDIR)$(ASTMODDIR)/*.so))) +BADMODS=$(strip $(filter-out $(shell ./build_tools/list_valid_installed_externals),$(OLDMODS))) oldmodcheck: - @if [ -n "$(OLDMODS)" ]; then \ + @if [ -n "$(BADMODS)" ]; then \ echo " WARNING WARNING WARNING" ;\ echo "" ;\ echo " Your Asterisk modules directory, located at" ;\ @@ -630,7 +631,7 @@ oldmodcheck: echo " modules are compatible with this version before" ;\ echo " attempting to run Asterisk." ;\ echo "" ;\ - for f in $(OLDMODS); do \ + for f in $(BADMODS); do \ echo " $$f" ;\ done ;\ echo "" ;\ @@ -980,7 +981,7 @@ menuselect/nmenuselect: menuselect/makeopts .lastclean menuselect/makeopts: makeopts .lastclean +$(MAKE_MENUSELECT) makeopts -menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts +menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc) $(wildcard $(dir)/*.xml)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts @echo "Generating input for menuselect ..." @echo "" > $@ @echo >> $@ diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules index 9b5f3f13a2..95e62788f2 100644 --- a/Makefile.moddir_rules +++ b/Makefile.moddir_rules @@ -146,6 +146,18 @@ clean:: install:: all @echo "Installing modules from `basename $(CURDIR)`..." @for x in $(LOADABLE_MODS:%=%.so); do $(INSTALL) -m 755 $$x "$(DESTDIR)$(ASTMODDIR)" ; done +ifneq ($(findstring :,$(XMLSTARLET)$(BASH)),:) + @if [ -f .moduleinfo ] ; then \ + declare -A DISABLED_MODS ;\ + for x in $(MENUSELECT_$(MENUSELECT_CATEGORY)) ; do DISABLED_MODS[$${x}]=1 ; done ;\ + EXTERNAL_MODS=$$(xmlstarlet sel -t -m "/category/member[support_level = 'external']" -v "@name" -n .moduleinfo) ;\ + for x in $${EXTERNAL_MODS} ; do \ + if [ -z "$${DISABLED_MODS[$${x}]}" ] ; then \ + $(ASTTOPDIR)/build_tools/download_externals $${x} ;\ + fi ;\ + done ;\ + fi +endif uninstall:: diff --git a/build_tools/download_externals b/build_tools/download_externals new file mode 100755 index 0000000000..8d5872df79 --- /dev/null +++ b/build_tools/download_externals @@ -0,0 +1,180 @@ +#!/usr/bin/env bash + +if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then + shopt -s compat41 +fi +set -e + +ASTTOPDIR=${ASTTOPDIR:-.} + +module_name=$1 + +if [[ -z ${module_name} ]] ; then + echo "You must supply a module name." + exit 64 +fi + +tmpdir=$(mktemp -d) +if [[ -z "${tmpdir}" ]] ; then + echo "${module_name}: Unable to create temporary directory." + exit 1 +fi +trap "rm -rf ${tmpdir}" EXIT + +sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts +source ${tmpdir}/makeopts +if [[ -z "${ASTMODDIR}" ]] ; then + echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." + exit 1 +fi + +XMLSTARLET=${XMLSTARLET:-xmlstarlet} +if [[ "${XMLSTARLET}" = ":" ]] ; then + echo "${module_name}: The externals downloader requires xmlstarlet to be installed." + exit 1 +fi + +cache_dir="${EXTERNALS_CACHE_DIR}" +if [[ -z ${cache_dir} ]] ; then + cache_dir=${tmpdir} +fi + +version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR}) +if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then + echo "${module_name}: Couldn't parse version ${version}" + exit 1 +fi +major_version=${BASH_REMATCH[2]} + +if [[ "${major_version}" == "master" ]] ; then + echo "${module_name}: External module downloading is not available in the 'master' git branch. Please disable in menuselect and download manually." + exit 1 +fi + +major_version=${major_version}.0 + +if [[ "${HOST_CPU}" = "x86_64" ]] ; then + host_bits=64 +else + host_bits=32 +fi + +remote_url=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@remote_url" ${ASTTOPDIR}/menuselect-tree || :) +if [[ -n "${remote_url}" ]] ; then + remote_url="${remote_url}/asterisk-${major_version}/x86-${host_bits}" +else + directory_name=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@directory_name" ${ASTTOPDIR}/menuselect-tree || :) + remote_url="http://downloads.digium.com/pub/telephony/${directory_name:-${module_name}}/asterisk-${major_version}/x86-${host_bits}" +fi + +version_convert() { + local v=${1##*_} + if [[ ${v} =~ ([0-9]+)[.]([0-9]+)[.]([0-9]+) ]] ; then + v=$(( ${BASH_REMATCH[1]}<<18 | ${BASH_REMATCH[2]}<<9 | ${BASH_REMATCH[3]} )) + fi + echo ${v} +} + +${WGET} -q -O ${tmpdir}/manifest.xml ${remote_url}/manifest.xml || { + echo "${module_name}: Unable to fetch ${remote_url}/manifest.xml" + exit 1 +} + +rpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${tmpdir}/manifest.xml) +rpvi=$(version_convert ${rpv}) +echo "${module_name}: Remote package version ${rpv} (${rpvi})" + +module_dir=${module_name}-${rpv}-x86_${host_bits} +tarball=${module_dir}.tar.gz +export need_install=0 + +if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then + package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + ipv=$(${XMLSTARLET} sel -t -v "/package/@version" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + ipvi=$(version_convert ${ipv}) + ip_major=${ipv%_*} + echo "${module_name}: Installed package version ${ipv} (${ipvi})" + if [[ "${ip_major}" != "${major_version}" || "${package_arch}" != "x86_${host_bits}" ]] ; then + echo "${module_name}: The installed package is not for this version of Asterisk. Reinstalling." + need_install=1 + elif [[ ${rpvi} > ${ipvi} ]] ; then + echo "${module_name}: A newer package is available" + need_install=1 + else + sums=$(${XMLSTARLET} sel -t -m "//file" -v "@md5sum" -n ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml) + for sum in ${sums} ; do + install_path=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@install_path" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ) + f=${DESTDIR}$(eval echo ${install_path}) + if [[ ! -f ${f} ]] ; then + echo Not found: ${f} + need_install=1 + else + cs=$(md5sum ${f} | cut -b1-32) + if [[ "${cs}" != "${sum}" ]] ; then + echo Checksum mismatch: ${f} + need_install=1 + fi + fi + done + fi +else + need_install=1 +fi + +if [[ ${need_install} == 1 ]] ; then + if [[ ( -n "${ipvi}" ) && ${ipvi} > ${rpvi} ]] ; then + echo "${module_name}: Installed package is newer than that available for download." + exit 0 + fi +else + echo "${module_name} is up to date." + exit 0; +fi + +need_download=1 +if [[ -f ${cache_dir}/${module_name}.manifest.xml ]] ; then + cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${module_name}.manifest.xml) + cpvi=$(version_convert ${cpv}) + echo "${module_name}: Cached package version ${cpv} (${cpvi})" + if [[ ${cpvi} == ${rpvi} && ( -f ${cache_dir}/${tarball} ) ]] ; then + echo "${module_name}: Cached version is available." + need_download=0 + fi +fi + +if [[ ${need_download} = 1 ]] ; then + echo "${module_name}: Downloading ${remote_url}/${tarball}" + ${WGET} -q -O ${cache_dir}/${tarball} ${remote_url}/${tarball} || { + echo "${module_name}: Unable to fetch ${remote_url}/${tarball}" + exit 1 + } + cp ${tmpdir}/manifest.xml ${cache_dir}/${module_name}.manifest.xml +fi + +tar -xzf ${cache_dir}/${tarball} -C ${cache_dir} +trap "rm -rf ${cache_dir}/${module_dir} ; rm -rf ${tmpdir}" EXIT + +echo "${module_name}: Installing." + +if [[ $EUID == 0 ]] ; then + install_params="--group=0 --owner=0" +fi + +names=$(${XMLSTARLET} sel -t -m "//file" -v "@name" -n ${cache_dir}/${module_dir}/manifest.xml) +for name in ${names} ; do + source_path=${cache_dir}/${module_dir}/${name} + install_path=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@install_path" ${cache_dir}/${module_dir}/manifest.xml) + install_path=${DESTDIR}$(eval echo ${install_path}) + executable=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@executable" ${cache_dir}/${module_dir}/manifest.xml || :) + if [[ "${executable}" = "yes" ]] ; then + mode=0755 + else + mode=0644 + fi + + ${INSTALL} -Dp ${install_params} --mode=${mode} ${source_path} ${install_path} + +done +${INSTALL} -Dp ${install_params} --mode=0644 ${cache_dir}/${module_dir}/manifest.xml ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml + +echo "${module_name}: Installed." diff --git a/build_tools/list_valid_installed_externals b/build_tools/list_valid_installed_externals new file mode 100755 index 0000000000..12aff3f95a --- /dev/null +++ b/build_tools/list_valid_installed_externals @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then + shopt -s compat41 +fi +set -e + +ASTTOPDIR=${ASTTOPDIR:-.} + +tmpdir=$(mktemp -d) +if [[ -z "${tmpdir}" ]] ; then + echo "${module_name}: Unable to create temporary directory." + exit 1 +fi +trap "rm -rf ${tmpdir}" EXIT + +sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts +source ${tmpdir}/makeopts +if [[ -z "${ASTMODDIR}" ]] ; then + echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts." + exit 1 +fi + +XMLSTARLET=${XMLSTARLET:-xmlstarlet} +if [[ "${XMLSTARLET}" = ":" ]] ; then + echo "${module_name}: The externals downloader requires xmlstarlet to be installed." + exit 1 +fi + +version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR}) +if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then + echo "${module_name}: Couldn't parse version ${version}" + exit 1 +fi +major_version=${BASH_REMATCH[2]}.0 + +if [[ "${HOST_CPU}" = "x86_64" ]] ; then + host_bits=64 +else + host_bits=32 +fi + +names="" +for manifest in ${DESTDIR}${ASTMODDIR}/*.manifest.xml ; do + if [ ! -f "$manifest" ] ; then + break + fi + package_version=$(${XMLSTARLET} sel -t -v "/package/@version" ${manifest}) + package_major_version=${package_version%_*} + package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${manifest}) + if [[ "$package_major_version" = "$major_version" && "${package_arch}" = "x86_${host_bits}" ]] ; then + names+=$(${XMLSTARLET} sel -t -m "//file[@executable = 'yes']" -v "concat(@name, ' ')" ${manifest}) + fi +done +echo $names diff --git a/build_tools/make_version b/build_tools/make_version index fd14a550aa..3e0f4a0b0f 100755 --- a/build_tools/make_version +++ b/build_tools/make_version @@ -89,11 +89,13 @@ elif [ -d ${1}/.git ]; then if [ -z ${GIT} ]; then GIT="git" fi - + if ! command -v ${GIT} >/dev/null 2>&1; then echo "UNKNOWN__and_probably_unsupported" exit 1 fi + cd ${1} + # If the first log commit messages indicates that this is checked into # subversion, we'll just use the SVN- form of the revision. MODIFIED="" diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in index a044409555..9b077680e6 100644 --- a/build_tools/menuselect-deps.in +++ b/build_tools/menuselect-deps.in @@ -31,6 +31,8 @@ KQUEUE=@PBX_KQUEUE@ LDAP=@PBX_LDAP@ LIBEDIT=@PBX_LIBEDIT@ LIBXML2=@PBX_LIBXML2@ +XMLSTARLET=@PBX_XMLSTARLET@ +BASH=@PBX_BASH@ LTDL=@PBX_LTDL@ LUA=@PBX_LUA@ MISDN=@PBX_MISDN@ diff --git a/codecs/codecs.xml b/codecs/codecs.xml new file mode 100644 index 0000000000..ac3c6e6389 --- /dev/null +++ b/codecs/codecs.xml @@ -0,0 +1,25 @@ + + external + xmlstarlet + bash + no + + + external + xmlstarlet + bash + no + + + external + xmlstarlet + bash + no + + + external + xmlstarlet + bash + no + + diff --git a/configure b/configure index 3e5140ddb6..6aecaa0c6a 100755 --- a/configure +++ b/configure @@ -822,6 +822,7 @@ PBX_SPANDSP SPANDSP_DIR SPANDSP_INCLUDE SPANDSP_LIB +EXTERNALS_CACHE_DIR SOUNDS_CACHE_DIR PBX_SDL_IMAGE SDL_IMAGE_DIR @@ -1202,6 +1203,8 @@ PTHREAD_CC ax_pthread_config MD5 SOXMIX +PBX_BASH +PBX_XMLSTARLET PBX_FLEX PBX_BISON OPENSSL @@ -1211,6 +1214,7 @@ DOWNLOAD FETCH ALEMBIC GIT +BASH XMLSTARLET XMLLINT KPATHSEA @@ -1398,6 +1402,7 @@ with_resample with_sdl with_SDL_image with_sounds_cache +with_externals_cache with_spandsp with_ss7 with_speex @@ -2144,6 +2149,8 @@ Optional Packages: --with-SDL_image=PATH use Sdl Image files in PATH --with-sounds-cache=PATH use cached sound tarfiles in PATH + --with-externals-cache=PATH + use cached external module tarfiles in PATH --with-spandsp=PATH use SPANDSP files in PATH --with-ss7=PATH use ISDN SS7 files in PATH --with-speex=PATH use Speex files in PATH @@ -7489,6 +7496,47 @@ $as_echo "no" >&6; } fi +# Extract the first word of "bash", so it can be a program name with args. +set dummy bash; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BASH+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BASH in + [\\/]* | ?:[\\/]*) + ac_cv_path_BASH="$BASH" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BASH="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_BASH" && ac_cv_path_BASH=":" + ;; +esac +fi +BASH=$ac_cv_path_BASH +if test -n "$BASH"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BASH" >&5 +$as_echo "$BASH" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "git", so it can be a program name with args. set dummy git; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -7796,6 +7844,20 @@ else fi +if test "x${XMLSTARLET}" = "x:" ; then + PBX_XMLSTARLET=0 +else + PBX_XMLSTARLET=1 +fi + + +if test "x${BASH}" = "x:" ; then + PBX_BASH=0 +else + PBX_BASH=1 +fi + + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}soxmix", so it can be a program name with args. set dummy ${ac_tool_prefix}soxmix; ac_word=$2 @@ -11526,6 +11588,30 @@ fi + +# Check whether --with-externals-cache was given. +if test "${with_externals_cache+set}" = set; then : + withval=$with_externals_cache; + case ${withval} in + n|no) + unset EXTERNALS_CACHE_DIR + ;; + *) + if test "x${withval}" = "x"; then + : + else + EXTERNALS_CACHE_DIR="${withval}" + fi + ;; + esac + +else + : +fi + + + + SPANDSP_DESCRIP="SPANDSP" SPANDSP_OPTION="spandsp" PBX_SPANDSP=0 diff --git a/configure.ac b/configure.ac index 950cfc5a13..4995d615b5 100644 --- a/configure.ac +++ b/configure.ac @@ -281,6 +281,7 @@ AC_PATH_PROG([CATDVI], [catdvi], :) AC_PATH_PROG([KPATHSEA], [kpsewhich], :) AC_PATH_PROG([XMLLINT], [xmllint], :) AC_PATH_PROG([XMLSTARLET], [xmlstarlet], :) +AC_PATH_PROG([BASH], [bash], :) AC_PATH_PROG([GIT], [git], :) AC_PATH_PROG([ALEMBIC], [alembic], :) if test "${WGET}" != ":" ; then @@ -340,6 +341,20 @@ else fi AC_SUBST(PBX_FLEX) +if test "x${XMLSTARLET}" = "x:" ; then + PBX_XMLSTARLET=0 +else + PBX_XMLSTARLET=1 +fi +AC_SUBST(PBX_XMLSTARLET) + +if test "x${BASH}" = "x:" ; then + PBX_BASH=0 +else + PBX_BASH=1 +fi +AC_SUBST(PBX_BASH) + AC_CHECK_TOOL([SOXMIX], [soxmix], [:]) if test "${SOXMIX}" != ":" ; then AC_DEFINE([HAVE_SOXMIX], 1, [Define to 1 if your system has soxmix application.]) @@ -521,6 +536,7 @@ AST_EXT_LIB_SETUP([RESAMPLE], [LIBRESAMPLE], [resample]) AST_EXT_LIB_SETUP([SDL], [Sdl], [sdl]) AST_EXT_LIB_SETUP([SDL_IMAGE], [Sdl Image], [SDL_image]) AST_OPTION_ONLY([sounds-cache], [SOUNDS_CACHE_DIR], [cached sound tarfiles], []) +AST_OPTION_ONLY([externals-cache], [EXTERNALS_CACHE_DIR], [cached external module tarfiles], []) AST_EXT_LIB_SETUP([SPANDSP], [SPANDSP], [spandsp]) AST_EXT_LIB_SETUP([SS7], [ISDN SS7], [ss7]) AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex]) diff --git a/makeopts.in b/makeopts.in index f0b0d0ef51..86b7f9d99a 100644 --- a/makeopts.in +++ b/makeopts.in @@ -28,11 +28,13 @@ WGET=@WGET@ FETCH=@FETCH@ DOWNLOAD=@DOWNLOAD@ SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@ +EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@ RUBBER=@RUBBER@ CATDVI=@CATDVI@ KPATHSEA=@KPATHSEA@ XMLLINT=@XMLLINT@ XMLSTARLET=@XMLSTARLET@ +BASH=@BASH@ MD5=@MD5@ SHA1SUM=@SHA1SUM@ OPENSSL=@OPENSSL@ diff --git a/res/res.xml b/res/res.xml new file mode 100644 index 0000000000..e9cb5f962c --- /dev/null +++ b/res/res.xml @@ -0,0 +1,6 @@ + + external + xmlstarlet + bash + no +