function help () {
cat <<EOF
-xremote.sh <script>
+xremote.sh [--help] [-h <remote_host>] [-d <remote_dir>] [-r <local_result_dir>] [-i] <script> [script arguments]
This script takes a script as argument and executes it remotely in a
temporary directory on a ssh-accessible server.
- It parses the script first to find embedded arguments which defines
+ It parses the script first to find embedded arguments which define
the hostname on which to run, the files to send, the files to get
back when the execution is over, and commands to execute before
running the executable remotely.
@XREMOTE_GET: *.dat
@XREMOTE_PRE: ln -s /home/fleuret/data/pytorch ./data
- If no argument is provided to @XREMOTE_HOST, the environment
- variable $XREMOTE_HOST is used instead
+ If a file with the same name as the script with the .xremote
+ extension appended to it exists, arguments will be read from it by
+ default.
+
+ If the -h option is provided @XREMOTE_HOST is ignored.
+
+ If the -d option is provided, the provided directory is used and
+ kept, instead of a temporary one
+
+ If the -i option is provided, all the files are installed and
+ scripts run in the specified directory on the remote host, but the
+ main executable and post-run commands are ignored
+
+ If the -r option is provided, the result files specified with
+ @XREMOTE_GET will be downloaded there instead of the current
+ directory.
+
+ If no argument is provided to @XREMOTE_HOST, and the -h option is
+ not specified, the environment variable \$XREMOTE_HOST is used
+ instead
Contact <francois@fleuret.org> for comments.
function cleanup_remote_tmp () {
if [[ "${REMOTE_HOST}" ]] && [[ "${REMOTE_DIR}" ]]
then
- echo "xremote: Clean up remote workdir."
- ssh "${REMOTE_HOST}" "rm -rf \"${REMOTE_DIR}\""
+ if [[ "${ARG_DIR}" ]]
+ then
+ echo "xremote: Keeping remote workdir."
+ else
+ echo "xremote: Cleaning up temporary remote workdir."
+ ssh "${REMOTE_HOST}" rm -rf "${REMOTE_DIR}"
+ fi
fi
}
######################################################################
-[[ -x "$1" ]] || (help && exit 1)
+while [[ "$1" =~ ^- ]]
+do
+ case "$1"
+ in
+ -h)
+ shift
+ ARG_HOST="$1"
+ [[ ${ARG_HOST} ]] || (echo "xremote: Hostname missing." && exit 1)
+ echo "xremote: remote forced to ${ARG_HOST}"
+ ;;
+
+ -d)
+ shift
+ ARG_DIR="$1"
+ [[ ${ARG_DIR} ]] || (echo "xremote: Directory missing." && exit 1)
+ echo "xremote: remote dir set to ${ARG_DIR}"
+ ;;
+
+ -i)
+ NO_RUN=1
+ echo "xremote: no run"
+ ;;
+
+ -r)
+ shift
+ ARG_RESULT_DIR="$1"
+ [[ ${ARG_RESULT_DIR} ]] || (echo "xremote: Directory missing." && exit 1)
+ echo "xremote: result dir set to ${ARG_RESULT_DIR}"
+ ;;
+
+ --help)
+ help
+ exit 0
+ ;;
+
+ *)
+ echo "xremote: Unknown option $1"
+ exit 1
+ ;;
+ esac
+ shift
+done
-main="$(basename "$1")"
+######################################################################
+
+[[ "$1" ]] || (echo "xremote: Script name missing" && exit 1)
+
+[[ -a "$1" ]] || (help && echo >&2 "xremote: Cannot find script \`$1'" && exit 1)
cd "$(dirname "$1")"
+main="$(basename "$1")"
+main_config="${main}.xremote"
+
+if [[ -f "${main_config}" ]]
+then
+ echo "xremote: found ${main_config}"
+else
+ main_config="${main}"
+fi
+
+shift
+
trap cleanup_remote_tmp EXIT
######################################################################
if [[ "${line}" =~ '@XREMOTE' ]]
then
- label=$(echo "${line}" | sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/')
- value=$(echo "${line}" | sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/')
+ label=$(sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/' <<<"${line}")
+ value=$(sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/' <<<"${line}")
case "${label}" in
HOST)
[[ "${REMOTE_DIR}" ]] && (exit "Remote host already defined!" >&2 && exit 1)
- REMOTE_HOST="${value}"
+ REMOTE_HOST="${ARG_HOST}" # Host given in argument has priority
+ [[ "${REMOTE_HOST}" ]] || REMOTE_HOST="${value}"
[[ "${REMOTE_HOST}" ]] || REMOTE_HOST="${XREMOTE_HOST}"
[[ "${REMOTE_HOST}" ]] || (echo "xremote: No remote host specified." >&2 && exit 1)
- REMOTE_DIR="$(ssh </dev/null "${REMOTE_HOST}" mktemp -d /tmp/xremote.from_"$(hostname)_$(date +%Y%m%d-%H%M%S)".XXXXXX)"
+ if [[ "${ARG_DIR}" ]]
+ then
+ ssh </dev/null "${REMOTE_HOST}" "mkdir -p \"${ARG_DIR}\""
+ REMOTE_DIR="${ARG_DIR}"
+ else
+ REMOTE_DIR="$(ssh </dev/null "${REMOTE_HOST}" mktemp -d /tmp/xremote_\$\(whoami\)_from_"$(hostname)_$(date +%Y%m%d_%H%M%S)".XXXXXX)"
+ fi
echo "xremote: target is ${REMOTE_HOST}"
;;
esac
fi
-done < "${main}"
+done < "${main_config}"
######################################################################
tar c "${main}" | ssh "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar mx"
+if [[ "${NO_RUN}" ]]
+then
+ echo "xremote: everything has been set up in ${REMOTE_HOST}:${ARG_DIR}"
+ exit 0
+fi
+
echo "xremote: -- running the executable -----------------------------------"
if [[ "${REMOTE_EXEC}" ]]
REMOTE_COMMAND="./${main}"
fi
-ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ${REMOTE_COMMAND}"
+######################################################################
+
+# I find this slightly ugly ...
+
+for s in "$@"
+do
+ quoted_args="${quoted_args} \"${s}\""
+done
+
+ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ${REMOTE_COMMAND} ${quoted_args}"
######################################################################
set -f
+if [[ "${ARG_RESULT_DIR}" ]]
+then
+ RESULT_DIR="${ARG_RESULT_DIR}"
+else
+ RESULT_DIR="."
+fi
+
+[[ "${ARG_RESULT_DIR}" ]] && mkdir -p "${ARG_RESULT_DIR}"
+
while read line
do
if [[ "${line}" =~ '@XREMOTE' ]]
then
- label=$(echo "${line}" | sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/')
- value=$(echo "${line}" | sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/')
+ label=$(sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/' <<<"${line}")
+ value=$(sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/' <<<"${line}")
case "${label}" in
+ POST)
+ check_remote_is_defined
+ echo "xremote: ${value}"
+ ssh < /dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ${value}"
+ ;;
+
GET)
check_remote_is_defined
- ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar 2>/dev/null c ${value}" | tar mxv
+ ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar 2>/dev/null c ${value}" | tar mxv -C "${RESULT_DIR}"
;;
esac
fi
-done < "${main}"
+
+done < "${main_config}"
set +f