diff --git a/Dockerfile b/Dockerfile index d06f675..ae7ad25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN \ wget http://download.opensuse.org/repositories/home:homueller:citadel/CentOS_7/home:homueller:citadel.repo && \ rpm --rebuilddb && yum clean all && \ yum install -y deltarpm && \ - yum install -y bind citadel webcit && \ + yum install -y bind citadel webcit net-tools && \ yum clean all ADD container-files/ / diff --git a/container-files/config/init/bootstrap.sh b/container-files/config/init/bootstrap.sh index 80d3fa3..5221b8c 100644 --- a/container-files/config/init/bootstrap.sh +++ b/container-files/config/init/bootstrap.sh @@ -42,7 +42,7 @@ dns_start() { atom_support() { if [[ ${ATOM_SUPPORT} == "true" ]]; then log "Atom editor support being installed." - curl -o /usr/local/bin/rmate https://raw.githubusercontent.com/aurora/rmate/master/rmate + mv /rmate /usr/local/bin/rmate chmod +x /usr/local/bin/rmate && \ mv /usr/local/bin/rmate /usr/local/bin/atom log "Atom editor support added." diff --git a/container-files/rmate b/container-files/rmate new file mode 100644 index 0000000..ac1e85e --- /dev/null +++ b/container-files/rmate @@ -0,0 +1,437 @@ +#!/usr/bin/env bash + +# rmate +# Copyright (C) 2011-present by Harald Lapp +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# +# This script can be found at: +# https://github.com/aurora/rmate +# + +# +# This script is a pure bash compatible shell script implementing remote +# textmate functionality +# + +# +# Thanks very much to all users and contributors! All bug-reports, +# feature-requests, patches, etc. are greatly appreciated! :-) +# + +# init +# +version="1.0.2" +version_date="2019-04-08" +version_string="rmate-sh $version ($version_date)" + +# determine hostname +function hostname_command(){ + if command -v hostname >/dev/null 2>&1; then + echo "hostname" + else { + HOSTNAME_DESCRIPTOR="/proc/sys/kernel/hostname" + if test -r "$HOSTNAME_DESCRIPTOR"; then + echo "cat $HOSTNAME_DESCRIPTOR" + else + echo "hostname" + fi + } + fi +} + +hostname=$($(hostname_command)) + +# default configuration +host=localhost +port=52698 +eval home=$(builtin printf "~%q" "${SUDO_USER:-$LOGNAME}") + +function load_config { + local rc_file=$1 + local row + + local host_pattern="^host(:[[:space:]]+|=)([^ ]+)" + local port_pattern="^port(:[[:space:]]+|=)([0-9]+)" + + if [ -f "$rc_file" ]; then + while read -r row; do + if [[ "$row" =~ $host_pattern ]]; then + host=${BASH_REMATCH[2]} + elif [[ "$row" =~ $port_pattern ]]; then + port=${BASH_REMATCH[2]} + fi + done < "$rc_file" + fi +} + +for i in "/etc/${0##*/}" $home/."${0##*/}/${0##*/}.rc" $home/."${0##*/}.rc"; do + load_config $i +done + +host="${RMATE_HOST:-$host}" +port="${RMATE_PORT:-$port}" + +tmp_dir="${TMPDIR:-/tmp}" + +# misc initialization +filepaths=() +displaynames=() +selections=() +filetypes=() +verbose=false +nowait=true +force=false +success=false + +# process command-line parameters +# +function showusage { + echo "usage: $(basename $0) [arguments] [--] file-path edit specified file + or: $(basename $0) [arguments] - read text from stdin + +-H, --host HOST Connect to HOST. Use 'auto' to detect the host from + SSH. Defaults to $host. +-p, --port PORT Port number to use for connection. Defaults to $port. +-w, --[no-]wait Wait for file to be closed by TextMate. +-l, --line LINE Place caret on line number after loading file. ++N Alias for --line, if N is a number (eg.: +5). +-m, --name NAME The display name shown in TextMate. +-t, --type TYPE Treat file as having specified type. +-n, --new Open in a new window (Sublime Text). +-f, --force Open even if file is not writable. +-v, --verbose Verbose logging messages. +-h, --help Display this usage information. + --version Show version and exit. +" +} + +function log { + if [[ $verbose = true ]]; then + echo "$@" 1>&2 + fi +} + +function dirpath { + (cd "$(dirname "$1")" >/dev/null 2>/dev/null || { echo "unable to cd to $1 directory" 1>&2; exit; } ; pwd -P) +} + +function resolvepath { + local filepath="$1" + local directory + + while [ -L "$filepath" ]; do + directory="$(cd -P "$(dirname "$filepath")" && pwd)" + filepath="$(readlink "$filepath")" + + if [[ "${filepath:0:1}" != "/" ]]; then + filepath="$directory/$filepath" + fi + done + + echo "$filepath" +} + +function canonicalize { + local filepath="$1" + local relativepath + local result + + if [[ "${filepath:0:1}" = "-" ]]; then + filepath="./$filepath" + fi + + local dir=$(dirpath "$filepath") + + if [ -L "$filepath" ]; then + relativepath=$(cd "$dir" || { echo "unable to cd to $dir" 1>&2; exit; } ; resolvepath "$(basename "$filepath")") + result=$(dirpath "$relativepath")/$(basename "$relativepath") + else + result=$(basename "$filepath") + if [ "$dir" = '/' ]; then + result="$dir$result" + else + result="$dir/$result" + fi + fi + + echo "$result" +} + +while [[ "$1" != "" ]]; do + case $1 in + -) + filepaths+=("-") + ;; + --) + shift + break + ;; + -H|--host) + host=$2 + shift + ;; + -p|--port) + port=$2 + shift + ;; + -w|--wait) + nowait=false + ;; + --no-wait) + nowait=true + ;; + -l|--line) + selections+=($2) + shift + ;; + -m|--name) + displaynames+=($2) + shift + ;; + -t|--type) + filetypes+=($2) + shift + ;; + -n|--new) + new=true + ;; + -f|--force) + force=true + ;; + -v|--verbose) + verbose=true + ;; + --version) + echo "$version_string" + exit 0 + ;; + -h|-\?|--help) + showusage + exit 0 + ;; + +[0-9][0-9]*) + selections+=(${1:1}) + ;; + *) + if [[ "${1:0:1}" = "-" ]]; then + showusage + exit 1 + else + filepaths+=("$1") + fi + ;; + esac + + shift +done + +if [[ "$host" = "auto" && "$SSH_CONNECTION" != "" ]]; then + host=${SSH_CONNECTION%% *} +fi + +filepaths=("${filepaths[@]}" "$@") + +if [ "${filepaths[*]}" = "" ]; then + if [[ $nowait = false ]]; then + filepaths=('-') + else + case "$-" in + *i*) + showusage + exit 1 + ;; + *) + filepaths=('-') + ;; + esac + fi +fi + + +#------------------------------------------------------------ +# main +#------------------------------------------------------------ + +function open_file { + local index="$1" + local filepath="${filepaths[$index]}" + local selection="${selections[$index]}" + local filetype="${filetypes[$index]}" + local displayname="${displaynames[$index]}" + local realpath + local data + + if [ "$filepath" != "-" ]; then + realpath=$(canonicalize "$filepath") + log "$realpath" + + if [ -d "$filepath" ]; then + echo "$filepath is a directory and rmate is unable to handle directories." + return 1 + fi + + if [ -f "$realpath" ] && [ ! -w "$realpath" ]; then + if [[ $force = false ]]; then + echo "File $filepath is not writable! Use -f to open anyway." + return 1 + elif [[ $verbose = true ]]; then + log "File $filepath is not writable! Opening anyway." + fi + fi + + if [ "$displayname" = "" ]; then + displayname="$hostname:$filepath" + fi + else + displayname="$hostname:untitled" + fi + + echo "open" 1>&3 + echo "display-name: $displayname" 1>&3 + echo "real-path: $realpath" 1>&3 + echo "data-on-save: yes" 1>&3 + echo "re-activate: yes" 1>&3 + echo "token: $filepath" 1>&3 + + if [[ $new = true ]]; then + echo "new: yes" 1>&3 + fi + + if [ "$selection" != "" ]; then + echo "selection: $selection" 1>&3 + fi + + if [ "$filetype" != "" ]; then + echo "file-type: $filetype" 1>&3 + fi + + if [ "$filepath" != "-" ] && [ -f "$filepath" ]; then + filesize=$(($(wc -c <"$realpath"))) + echo "data: $filesize" 1>&3 + cat "$realpath" 1>&3 + elif [ "$filepath" = "-" ]; then + if [ -t 0 ]; then + echo "Reading from stdin, press ^D to stop" + else + log "Reading from stdin" + fi + + # preserve trailing newlines + data=$(cat; echo x) + data=${data%x} + filesize=$(($(echo -ne "$data" | wc -c))) + echo "data: $filesize" 1>&3 + echo -n "$data" 1>&3 + else + echo "data: 0" 1>&3 + fi + + echo 1>&3 +} + +function handle_connection { + local cmd + local name + local value + local token + local tmp + local content + + while read -r 0<&3; do + REPLY="${REPLY#"${REPLY%%[![:space:]]*}"}" + REPLY="${REPLY%"${REPLY##*[![:space:]]}"}" + + cmd=$REPLY + + token="" + tmp="" + + while read -r 0<&3; do + REPLY="${REPLY#"${REPLY%%[![:space:]]*}"}" + REPLY="${REPLY%"${REPLY##*[![:space:]]}"}" + + if [ "$REPLY" = "" ]; then + break + fi + + name="${REPLY%%:*}" + value="${REPLY##*:}" + value="${value#"${value%%[![:space:]]*}"}" # fix textmate syntax highlighting: " + + case $name in + "token") + token=$value + ;; + "data") + if [ "$tmp" = "" ]; then + tmp="$tmp_dir/rmate.$RANDOM.$$" + touch "$tmp" + fi + + dd bs=1 count=$value <&3 >>"$tmp" 2>/dev/null + ;; + *) + ;; + esac + done + + if [[ "$cmd" = "close" ]]; then + log "Closing $token" + if [[ "$token" == "-" ]]; then + echo -n "$content" + fi + elif [[ "$cmd" = "save" ]]; then + log "Saving $token" + if [ "$token" != "-" ]; then + cat "$tmp" > "$token" + else + content=$(cat "$tmp") + fi + rm "$tmp" + fi + done + + log "Done" +} + +# connect to textmate and send command +# +exec 3<> "/dev/tcp/$host/$port" + +if [ $? -gt 0 ]; then + echo "Unable to connect to TextMate on $host:$port" + exit 1 +fi + +read -r server_info 0<&3 + +log $server_info + +for i in "${!filepaths[@]}"; do + open_file "$i" + [[ $? = 0 ]] && new=false && success=true +done + +[[ $success = false ]] && exit 1 + +echo "." 1>&3 + +if [[ $nowait = true ]]; then + exec /dev/null 2>/dev/null + ( (handle_connection &) &) +else + handle_connection +fi