Some command line options are not GNU/POSIX compliant (3)
[geeqie.git] / geeqie-install-debian.sh
1 #!/bin/sh
2
3 ## @file
4 ## @brief Download, compile, and install Geeqie on Debian-based systems.
5 ##
6 ## If run from a folder that already contains the Geeqie sources, the source
7 ## code will be updated from the repository.
8 ## Dialogs allow the user to install additional features.
9 ##
10
11 version="2024-01-22"
12 description='
13 Geeqie is an image viewer.
14 This script will download, compile, and install Geeqie on Debian-based systems.
15 If run from a folder that already contains the Geeqie sources, the source
16 code will be updated from the repository.
17 Dialogs allow the user to install additional features.
18
19 Command line options are:
20 -v --version The version of this file
21 -h --help Output this text
22 -c --commit=ID Checkout and compile commit ID
23 -t --tag=TAG Checkout and compile TAG (e.g. v1.4 or v1.3)
24 -b --back=N Checkout commit -N (e.g. "-b 1" for last-but-one commit)
25 -l --list List required dependencies
26 '
27
28 # Essential for compiling
29 essential_array="git
30 build-essential
31 libglib2.0-0
32 libtool
33 meson
34 ninja-build
35 yelp-tools
36 help2man
37 doclifter"
38
39 # Optional for GTK3
40 optional_array="LCMS (for color management)
41 liblcms2-dev
42 exiv2 (for exif handling)
43 libgexiv2-dev
44 evince (for print preview)
45 evince
46 lua (for --remote commands)
47 liblua5.3-dev
48 libffmpegthumbnailer (for mpeg thumbnails)
49 libffmpegthumbnailer-dev
50 libtiff (for tiff support)
51 libtiff-dev
52 libjpeg (for jpeg support)
53 libjpeg-dev
54 librsvg2 (for viewing .svg images)
55 librsvg2-common
56 libwmf (for viewing .wmf images)
57 libwmf0.2-7-gtk
58 exiftran (for image rotation)
59 exiftran
60 imagemagick (for image rotation)
61 imagemagick
62 exiv2 command line (for jpeg export)
63 exiv2
64 jpgicc (for jpeg export color correction)
65 liblcms2-utils
66 pandoc (for generating README help file)
67 pandoc
68 gphoto2 (for tethered photography and camera download plugins)
69 gphoto2
70 libimage-exiftool-perl (for jpeg extraction plugin)
71 libimage-exiftool-perl
72 libheif (for HEIF support)
73 libheif-dev
74 libwebp (for WebP images)
75 libwebp-dev
76 libdjvulibre (for DjVu images)
77 libdjvulibre-dev
78 libopenjp2 (for JP2 images)
79 libopenjp2-7-dev
80 libraw (for CR3 images)
81 libraw-dev
82 libomp (required by libraw)
83 libomp-dev
84 libarchive (for compressed files e.g. zip, including timezone)
85 libarchive-dev
86 libgspell (for spelling checks)
87 libgspell-1-dev
88 libchamplain gtk (for GPS maps)
89 libchamplain-gtk-0.12-dev
90 libchamplain (for GPS maps)
91 libchamplain-0.12-dev
92 libpoppler (for pdf file preview)
93 libpoppler-glib-dev
94 libjxl (for viewing .jxl images)
95 libjxl-dev"
96
97 ####################################################################
98 # Get System Info
99 # Derived from: https://github.com/coto/server-easy-install (GPL)
100 ####################################################################
101 lowercase()
102 {
103         printf '%b\n' "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"
104 }
105
106 systemProfile()
107 {
108         OS="$(lowercase "$(uname)")"
109         KERNEL=$(uname -r)
110         MACH=$(uname -m)
111
112         if [ "${OS}" = "windowsnt" ]
113         then
114                 OS=windows
115         elif [ "${OS}" = "darwin" ]
116         then
117                 OS=mac
118         else
119                 OS=$(uname)
120                 if [ "${OS}" = "SunOS" ]
121                 then
122                         OS=Solaris
123                         ARCH=$(uname -p)
124                         OSSTR="${OS} ${REV}(${ARCH} $(uname -v))"
125                 elif [ "${OS}" = "AIX" ]
126                 then
127                         # shellcheck disable=SC2034
128                         OSSTR="${OS} $(oslevel) ($(oslevel -r))"
129                 elif [ "${OS}" = "Linux" ]
130                 then
131                         if [ -f /etc/redhat-release ]
132                         then
133                                 DistroBasedOn='RedHat'
134                                 DIST=$(sed s/\ release.*// /etc/redhat-release)
135                                 PSUEDONAME=$(sed s/.*\(// /etc/redhat-release | sed s/\)//)
136                                 REV=$(sed s/.*release\ // /etc/redhat-release | sed s/\ .*//)
137                         elif [ -f /etc/SuSE-release ]
138                         then
139                                 DistroBasedOn='SuSe'
140                                 PSUEDONAME=$(tr "\n" ' ' < /etc/SuSE-release | sed s/VERSION.*//)
141                                 REV=$(tr "\n" ' ' < /etc/SuSE-release | sed s/.*=\ //)
142                         elif [ -f /etc/mandrake-release ]
143                         then
144                                 DistroBasedOn='Mandrake'
145                                 PSUEDONAME=$(sed s/.*\(// /etc/mandrake-release | sed s/\)//)
146                                 REV=$(cat | sed s/.*release\ // /etc/mandrake-release | sed s/\ .*//)
147                         elif [ -f /etc/debian_version ]
148                         then
149                                 DistroBasedOn='Debian'
150                                 if [ -f /etc/lsb-release ]
151                                 then
152                                         DIST=$(grep '^DISTRIB_ID' /etc/lsb-release | awk -F= '{ print $2 }')
153                                         PSUEDONAME=$(grep '^DISTRIB_CODENAME' /etc/lsb-release | awk -F= '{ print $2 }')
154                                         REV=$(grep '^DISTRIB_RELEASE' /etc/lsb-release | awk -F= '{ print $2 }')
155                                 fi
156                         fi
157                         if [ -f /etc/UnitedLinux-release ]
158                         then
159                                 DIST="${DIST}[$(tr "\n" ' ' < /etc/UnitedLinux-release | sed s/VERSION.*//)]"
160                         fi
161                         OS=$(lowercase "$OS")
162                         DistroBasedOn=$(lowercase "$DistroBasedOn")
163                         readonly OS
164                         readonly DIST
165                         readonly DistroBasedOn
166                         readonly PSUEDONAME
167                         readonly REV
168                         readonly KERNEL
169                         readonly MACH
170                 fi
171         fi
172 }
173
174 install_essential()
175 {
176         for file in $essential_array
177         do
178                 if package_query "$file"
179                 then
180                         package_install "$file"
181                 fi
182         done
183
184         if [ "$1" = "GTK3" ]
185         then
186                 if package_query "libgtk-3-dev"
187                 then
188                         package_install libgtk-3-dev
189                 fi
190         else
191                 if package_query "libgtk2.0-dev"
192                 then
193                         package_install libgtk2.0-dev
194                 fi
195         fi
196 }
197
198 install_options()
199 {
200         if [ -n "$options" ]
201         then
202                 OLDIFS=$IFS
203                 IFS='|'
204                 # shellcheck disable=SC2086
205                 set $options
206                 while [ $# -gt 0 ]
207                 do
208                         package_install "$1"
209                         shift
210                 done
211                 IFS=$OLDIFS
212         fi
213 }
214
215 uninstall()
216 {
217         current_dir="$(basename "$PWD")"
218         if [ "$current_dir" = "geeqie" ]
219         then
220
221                 sudo --askpass  ninja -C build uninstall
222
223                 if ! zenity --title="Uninstall Geeqie" --width=370 --text="WARNING.\nThis will delete folder:\n\n$PWD\n\nand all sub-folders!" --question --ok-label="Cancel" --cancel-label="OK" 2> /dev/null
224                 then
225                         cd ..
226                         sudo --askpass rm -rf geeqie
227                 fi
228         else
229                 zenity --title="Uninstall Geeqie" --width=370 --text="This is not a geeqie installation folder!\n\n$PWD" --warning 2> /dev/null
230         fi
231
232         exit_install
233 }
234
235 package_query()
236 {
237         if [ "$DistroBasedOn" = "debian" ]
238         then
239
240                 # shellcheck disable=SC2086
241                 res=$(dpkg-query --show --showformat='${Status}' "$1" 2>> $install_log)
242                 if [ "${res}" = "install ok installed" ]
243                 then
244                         status=1
245                 else
246                         status=0
247                 fi
248         fi
249         return "$status"
250 }
251
252 package_install()
253 {
254         if [ "$DistroBasedOn" = "debian" ]
255         then
256                 # shellcheck disable=SC2024
257                 sudo --askpass apt-get --assume-yes install "$@" >> "$install_log" 2>&1
258         fi
259 }
260
261 exit_install()
262 {
263         rm "$install_pass_script" > /dev/null 2>&1
264
265         if [ -p "$zen_pipe" ]
266         then
267                 printf '%b\n' "100" > "$zen_pipe"
268                 printf '%b\n' "#End" > "$zen_pipe"
269         fi
270
271         zenity --title="$title" --width=370 --text="Geeqie is not installed\nLog file: $install_log" --info 2> /dev/null
272
273         rm "$zen_pipe" > /dev/null 2>&1
274
275         exit 1
276 }
277
278 # Entry point
279
280 IFS='
281 '
282
283 # If uninstall has been run, maybe the current directory no longer exists
284 if [ ! -d "$PWD" ]
285 then
286         zenity --error --title="Install Geeqie and dependencies" --width=370 --text="Folder $PWD does not exist!" 2> /dev/null
287
288         exit
289 fi
290
291 # Check system type
292 systemProfile
293 if [ "$DistroBasedOn" != "debian" ]
294 then
295         zenity --error --title="Install Geeqie and dependencies" --width=370 --text="Unknown operating system:\n
296 Operating System: $OS
297 Distribution: $DIST
298 Psuedoname: $PSUEDONAME
299 Revision: $REV
300 DistroBasedOn: $DistroBasedOn
301 Kernel: $KERNEL
302 Machine: $MACH" 2> /dev/null
303
304         exit
305 fi
306
307 # Parse the command line
308 OPTS=$(getopt -o vhc:t:b:ld: --long version,help,commit:,tag:,back:,list,debug: -- "$@")
309 eval set -- "$OPTS"
310
311 while true
312 do
313         case "$1" in
314                 -v | --version)
315                         printf '%b\n' "$version"
316                         exit
317                         ;;
318                 -h | --help)
319                         printf '%b\n' "$description"
320                         exit
321                         ;;
322                 -c | --commit)
323                         COMMIT="$2"
324                         shift
325                         shift
326                         ;;
327                 -t | --tag)
328                         TAG="$2"
329                         shift
330                         shift
331                         ;;
332                 -b | --back)
333                         BACK="$2"
334                         shift
335                         shift
336                         ;;
337                 -l | --list)
338                         LIST="$2"
339                         shift
340                         shift
341                         ;;
342                 *)
343                         break
344                         ;;
345         esac
346 done
347
348 if [ -n "$LIST" ]
349 then
350         printf '%b\n' "Essential libraries:"
351         for file in $essential_array
352         do
353                 printf '%b\n' "$file"
354         done
355
356         printf '\n'
357         printf '%b\n' "Optional libraries:"
358         for file in $optional_array
359         do
360                 printf '%b\n' "$file"
361         done
362
363         exit
364 fi
365
366 # If a Geeqie folder already exists here, warn the user
367 if [ -d "geeqie" ]
368 then
369         zenity --info --title="Install Geeqie and dependencies" --width=370 --text="This script is for use on Ubuntu and other\nDebian-based installations.\nIt will download, compile, and install Geeqie source\ncode and its dependencies.\n\nA sub-folder named \"geeqie\" will be created in the\nfolder this script is run from, and the source code\nwill be downloaded to that sub-folder.\n\nA sub-folder of that name already exists.\nPlease try another folder." 2> /dev/null
370
371         exit
372 fi
373
374 # If it looks like a Geeqie download folder, assume an update
375 if [ -d ".git" ] && [ -d "src" ] && [ -f "geeqie.1" ]
376 then
377         mode="update"
378 else
379         # If it looks like something else is already installed here, warn the user
380         if [ -d ".git" ] || [ -d "src" ]
381         then
382                 zenity --info --title="Install Geeqie and dependencies" --width=370 --text="This script is for use on Ubuntu and other\nDebian-based installations.\nIt will download, compile, and install Geeqie source\ncode and its dependencies.\n\nIt looks like you are running this script from a folder which already has software installed.\n\nPlease try another folder." 2> /dev/null
383
384                 exit
385         else
386                 mode="install"
387         fi
388 fi
389
390 # Use GTK3 as default
391 gtk3_installed=TRUE
392
393 if [ "$mode" = "install" ]
394 then
395         message="This script is for use on Ubuntu and other\nDebian-based installations.\nIt will download, compile, and install Geeqie source\ncode and its dependencies.\n\nA sub-folder named \"geeqie\" will be created in the\nfolder this script is run from, and the source code\nwill be downloaded to that sub-folder.\n\nIn subsequent dialogs you may choose which\noptional features to install."
396
397         title="Install Geeqie and dependencies"
398         install_option=TRUE
399 else
400         message="This script is for use on Ubuntu and other\nDebian-based installations.\nIt will update the Geeqie source code and its\ndependencies, and will compile and install Geeqie.\n\nIn subsequent dialogs you may choose which\noptional features to install."
401
402         title="Update Geeqie and re-install"
403         install_option=FALSE
404 fi
405
406 # Ask whether to install GTK3 or uninstall
407
408 if ! gtk_version=$(zenity --title="$title" --width=370 --text="$message" --list --radiolist --column "" --column "" "$gtk3_installed" "Install" FALSE "Uninstall" --cancel-label="Cancel" --ok-label="OK" --hide-header 2> /dev/null)
409 then
410         exit
411 fi
412
413 # Environment variable SUDO_ASKPASS cannot be "zenity --password",
414 # so create a temporary script containing the command
415 install_pass_script=$(mktemp "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX")
416 printf '%b\n' "#!/bin/sh
417 if zenity --password --title=\"$title\" --width=370 2>/dev/null
418 then
419         exit 1
420 fi" > "$install_pass_script"
421 chmod +x "$install_pass_script"
422 export SUDO_ASKPASS="$install_pass_script"
423
424 if [ "$gtk_version" = "Uninstall" ]
425 then
426         uninstall
427 fi
428
429 # Put the install log in tmp, to avoid writing to PWD during a new install
430 rm install.log 2> /dev/null
431 install_log=$(mktemp "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX")
432
433 sleep 100 | zenity --title="$title" --text="Checking for installed files" --width=370 --progress --pulsate 2> /dev/null &
434 zen_pid=$!
435
436 # Get the standard options that are not yet installed
437 i=0
438 for file in $optional_array
439 do
440         if [ $((i % 2)) -eq 0 ]
441         then
442                 package_title="$file"
443         else
444                 if package_query "$file"
445                 then
446                         if [ -z "$option_string" ]
447                         then
448                                 option_string="${install_option:+${install_option}}\n${package_title}\n${file}"
449                         else
450                                 option_string="${option_string:+${option_string}}\n$install_option\n${package_title}\n${file}"
451                         fi
452                 fi
453         fi
454         i=$((i + 1))
455 done
456
457 kill "$zen_pid" 2> /dev/null
458
459 # Ask the user which options to install
460 if [ -n "$option_string" ]
461 then
462         if ! options=$(printf '%b\n' "$option_string" | zenity --title="$title" --width=400 --height=500 --list --checklist --text 'Select which library files to install:' --column='Select' --column='Library files' --column='Library' --hide-column=3 --print-column=3 2> /dev/null)
463         then
464                 exit_install
465         fi
466 fi
467
468 # Start of Zenity progress section
469 zen_pipe=$(mktemp -u "${TMPDIR:-/tmp}/geeqie.XXXXXXXXXX")
470 mkfifo "$zen_pipe"
471 (tail -f "$zen_pipe" 2> /dev/null) | zenity --progress --title="$title" --width=370 --text="Installing options..." --auto-close --auto-kill --percentage=0 2> /dev/null &
472
473 printf '%b\n' "2" > "$zen_pipe"
474 printf '%b\n' "#Installing essential libraries..." > "$zen_pipe"
475
476 install_essential "$gtk_version"
477
478 printf '%b\n' "4" > "$zen_pipe"
479 printf '%b\n' "#Installing options..." > "$zen_pipe"
480
481 install_options
482
483 printf '%b\n' "6" > "$zen_pipe"
484 printf '%b\n' "#Installing extra loaders..." > "$zen_pipe"
485
486 printf '%b\n' "10" > "$zen_pipe"
487 printf '%b\n' "#Getting new sources from server..." > "$zen_pipe"
488
489 if [ "$mode" = "install" ]
490 then
491         if ! git clone http://git.geeqie.org/git/geeqie.git >> "$install_log" 2>&1
492         then
493                 git_error=$(tail -n5 "$install_log" 2>&1)
494                 zenity --title="$title" --width=370 --height=400 --error --text="Git error:\n\n$git_error" 2> /dev/null
495                 exit_install
496         fi
497 else
498         if ! git checkout master >> "$install_log" 2>&1
499         then
500                 git_error="$(tail -n25 "$install_log" 2>&1)"
501                 zenity --title="$title" --width=370 --height=400 --error --text="Git error:\n\n$git_error" 2> /dev/null
502                 exit_install
503         fi
504         if ! git pull >> "$install_log" 2>&1
505         then
506                 git_error=$(tail -n5 "$install_log" 2>&1)
507                 zenity --title="$title" --width=370 --height=400 --error --text="Git error:\n\n$git_error" 2> /dev/null
508                 exit_install
509         fi
510 fi
511
512 printf '%b\n' "20" > "$zen_pipe"
513 printf '%b\n' "#Cleaning installed version..." > "$zen_pipe"
514
515 if [ "$mode" = "install" ]
516 then
517         cd geeqie || exit 1
518 else
519         sudo --askpass  ninja -C build uninstall
520 fi
521
522 printf '%b\n' "30" > "$zen_pipe"
523 printf '%b\n' "#Checkout required version..." > "$zen_pipe"
524
525 if [ -n "$BACK" ]
526 then
527         if ! git checkout master~"$BACK" >> "$install_log" 2>&1
528         then
529                 git_error=$(tail -n5 "$install_log" 2>&1)
530                 zenity --title="$title" --width=370 --height=400 --error --text="Git error:\n\n$git_error" 2> /dev/null
531                 exit_install
532         fi
533 elif [ -n "$COMMIT" ]
534 then
535
536         if ! git checkout "$COMMIT" >> "$install_log" 2>&1
537         then
538                 git_error=$(tail -n5 "$install_log" 2>&1)
539                 zenity --title="$title" --width=370 --height=400 --error --text="Git error:\n\n$git_error" 2> /dev/null
540                 exit_install
541         fi
542 elif [ -n "$TAG" ]
543 then
544         if ! git checkout "$TAG" >> "$install_log" 2>&1
545         then
546                 git_error=$(tail -n5 "$install_log" 2>&1)
547                 zenity --title="$title" --width=370 --height=400 --error --text="Git error:\n\n$git_error" 2> /dev/null
548                 exit_install
549         fi
550 fi
551
552 printf '%b\n' "40" > "$zen_pipe"
553 printf '%b\n' "#Creating configuration files..." > "$zen_pipe"
554
555 if [ -z "${gtk_version%%GTK3*}" ]
556 then
557         meson setup build
558         printf '%b\n' "90 " > "$zen_pipe"
559         printf '%b\n' "#Installing Geeqie..." > "$zen_pipe"
560         ninja -C build install
561 else
562         meson setup build
563         meson configure --no-pager build
564         printf '%b\n' "90 " > "$zen_pipe"
565         printf '%b\n' "#Installing Geeqie..." > "$zen_pipe"
566         sudo --askpass meson install -C build
567 fi
568
569 rm "$install_pass_script"
570 mv -f "$install_log" "./build/install.log"
571
572 printf '%b\n' "100 " > "$zen_pipe"
573 rm "$zen_pipe"
574
575 (for i in $(seq 0 4 100)
576 do
577         printf '%b\n' "$i"
578         sleep 0.1
579 done) | zenity --progress --title="$title" --width=370 --text="Geeqie installation complete...\n" --auto-close --percentage=0 2> /dev/null
580
581 exit