9b753e09a61d7cbcb0cd6257e18b19fe099b0cd7
[xremote.git] / xremote.sh
1 #!/bin/bash
2
3 #########################################################################
4 # This program is free software: you can redistribute it and/or modify  #
5 # it under the terms of the version 3 of the GNU General Public License #
6 # as published by the Free Software Foundation.                         #
7 #                                                                       #
8 # This program is distributed in the hope that it will be useful, but   #
9 # WITHOUT ANY WARRANTY; without even the implied warranty of            #
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      #
11 # General Public License for more details.                              #
12 #                                                                       #
13 # You should have received a copy of the GNU General Public License     #
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.  #
15 #                                                                       #
16 # Written by and Copyright (C) Francois Fleuret                         #
17 # Contact <francois@fleuret.org> for comments & bug reports             #
18 #########################################################################
19
20 set -e
21 set -o pipefail
22
23 ######################################################################
24
25 function check_remote_is_defined () {
26     if [[ "${REMOTE_HOST}" ]] && [[ "${REMOTE_DIR}" ]]
27     then
28         return 0
29     else
30         echo "@XREMOTE_HOST should come first." >&2
31         exit 1
32     fi
33 }
34
35 function help () {
36     cat <<EOF
37 xremote.sh <executable>
38
39   This script takes a script as argument and executes it remotely in a
40   temporary directory on a ssh-accessible server.
41
42   It parses the script first to find embedded arguments which defines
43   the hostname on which to run it, the files to send, the files to
44   get back when the execution is done, and commands to execute before
45   running the executable remotely.
46
47   These arguments can appear multiple times, except the one that
48   specifies the remote host.
49
50   Example:
51
52     @XREMOTE_HOST: elk.fleuret.org
53     @XREMOTE_SEND: mnist.py
54     @XREMOTE_GET: *.dat
55     @XREMOTE_PRE: ln -s /home/fleuret/data/pytorch ./data
56
57  Contact <francois@fleuret.org> for comments.
58
59 EOF
60     return 0
61 }
62
63 function cleanup_remote_tmp () {
64     if [[ "${REMOTE_HOST}" ]] && [[ "${REMOTE_DIR}" ]]
65     then
66         echo "Clean up remote workdir."
67         ssh "${REMOTE_HOST}" "rm -rf \"${REMOTE_DIR}\""
68     fi
69 }
70
71 ######################################################################
72
73 [[ -x "$1" ]] || (help && exit 1)
74
75 main="$(basename "$1")"
76
77 cd "$(dirname "$1")"
78
79 trap cleanup_remote_tmp EXIT
80
81 ######################################################################
82
83 while read line
84 do
85
86     if [[ "${line}" =~ '@XREMOTE' ]]
87     then
88
89         label=$(echo "${line}" | sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/')
90         value=$(echo "${line}" | sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/')
91
92         case "${label}" in
93
94             PRE)
95                 check_remote_is_defined
96                 ssh < /dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ${value}"
97                 ;;
98
99             SEND)
100                 check_remote_is_defined
101                 tar c "${value}" | ssh "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar mx"
102                 ;;
103
104             HOST)
105                 [[ "${REMOTE_DIR}" ]] && (exit "Remote host already defined!" >&2 && exit 1)
106                 cleanup_remote_tmp
107                 REMOTE_HOST=${value}
108                 REMOTE_DIR="$(ssh </dev/null "${REMOTE_HOST}" mktemp -d /tmp/xremote.from_"$(hostname)_$(date +%Y%m%d)".XXXXXX)"
109                 ;;
110         esac
111     fi
112
113 done < "${main}"
114
115 ######################################################################
116
117 check_remote_is_defined
118
119 tar c "${main}" | ssh "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar mx"
120
121 echo "----------------------------------------------------------------------"
122 echo "-- On ${REMOTE_HOST}"
123 echo "----------------------------------------------------------------------"
124 ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ./$(basename "${main}")"
125 echo "----------------------------------------------------------------------"
126
127 ######################################################################
128
129 # Disable globbing to keep wildcards for the remote side
130
131 set -f
132
133 while read line
134 do
135     if [[ "${line}" =~ '@XREMOTE' ]]
136     then
137         label=$(echo "${line}" | sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/')
138         value=$(echo "${line}" | sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/')
139         case "${label}" in
140             GET)
141                 check_remote_is_defined
142                 ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar c ${value}" | tar mxv
143                 ;;
144         esac
145     fi
146 done < "${main}"
147
148 set +f
149
150 ######################################################################