#!/usr/bin/env bash defaultcmd="mtgo" image=docker.io/panard/mtgo:latest docker_client=docker limit_cpus=4 name=mtgo_running cmd=$defaultcmd cmdargs="" opts="" data="mtgo64-data-$USER" do_sound=false do_update=false local_data="$HOME/.local/share/mtgo" bind_documents="${local_data}/files" usage() { echo " Usage: $0 [opts] [image] Options: -h, --help display this message and exit --sound enable sound (requires PulseAudio and Linux) --disable-sound ensure that sound is disabled --cmd CMD initial command (default: $cmd) --data-volume VOL docker volume to store data (default: ${data}) --reset reset local data and docker volume --name NAME container name (default: $name) --shell start an interactive shell instead of MTGO --winecfg run winecfg before calling MTGO --dry-run simply print the docker run command --no-tz disable timezone detection --debug enable debug information --test test environment --update update docker image before run --limit-cpus N limit number of CPUs (first N will be used) --bind PATH bind given path to the user 'Documents' folder -e docker run option (environment) -v docker run option (mount volume) -u docker run option (change user) " } lopts="dry-run,help,winecfg,shell,cmd:,name:" lopts="${lopts},bind:" lopts="${lopts},data-volume:,reset" lopts="${lopts},sound,disable-sound" lopts="${lopts},test" lopts="${lopts},limit-cpus:" lopts="${lopts},no-tz" lopts="${lopts},update" lopts="${lopts},debug" getopt=getopt if [[ $OSTYPE == darwin* ]]; then set -x getopt="$(brew ls --verbose gnu-getopt|grep '/bin/getopt')" if [ $? -ne 0 ]; then for d in "/opt/homebrew/opt/gnu-getopt/bin" "/usr/local/opt/gnu-getopt/bin"; do brew_getopt="${d}/getopt" if [ -x $brew_getopt ]; then getopt=$brew_getopt break fi done fi fi args="$($getopt -n "${0}" -o hv:u:e: --longoptions $lopts -- "${0}" "${@}")" if [ $? -ne 0 ]; then usage exit 1 fi eval set -- $args do_run=true do_reset=false do_test=false mytz=${TZ:-} detect_tz=false if [ -z "${mytz}" ]; then detect_tz=true fi while [ -n "${1:-}" ]; do case "${1:-}" in --help|-h) usage && exit 0 ;; --bind) shift bind_documents="$(realpath "$1")" ;; --data-volume) shift data="$1" ;; --debug) opts="${opts} -e WINEDEBUG=warn+all" ;; --dry-run) do_run=false ;; --winecfg) [[ "$cmd" == "mtgo" ]] && cmdargs="${cmdargs} $1";; --sound) [[ "$cmd" == "mtgo" ]] && cmdargs="${cmdargs} $1" image=panard/mtgo:sound do_update=true do_sound=true ;; --disable-sound) [[ "$cmd" == "mtgo" ]] && cmdargs="${cmdargs} $1" ;; --limit-cpus) shift limit_cpus="$1" ;; --reset) do_reset=true ;; --shell) cmd="bash" cmdargs="" opts="${opts} -it" ;; --test) local_data="$HOME/.local/share/mtgo-test" bind_documents="${local_data}/files" data="${data}-test" do_test=true ;; --cmd) shift; cmd="$1" cmdargs="" opts="${opts} -it" ;; --no-tz) detect_tz=false mytz="" ;; --name) shift; name="$1" ;; --update) do_update=true ;; -e|-v|-u) opts="${opts} $1 $2" ;; --) shift ; shift if [ -n "${1:-}" ]; then while [ -n "${2}" ]; do opts="${opts} ${1}" shift done image=$1 fi ;; esac shift done echo "IMAGE=${image}" if [ -n "${opts}" ]; then echo "CUSTOM DOCKER OPTS=${opts}" fi run() { echo "run(): ${@}" >&2 if $do_run; then "${@}" fi } _host_uid=$(id -u) if [[ ${_host_uid} == 0 ]]; then echo "Error: you should not run this script as root." >&2 echo "Instead, consider adding your user to the 'docker' group:" >&2 echo ' sudo usermod -aG docker \$USER' >&2 echo "then restarting your session." >&2 exit 1 fi if $detect_tz; then if [ -f /etc/timezone ]; then mytz=$(&2 echo "Press Enter to continue, CTRL+C to abort" >&2 read run ${docker_client} volume rm $data fi if $do_update; then echo "Updating image ${image}..." >&2 run ${docker_client} pull ${image} fi ${docker_client} volume inspect "$data" >/dev/null 2>&1 if [ $? -ne 0 ]; then set -e run ${docker_client} volume create "${data}" # migration old_data=mtgo-data set +e ${docker_client} volume inspect ${old_data}>/dev/null 2>&1 if [ $? -eq 0 ]; then set -e echo "Migrating from previous configuration..." >&2 run ${docker_client} run --rm -v ${data}:/home/wine/.wine/host \ -v ${old_data}:/data \ -v ${local_data}:/ldata \ -i ${image} bash</dev/null | awk '/interface: / {print $2}') echo "Using network interface '${iface}'" >&2 ip=$(ifconfig $iface | grep inet | awk '$1=="inet" {print $2}') if [ -z ${ip} ]; then echo "FATAL: Cannot find your local IP address (iface=$iface)." >&2 exit 1 fi run open -a XQuartz echo "socat on $ip forwarding to $DISPLAY" >&2 socat TCP4-LISTEN:6000,bind=$ip,range=$ip/32,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" & socat_pid=$! sleep 2 export DISPLAY=$ip:0 opts="${opts} -e WINE_X11_NO_MITSHM=1" WEBBROWSER=open else if [ ${_host_uid} -ne 1000 ]; then run xhost +local:1000 reset_xhost=true fi XSOCK="/tmp/.X11-unix" XAUTH="${local_data}/Xauthority" > ${XAUTH} xauth nlist ${DISPLAY} | sed -e 's/^..../ffff/' | xauth -f ${XAUTH} nmerge - opts="${opts} -v ${XSOCK}:${XSOCK}:rw" opts="${opts} -v ${XAUTH}:/home/wine/.Xauthority:ro" WEBBROWSER=xdg-open fi if $do_sound; then if [[ ${OSTYPE} == darwin* ]]; then set +e pulseaudio --version >/dev/null 2>&1 if [ $? -ne 0 ]; then echo "PulseAudio does not seem to be installed. Attempting install..." >&2 run brew install pulseaudio fi set -e pascript="$(pulseaudio --dump-conf|grep '^default-script-file = '|sed 's/^.*= *//')" echo "PAScript is $pascript" >&2 pa_modified=false set +e pa_has_esound=$(grep "^load-module module-esound-protocol-tcp" "${pascript}") pa_has_native=$(grep "^load-module module-native-protocol-tcp" "${pascript}") set -e pa_enable_module() { echo "PulseAudio: enabling $1 module" >&2 echo "load-module module-$1" | sudo tee -a "${pascript}" } if [ -z "${pa_has_esound}" ]; then pa_enable_module "esound-protocol-tcp" pa_modified=true fi if [ -z "${pa_has_native}" ]; then pa_enable_module "native-protocol-tcp" pa_modified=true fi pulseaudio --check && pulseaudio -k || true run pulseaudio -D opts="${opts} -v $HOME/.config/pulse:/home/wine/.config/pulse" opts="${opts} -e PULSE_SERVER=$ip" else _host_pulse="/run/user/${_host_uid}/pulse/native" if [ ! -S $_host_pulse ]; then echo "PulseAudio does not seem active (${_host_pulse} not found)" >&2 run pulseaudio --start fi opts="${opts} -i -v ${_host_pulse}:/run/user/1000/pulse/native" fi fi opts="${opts} --net=host --ipc=host" if [ -n "${mytz}" ]; then opts="${opts} -e TZ=/usr/share/zoneinfo/${mytz}" fi if [ -n "${name}" ]; then opts="${opts} --name ${name}" fi if [ -n "${bind_documents}" ]; then opts="${opts} -v ${bind_documents}:/home/wine/.wine/drive_c/users/wine/Documents" fi if [ ${limit_cpus} -gt 0 ]; then opts="${opts} --cpuset-cpus 0-$(( ${limit_cpus} - 1 ))" fi docker_mtgo() { run ${docker_client} run --privileged --rm -e DISPLAY \ ${opts} ${image} ${cmd} ${cmdargs} } watch_openurl() { while read -r line; do echo "$line" if [[ "${line:0:8}" == "OPENURL " ]]; then url="${line:8}" run $WEBBROWSER "${url}" fi done } if [[ "${cmd}" == "mtgo" ]]; then docker_mtgo 2>&1 | watch_openurl else docker_mtgo fi if $reset_xhost; then run xhost -local:1000 fi if [[ ${OSTYPE} == darwin* ]]; then kill ${socat_pid} fi