Removed -o pipefail.
[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
22 # set -o pipefail
23
24 ######################################################################
25
26 function check_remote_is_defined () {
27     if [[ "${REMOTE_HOST}" ]] && [[ "${REMOTE_DIR}" ]]
28     then
29         return 0
30     else
31         echo "@XREMOTE_HOST should come first." >&2
32         exit 1
33     fi
34 }
35
36 function help () {
37     cat <<EOF
38 xremote.sh <script>
39
40   This script takes a script as argument and executes it remotely in a
41   temporary directory on a ssh-accessible server.
42
43   It parses the script first to find embedded arguments which defines
44   the hostname on which to run, the files to send, the files to get
45   back when the execution is over, and commands to execute before
46   running the executable remotely.
47
48   These arguments can appear multiple times, except the one that
49   specifies the remote host.
50
51   Example:
52
53     @XREMOTE_HOST: elk.fleuret.org
54     @XREMOTE_EXEC: python3
55     @XREMOTE_SEND: main.cf
56     @XREMOTE_GET: *.dat
57     @XREMOTE_PRE: ln -s /home/fleuret/data/pytorch ./data
58
59   If no argument is provided to @XREMOTE_HOST, the environment
60   variable $XREMOTE_HOST is used instead
61
62   Contact <francois@fleuret.org> for comments.
63
64 EOF
65     return 0
66 }
67
68 function cleanup_remote_tmp () {
69     if [[ "${REMOTE_HOST}" ]] && [[ "${REMOTE_DIR}" ]]
70     then
71         echo "xremote: Clean up remote workdir."
72         ssh "${REMOTE_HOST}" "rm -rf \"${REMOTE_DIR}\""
73     fi
74 }
75
76 ######################################################################
77
78 [[ -x "$1" ]] || (help && exit 1)
79
80 main="$(basename "$1")"
81
82 cd "$(dirname "$1")"
83
84 trap cleanup_remote_tmp EXIT
85
86 ######################################################################
87
88 while read line
89 do
90
91     if [[ "${line}" =~ '@XREMOTE' ]]
92     then
93
94         label=$(echo "${line}" | sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/')
95         value=$(echo "${line}" | sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/')
96
97         case "${label}" in
98
99             EXEC)
100                 check_remote_is_defined
101                 [[ "${REMOTE_EXEC}" ]] && (exit "Remote executable already defined!" >&2 && exit 1)
102                 REMOTE_EXEC="${value}"
103                 ;;
104
105             PRE)
106                 check_remote_is_defined
107                 echo "xremote: ${value}"
108                 ssh < /dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ${value}"
109                 ;;
110
111             SEND)
112                 check_remote_is_defined
113                 echo "xremote: -- sending files --------------------------------------------"
114                 tar ch ${value} | ssh "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar mxv"
115                 ;;
116
117             HOST)
118                 [[ "${REMOTE_DIR}" ]] && (exit "Remote host already defined!" >&2 && exit 1)
119                 REMOTE_HOST="${value}"
120                 [[ "${REMOTE_HOST}" ]] || REMOTE_HOST="${XREMOTE_HOST}"
121                 [[ "${REMOTE_HOST}" ]] || (echo "xremote: No remote host specified." >&2 && exit 1)
122                 REMOTE_DIR="$(ssh </dev/null "${REMOTE_HOST}" mktemp -d /tmp/xremote.from_"$(hostname)_$(date +%Y%m%d-%H%M%S)".XXXXXX)"
123                 echo "xremote: target is ${REMOTE_HOST}"
124                 ;;
125         esac
126     fi
127
128 done < "${main}"
129
130 ######################################################################
131
132 check_remote_is_defined
133
134 tar c "${main}" | ssh "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar mx"
135
136 echo "xremote: -- running the executable -----------------------------------"
137
138 if [[ "${REMOTE_EXEC}" ]]
139 then
140     REMOTE_COMMAND="${REMOTE_EXEC} ${main}"
141 else
142     REMOTE_COMMAND="./${main}"
143 fi
144
145 ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && ${REMOTE_COMMAND}"
146
147 ######################################################################
148
149 # Disable globbing to keep wildcards for the remote side
150
151 echo "xremote: -- retrieving files -----------------------------------------"
152
153 set -f
154
155 while read line
156 do
157     if [[ "${line}" =~ '@XREMOTE' ]]
158     then
159         label=$(echo "${line}" | sed -e 's/^.*@XREMOTE_\([^:]*\):.*$/\1/')
160         value=$(echo "${line}" | sed -e 's/^.*@XREMOTE_[^:]*: *\(.*\)$/\1/')
161         case "${label}" in
162             GET)
163                 check_remote_is_defined
164                 ssh </dev/null "${REMOTE_HOST}" "cd \"${REMOTE_DIR}\" && tar 2>/dev/null c ${value}" | tar mxv
165                 ;;
166         esac
167     fi
168 done < "${main}"
169
170 set +f
171
172 echo "xremote: -- finished -------------------------------------------------"
173
174 ######################################################################