| #!/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 |