9b2b841821fd275a5b53459172b18de9b6bb5e0f
[asterisk/asterisk.git] / build_tools / download_externals
1 #!/usr/bin/env bash
2
3 if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then
4         shopt -s compat41
5 fi
6 set -e
7
8 ASTTOPDIR=${ASTTOPDIR:-.}
9
10 module_name=${1%%-*}
11 variant=${1##*-}
12
13 if [[ "${variant}" = "${module_name}" ]] ; then
14         unset variant
15 fi
16
17 if [[ -z ${module_name} ]] ; then
18         echo "You must supply a module name."
19         exit 64
20 fi
21
22 tmpdir=$(mktemp -d)
23 if [[ -z "${tmpdir}" ]] ; then
24         echo "${module_name}: Unable to create temporary directory."
25         exit 1
26 fi
27 trap "rm -rf ${tmpdir}" EXIT
28
29 sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts
30 source ${tmpdir}/makeopts
31 if [[ -z "${ASTMODDIR}" ]] ; then
32         echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts."
33         exit 1
34 fi
35
36 XMLSTARLET=${XMLSTARLET:-xmlstarlet}
37 if [[ "${XMLSTARLET}" = ":" ]] ; then
38         echo "${module_name}: The externals downloader requires xmlstarlet to be installed."
39         exit 1
40 fi
41
42 cache_dir="${EXTERNALS_CACHE_DIR}"
43 if [[ -z ${cache_dir} ]] ; then
44         cache_dir=${tmpdir}
45 fi
46
47 version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR})
48 if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then
49         echo "${module_name}: Couldn't parse version ${version}"
50         exit 1
51 fi
52 major_version=${BASH_REMATCH[2]}
53
54 if [[ "${major_version}" == "master" ]] ; then
55         echo "${module_name}: External module downloading is not available in the 'master' git branch.  Please disable in menuselect and download manually."
56         exit 1
57 fi
58
59 major_version=${major_version}.0
60
61 if [[ "${HOST_CPU}" = "x86_64" ]] ; then
62         host_bits=64
63 else
64         host_bits=32
65 fi
66
67 if [[ -z "${variant}" ]] ; then
68         variants=$(${XMLSTARLET} sel -t -m "/menu/category/member[@name = '${module_name}']/member_data/downloader/variants/variant" -v "@tag" -n ${ASTTOPDIR}/menuselect-tree || :)
69         member_name=${module_name}
70         for tag in ${variants} ; do
71                 condition=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/variants/variant[@tag = '${tag}']/@condition" ${ASTTOPDIR}/menuselect-tree || :)
72                 variant=$(eval "if $condition ; then echo $tag ; fi")
73                 if [[ -n "${variant}" ]] ; then
74                         break
75                 fi
76         done
77 else
78         member_name=${module_name}${variant:+-${variant}}
79 fi
80
81 full_name=${module_name}${variant:+-${variant}}
82 variant_manifest=manifest${variant:+-${variant}}.xml
83
84 # Override the remote base for all packages
85 # useful for testing
86 remote_url=${REMOTE_BASE:+${REMOTE_BASE}/asterisk-${major_version}/x86-${host_bits}}
87
88 if [[ -z "${remote_url}" ]] ; then
89         remote_url=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${member_name}']/member_data/downloader/@remote_url" ${ASTTOPDIR}/menuselect-tree || :)
90         if [[ -n "${remote_url}" ]] ; then
91                 remote_url="${remote_url}/asterisk-${major_version}/x86-${host_bits}"
92         else
93                 directory_name=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${member_name}']/member_data/downloader/@directory_name" ${ASTTOPDIR}/menuselect-tree || :)
94                 remote_url="http://downloads.digium.com/pub/telephony/${directory_name:-${module_name}}/asterisk-${major_version}/x86-${host_bits}"
95         fi
96 fi
97
98 version_convert() {
99         local v=${1##*_}
100         if [[ ${v} =~ ([0-9]+)[.]([0-9]+)[.]([0-9]+) ]] ; then
101                 v=$(( ${BASH_REMATCH[1]}<<18 | ${BASH_REMATCH[2]}<<9 | ${BASH_REMATCH[3]} ))
102         fi
103         echo ${v}
104 }
105
106 ${WGET} -q -O ${tmpdir}/${variant_manifest} ${remote_url}/${variant_manifest} || {
107         echo "${full_name}: Unable to fetch ${remote_url}/${variant_manifest}"
108         exit 1
109 }
110
111 rpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${tmpdir}/${variant_manifest})
112 rpvi=$(version_convert ${rpv})
113 echo "${full_name}: Remote package version ${rpv} (${rpvi})"
114
115 module_dir=${full_name}-${rpv}-x86_${host_bits}
116 tarball=${module_dir}.tar.gz
117
118 export need_install=0
119
120 if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then
121         package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml)
122         ipv=$(${XMLSTARLET} sel -t -v "/package/@version" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml)
123         package_variant=$(${XMLSTARLET} sel -t -v "/package/@variant" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml || :)
124         ipvi=$(version_convert ${ipv})
125         ip_major=${ipv%_*}
126         echo "${full_name}: Installed package version ${ipv} (${ipvi})"
127         if [[ "${ip_major}" != "${major_version}" || "${package_arch}" != "x86_${host_bits}" || "${package_variant}" != "${variant}" ]] ; then
128                 echo "${full_name}: The installed package is not for this version of Asterisk.  Reinstalling."
129                 need_install=1
130         elif [[ ${rpvi} > ${ipvi} ]] ; then
131                 echo "${full_name}: A newer package is available"
132                 need_install=1
133         else
134                 sums=$(${XMLSTARLET} sel -t -m "//file" -v "@md5sum" -n ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml)
135                 for sum in ${sums} ; do
136                         install_path=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@install_path" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml )
137                         executable=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@executable" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml )
138                         f=${DESTDIR}$(eval echo ${install_path})
139                         if [[ ! -f ${f} ]] ; then
140                                 echo Not found: ${f}
141                                 need_install=1
142                                 break
143                         else
144                                 if [[ "$executable" = "yes" ]] ; then
145                                         # There are easier ways of doing this (objcopy --dump-section) but not in older bunutils
146                                         length_offset=$(objdump -h $f | sed -n -r -e "s/^\s+[0-9]+\s+.ast_manifest\s+([0-9a-fA-F]+)\s+[0-9a-fA-F]+\s+[0-9a-fA-F]+\s+([0-9a-fA-F]+)\s+.*$/0x\1 0x\2/p")
147                                         tags=$($(eval 'printf "dd if=$f bs=1 count=%d skip=%d\n" $length_offset') 2>/dev/null)
148                                         if [[ -n "${tags}" && "${tags}" != "${module_name},${variant},${rpv}" ]] ; then
149                                                 echo Tag mismatch: ${f} File: "${tags}" Manifest: "${module_name},${variant},${rpv}"
150                                                 need_install=1
151                                                 break
152                                         fi
153                                 fi
154
155                                 cs=$(md5sum ${f} | cut -b1-32)
156                                 if [[ "${cs}" !=  "${sum}" ]] ; then
157                                         echo Checksum mismatch: ${f}
158                                         need_install=1
159                                         break
160                                 fi
161                         fi
162                 done
163         fi
164 else
165         need_install=1
166 fi
167
168 if [[ ${need_install} == 1 ]] ; then
169         if [[ ( -n "${ipvi}" ) && ${ipvi} > ${rpvi} ]] ; then
170                 echo "${full_name}: Installed package is newer than that available for download."
171                 exit 0
172         fi
173 else
174         echo "${full_name} is up to date."
175         exit 0;
176 fi
177
178 need_download=1
179 if [[ -f ${cache_dir}/${full_name}.manifest.xml ]] ; then
180         cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${full_name}.manifest.xml)
181         cpvi=$(version_convert ${cpv})
182         echo "${full_name}: Cached package version ${cpv} (${cpvi})"
183         if [[ ${cpvi} == ${rpvi} && ( -f ${cache_dir}/${tarball} ) ]] ; then
184                 echo "${full_name}: Cached version is available."
185                 need_download=0
186         fi
187 fi
188
189 if [[ ${need_download} = 1 ]] ; then
190         echo "${full_name}: Downloading ${remote_url}/${tarball}"
191         ${WGET} -q -O ${cache_dir}/${tarball} ${remote_url}/${tarball} || {
192                 echo "${full_name}: Unable to fetch ${remote_url}/${tarball}"
193                 exit 1
194         }
195         cp ${tmpdir}/${variant_manifest}  ${cache_dir}/${full_name}.manifest.xml
196 fi
197
198 tar -xzf ${cache_dir}/${tarball} -C ${cache_dir}
199 trap "rm -rf ${cache_dir}/${module_dir} ; rm -rf ${tmpdir}" EXIT
200
201 echo "${full_name}: Installing."
202
203 if [[ $EUID == 0 ]] ; then
204         install_params="--group=0 --owner=0"
205 fi
206
207 names=$(${XMLSTARLET} sel -t -m "//file" -v "@name" -n ${cache_dir}/${module_dir}/manifest.xml)
208 for name in ${names} ; do
209         source_path=${cache_dir}/${module_dir}/${name}
210         install_path=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@install_path" ${cache_dir}/${module_dir}/manifest.xml)
211         install_path=${DESTDIR}$(eval echo ${install_path})
212         executable=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@executable" ${cache_dir}/${module_dir}/manifest.xml || :)
213         if [[ "${executable}" = "yes" ]] ; then
214                 mode=0755
215         else
216                 mode=0644
217         fi
218
219         ${INSTALL} -Dp ${install_params} --mode=${mode} ${source_path} ${install_path}
220
221 done
222 ${INSTALL} -Dp ${install_params} --mode=0644 ${cache_dir}/${module_dir}/manifest.xml ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml
223
224 echo "${full_name}: Installed."