-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathinstall
executable file
·10747 lines (10561 loc) · 456 KB
/
install
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
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
538
539
540
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
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
# This file is part of CO𝘕CEPT, the cosmological 𝘕-body code in Python.
# Copyright © 2015–2024 Jeppe Mosgaard Dakin.
#
# CO𝘕CEPT is free software: You can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CO𝘕CEPT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with CO𝘕CEPT. If not, see https://www.gnu.org/licenses/
#
# The author of CO𝘕CEPT can be contacted at dakin(at)phys.au.dk
# The latest version of CO𝘕CEPT is available at
# https://github.com/jmd-dk/concept/
# Help text which gets printed if invoked with -h or --help.
help_text='This script downloads and installs the CO𝘕CEPT code with all its
dependencies.
Below you will find a short description of how to run this script.
This is more thoroughly documented in the CO𝘕CEPT documentation:
https://jmd-dk.github.io/concept/installation.html
If run without an argument, this script will prompt for an
installation directory. Alternatively, this directory can be passed as
an argument. Everything will be installed within this directory.
Options taken by this script:
-h, --help Show this help message and exit.
-t, --tests Test the various dependency programs after their
individual installations. CO𝘕CEPT itself will similarly
be tested. On failure (fatal or non-fatal) of any test,
a log file of the test output will be placed in the
installation subdirectory of the given program. Any
test failures will be reported at the end of the entire
installation process.
-y, --yes_to_defaults Accept default options on future queries. These include
system-wide installations of system dependencies,
should they be missing, as well as termination of
already running CO𝘕CEPT installation process, should
one exist.
--slim Slim down the installation in order to save disk space.
This removes uncritical content from all installed
dependency programs and CO𝘕CEPT itself.
--fix-ssh Set up the ~/.ssh directory so that it allows for
password-less SSH login between nodes. This may be
needed in order to run multi-node MPI computations on
clusters. The original state of the ~/.ssh directory
will be backed up. Note that this option will perform
the changes to ~/.ssh only; no actual installation will
take place.
The full invocation signature of this script thus looks like
/path/to/install [/path/to/concept] [-t] [-y] [--slim]
or
/path/to/install --fix-ssh
where brackets indicate optional arguments.
The system dependencies mentioned above consist of the following
(GNU implementations, specifically):
- awk
- gcc
- g++
- gfortran
- grep
- gzip
- make
- sed
- tar
- wget
- glibc
- as and ld
- Linux headers
If any of these are missing, an attempt will be made to locate the
package manager on the system. If successful, you will be prompted to install
the missing system dependency, which will require root access.
The only system dependencies needed but not installed are the GNU core
utilities and Bash. This script (and others used in CO𝘕CEPT) should be
compatible with Bash version 3.0 or later.
The programs which will be installed into the specified installation
directory consist of the following and will be installed in order:
- zlib (needed by HDF5, Python, pillow (needed by Matplotlib))
- GSL
- Perl (needed by OpenSSL, OpenBLAS, MPICH/OpenMPI)
- MPICH/OpenMPI
- HDF5
- FFTW
- ncurses (needed by _curses (needed by Blessings))
- OpenSSL (needed by pip)
- libffi (needed by _ctypes (needed by pip))
- OpenBLAS (needed by SciPy, used by NumPy)
- Python, with the following packages
(along with their own Python package dependencies):
- pip, setuptools, wheel (if any of the below)
- Blessings
- Cython
- CythonGSL
- NumPy
- SciPy
- Matplotlib
- MPI4Py
- H5Py
- Sphinx
- Sphinx-copybutton
- Sphinx-rtd-theme
- Sphinx-tabs
- CO𝘕CEPT
- CLASS
- FFTW 2 (needed by GADGET)
- GADGET
Due to the numerosity of the above list, the installation process will take
a couple of hours on modern hardware. Should the installation process end
prematurely, simply rerun this script with the same arguments and environment
as originally, and it will pick up the installation from where it left off.
See https://jmd-dk.github.io/concept/installation.html for further information.
'
# Print help text and exit, if help is requested
for var in "$@"; do
if [ "${var}" == "-h" ] \
|| [ "${var}" == "--h" ] \
|| [ "${var}" == "--he" ] \
|| [ "${var}" == "--hel" ] \
|| [ "${var}" == "--help" ]; then
printf "${help_text}"
exit 0
fi
done
# Absolute paths to this file
this_file="$(readlink -f "${BASH_SOURCE[0]}")"
# If invoked directly from the web (e.g. via wget), a small pause
# ensures that the print outs will not corrupt the loading bar.
sleep 2
# Newer versions of wget saves a copy of the printout when using the
# -O- option to a file called wget-log[.x], x ∈ ℕ. Remove any such log
# produced from invoking this script via wget.
wget_log_maxage=300
for filename in *; do
if [ ! -f "${filename}" ] || [[ "${filename}" != "wget-log"* ]]; then
continue
fi
fileage=$(($(date +%s) - $(stat -c '%Y' "${filename}")))
if [ ${fileage} -lt ${wget_log_maxage} ]; then
rm -f "${filename}" || :
fi
done
##################
# Specifications #
##################
# The MPI implementation to use
mpi_lower="$(echo "${mpi}" | tr '[:upper:]' '[:lower:]')"
if [ -z "${mpi}" ]; then
# If mpi_dir is specified,
# try to determine whether MPICH or OpenMPI is used.
if [ -n "${mpi_dir}" ]; then
if [ -f "${mpi_dir}/bin/mpichversion" ] \
|| [ -f "$(dirname "${mpi_dir}")/bin/mpichversion" ] \
|| [ -f "$(dirname "$(dirname "${mpi_dir}")")/bin/mpichversion" ] \
; then
mpi="mpich"
elif [ -f "${mpi_dir}/bin/ompi_info" ] \
|| [ -f "$(dirname "${mpi_dir}")/bin/ompi_info" ] \
|| [ -f "$(dirname "$(dirname "${mpi_dir}")")/bin/ompi_info" ] \
; then
mpi="openmpi"
else
mpi="unknown"
fi
else
# Use MPICH by default
mpi="mpich"
fi
elif [ "${mpi_lower}" != "mpich" ] && [ "${mpi_lower}" != "openmpi" ]; then
echo "Specified MPI implementation mpi=\"${mpi}\" not recognised.
Will use MPICH" >&2
mpi="mpich"
fi
mpi="$(echo "${mpi}" | tr '[:upper:]' '[:lower:]')"
mpi_formatted="${mpi}"
if [ "${mpi_formatted}" == "mpich" ]; then
mpi_formatted="MPICH"
elif [ "${mpi_formatted}" == "openmpi" ]; then
mpi_formatted="OpenMPI"
fi
# This function sets the variables "name_dir" (if not set already)
# and "name_preinstalled".
set_dir() {
# Arguments: Program name, install directory.
# Set "name_preinstalled" if "name_dir" is already set
eval "${1}_preinstalled=True"
eval "[ -n \"\${${1}_dir}\" ] || ${1}_preinstalled=\"False\""
# Set "name_dir" if "name_dir" is not already set
# or "name" should be installed.
eval "[ -n \"\${${1}_dir}\" ] || ${1}_dir=\"${2}\""
eval "(! ( [ \"\${${1}_install}\" == \"False\" ] \
&& [ \"\${${1}_preinstalled}\" == \"False\" ])) || ${1}_dir=\"\""
}
# The install_explicit_only environment variable, when set to "True",
# disables all implicit installations.
if [ "${install_explicit_only}" == "True" ]; then
for progname in \
"concept" \
"blas" \
"class" \
"fftw" \
"fftw_for_gadget" \
"gadget" \
"gsl" \
"hdf5" \
"libffi" \
"mpi" \
"ncurses" \
"openssl" \
"perl" \
"python" \
"zlib" \
"blessings" \
"cython" \
"cythongsl" \
"h5py" \
"matplotlib" \
"mpi4py" \
"numpy" \
"scipy" \
"sphinx" \
"sphinx_copybutton" \
"sphinx_rtd_theme" \
"sphinx_tabs" \
; do
eval "[ -n \"\${${progname}_install}\" ] || ${progname}_install=\"False\""
done
fi
# Specification of paths. The substring "__concept_dir__"
# will later be replaced with the top-level directory.
set_dir "concept" "__concept_dir__"
set_dir "class" "__concept_dir__/dep/class"
set_dir "fftw" "__concept_dir__/dep/fftw"
set_dir "gadget" "__concept_dir__/dep/gadget"
set_dir "fftw_for_gadget" "${gadget_dir}/fftw"
set_dir "gsl" "__concept_dir__/dep/gsl"
set_dir "hdf5" "__concept_dir__/dep/hdf5"
set_dir "mpi" "__concept_dir__/dep/${mpi}"
set_dir "blas" "__concept_dir__/dep/openblas"
set_dir "perl" "__concept_dir__/dep/perl"
set_dir "python" "__concept_dir__/dep/python"
set_dir "ncurses" "${python_dir}"
set_dir "openssl" "${python_dir}"
set_dir "libffi" "${python_dir}"
set_dir "zlib" "__concept_dir__/dep/zlib"
tmp_dir="__concept_dir__/.tmp"
dep_dir="__concept_dir__/dep"
log="${tmp_dir}/install_log"
env="__concept_dir__/.env"
path="__concept_dir__/.path"
# This function sets the variable "name_version" if not set already.
# For pre-installed software, set "name_version" to "pre-installed".
# If a third argument is given, this is the version to fall back to,
# in case of unsuccessful retrieval of the link to the first version.
set_version() {
# Arguments: Program name, version, [fallback version]
progname="$1"
version="$2"
version_fallback="$3"
eval "[ -z \"\${${progname}_version}\" ] || ${progname}_version_specifiedbyuser=\"True\""
eval "[ -n \"\${${progname}_version}\" ] || ${progname}_version=\"${version}\""
eval "[ \"\${${progname}_preinstalled}\" != \"True\" ] || ${progname}_version=\"pre-installed\""
if [ -n "${version_fallback}" ]; then
eval "${progname}_version_fallback=\"${version_fallback}\""
fi
eval "${progname}_version=\"\${${progname}_version/v/}\""
eval "${progname}_version_fallback=\"\${${progname}_version_fallback/v/}\""
}
# Specification of software versions.
# The rightmost column are fallbacks, which will be used if the
# link to the version given by the middle column is broken.
# In case of CO𝘕CEPT and CLASS, possible versions are the corresponding
# GitHub branches and releases.
concept_version_specified="False"
if [ -n "${concept_version}" ]; then
concept_version_specified="True"
fi
set_version "concept" "master"
set_version "blas" "0.3.23" "0.3.23"
set_version "class" "2.7.2"
set_version "fftw" "3.3.10" "3.3.10"
set_version "fftw_for_gadget" "2.1.5" "2.1.5" # Do not change
set_version "gadget" "2.0.7" "2.0.7" # Do not change
set_version "gsl" "2.7.1" "2.7.1"
set_version "hdf5" "1.14.0"
set_version "libffi" "3.4.4" "3.4.3"
if [ "${mpi}" == "mpich" ]; then
set_version "mpi" "4.1.1" "4.1.1"
elif [ "${mpi}" == "openmpi" ]; then
set_version "mpi" "4.1.5"
fi
set_version "ncurses" "6.4" "6.4"
set_version "openssl" "3.0.8" "3.0.7"
set_version "perl" "5.36.0"
set_version "python" "3.11.3"
set_version "zlib" "1.2.13" "1.2.13"
# Python packages
set_version "blessings" "1.7"
set_version "cython" "0.29.33"
set_version "cythongsl" "0.2.2"
set_version "h5py" "3.8.0"
set_version "matplotlib" "3.7.1"
set_version "mpi4py" "3.1.4"
set_version "numpy" "1.24.2"
set_version "pip" "23.1.2"
set_version "scipy" "1.10.1"
set_version "setuptools" "67.7.2"
set_version "sphinx" "6.2.1"
set_version "sphinx_copybutton" "0.5.0"
set_version "sphinx_rtd_theme" "1.2.1"
set_version "sphinx_tabs" "3.4.1"
set_version "wheel" "0.38.4"
# Note that the versions may be changed further down due to known
# compatibility issues between specific versions of the above programs
# and specific versions of system dependencies.
#################
# Initial setup #
#################
# Set up error trapping
ctrl_c() {
current_step="aborting"
sleep 0.5
kill -9 -- -$$ > /dev/null 2>&1 || :
exit 2
}
abort() {
sleep 0.5
kill -9 -- -$$ > /dev/null 2>&1 || :
exit 1
}
trap 'ctrl_c' SIGINT
trap 'abort' EXIT
set -e
# Set sleep_time, the amount of seconds spend sleeping at various stages
if [ -z "${sleep_time}" ]; then
sleep_time=10
fi
# For the terminal to be able to print Unicode characters correctly,
# we need to use a UTF-8 locale.
set_locale() {
# This function will set the locale through the LC_ALL and LANG
# environment variables. We want to use a supported UTF-8 locale.
# The preference order is as follows:
# en_US.UTF-8
# en_*.UTF-8
# C.UTF-8
# POSIX.UTF-8
# *.UTF-8
# We consider the suffix (UTF-8) valid regardless of the case and
# presence of the dash.
# Get all available locals.
locales="$(locale -a 2>/dev/null || :)"
if [ -z "${locales}" ]; then
return
fi
# Look for available UTF-8 locale
for prefix in "en_US" "en_*" "C" "POSIX" "*"; do
for suffix in "UTF-8" "UTF8" "utf-8" "utf8"; do
pattern="${prefix}.${suffix}"
for loc in ${locales}; do
if [[ "${loc}" == ${pattern} ]]; then
export LC_ALL="${loc}"
export LANG="${loc}"
return
fi
done
done
done
}
set_locale
# Set the terminal if unset or broken
if [ -z "${TERM}" ] || [ "${TERM}" == "dumb" ]; then
export TERM="linux"
fi
# ANSI/VT100 escape sequences
esc="\x1b"
# Text formatting
esc_normal="${esc}[0m"
esc_bold="${esc}[1m"
esc_italic="${esc}[3m"
esc_reverted="${esc}[7m"
esc_no_italic="${esc}[23m"
# The name of the program, nicely typeset
if [ -z "${esc_concept}" ]; then
esc_concept="CO${esc_italic}N${esc_no_italic}CEPT"
else
esc_concept="${esc_concept//\$\{esc_italic\}/${esc_italic}}"
esc_concept="${esc_concept//\$\{esc_no_italic\}/${esc_no_italic}}"
fi
# Text colours
esc_red="${esc}[91m"
esc_green="${esc}[92m"
esc_yellow="${esc}[93m"
esc_blue="${esc}[94m"
# Cursor movement
esc_up="${esc}[1A"
esc_erase="${esc}[K"
# Special characters
en_quad="\xE2\x80\x80"
# Functions for pretty printing text
heading() {
printf "\n${esc_bold}${esc_yellow}${1}${esc_normal}\n"
}
error() {
printf "\n${esc_bold}${esc_red}${1}${esc_normal}\n\n" >&2
}
# Print out welcome message
if [ "${say_welcome}" != "False" ]; then
printf "\n${esc_bold}This is the installation script for ${esc_concept},
the cosmological ${esc_italic}N${esc_no_italic}-body code in Python${esc_normal}\n"
fi
# Status control sequences
status="initialization"
status_prefix="__new_status__="
status_prefix_length=${#status_prefix}
status_disable="disable"
status_enable="enable"
status_on="on"
status_off="off"
status_visible="${status_on}"
status_finish_successfully="finish_successfully"
status_installpid="installpid="
status_setvar="setvar:"
# Set test_success variables
blas_test_success="True"
class_test_success="True"
concept_test_success="True"
fftw_test_success="True"
fftw_for_gadget_test_success="True"
gadget_test_success="True"
gsl_test_success="True"
hdf5_test_success="True"
libffi_test_success="True"
mpi_test_success="True"
ncurses_test_success="True"
openssl_test_success="True"
perl_test_success="True"
python_test_success="True"
zlib_test_success="True"
numpy_test_success="True"
scipy_test_success="True"
# Read in command-line arguments
if [ -z "${do_tests}" ]; then
do_tests="False"
fi
if [ -z "${yes_to_defaults}" ]; then
yes_to_defaults="False"
fi
if [ -z "${fix_ssh}" ]; then
fix_ssh="False"
fi
if [ -z "${slim}" ]; then
slim="False"
fi
if [ -z "${concept_dir_specified}" ]; then
concept_dir_specified="False"
fi
for var in "$@"; do
# Strip command-line argument for brackets, which may have
# been added by users not familiar with this syntax for
# specifying optional arguments.
var="${var//\[/}"
var="${var//\]/}"
# Parse command-line argument
if [ "${var}" == "-t" ] \
|| [ "${var}" == "--t" ] \
|| [ "${var}" == "--te" ] \
|| [ "${var}" == "--tes" ] \
|| [ "${var}" == "--test" ] \
|| [ "${var}" == "--tests" ] \
; then
do_tests="True"
elif [ "${var}" == "-y" ] \
|| [ "${var}" == "--y" ] \
|| [ "${var}" == "--ye" ] \
|| [ "${var}" == "--yes" ] \
|| [ "${var}" == "--yes-" ] \
|| [ "${var}" == "--yes-t" ] \
|| [ "${var}" == "--yes-to" ] \
|| [ "${var}" == "--yes-to-" ] \
|| [ "${var}" == "--yes-to-d" ] \
|| [ "${var}" == "--yes-to-de" ] \
|| [ "${var}" == "--yes-to-def" ] \
|| [ "${var}" == "--yes-to-defa" ] \
|| [ "${var}" == "--yes-to-defau" ] \
|| [ "${var}" == "--yes-to-defaul" ] \
|| [ "${var}" == "--yes-to-default" ] \
|| [ "${var}" == "--yes-to-defaults" ] \
; then
yes_to_defaults="True"
elif [ "${var}" == "--f" ] \
|| [ "${var}" == "--fi" ] \
|| [ "${var}" == "--fix" ] \
|| [ "${var}" == "--fix-" ] \
|| [ "${var}" == "--fix-s" ] \
|| [ "${var}" == "--fix-ss" ] \
|| [ "${var}" == "--fix-ssh" ] \
; then
fix_ssh="True"
elif [ "${var}" == "--s" ] \
|| [ "${var}" == "--sl" ] \
|| [ "${var}" == "--sli" ] \
|| [ "${var}" == "--slim" ] \
; then
slim="True"
elif [ "${var}" == "--fast" ]; then
# This is a deprecated option for skipping tests,
# which is now the default. Allow it but do nothing.
:
elif [ "${concept_dir_specified}" == "False" ]; then
concept_dir="${var}"
concept_dir_specified="True"
else
if [ "${var}" != "${concept_dir}" ]; then
error "Got command-line argument \"${var}\", "\
"but the installation path is already set to \"${concept_dir}\""
exit 1
fi
fi
done
# Changes to initial environment variables due to command-line arguments
if [ "${slim}" == "True" ]; then
export CFLAGS="${CFLAGS} -g0"
export CXXFLAGS="${CXXFLAGS} -g0"
export LDFLAGS="${LDFLAGS} -Wl,-s"
fi
# The possible values for $pyuser to try for installation of Python
# packages. To first attempt global installation, then user specific
# installation, set pyuser_possibilities="global user"
if [ -z "${pyuser_possibilities}" ]; then
pyuser_possibilities="global"
fi
pyuser_possibilities_in="${pyuser_possibilities}"
pyuser_possibilities=()
for pyuser in ${pyuser_possibilities_in}; do
if [ "${pyuser}" == "global" ]; then
pyuser=""
elif [ "${pyuser}" == "user" ]; then
pyuser="--user"
fi
if [ -n "${pyuser}" ] && [ "${pyuser}" != "--user" ]; then
echo "Unknown value for pyuser: \"${pyuser}\"" >&2
exit 1
fi
pyuser_possibilities=("${pyuser_possibilities[@]}" "${pyuser}")
done
# Backup of initial environment variables
env_var_names=( \
BLAS \
BUILD_ZLIB \
CC \
CFLAGS \
CPPFLAGS \
CXX \
CXXFLAGS \
F77 \
F90 \
F9X \
FC \
FCFLAGS \
FFLAGS \
HDF5_DIR \
HDF5_MPI \
LAPACK \
LD_LIBRARY_PATH \
LD_PRELOAD \
LDFLAGS \
LIBFFI_CFLAGS \
LIBFFI_LIBS \
LIBS \
MATHLIB \
MPICC \
MPILIBS \
MPLSETUPCFG \
NPY_BLAS_ORDER \
NPY_LAPACK_ORDER \
PATH \
PERL \
PKG_CONFIG_PATH \
SCIPY_USE_PYTHRAN \
TEMP \
TMP \
TMPDIR \
ZLIB_INCLUDE \
ZLIB_LIB \
)
for env_var_name in "${env_var_names[@]}"; do
# Save initial state (set/unset) of the environment variable
if [ -n "$(eval "echo "\${${env_var_name}+x}"")" ]; then
eval "${env_var_name}_set=\"True\""
else
eval "${env_var_name}_set=\"False\""
fi
# Save initial value of the environment variable
eval "${env_var_name}_backup=\"\${${env_var_name}}\""
done
# Function that resets all above environment
# variables to their initial state.
reset_environment() {
for env_var_name in "${env_var_names[@]}"; do
eval "env_var_set=\"\${${env_var_name}_set}\""
if [ "${env_var_set}" == "True" ]; then
# env_var_name initially set
eval "export ${env_var_name}=\"\${${env_var_name}_backup}\""
else
# env_var_name initially unset
unset "${env_var_name}"
fi
done
}
# Function for converting a path to its absolute form
initial_dir="$(pwd)" # it is crucial that this line is before any cd
convert_to_abs_path() {
# Arguments: path
current_dir="$(pwd)"
cd "${initial_dir}"
# Place backslashes before spaces, dollar signs and parentheses.
# These are needed when expanding tilde, but they will not persist.
local abs_path="${1// /\\ }"
abs_path="${abs_path//$/\\$}"
abs_path="${abs_path//\(/\\(}"
abs_path="${abs_path//\)/\\)}"
# Expand tilde
eval abs_path="${abs_path}"
# Convert to absolute path
abs_path="$(readlink -m "${abs_path}")"
cd "${current_dir}"
echo "${abs_path}"
}
# Setup password-less SSH login between nodes (and exit), if requested
if [ "${fix_ssh}" == "True" ]; then
# Move the pre-existing ~/.ssh directory into a directory
# ~/.ssh_backup/<date>,
# with <date> the current time.
if [ -d ~/".ssh" ]; then
passwordless_ssh_timestamp="$(date)"
passwordless_ssh_timestamp="${passwordless_ssh_timestamp// /-}"
passwordless_ssh_backup_dir="$(convert_to_abs_path \
"~/.ssh_backup/${passwordless_ssh_timestamp}")"
mkdir -p ~/".ssh_backup/${passwordless_ssh_timestamp}"
mv ~/".ssh" ~/".ssh_backup/${passwordless_ssh_timestamp}/"
echo "The existing ~/.ssh directory has been moved to ${passwordless_ssh_backup_dir}/.ssh"
fi
mkdir -p ~/".ssh"
# The type of encryption to use for the ssh keys.
# Should be "dsa" or "rsa".
key_type="rsa"
# Generate a public/private key pair
ssh-keygen -t "${key_type}" -N "" -f ~/".ssh/id_${key_type}" >/dev/null
# Add public key to the list of keys allowed to log in
cat ~/".ssh/id_${key_type}.pub" >> ~/".ssh/authorized_keys"
cat ~/".ssh/id_${key_type}.pub" >> ~/".ssh/authorized_keys2"
# Suppress future confirmation dialogues
echo "Host *
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
LogLevel ERROR
" >> ~/".ssh/config"
# Remove any previously known hosts (there should be none
# as the ~/.ssh directory has just been created).
rm -f "known_hosts"* 2>/dev/null || :
# Set proper permissions in order for ssh
# to allow password-less login.
chmod go-w ~
chmod 700 ~/".ssh"
chmod 644 ~/".ssh/authorized_keys"
chmod 644 ~/".ssh/authorized_keys2"
chmod go-rwx ~/".ssh/config" || :
chmod go-rwx ~/".ssh/id_${key_type}"
chmod go+r ~/".ssh/id_${key_type}.pub"
# Inform the user on this change
printf "\nPassword-less ssh login between nodes has been configured\n"
# Do not install CO𝘕CEPT
trap : 0
exit 0
fi
# Function which prints the absolute path of a given command.
# If the command is not an executable file on the PATH but instead a
# known function, the input command is printed as is. If the command
# cannot be found at all, nothing is printed and an exit code of 1
# is returned.
get_command() {
command_name="${1}"
# Use the type built-in to locate the command
command_path="$(type "${command_name}" 2>/dev/null || :)"
command_path="${command_path##* }"
if [[ "${command_path}" == "/"* ]]; then
# The command is a path
command_path="$(readlink -f "${command_path}")"
echo "${command_path}"
return 0
elif [ -n "${command_path}" ]; then
# The command exists as a function
echo "${command_name}"
return 0
fi
# The command does not exist
return 1
}
# Creating top-level directory (concept_dir)
current_step="setup of top-level directory"
set_concept_files() {
files=( \
".env" \
".dockerignore" \
".github" \
".gitignore" \
".path" \
"Dockerfile" \
"Makefile" \
"concept" \
"doc" \
"install" \
"param" \
"src" \
"test" \
"util" \
)
if [ "${slim}" != "True" ]; then
files=("${files[@]}" "CHANGELOG.md" "LICENSE" "README.md")
fi
}
if [ "${concept_dir_specified}" == "False" ]; then
printf "\nYou must now specify an installation directory for ${esc_concept}"
if [ -n "${HOME}" ] && [ -d "${HOME}" ] && [ ! -d "${HOME}/concept" ]; then
concept_dir_suggestion="${HOME}/concept"
printf ", e.g.\n${concept_dir_suggestion}"
else
printf "."
fi
concept_dir=""
while [ -z "${concept_dir}" ]; do
printf "\nWhere should ${esc_concept} be installed?\n"
read -p "> " concept_dir
if [ -n "${concept_dir}" ]; then
break
fi
done
fi
concept_dir="$(convert_to_abs_path "${concept_dir}")"
if [ "${concept_dir_specified}" == "False" ]; then
concept_dir_reasonable="False"
if [ "${concept_dir}" == "${HOME}" ]; then
printf "\nYou have specified your home directory \"${HOME}\" for the installation path.\n"
elif [ "${concept_dir}" == "${HOME}/Desktop" ]; then
printf "\nYou have specified your desktop \"${HOME}/Desktop\" for the installation path.\n"
elif [ "${concept_dir}" == "/home" ]; then
printf "\nYou have specified the \"/home\" directory for the installation path.\n"
elif [ "${concept_dir}" == "/" ]; then
printf "\nYou have specified the root directory \"/\" for the installation path.\n"
elif [ "${concept_dir}" == "/root" ]; then
printf "\nYou have specified the \"/root\" directory for the installation path.\n"
else
if [ -d "${concept_dir}" ]; then
if [ -z "$(ls -A "${concept_dir}")" ]; then
concept_dir_reasonable="True"
else
for n in 0 1; do
if [ "${concept_dir_reasonable}" == "True" ]; then
break
fi
if [ ${n} -eq 0 ]; then
set_concept_files
else
files=( \
"dep" \
".tmp/install_log" \
)
fi
for f in "${files[@]}"; do
f="${concept_dir}/${f}"
if [ -f "${f}" ] || [ -d "${f}" ]; then
concept_dir_reasonable="True"
break
fi
done
done
fi
else
concept_dir_reasonable="True"
fi
if [ "${concept_dir_reasonable}" == "False" ]; then
printf "\nYou have specified the non-empty \"${concept_dir}\" directory \
for the installation path.\n"
fi
fi
if [ "${concept_dir_reasonable}" == "False" ]; then
concept_dir_suggestion="$(convert_to_abs_path "${concept_dir}/concept")"
printf "You should probably change the installation path to a subdirectory within \
this directory — e.g. \"${concept_dir_suggestion}\" — so that ${esc_concept} is fully contained \
within a dedicated directory (to abort the installation, press Ctrl+C).\n"
while :; do
read -p "Change installation path to \"${concept_dir_suggestion}\"? [Y/n] " yn
case "${yn}" in
[Yy]*)
concept_dir="${concept_dir_suggestion}"
break
;;
[Nn]*)
break
;;
"")
concept_dir="${concept_dir_suggestion}"
break
;;
*)
;;
esac
done
fi
fi
concept_dir="$(convert_to_abs_path "${concept_dir}")"
concept_dir_is_sane="True"
mkdir -p "${concept_dir}" 2>/dev/null || concept_dir_is_sane="False"
if [ "${concept_dir_is_sane}" == "False" ]; then
error "\nThe installation path \"${concept_dir}\" cannot be created."
exit 1
fi
cd "${concept_dir}"
# Print out values of common installation options
heading "Installation options"
echo "Path \"${concept_dir}\""
if [[ "${mpi_dir}" == "__concept_dir__"* ]]; then
echo "MPI Dedicated ${mpi_formatted}"
else
if [ "${mpi_formatted}" == "unknown" ]; then
echo "MPI \"${mpi_dir}\""
else
echo "MPI \"${mpi_dir}\" (${mpi_formatted})"
fi
fi
echo "Slim installation ${slim}"
echo "Yes to defaults ${yes_to_defaults}"
echo "Tests ${do_tests}"
if [ "${concept_dir_reasonable}" == "False" ]; then
sleep 2
fi
# Replace "__concept_dir__" with the user specified concept_dir
# within the path to the tmp and dep directory and the log file.
tmp_dir="${tmp_dir/__concept_dir__/${concept_dir}}"
dep_dir="${dep_dir/__concept_dir__/${concept_dir}}"
log="${log/__concept_dir__/${concept_dir}}"
# Create the tmp directory.
# This will not be removed until the end,
# and here only if it is empty.
mkdir -p "${tmp_dir}"
# Check for another installation that is already running
if [ "${check_other_running_installation}" != "False" ] && [ -f "${log}" ]; then
installpid_line=""
while read logline; do # we really want to 'grep', but this might not (yet) be installed
if [[ "${logline}" == "${status_prefix}${status_installpid}"* ]]; then
installpid_line="${logline}"
fi
done <<< "$(cat "${log}")"
installpid_old=""
if [ -n "${installpid_line}" ]; then
installpid_old="${installpid_line#*=}"
installpid_old="${installpid_old#*=}"
fi
if [ -n "${installpid_old}" ] \
&& [ 0 -le ${installpid_old} 2>/dev/null ] \
&& kill -0 ${installpid_old} 2>/dev/null \
; then
# Other installation detected
printf "\nAnother installation is still running.\n"
printf "We should kill this other installation if we wish to start anew."
if [ "${yes_to_defaults}" == "True" ]; then
printf "\nKilling other installation\n"
kill ${installpid_old} || :
wait ${installpid_old} >/dev/null 2>&1 || :
echo "Other installation killed"
else
while :; do
printf "
How to proceed?
0) Kill other installation and continue with this one
1) Abort this installation
2) Abort both installations
3) Continue both installations (not recommended)
: "
read answer
answer="${answer//(/}"
answer="${answer//)/}"
case "${answer}" in
0)
echo "Killing other installation"
kill ${installpid_old} || :
wait ${installpid_old} >/dev/null 2>&1 || :
echo "Other installation killed"
break
;;
1)
echo "Aborting"
trap : 0
exit 0
;;
2)
echo "Killing other installation"
kill ${installpid_old} || :
wait ${installpid_old} >/dev/null 2>&1 || :
echo "Other installation killed"
echo "Aborting"
trap : 0
exit 0
;;
3)
echo "Continuing regardless"
break
;;
*)
;;
esac
done
fi
fi
fi
# This function should be called before any use of sudo and will cache
# the root password to the sudo_command variable. After this, instead of
# involving sudo, invoke ${sudo_command} (using eval). This way, the root
# password has to be entered at most once.
sudo_func_built="False"
build_sudo_func() {
if [ "${sudo_func_built}" == "True" ]; then
return
fi
sudo_command_only="False"
if [ "$1" == "sudo_command_only" ]; then
sudo_command_only="True"
fi
if [ "${sudo_command_only}" == "False" ]; then
sudo_func_built="True"
fi
# If root, no sudo/su is needed
if [ "${EUID}" == "0" ]; then
sudo_func() {
eval "$@"
}
sudo_command() {
echo "$@"
}
return
fi
# Check for sudo and su command
sudo_exist="False"
if get_command "sudo" >/dev/null; then
sudo_exist="True"
fi
su_exist="False"
if get_command "su" >/dev/null; then
su_exist="True"
fi
if [ "${sudo_exist}" == "False" ] && [ "${su_exist}" == "False" ]; then
# Neither the sudo nor the su command exist.
# Assume root privileges by default.
sudo_func() {
eval "$@"
}