doc/install/automatic: palm_installer

File palm_installer, 20.1 KB (added by knoop, 4 years ago)

Automaitic PALM installer script.

Line 
1#!/usr/bin/env bash
2#------------------------------------------------------------------------------#
3# This file is part of PALM.
4#
5# PALM is free software: you can redistribute it and/or modify it under the
6# terms of the GNU General Public License as published by the Free Software
7# Foundation, either version 3 of the License, or (at your option) any later
8# version.
9#
10# PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along with
15# PALM. If not, see <http://www.gnu.org/licenses/>.
16#
17# Copyright 1997-2018  Leibniz Universitaet Hannover
18#------------------------------------------------------------------------------#
19# palm_installer - an automatic installation scipt for PALM
20#------------------------------------------------------------------------------#
21
22# script version
23installer_version="v0.6.2"
24
25# log all output of this script in a file
26this_script=$(basename $0)
27logfile_all="$(pwd)/palm_installer.log"
28rm -f ${logfile_all}
29exec >  >(tee -ia ${logfile_all})
30exec 2> >(tee -ia ${logfile_all} >&2)
31
32# opens a terminal in case started with a double click
33if [ ! -t 0 ]; then
34   if type konsole > /dev/null; then
35      konsole --noclose -e $@
36   elif type terminal > /dev/null; then
37      xterm -hold -e $@
38   fi
39   exit 0
40fi
41
42get_number_of_cpu_cores() {
43   {
44      # OSX
45      n=$(sysctl -n machdep.cpu.core_count 2> /dev/null)
46   } || {
47      # Linux
48      n=$(grep -c ^processor /proc/cpuinfo 2> /dev/null)
49   } || {
50      # fallback
51      if ! [[ $n =~ ^-?[0-9]+$ ]]; then
52         n=2
53      fi
54   }
55   echo $n
56}
57
58install_prefix=${HOME}/palm/current_version
59shell_profile=${HOME}/.bashrc
60program_name="PALM"
61NUM_PROC_BUILD=$(get_number_of_cpu_cores)
62max_cores_test=4
63NUM_PROC_TEST=$(($NUM_PROC_BUILD<${max_cores_test}?$NUM_PROC_BUILD:${max_cores_test}))
64palm_base_url="https://palm.muk.uni-hannover.de"
65palm_svn_url="${palm_base_url}/svn/palm/trunk"
66palm_min_rev=2774
67number_of_cols=70
68logfile_test="palm_test.log"
69
70palm_installer_url="http://palm.muk.uni-hannover.de/trac/raw-attachment/wiki/doc/install/automatic/palm_installer"
71newest_installer_version=$(wget -qO- ${palm_installer_url} | \
72                           sed -n '/installer_version=\"v.*/p' | \
73                           sed  's/installer_version=\"\(v.*\)\"/\1/g')
74
75palm_installer_update() {
76   hrule
77   if [[ "${newest_installer_version}" == "" ]]; then
78      printf "| \e[1;33m%-${number_of_cols}s\e[0m |\n" "Please make sure you are using the latest ${program_name} installer version."
79   elif [[ "${newest_installer_version}" == "${installer_version}" ]]; then
80      printf "| \e[1;32m%-${number_of_cols}s\e[0m |\n" "This automatic installer is up to date."
81   else
82      printf "\e[1;33m%-${number_of_cols}s\e[0m\n" "This automatic installer is outdated!"
83      palm_read_yn "Do you wish to update to ${newest_installer_version}?" "RESPONSE_INSTALLER_UPDATE"
84      if [[ "$RESPONSE_INSTALLER_UPDATE" == "y" ]]; then
85         if wget ${palm_installer_url} --output-document=${this_script} &> /dev/null ; then
86            printf "\e[1;32m%-${number_of_cols}s\e[0m\n" "Successfully updated to ${newest_installer_version}"
87            bash ${this_script}
88            exit 0
89         else
90            printf "\e[1;33m%-${number_of_cols}s\e[0m\n"  "Update failed. Please manually download the newest installer from."
91            printf "\e[1;33m%-${number_of_cols}s\e[0m\n"  "   https://palm.muk.uni-hannover.de/trac/wiki/doc/install#automatic"
92            palm_installer_abort_message
93         fi
94      else
95         printf "\e[1;33m%-${number_of_cols}s\e[0m\n"  "WARNING: You are using an outdated ${program_name} installer."
96         printf "\e[1;33m%-${number_of_cols}s\e[0m\n"  "         You will not get any support in case something goes wrong."
97      fi
98   fi
99}
100
101palm_installer_check_software_all() {
102   hrule
103   printf "%s\n" "Checking general software requirements..."
104   palm_installer_check_software_required "a Fortran compiler" ifort ftn gfortran mpif90
105   palm_installer_check_software_required "mpirun" mpirun
106   palm_installer_check_software_optional "svn" "${program_name} has to be downloaded manually" svn
107   palm_installer_check_software_required "make" make
108   palm_installer_check_software_required "cmake" cmake
109   palm_installer_check_software_optional "python3" "The GUI will not be available" python3
110   if [[ "${required_software_available}" == "false" ]]; then
111      hrule
112      printf "| \e[1;31m%-${number_of_cols}s\e[0m |\n" "Please provide missing software and try again!"
113      palm_installer_abort_message
114   fi
115   if [[ "${optional_software_available}" == "false" ]]; then
116      printf "\e[1;33m%s\e[0m\n" "Some optional software is missing."
117      palm_read_yn "Do you wish to continue anyways?" "RESPONSE_CONTINUE"
118      hrule
119      if [[ "$RESPONSE_CONTINUE" == "y" ]]; then
120         printf "| \e[1;33m%-${number_of_cols}s\e[0m |\n"  "Some optional software is missing. Continue anyways..."
121      else
122         printf "| \e[1;31m%-${number_of_cols}s\e[0m |\n" "Please provide missing software and try again!"
123         palm_installer_abort_message
124      fi
125   else
126      hrule
127      printf "| \e[1;32m%-${number_of_cols}s\e[0m |\n"  "All required software found. Lets continue..."
128   fi
129}
130
131palm_installer_check_software() {
132   local software_found="false"
133   for current_software in ${@}; do
134      if command -v ${current_software} > /dev/null; then
135         local software_found="true"
136         local found_software="${found_software} ${current_software}"
137      fi
138   done
139   if [[ "${software_found}" == "false" ]]; then
140      return 1
141   else
142      echo "${found_software}"
143      return 0
144   fi
145   
146}
147
148palm_installer_check_software_required() {
149   local description=${1}
150   shift
151   printf "%s %-25s " "-- Looking for" "${description}..."
152   if palm_installer_check_software ${@} > /dev/null; then
153      printf "\e[1;32mfound\e[0m$(palm_installer_check_software ${@})"
154   else
155      printf "\e[1;31mnot found!\e[0m"
156      required_software_available="false"
157   fi
158   printf "\n"
159}
160
161palm_installer_check_software_optional() {
162   local description=${1}
163   shift
164   local feature=${1}
165   shift
166   printf "%s %-25s " "-- Looking for" "${description} (optional)..."
167   if palm_installer_check_software ${@} > /dev/null; then
168      printf "\e[1;32mfound\e[0m$(palm_installer_check_software ${@})"
169   else
170      printf "\e[1;33mnot found!\e[0m (${feature})"
171      optional_software_available="false"
172   fi
173   printf "\n"
174}
175
176# clean any old build and promt the user for all required info for installation
177palm_installer_init() {
178   hrule
179   printf "\n"
180   printf "The default installation directory is \"${install_prefix}\".\n"
181   palm_read_yn "Do you wish to install ${program_name} in the default directory?" "RESPONSE_PREFIX"
182   if [[ "$RESPONSE_PREFIX" != "y" ]]; then
183      read -p "-- Please enter a new installation directory: " CUSTOM_PREFIX
184      local input_dir=$(eval echo $CUSTOM_PREFIX)
185      local tmp=""
186      while ! readlink -f $input_dir > /dev/null; do
187         tmp="/$(basename $input_dir)${tmp}"
188         input_dir=$(dirname $input_dir)
189      done
190      install_prefix="$(readlink -f $input_dir)${tmp}"
191   fi
192   trunk_dir=${install_prefix}/trunk
193   source_dir=${install_prefix}/.installer.tmp
194   build_dir=${source_dir}/build
195   printf "%s \"\e[1;32m${install_prefix}\e[0m\"\n" "-- ${program_name} will be installed in:"
196   printf "\n"
197   
198   AVAILABLE_FORTRAN_COMPILER=$(palm_installer_check_software ftn mpif90 ifort gfortran)
199   CUSTOM_FORTRAN_COMPILER=$(echo ${AVAILABLE_FORTRAN_COMPILER} | awk '{print $1;}')
200   printf "%s\n" "Available Fortran compilers on this computer:${AVAILABLE_FORTRAN_COMPILER}"
201   printf "%s \"\e[1;32m${CUSTOM_FORTRAN_COMPILER}\e[0m\".\n" "-- The default Fortran compiler for this installation is"
202   palm_read_yn "Do you wish to use the default Fortran compiler?" "RESPONSE_COMPILER"
203   if [[ "$RESPONSE_COMPILER" != "y" ]]; then
204      read -p "-- Please enter your prefered Fortran compiler: " CUSTOM_FORTRAN_COMPILER
205      while ! command -v ${CUSTOM_FORTRAN_COMPILER} > /dev/null; do
206         printf "%s \e[1;31mnot found!\e[0m\n" "-- \"${CUSTOM_FORTRAN_COMPILER}\""
207         read -p "Please try again: " CUSTOM_FORTRAN_COMPILER
208      done
209   fi
210   printf "%s \"\e[1;32m${CUSTOM_FORTRAN_COMPILER}\e[0m\" will be used.\n" "-- The Fortran compiler"
211   printf "\n"
212
213   printf "%s\n" "This installer can try to find your NetCDF libraries automatically."
214   palm_read_yn "Do you wish to use the automatic NetCDF library detection?" "RESPONSE_NETCDF"
215   if [[ "$RESPONSE_NETCDF" != "y" ]]; then
216      read -p "-- Please enter the netCDF C root path: " NETCDF_C_ROOT
217      read -p "-- Please enter the netCDF Fortran root path: " NETCDF_FORTRAN_ROOT
218      printf "%s \e[1;33mdisabled\e[0m.\n" "-- Automatic NetCDF library detection is"
219   else
220      printf "%s \e[1;32menabled\e[0m.\n" "-- Automatic NetCDF library detection is"
221   fi
222   printf "\n"
223
224   if [[ "$palm_installer_build_rrtmg" == "true" ]]; then
225      RRTMG_ROOT=${install_prefix}/rrtmg
226      printf "%s\n" "This installer can install the RRTMG library for you."
227      palm_read_yn "Do you wish to install the RRTMG library?" "RESPONSE_RRTMG"
228      if [[ "$RESPONSE_RRTMG" == "y" ]]; then
229         printf "%s\n" "-- The default installation directory is \"${RRTMG_ROOT}\"."
230         palm_read_yn "Do you wish to install the RRTMG library in the default directory?" "RESPONSE_PREFIX"
231         if [[ "$RESPONSE_PREFIX" != "y" ]]; then
232            read -p "-- Please enter a new installation directory: " CUSTOM_PREFIX
233            local input_dir=$(eval echo $CUSTOM_PREFIX)
234            local tmp=""
235            while ! readlink -f $input_dir > /dev/null; do
236               tmp="/$(basename $input_dir)${tmp}"
237               input_dir=$(dirname $input_dir)
238            done
239            RRTMG_ROOT="$(readlink -f $input_dir)${tmp}"
240         fi
241         printf "%s \"\e[1;32m${RRTMG_ROOT}\e[0m\"\n" "-- The RRTMG library will be installed in:"
242      else
243         palm_installer_build_rrtmg="false"
244      fi
245      printf "\n"
246   fi
247
248   if [[ -d ${trunk_dir} ]] && [[ "$(svn status ${trunk_dir})" == ""  ]]; then
249      local existing_revision=$(palm_svn_local_revision)
250   fi
251
252   if [[ "${existing_revision}" != ""  ]]; then
253      printf "%s\n" "A working copy of ${program_name} (revision: ${existing_revision}) was found..."
254      palm_read_yn "Do you wish to update ${program_name}?" "RESPONSE_SVN"
255   else
256      printf "%s\n" "No working copy of ${program_name} was found so far..."
257      palm_read_yn "Do you wish to download ${program_name} via Subversion?" "RESPONSE_SVN"
258   fi
259   
260   if [[ "$RESPONSE_SVN" == "y" ]]; then
261      SVN_USER=$(palm_svn_get_username)
262      printf "%s \e[1;32m$SVN_USER\e[0m \n" "-- Your ${program_name} username is:"
263      palm_svn_check_remote
264      newest_revision=$(palm_svn_newest_revision)
265      printf "%s\n" "-- By default the latest ${program_name} revision (revision: ${newest_revision}) will be aquired."
266      palm_read_yn "Do you wish to get the latest ${program_name} revision?" "RESPONSE_REVISION"
267      if [[ "$RESPONSE_REVISION" != "y" ]]; then
268         read -p "-- Please enter the desired ${program_name} revision (${palm_min_rev} to ${newest_revision}): " CUSTOM_REVISION
269         while [[ ${CUSTOM_REVISION} -gt ${newest_revision} ]] || [[ ${CUSTOM_REVISION} -lt ${palm_min_rev} ]]; do
270            printf "%s \e[1;31mnot a valid ${program_name} revision!\e[0m \n" "--"
271            printf "%s \e[1;31mThis installer only supports ${program_name} revisions >${palm_min_rev}!\e[0m \n" "--"
272            sleep 0.2
273            read -p "-- Please choose a value between ${palm_min_rev} and ${newest_revision}: " CUSTOM_REVISION
274         done
275      else
276         CUSTOM_REVISION=${newest_revision}
277      fi
278      if [[ -d ${trunk_dir} ]] && [[ "$(svn status ${trunk_dir}/)" == ""  ]]; then
279         palm_svn_update
280      else
281         rm -rf ${trunk_dir}
282         mkdir -p ${install_prefix}
283         palm_svn_checkout
284      fi
285      if [[ "$(svn status ${trunk_dir}/)" != ""  ]]; then
286         printf "%s \e[1;31mnot able\e[0m to optain a working copy of ${program_name}. Please optain it manually.\n" "-- Subversion was"
287         palm_read_yn "Is there a working copy of ${program_name} in the current directory?" "IS_TRUNK"
288         [[ "$IS_TRUNK" != "y" ]] && palm_installer_abort_message
289      fi
290   fi
291   SVN_CMAKE_CHECK="YES"
292   palm_svn_check_local
293   if [[ -d ${trunk_dir} ]]; then
294      if [[ "$SVN_CMAKE_CHECK" == "YES" ]]; then
295         if [[ "$(svn status ${trunk_dir}/)" == ""  ]]; then
296            local tmp_revision=( $(svn info ${trunk_dir}/ | grep Revision:) )
297            local new_revision=${tmp_revision[1]}
298            printf "%s \e[1;32mfound\e[0m.\n" "-- ${program_name} (revision: ${new_revision})"
299         fi
300      else
301         printf "%s It is \e[1;33massumed\e[0m a working copy of ${program_name} can be found under: ${trunk_dir}\n" "--"
302      fi
303   else
304      printf "%s \e[1;31m${program_name} was not able to find a working PALM copy. Aborting!\e[0m\n" "--"
305      palm_installer_abort_message
306   fi
307   printf "\n"
308   hrule
309   printf "| \e[1;32m%-${number_of_cols}s\e[0m |\n" "${program_name} installer initialization done."
310   hrule
311   palm_read_yn "Are you happy with your choices and ready to continue?" "RESPONSE_CONFIGURE"
312   if [[ "$RESPONSE_CONFIGURE" != "y" ]]; then
313      palm_installer_abort_message
314   fi
315}
316
317# check if svn server is reachable
318palm_svn_check_remote() {
319   svn info --username "$SVN_USER" ${palm_svn_url} > /dev/null
320   local status=$?
321   if [[ $status -ne 0 ]]; then
322      printf "\e[1;31m%-${number_of_cols}s\e[0m \n" "ERROR: svn server not reachable."
323      palm_installer_error_message
324   fi
325}
326# check if svn server is reachable
327palm_svn_check_local() {
328   svn info ${trunk_dir}/ > /dev/null
329   local status=$?
330   if [[ $status -ne 0 ]]; then
331      printf "\e[1;31m%-${number_of_cols}s\e[0m \n" "ERROR: no healthy local svn repository was found."
332      printf "As a workaround you could optain a working copy of the ${program_name} trunk without using Subversion.\n"
333      printf "Please place this copy under: ${trunk_dir}\n"
334      palm_read_yn "Can you ensure a working copy of the ${program_name} trunk can be found?" "RESPONSE_SVN_ERROR"
335      if [[ "$RESPONSE_SVN_ERROR" != "y" ]]; then
336         palm_installer_abort_message
337      fi
338      SVN_CMAKE_CHECK="NO"
339   fi
340}
341
342# get svn username
343palm_svn_get_username() {
344   for svn_auth_file in ~/.subversion/auth/svn.simple/*; do
345      if [[ $(cat ${svn_auth_file} | grep "${palm_base_url}") != "" ]]; then
346         cat ${svn_auth_file} | awk '/^K / { key=1; val=0; } /^V / { key=0; val=1; } ! /^[KV] / { if(key) { kname=$1; } if(val && kname == "username") { print $1; val = 0; } }'
347         return 0
348      fi
349   done
350   read -p "-- Please enter your ${program_name} svn username: " username
351   echo ${username}
352   return 0
353}
354
355# check if svn server is reachable
356palm_svn_newest_revision() {
357   local tmp_revision=( $(svn info --username "$SVN_USER" ${palm_svn_url} | grep Revision:) )
358   echo ${tmp_revision[1]}
359}
360
361# check if svn server is reachable
362palm_svn_local_revision() {
363   local tmp_revision=( $(svn info ${trunk_dir}/ | grep Revision:) )
364   echo ${tmp_revision[1]}
365}
366
367
368palm_svn_checkout() {
369   local n=$(($(svn info --username "$SVN_USER" -R ${palm_svn_url} | grep "URL: " | uniq | wc -l)/2))
370   printf "%s" "-- Number of files to be downloaded: $n\n"
371   local i=1
372   while read line filename; do
373      if [[ $i -le $n ]]; then
374         ((++i))
375         local percent=$(printf "%3s" "$(((${i:-0}*100)/${n:-100}))")
376         local status_line=$(printf "[ %s%% ] Downloading file: %s" "$percent" "$(basename $filename)")
377         printf "\r-- %$(($(tput cols)-3))s" " "
378         printf "\r-- %s" "$status_line"
379      fi
380   done < <(svn checkout --username "$SVN_USER" ${CUSTOM_REVISION:+"-r${CUSTOM_REVISION}"} ${palm_svn_url} ${trunk_dir})
381   printf "\r-- %$(($(tput cols)-3))s" " "
382   printf "\r-- [ %3s%% ] \e[1;32m%s\e[0m\n" "100" "Download finished!"
383}
384
385palm_svn_update() {
386   local n=$(($(svn diff -r ${existing_revision}:${CUSTOM_REVISION} --summarize ${palm_svn_url} | uniq | wc -l)/2))
387   printf "%s\n" "-- Number of files to be updated: $n"
388   local i=1
389   while read line filename; do
390      if [[ $i -le $n ]]; then
391         ((++i))
392         local percent=$(printf "%3s" "$(((${i:-0}*100)/${n:-100}))")
393         local status_line=$(printf "[ %s%% ] Updating file: %s" "$percent" "$(basename $filename)")
394         printf "\r-- %$(($(tput cols)-3))s" " "
395         printf "\r-- %s" "$status_line"
396      fi
397   done < <(svn update ${CUSTOM_REVISION:+"-r${CUSTOM_REVISION}"} ${trunk_dir})
398   printf "\r-- %$(($(tput cols)-3))s" " "
399   printf "\r-- [ %3s%% ] \e[1;32m%s\e[0m\n" "100" "Update finished!"
400}
401
402################################################################################
403
404# startup message
405palm_installer_startup_message() {
406   printf "\n"
407   hrule
408   printf "|                                                                        |\n"
409   printf "|                       PALM installer (${installer_version})                         |\n"
410   printf "|                   https://palm.muk.uni-hannover.de/                    |\n"
411   printf "|                                                                        |\n"
412}
413
414# shutdown message
415palm_installer_shutdown_message() {
416   hrule
417   printf "| %-${number_of_cols}s |\n" "${program_name} installer finished."
418   hrule
419   rm -f ${logfile_all}
420   exit 0
421}
422
423# shutdown message
424palm_installer_abort_message() {
425   hrule
426   printf "| \e[1;31m%-${number_of_cols}s\e[0m |\n" "${program_name} installer aborted."
427   hrule
428   exit 0
429}
430
431# error wrap-up message
432palm_installer_error_message() {
433   hrule
434   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" "${program_name} installer crashed."
435   palm_installer_ticket_message
436   hrule
437   exit 1
438}
439
440palm_installer_ticket_message() {
441   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" " "
442   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" "In order to get help, please use our ticket system at:"
443   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" "   \"https://palm.muk.uni-hannover.de/trac/wiki/help\""
444   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" " "
445   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" "Please allways attach the following file to the ticket:"
446   printf "| \e[1;31m%-${number_of_cols}s\e[0m \n" "   \"${logfile_all}\""
447}
448
449hrule() {
450   printf "#"
451   printf -- '-%.0s' {1..72}
452   printf "#\n"
453}
454
455palm_read_yn() {
456   sleep 0.1
457   while true; do
458   read -p "-- ${1} (y|n): " CURRENT_RESPONSE
459   if [[ "${CURRENT_RESPONSE}" == "y" ]] || [[ "${CURRENT_RESPONSE}" == "n" ]]; then
460      eval ${2}="${CURRENT_RESPONSE}"
461      break
462   fi
463   done
464}
465
466palm_installer_help() {
467   hrule
468   printf "| %-${number_of_cols}s |\n" "USAGE: bash ${0} [--init|--version|--prep]"
469   hrule
470   rm -f ${logfile_all}
471   exit 0
472}
473
474palm_installer_version() {
475   hrule
476   printf "| %-${number_of_cols}s |\n" "VERSION: This PALM installer has version number: ${installer_version}"
477   hrule
478   rm -f ${logfile_all}
479   exit 0
480}
481
482palm_installer_prep_mpi() {
483   sudo apt-get install mpich
484}
485
486palm_installer_prep_netcdf() {
487   sudo apt-get install libnetcdf-dev libnetcdff-dev ncview
488}
489
490palm_installer_prep_gt() {
491   sudo apt-get install libqt4-dev
492}
493
494palm_installer_prep_fftw() {
495   sudo apt-get install libfftw3-dev
496}
497
498################################################################################
499
500palm_installer_startup_message
501palm_installer_update
502
503if [[ "${1}" =~ "--help" ]]; then
504   palm_installer_help
505fi
506
507if [[ "${1}" =~ "--version" ]]; then
508   palm_installer_version
509fi
510
511if [[ "${1}" =~ "--prep" ]]; then
512   palm_installer_prep_mpi
513   palm_installer_prep_netcdf
514   palm_installer_prep_gt
515   palm_installer_prep_fftw
516   palm_installer_shutdown_message
517fi
518
519if [[ "${1}" =~ "--rrtmg" ]]; then
520   palm_installer_build_rrtmg="true"
521else
522   palm_installer_build_rrtmg="false"
523fi
524
525palm_installer_check_software_all
526palm_installer_init
527
528if [[ -f ${trunk_dir}/INSTALL/palm_installer_components ]]; then
529   # temporary solution only
530   source ${trunk_dir}/INSTALL/palm_installer_components
531else
532   printf "\e[1;31m%-${number_of_cols}s\e[0m \n" "ERROR: file not found: ${trunk_dir}/INSTALL/palm_installer_components"
533   palm_installer_error_message
534fi
535
536palm_installer_shutdown_message