| #!/bin/bash |
| ############################################################################### |
| # BRLTTY - A background process providing access to the console screen (when in |
| # text mode) for a blind person using a refreshable braille display. |
| # |
| # Copyright (C) 1995-2023 by The BRLTTY Developers. |
| # |
| # BRLTTY comes with ABSOLUTELY NO WARRANTY. |
| # |
| # This is free software, placed under the terms of the |
| # GNU Lesser General Public License, as published by the Free Software |
| # Foundation; either version 2.1 of the License, or (at your option) any |
| # later version. Please see the file LICENSE-LGPL for details. |
| # |
| # Web Page: http://brltty.app/ |
| # |
| # This software is maintained by Dave Mielke <dave@mielke.cc>. |
| ############################################################################### |
| |
| . "`dirname "${0}"`/../brltty-prologue.sh" |
| . "${programDirectory}/mingw.sh" |
| |
| set -e |
| umask 022 |
| |
| readonly defaultArchiveRoot="http://brltty.app/archive/Windows" |
| readonly defaultTemporaryDirectory="${TMPDIR:-/tmp}/brltty-${programName}" |
| |
| havePath() { |
| local path="${1}" |
| |
| [ -n "${path}" ] || return 1 |
| [ -e "${path}" ] || return 2 |
| return 0 |
| } |
| |
| verifyDirectory() { |
| local path="${1}" |
| |
| [ -e "${path}" ] || semanticError "directory not found: ${path}" |
| [ -d "${path}" ] || semanticError "not a directory: ${path}" |
| [ -w "${path}" ] || semanticError "directory not writable: ${path}" |
| [ -r "${path}" ] || semanticError "directory not readable: ${path}" |
| [ -x "${path}" ] || semanticError "directory not searchable: ${path}" |
| } |
| |
| findCommand() { |
| local variable="${1}" |
| shift 1 |
| |
| for name |
| do |
| local path="$(command -v "${name}")" |
| [ -n "${path}" ] && { |
| setVariable "${variable}" "${path}" |
| return 0 |
| } |
| done |
| |
| return 1 |
| } |
| |
| executeCommand() { |
| logMessage detail "executing command: ${*}" |
| |
| exitStatus=0 |
| "${@}" || exitStatus="${?}" |
| |
| [ "${exitStatus}" -eq 0 ] || logWarning "command failed: ${1}: exit status ${exitStatus}" |
| return "${exitStatus}" |
| } |
| |
| downloadFile() { |
| local source="${1}" |
| local target="${2}" |
| |
| logNote "downloading file: ${source}" |
| [ -z "${target}" ] && target="${source##*/}" |
| executeCommand wget -nv -O "${target}" "${archiveRoot}/${source}" |
| } |
| |
| unpackArchive() { |
| local path="${1}" |
| |
| case "${path}" |
| in |
| *.zip) set -- unzip -q;; |
| *.tar.gz) set -- tar xfz;; |
| *) semanticError "unsupported archive: ${path}";; |
| esac |
| |
| executeCommand "${@}" "${path}" |
| } |
| |
| applyPatch() { |
| local patch="${1}" |
| local directory="${2}" |
| local file="${3}" |
| local pattern="${4}" |
| |
| local path="${directory}/${file}" |
| |
| if [ -f "${path}" ] |
| then |
| grep -q "${pattern}" "${path}" || { |
| local name="${patch##*/}" |
| logMessage task "applying patch: ${name}" |
| |
| "${dryRun}" || { |
| downloadFile "${patch}" |
| executeCommand patch -N -i "${temporaryDirectory}/${name}" -d "${directory}" "${file}" |
| } |
| } |
| else |
| logWarning "file not found: ${path}" |
| fi |
| } |
| |
| installFile() { |
| local file="${1}" |
| local directory="${2}" |
| |
| local source="${file##*/}" |
| local target="${directory}/${source}" |
| |
| [ -e "${target}" ] || { |
| logMessage task "installing file: ${target}" |
| |
| "${dryRun}" || { |
| downloadFile "${file}" |
| [ -d "${directory}" ] || executeCommand mkdir -p "${directory}" |
| executeCommand cp "${source}" "${target}" |
| } |
| } |
| } |
| |
| installLink() { |
| local to="${1}" |
| local directory="${2}" |
| local name="${3}" |
| |
| [ -n "${name}" ] || name="${to##*/}" |
| local from="${directory}/${name}" |
| |
| havePath "${from}" || { |
| logMessage task "installing link: ${from} -> ${to}" |
| [ -e "${to}" ] || semanticError "link target not found: ${to}" |
| "${dryRun}" || executeCommand ln -s "${to}" "${from}" |
| } |
| } |
| |
| installWindowsArchive() { |
| local archive="${1}" |
| local path="${2}" |
| |
| havePath "${path}" || { |
| logMessage task "installing Windows archive: ${archive}" |
| |
| "${dryRun}" || { |
| downloadFile "${archive}" |
| |
| local directory="content-${archive}" |
| executeCommand mkdir "${directory}" |
| executeCommand cd "${directory}" |
| |
| unpackArchive "../${archive}" |
| set -- * |
| |
| if [ "${#}" -eq 1 -a -d "${1}" ] |
| then |
| executeCommand mv "${1}" "${path}" |
| executeCommand cd .. |
| executeCommand rmdir "${directory}" |
| else |
| executeCommand cd .. |
| executeCommand mv "${directory}" "${path}" |
| fi |
| } |
| } |
| } |
| |
| installMingwArchive() { |
| local archive="${1}" |
| local path="${2}" |
| |
| havePath "${mingwDirectory}/${path}" || { |
| logMessage task "installing MinGW archive: ${archive}" |
| |
| "${dryRun}" || { |
| downloadFile "MinGW/${archive}" |
| executeCommand cd "${mingwDirectory}" |
| unpackArchive "${temporaryDirectory}/${archive}" |
| executeCommand cd "${temporaryDirectory}" |
| } |
| } |
| } |
| |
| installMingwPackage() { |
| local package="${1}" |
| local path="${2}" |
| |
| havePath "${path}" || { |
| logMessage task "installing MinGW package: ${package}" |
| "${dryRun}" || executeCommand mingw-get --verbose=0 install "${package}" |
| } |
| } |
| |
| installMicrosoftVisualCTools() { |
| local file |
| |
| for file in lib.exe link.exe mspdb100.dll msvcr100.dll |
| do |
| installFile "MSVC/${file}" "/usr/local/bin" |
| done |
| } |
| |
| installPackageConfigurationFiles() { |
| local package |
| |
| for package in libusb libusb-1.0 |
| do |
| installFile "pkgconfig/${package}.pc" "${librariesDirectory}/pkgconfig" |
| done |
| } |
| |
| installBluetoothHeaders() { |
| local name |
| |
| for name in ws2bth bthdef bthsdpdef |
| do |
| installFile "Bluetooth/${name}.h" "${headersDirectory}" |
| done |
| } |
| |
| installLibUSB0() { |
| local directory="${windowsDirectory}/LibUSB-Win32" |
| installWindowsArchive libusb-win32-bin-1.2.6.0.zip "${directory}" |
| installLink "${directory}/include/lusb0_usb.h" "${headersDirectory}" usb.h |
| installLink "${directory}/lib/gcc/libusb.a" "${librariesDirectory}" |
| installLink "${directory}/bin/x86/libusb0_x86.dll" "${commandsDirectory}" libusb0.dll |
| } |
| |
| installLibUSB1() { |
| local directory="${windowsDirectory}/LibUSB-1.0" |
| installWindowsArchive libusbx-1.0.18-win.tar.gz "${directory}" |
| installLink "${directory}/include/libusbx-1.0" "${headersDirectory}" libusb-1.0 |
| installLink "${directory}/MinGW32/dll/libusb-1.0.dll.a" "${librariesDirectory}" |
| installLink "${directory}/MinGW32/dll/libusb-1.0.dll" "${commandsDirectory}" |
| installWindowsArchive winusb.zip "${windowsDirectory}/WinUSB" |
| } |
| |
| installCython() { |
| local python |
| |
| if findCommand python python py |
| then |
| export PYTHONIOENCODING="utf-8" |
| local directory="${python%/*}" |
| |
| findCommand cython cython || { |
| logMessage task "installing Cython" |
| "${dryRun}" || executeCommand pip -q install cython |
| } |
| |
| installFile Cython/vcruntime140.dll "${directory}/libs" |
| installFile Cython/distutils.cfg "${directory}/lib/distutils" |
| applyPatch "Cython/PythonCygwinCCompiler.patch" "${directory}/lib/distutils" "cygwinccompiler.py" "vcruntime140" |
| else |
| logWarning "Python not found" |
| fi |
| } |
| |
| addProgramOption a string.URL archiveRoot "the URL for BRLTTY's Windows archive" "${defaultArchiveRoot}" |
| addProgramOption d flag dryRun "dry run - don't actually install anything" |
| addProgramOption k flag keepFiles "keep (do not remove) the temporary directory" |
| addProgramOption p string.directory pythonDirectory "the directory where Python has been installed" |
| addProgramOption t string.directory temporaryDirectory "the temporary directory to use" "${defaultTemporaryDirectory}" |
| parseProgramArguments "${@}" |
| |
| [ -n "${archiveRoot}" ] || archiveRoot="${defaultArchiveRoot}" |
| |
| [ -n "${pythonDirectory}" ] && { |
| [ -d "${pythonDirectory}" ] || semanticError "Python directory not found: ${pythonDirectory}" |
| PATH="${pythonDirectory}:${pythonDirectory}/scripts:${PATH}" |
| } |
| |
| readonly windowsDirectory="/c" |
| verifyDirectory "${windowsDirectory}" |
| |
| readonly mingwDirectory="/mingw" |
| verifyDirectory "${mingwDirectory}" |
| |
| readonly commandsDirectory="${mingwDirectory}/bin" |
| verifyDirectory "${commandsDirectory}" |
| |
| readonly librariesDirectory="${mingwDirectory}/lib" |
| verifyDirectory "${librariesDirectory}" |
| |
| readonly headersDirectory="${mingwDirectory}/include" |
| verifyDirectory "${headersDirectory}" |
| |
| if [ -z "${temporaryDirectory}" ] |
| then |
| temporaryDirectory="${defaultTemporaryDirectory}" |
| rm -f -r "${temporaryDirectory}" |
| elif [ -e "${temporaryDirectory}" ] |
| then |
| semanticError "directory already exists: ${temporaryDirectory}" |
| fi |
| |
| mkdir -p "${temporaryDirectory}" |
| cd "${temporaryDirectory}" |
| temporaryDirectory="$(pwd -W)" |
| |
| installMingwPackage msys-bison /bin/bison |
| installMingwPackage msys-dos2unix /bin/dos2unix |
| installMingwPackage msys-groff /bin/groff |
| installMingwPackage msys-m4 /bin/m4 |
| installMingwPackage msys-tar /bin/tar |
| installMingwPackage msys-unzip /bin/unzip |
| installMingwPackage msys-wget /bin/wget |
| installMingwPackage msys-zip /bin/zip |
| |
| installMingwPackage mingw32-libpdcurses /mingw/include/curses.h |
| installMingwPackage mingw32-pthreads-w32 /mingw/include/pthread.h |
| installMingwPackage mingw32-tcl /mingw/bin/tclsh |
| |
| installMicrosoftVisualCTools |
| installPackageConfigurationFiles |
| installBluetoothHeaders |
| |
| installMingwArchive pkg-config_0.28-1_win32.zip "bin/pkg-config.exe" |
| installMingwArchive glib_2.34.3-1_win32.zip "bin/libgobject-2.0-0.dll" |
| |
| installWindowsArchive AutoHotkey104805.tar.gz "${ahkLocation}" |
| installWindowsArchive nsis-3.0b0.tar.gz "${nsisLocation}" |
| installWindowsArchive icu4c-53_1-Win32-msvc10.zip "${icuLocation}" |
| |
| installLibUSB0 |
| installLibUSB1 |
| installCython |
| |
| "${keepFiles}" || { |
| logMessage task "cleaning up" |
| cd "${initialDirectory}" |
| rm -f -r "${temporaryDirectory}" |
| } |
| |
| logMessage task "done" |
| exit 0 |