]> gitweb.factorcode.org Git - factor.git/blob - build.sh
scryfall: better moxfield words
[factor.git] / build.sh
1 #!/usr/bin/env bash
2
3 # Programs returning != 0 will not cause script to exit
4 set +e
5
6 # Case insensitive string comparison
7 shopt -s nocaseglob
8 #shopt -s nocasematch
9
10 ECHO="echo"
11 OS=
12 ARCH=
13 WORD=
14 GIT_PROTOCOL=${GIT_PROTOCOL:="https"}
15 GIT_URL=${GIT_URL:=$GIT_PROTOCOL"://github.com/factor/factor.git"}
16
17 test_program_installed() {
18     command -v "$1" >/dev/null 2>&1
19 }
20
21 # return 1 on found
22 test_programs_installed() {
23     local installed=0
24     $ECHO -n "Checking for all($*)..."
25     for cmd in "$@" ;
26     do
27         if test_program_installed "$cmd"; then
28             ((installed++))
29         fi
30     done
31     if [[ $installed -eq $# ]] ; then
32         $ECHO "found!"
33         return 0
34     fi
35     return 1
36 }
37
38 exit_script() {
39     if [[ $FIND_MAKE_TARGET = true ]] ; then
40         # not $ECHO here
41         echo "$MAKE_TARGET"
42     fi
43     exit "$1"
44 }
45
46 ensure_program_installed() {
47     local installed=0
48     $ECHO -n "Checking for any($*)..."
49     for cmd in "$@" ;
50     do
51         if test_program_installed "$cmd"; then
52             $ECHO "found $cmd!"
53             ((installed++))
54             return
55         fi
56     done
57     $ECHO "none found."
58     $ECHO -n "Install "
59     if [[ $# -eq 1 ]] ; then
60         $ECHO -n "$1"
61     else
62         $ECHO -n "any of [ $* ]"
63     fi
64     $ECHO " and try again."
65     if [[ $OS == macosx ]] ; then
66         $ECHO "If you have Xcode 4.3 or higher installed, you must install the"
67         $ECHO "Command Line Tools from Xcode Preferences > Downloads in order"
68         $ECHO "to build Factor."
69     fi
70     exit_script 1
71 }
72
73 check_ret() {
74     # Can't execute any commands before saving $?
75     # $1 is the name of the command we are checking
76     RET=$?
77     if [[ $RET -ne 0 ]] ; then
78        $ECHO "$1" failed
79        exit_script 2
80     fi
81 }
82
83 download_with_wget() {
84     local url="$1"
85     local filename
86     filename=$(basename "$url")
87     $ECHO filename is "$filename"
88     $ECHO wget -nd --prefer-family=IPv4 -O "$filename" "$url"
89     wget -nd --prefer-family=IPv4 -O "$filename" "$url"
90 }
91
92 download_with_curl() {
93     local url="$1"
94     local filename
95     filename=$(basename "$url")
96     curl -L -f -o "$filename" "$url"
97 }
98
99 download_with_downloader() {
100     local url="$1"
101     if [[ -z $DOWNLOADER_NAME ]] ; then
102         set_downloader
103     fi
104     if [[ $DOWNLOADER_NAME == 'wget' ]]; then
105         download_with_wget "$url"
106     elif [[ $DOWNLOADER_NAME == 'curl' ]]; then
107         download_with_curl "$url"
108     else
109         $ECHO "error: wget or curl required in download_with_downloader"
110         exit_script 12
111     fi
112 }
113
114 set_downloader() {
115     if test_program_installed wget; then
116         DOWNLOADER_NAME=wget
117         return
118     fi
119     if test_program_installed curl; then
120         DOWNLOADER_NAME=curl
121         return
122     fi
123     $ECHO "error: wget or curl required"
124     exit_script 11
125 }
126
127 set_md5sum() {
128     if test_program_installed md5sum; then
129         MD5SUM=md5sum
130     else
131         MD5SUM="md5 -r"
132     fi
133 }
134
135 set_cc() {
136     # on Cygwin we MUST use the MinGW "cross-compiler", therefore check these first
137     # furthermore, we prefer 64 bit over 32 bit versions if both are available
138
139     # we need this condition so we don't find a mingw32 compiler on linux
140     if [[ $OS == windows ]] ; then
141         if test_programs_installed x86_64-w64-mingw32-gcc x86_64-w64-mingw32-g++; then
142             [ -z "$CC" ] && CC=x86_64-w64-mingw32-gcc
143             [ -z "$CXX" ] && CXX=x86_64-w64-mingw32-g++
144             return
145         fi
146
147         if test_programs_installed i686-w64-mingw32-gcc i686-w64-mingw32-g++; then
148             [ -z "$CC" ] && CC=i686-w64-mingw32-gcc
149             [ -z "$CXX" ] && CXX=i686-w64-mingw32-g++
150             return
151         fi
152     fi
153
154     if test_programs_installed clang clang++ ; then
155         [ -z "$CC" ] && CC=clang
156         [ -z "$CXX" ] && CXX=clang++
157         return
158     fi
159
160     # gcc and g++ will fail to correctly build Factor on Cygwin
161     if test_programs_installed gcc g++ ; then
162         [ -z "$CC" ] && CC=gcc
163         [ -z "$CXX" ] && CXX=g++
164         return
165     fi
166
167     $ECHO "error: high enough version of either (clang/clang++) or (gcc/g++) required!"
168     exit_script 10
169 }
170
171 set_make() {
172     case $OS in
173         freebsd) MAKE="gmake" ;;
174         *) MAKE="make" ;;
175     esac
176     if [[ $MAKE = "gmake" ]] ; then
177         ensure_program_installed gmake
178     fi
179 }
180
181 check_installed_programs() {
182     ensure_program_installed chmod
183     ensure_program_installed uname
184     ensure_program_installed git
185     ensure_program_installed wget curl
186     ensure_program_installed clang x86_64-w64-mingw32-gcc i686-w64-mingw32-gcc gcc
187     ensure_program_installed clang++ x86_64-w64-mingw32-g++ i686-w64-mingw32-g++ g++ cl
188     ensure_program_installed make gmake
189     ensure_program_installed md5sum md5
190     ensure_program_installed cut
191 }
192
193 check_library_exists() {
194     GCC_TEST=factor-library-test.c
195     GCC_OUT=factor-library-test.out
196     $ECHO -n "Checking for library $1..."
197     $ECHO "int main(){return 0;}" > $GCC_TEST
198     if $CC $GCC_TEST -o $GCC_OUT -l "$1" 2>&- ; then
199         $ECHO "not found."
200     else
201         $ECHO "found."
202     fi
203     rm -f $GCC_TEST
204     check_ret rm
205     rm -f $GCC_OUT
206     check_ret rm
207 }
208
209 check_X11_libraries() {
210     check_library_exists GL
211     check_library_exists X11
212     check_library_exists pango-1.0
213 }
214
215 check_gtk_libraries() {
216     check_library_exists gobject-2.0
217     check_library_exists gtk-x11-2.0
218     check_library_exists gdk-x11-2.0
219     check_library_exists gdk_pixbuf-2.0
220     check_library_exists gtkglext-x11-1.0
221     check_library_exists atk-1.0
222     check_library_exists gio-2.0
223     check_library_exists gdkglext-x11-1.0
224     check_library_exists pango-1.0
225 }
226
227
228 check_libraries() {
229     case $OS in
230         linux) check_X11_libraries
231                check_gtk_libraries ;;
232         unix) check_gtk_libraries ;;
233     esac
234 }
235
236 check_factor_exists() {
237     if [[ -d "factor" ]] ; then
238         $ECHO "A directory called 'factor' already exists."
239         $ECHO "Rename or delete it and try again."
240         exit_script 4
241     fi
242 }
243
244 find_os() {
245     if [[ -n $OS ]] ; then return; fi
246     $ECHO "Finding OS..."
247     local uname_s
248     uname_s=$(uname -s)
249     check_ret uname
250     case $uname_s in
251         CYGWIN_NT-5.2-WOW64) OS=windows ;;
252         *CYGWIN_NT*) OS=windows ;;
253         *CYGWIN*) OS=windows ;;
254         MINGW32*) OS=windows ;;
255         MINGW64*) OS=windows ;;
256         MSYS_NT*) OS=windows ;;
257         *darwin*) OS=macosx ;;
258         *Darwin*) OS=macosx ;;
259         *linux*) OS=linux ;;
260         *Linux*) OS=linux ;;
261         FreeBSD) OS=freebsd ;;
262         Haiku) OS=haiku ;;
263     esac
264 }
265
266 find_architecture() {
267     if [[ -n $ARCH ]] ; then return; fi
268     $ECHO "Finding ARCH..."
269     uname_m=$(uname -m)
270     check_ret uname
271     case $uname_m in
272        i386) ARCH=x86 ;;
273        i686) ARCH=x86 ;;
274        i86pc) ARCH=x86 ;;
275        amd64) ARCH=x86 ;;
276        ppc64) ARCH=ppc ;;
277        *86) ARCH=x86 ;;
278        *86_64) ARCH=x86 ;;
279        aarch64) ARCH=arm ;;
280        arm64) ARCH=arm ;;
281        iPhone5*[3-9]) ARCH=arm ;;
282        iPhone[6-9]*) ARCH=arm ;;
283        iPhone[1-9][0-9]*) ARCH=arm ;;
284        iPad[4-9]*) ARCH=arm ;;
285        iPad[1-9][0-9]*) ARCH=arm ;;
286        AppleTV[5-9]*) ARCH=arm ;;
287        AppleTV[1-9][0-9]*) ARCH=arm ;;
288        "Power Macintosh") ARCH=ppc ;;
289     esac
290 }
291
292 find_num_cores() {
293     $ECHO "Finding NUM_CORES..."
294     NUM_CORES=1
295     uname_s=$(uname -s)
296     check_ret uname
297     case $uname_s in
298         CYGWIN_NT-5.2-WOW64 | *CYGWIN_NT* | *CYGWIN* | MINGW32*) NUM_CORES=$NUMBER_OF_PROCESSORS ;;
299         *linux* | *Linux*) NUM_CORES=$(getconf _NPROCESSORS_ONLN || nproc) ;;
300         *darwin* | *Darwin* | freebsd) NUM_CORES=$(sysctl -n hw.ncpu) ;;
301     esac
302 }
303
304 find_word_size() {
305     if [[ -n $WORD ]] ; then return; fi
306     $ECHO "Finding WORD..."
307     WORD=$(getconf LONG_BIT || find_word_size_cpp || find_word_size_c)
308 }
309
310 find_word_size_cpp() {
311     SIXTY_FOUR='defined(__aarch64__) || defined(__x86_64__) || defined(_M_AMD64) || defined(__PPC64__) || defined(__64BIT__)'
312     THIRTY_TWO='defined(i386) || defined(__i386) || defined(__i386__) || defined(_MIX86)'
313     $CC -E -xc <(echo -e "#if ${SIXTY_FOUR}\n64\n#elif ${THIRTY_TWO}\n32\n#endif") | tail -1
314 }
315
316 find_word_size_c() {
317     C_WORD="factor-word-size"
318     TEST_PROGRAM="int main(){ return (long)(8*sizeof(void*)); }"
319     echo "$TEST_PROGRAM" | $CC -o $C_WORD -xc -
320     check_ret "$CC"
321     ./$C_WORD
322     WORD_OUT=$?
323     case $WORD_OUT in
324         32) ;;
325         64) ;;
326         *)
327             echo "Word size should be 32/64, got '$WORD_OUT'"
328             exit_script 15 ;;
329     esac
330     rm -f $C_WORD
331     echo "$WORD_OUT"
332 }
333
334 set_factor_binary() {
335     case $OS in
336         windows) FACTOR_BINARY=factor.com ;;
337         *) FACTOR_BINARY=factor ;;
338     esac
339 }
340
341 set_factor_library() {
342     case $OS in
343         windows) FACTOR_LIBRARY=factor.dll ;;
344         macosx) FACTOR_LIBRARY=libfactor.dylib ;;
345         *) FACTOR_LIBRARY=libfactor.a ;;
346     esac
347 }
348
349 set_factor_image() {
350     FACTOR_IMAGE=factor.image
351     FACTOR_IMAGE_FRESH=factor.image.fresh
352 }
353
354 echo_build_info() {
355     $ECHO "OS=$OS"
356     $ECHO "ARCH=$ARCH"
357     $ECHO "NUM_CORES=$NUM_CORES"
358     $ECHO "WORD=$WORD"
359     $ECHO "DEBUG=$DEBUG"
360     $ECHO "REPRODUCIBLE=$REPRODUCIBLE"
361     $ECHO "CURRENT_BRANCH=$CURRENT_BRANCH"
362     $ECHO "CURRENT_BRANCH_FULL=$CURRENT_BRANCH_FULL"
363     $ECHO "FACTOR_BINARY=$FACTOR_BINARY"
364     $ECHO "FACTOR_LIBRARY=$FACTOR_LIBRARY"
365     $ECHO "FACTOR_IMAGE=$FACTOR_IMAGE"
366     $ECHO "MAKE_TARGET=$MAKE_TARGET"
367     $ECHO "BOOT_IMAGE=$BOOT_IMAGE"
368     $ECHO "MAKE_IMAGE_TARGET=$MAKE_IMAGE_TARGET"
369     $ECHO "GIT_PROTOCOL=$GIT_PROTOCOL"
370     $ECHO "GIT_URL=$GIT_URL"
371     $ECHO "CHECKSUM_URL=$CHECKSUM_URL"
372     $ECHO "BOOT_IMAGE_URL=$BOOT_IMAGE_URL"
373     $ECHO "DOWNLOADER_NAME=$DOWNLOADER_NAME"
374     $ECHO "CC=$CC"
375     $ECHO "CXX=$CXX"
376     $ECHO "MAKE=$MAKE"
377 }
378
379 check_os_arch_word() {
380     if ! [[ -n $OS && -n $ARCH && -n $WORD ]] ; then
381         $ECHO "OS: $OS"
382         $ECHO "ARCH: $ARCH"
383         $ECHO "WORD: $WORD"
384         $ECHO "OS, ARCH, or WORD is empty.  Please report this."
385
386         $ECHO $MAKE_TARGET
387         exit_script 5
388     fi
389 }
390
391 set_build_info() {
392     check_os_arch_word
393     if [[ $OS == "windows" ]] ; then
394         MAKE_IMAGE_TARGET=windows-$ARCH.$WORD
395         MAKE_TARGET=$OS-$ARCH-$WORD
396     else
397         MAKE_IMAGE_TARGET=unix-$ARCH.$WORD
398         MAKE_TARGET=$OS-$ARCH-$WORD
399     fi
400     BOOT_IMAGE=boot.$MAKE_IMAGE_TARGET.image
401 }
402
403 parse_build_info() {
404     ensure_program_installed cut
405     $ECHO "Parsing make target from command line: $1"
406     OS=$(echo "$1" | cut -d '-' -f 1)
407     ARCH=$(echo "$1" | cut -d '-' -f 2)
408     WORD=$(echo "$1" | cut -d '-' -f 3)
409
410     if [[ $OS == linux && $ARCH == ppc ]] ; then WORD=32; fi
411     if [[ $OS == linux && $ARCH == arm ]] ; then WORD=32; fi
412     if [[ $OS == macosx && $ARCH == ppc ]] ; then WORD=32; fi
413
414     $ECHO "OS=$OS"
415     $ECHO "ARCH=$ARCH"
416     $ECHO "WORD=$WORD"
417 }
418
419 prepare_build_info() {
420     find_os
421     find_architecture
422     find_num_cores
423     set_cc
424     find_word_size
425     set_current_branch
426     set_factor_binary
427     set_factor_library
428     set_factor_image
429     set_build_info
430     set_downloader
431     set_boot_image_vars
432     set_make
433 }
434
435 find_build_info() {
436     prepare_build_info
437     echo_build_info
438 }
439
440 invoke_git() {
441     git "$@"
442     check_ret git
443 }
444
445 git_clone() {
446     $ECHO "Downloading the git repository from github.com..."
447     invoke_git clone "$GIT_URL"
448 }
449
450 update_script_name() {
451     $ECHO "$(dirname "$0")/_update.sh"
452 }
453
454 update_script() {
455   set_current_branch
456   local -r update_script=$(update_script_name)
457   local -r shell_path="$SHELL"
458   {
459     echo "#!$shell_path"
460     echo "set -ex"
461     echo "git pull ${GIT_URL} ${CURRENT_BRANCH}"
462     echo "exit 0"
463   } > "$update_script"
464   chmod 755 "$update_script"
465   $ECHO "Running the build.sh updater script: $update_script"
466   exec "$update_script"
467 }
468
469 update_script_changed() {
470     invoke_git diff --stat "$(invoke_git merge-base HEAD FETCH_HEAD)" FETCH_HEAD | grep "build.sh" >/dev/null
471 }
472
473 git_fetch() {
474     $ECHO "Fetching the git repository from github.com..."
475     set_current_branch
476
477     rm -f "$(update_script_name)"
478     $ECHO git fetch "$GIT_URL" "${CURRENT_BRANCH}"
479     invoke_git fetch "$GIT_URL" "${CURRENT_BRANCH}"
480
481     if update_script_changed; then
482         $ECHO "Updating and restarting the build.sh script..."
483         update_script
484     else
485         $ECHO "Updating the working tree..."
486         invoke_git pull "$GIT_URL" "${CURRENT_BRANCH}"
487     fi
488 }
489
490 cd_factor() {
491     cd "factor" || exit 12
492     check_ret cd
493 }
494
495 backup_factor() {
496     $ECHO "Backing up factor..."
497     cp "$FACTOR_BINARY" "$FACTOR_BINARY.bak"
498     cp "$FACTOR_LIBRARY" "$FACTOR_LIBRARY.bak"
499     cp "$BOOT_IMAGE" "$BOOT_IMAGE.bak"
500     cp "$FACTOR_IMAGE" "$FACTOR_IMAGE.bak"
501     $ECHO "Done with backup."
502 }
503
504 check_makefile_exists() {
505     if [[ ! -e "GNUmakefile" ]] ; then
506         $ECHO ""
507         $ECHO "***GNUmakefile not found***"
508         $ECHO "You are likely in the wrong directory."
509         $ECHO "Run this script from your factor directory:"
510         $ECHO "     ./build.sh"
511         exit_script 6
512     fi
513 }
514
515 invoke_make() {
516     check_makefile_exists
517     if [ -n "$MAKE_OPTS" ]; then
518         "$MAKE" "$MAKE_OPTS" "$@"
519     else
520         "$MAKE" "$@"
521     fi
522     check_ret $MAKE
523 }
524
525 make_clean() {
526     invoke_make clean
527 }
528
529 make_factor() {
530     $ECHO "Building factor with $NUM_CORES cores"
531     invoke_make "CC=$CC" "CXX=$CXX" "$MAKE_TARGET" "-j$NUM_CORES"
532 }
533
534 make_clean_factor() {
535     make_clean
536     make_factor
537 }
538
539 current_git_branch() {
540     # git rev-parse --abbrev-ref HEAD # outputs HEAD for detached head
541     # outputs nothing for detached HEAD, which is fine for ``git fetch``
542     git describe --all --exact-match 2>/dev/null
543 }
544
545
546 check_url() {
547     if [[ $DOWNLOADER_NAME == 'wget' ]]; then
548         wget -S --spider --prefer-family=IPv4 "$1" 2>&1 | grep -q 'HTTP/[12].[01] [23]..' && return 0 || return 1
549     elif [[ $DOWNLOADER_NAME == 'curl' ]]; then
550         curl -4 -sL -w "%{http_code}\\n" "$1" -o /dev/null | grep -qE '^(2[0-9]{2})$' && return 0 || return 1
551     else
552         echo "error: wget or curl required to check URL"
553         exit 12
554     fi
555 }
556
557 # If we are on a branch, first try to get a boot image for that branch.
558 # Otherwise, just use `master`
559 set_boot_image_vars() {
560     set_current_branch
561     local url="https://downloads.factorcode.org/images/${CURRENT_BRANCH}/checksums.txt"
562     $ECHO "Getting checksum from ${url}"
563
564     if check_url "$url"; then
565         $ECHO "got checksum!"
566         CHECKSUM_URL="$url"
567         BOOT_IMAGE_URL="https://downloads.factorcode.org/images/${CURRENT_BRANCH}/${BOOT_IMAGE}"
568     else
569         $ECHO "boot image for branch \`${CURRENT_BRANCH}\` is not on server, trying master instead"
570         $ECHO "  tried nonexistent url: ${url}"
571         CHECKSUM_URL="https://downloads.factorcode.org/images/master/checksums.txt"
572         BOOT_IMAGE_URL="https://downloads.factorcode.org/images/master/${BOOT_IMAGE}"
573     fi
574 }
575
576 set_current_branch() {
577     if [ -n "${CI_BRANCH}" ]; then
578         CURRENT_BRANCH="${CI_BRANCH}"
579     else
580         CURRENT_BRANCH_FULL=$(current_git_branch)
581         CURRENT_BRANCH=$($ECHO "$CURRENT_BRANCH_FULL" | sed 's=heads/==;s=remotes/==')
582     fi
583 }
584
585 update_boot_image() {
586     set_boot_image_vars
587     $ECHO "Deleting old images..."
588     rm -f checksums.txt* > /dev/null 2>&1
589     rm -f "$BOOT_IMAGE".{?,??} > /dev/null 2>&1
590     rm -f temp/staging.*.image > /dev/null 2>&1
591     if [[ -f $BOOT_IMAGE ]] ; then
592         get_url "$CHECKSUM_URL"
593         local factorcode_md5
594         factorcode_md5=$(grep "$BOOT_IMAGE" checksums.txt | cut -f2 -d' ')
595         set_md5sum
596         local disk_md5
597         disk_md5=$($MD5SUM "$BOOT_IMAGE" | cut -f1 -d' ')
598         $ECHO "Factorcode md5: $factorcode_md5"
599         $ECHO "Disk md5: $disk_md5"
600         if [[ "$factorcode_md5" == "$disk_md5" ]] ; then
601             $ECHO "Your disk boot image matches the one on downloads.factorcode.org."
602         else
603             rm -f "$BOOT_IMAGE" > /dev/null 2>&1
604             get_boot_image
605         fi
606     else
607         get_boot_image
608     fi
609 }
610
611 get_boot_image() {
612     $ECHO "Downloading boot image $BOOT_IMAGE."
613     get_url "${BOOT_IMAGE_URL}"
614 }
615
616 get_url() {
617     if [[ -z $DOWNLOADER_NAME ]] ; then
618         set_downloader_name
619     fi
620     download_with_downloader "$1"
621 }
622
623 get_config_info() {
624     find_build_info
625     check_installed_programs
626     check_libraries
627 }
628
629 copy_fresh_image() {
630     $ECHO "Copying $FACTOR_IMAGE to $FACTOR_IMAGE_FRESH..."
631     cp "$FACTOR_IMAGE" "$FACTOR_IMAGE_FRESH"
632 }
633
634 check_launch_factor() {
635     "./$FACTOR_BINARY" -e=
636     check_ret "Could not launch ./$FACTOR_BINARY"
637 }
638
639 is_boot_image_outdated() {
640     "./$FACTOR_BINARY" "-e=USE: system \"\" to-refresh 2drop length 0 > 1 0 ? exit"
641     return $?
642 }
643
644 info_boot_image() {
645     prepare_build_info
646     if [[ -f $BOOT_IMAGE ]] ; then
647         get_url "$CHECKSUM_URL"
648         local factorcode_md5
649         factorcode_md5=$(grep "$BOOT_IMAGE" checksums.txt | cut -f2 -d' ')
650         set_md5sum
651         local disk_md5
652         disk_md5=$($MD5SUM "$BOOT_IMAGE" | cut -f1 -d' ')
653         $ECHO "Boot image @factorcode.org md5: $factorcode_md5"
654         $ECHO "Boot image @local disk     md5: $disk_md5"
655         if [[ "$factorcode_md5" == "$disk_md5" ]] ; then
656             $ECHO "Your disk boot image matches the one on downloads.factorcode.org."
657         else
658             $ECHO "Your disk boot image and the one on downloads.factorcode.org mismatch"
659         fi
660     fi
661 }
662
663 info_check_factor_refresh_all_locally() {
664     prepare_build_info
665     check_launch_factor
666
667     if is_boot_image_outdated; then
668         $ECHO "Your Factor image is consistent with the local source code."
669     else
670         $ECHO "Your Factor image is not consistent with the local source code."
671     fi
672 }
673
674 bootstrap() {
675     ./$FACTOR_BINARY -i="$BOOT_IMAGE"
676     check_ret "./$FACTOR_BINARY bootstrap failed"
677     copy_fresh_image
678 }
679
680 install() {
681     check_factor_exists
682     get_config_info
683     git_clone
684     cd_factor
685     make_factor
686     set_boot_image_vars
687     get_boot_image
688     bootstrap
689 }
690
691 update() {
692     get_config_info
693     git_fetch
694     backup_factor
695     make_clean_factor
696 }
697
698 download_and_bootstrap() {
699     update_boot_image
700     bootstrap
701 }
702
703 net_bootstrap_no_pull() {
704     get_config_info
705     make_clean_factor
706     download_and_bootstrap
707 }
708
709 refresh_image() {
710     ./$FACTOR_BINARY -e="USING: vocabs.loader vocabs.refresh system memory ; refresh-all save 0 exit"
711     check_ret factor
712 }
713
714 make_boot_image() {
715     ./$FACTOR_BINARY -run="bootstrap.image" "$MAKE_IMAGE_TARGET"
716     check_ret factor
717 }
718
719 install_deps_apt() {
720     sudo apt install --yes libc6-dev libpango1.0-dev libx11-dev xorg-dev libgtk2.0-dev gtk2-engines-pixbuf libgtkglext1-dev wget git git-doc rlwrap clang make screen tmux libssl-dev
721     check_ret sudo
722 }
723
724 install_deps_pacman() {
725     sudo pacman --noconfirm -Syu gcc clang make rlwrap git wget pango glibc gtk2 gtk3 gtkglext gtk-engines gdk-pixbuf2 libx11 screen tmux
726     check_ret sudo
727 }
728
729 install_deps_dnf() {
730     sudo dnf --assumeyes install gcc gcc-c++ glibc-devel binutils libX11-devel pango-devel gtk3-devel gdk-pixbuf2-devel gtkglext-devel tmux rlwrap wget
731     check_ret sudo
732 }
733
734 install_deps_pkg() {
735     sudo pkg install --yes bash git gmake gcc rlwrap ripgrep curl gmake x11-toolkits/gtk30 x11-toolkits/gtkglext pango cairo vim
736 }
737
738
739 install_deps_macosx() {
740     if test_program_installed git; then
741         ensure_program_installed yes
742         $ECHO "git not found."
743         $ECHO "This script requires either git-core or port."
744         $ECHO "If it fails, install git-core or port and try again."
745         ensure_program_installed port
746         $ECHO "Installing git-core with port...this will take awhile."
747         yes | sudo port install git-core
748     fi
749 }
750
751 usage() {
752     $ECHO "usage: $0 command [optional-target]"
753     $ECHO "  install - git clone, compile, bootstrap"
754     $ECHO "  deps-apt - install required packages for Factor on Linux using apt"
755     $ECHO "  deps-pacman - install required packages for Factor on Linux using pacman"
756     $ECHO "  deps-dnf - install required packages for Factor on Linux using dnf"
757     $ECHO "  deps-pkg - install required packages for Factor on FreeBSD using pkg"
758     $ECHO "  deps-macosx - install git on MacOSX using port"
759     $ECHO "  info-boot-image - print remote and disk boot image MD5"
760     $ECHO "  info-check-factor-refresh-all-locally - check if local sources would cause refresh-all to change the image"
761     $ECHO "  self-bootstrap - make local boot image, bootstrap"
762     $ECHO "  self-update - git pull, recompile, make local boot image, bootstrap"
763     $ECHO "  quick-update - git pull, refresh-all, save"
764     $ECHO "  update|latest - git pull, recompile, download a boot image, bootstrap"
765     $ECHO "  compile - compile the binary"
766     $ECHO "  recompile - recompile the binary"
767     $ECHO "  bootstrap - bootstrap with existing boot image"
768     $ECHO "  net-bootstrap - recompile, download a boot image, bootstrap"
769     $ECHO "  make-target - find and print the os-arch-cpu string"
770     $ECHO "  report|info - print the build variables"
771     $ECHO "  full-report - print the build variables, check programs and libraries"
772     $ECHO "  update-boot-image - get the boot image for the current branch"
773     $ECHO ""
774     $ECHO "If you are behind a firewall, invoke as:"
775     $ECHO "env GIT_PROTOCOL=http $0 <command>"
776     $ECHO ""
777     $ECHO "Example for overriding the default target:"
778     $ECHO "    $0 update macosx-x86-32"
779 }
780
781 MAKE_TARGET=unknown
782
783 # -n is nonzero length, -z is zero length
784 if [[ -n "$2" ]] ; then
785     parse_build_info "$2"
786 fi
787
788 if [ "$#" -gt 3 ]; then
789     usage
790     $ECHO "error: too many arguments"
791     exit 1
792 fi
793
794 case "$1" in
795     install) install ;;
796     deps-apt) install_deps_apt ;;
797     deps-pacman) install_deps_pacman ;;
798     deps-macosx) install_deps_macosx ;;
799     deps-dnf) install_deps_dnf ;;
800     deps-pkg) install_deps_pkg ;;
801     info-boot-image) info_boot_image ;;
802     info-check-factor-refresh-all-locally) info_check_factor_refresh_all_locally ;;
803     update-boot-image) find_build_info; check_installed_programs; update_boot_image ;;
804     self-bootstrap) get_config_info; make_boot_image; bootstrap  ;;
805     self-update) update; make_boot_image; bootstrap  ;;
806     quick-update) update; refresh_image ;;
807     update|latest) update; download_and_bootstrap ;;
808     compile) find_build_info; make_factor ;;
809     recompile) find_build_info; make_clean; make_factor ;;
810     bootstrap) get_config_info; bootstrap ;;
811     net-bootstrap) net_bootstrap_no_pull ;;
812     make-target) FIND_MAKE_TARGET=true; ECHO=false; find_build_info; exit_script 0;;
813     report|info) find_build_info ;;
814     full-report) find_build_info; check_installed_programs; check_libraries ;;
815     update-script) update_script ;;
816     *) usage ;;
817 esac
818