-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbld-deploy-remote.py
executable file
·192 lines (180 loc) · 5.77 KB
/
bld-deploy-remote.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env python3
"""Small portable helper script to build, deply and run a Rust application
on a remote machine, e.g. a Raspberry Pi"""
import argparse
import os
import sys
import platform
import time
from typing import Final
# This script can easily be adapted to other remote machines, Linux boards and
# remote configurations by tweaking / hardcoding these parameter, which generally are constant
# for a given board
DEFAULT_USER_NAME: Final = "pi"
DEFAULT_ADDRESS: Final = "raspberrypi.local"
DEFAULT_TOOLCHAIN: Final = "armv7-unknown-linux-gnueabihf"
DEFAULT_APP_NAME: Final = "rpi-rs-crosscompile"
DEFAULT_TARGET_FOLDER: Final = "/tmp"
DEFAULT_DEBUG_PORT: Final = "17777"
DEFAULT_GDB_APP = "gdb-multiarch"
def main():
bld_deploy_run(parse_arguments())
def parse_arguments():
desc = (
"Rust Remote Deployment Helper."
"Builds the image and can optionally transfer and run "
"it on the target system as well."
)
parser = argparse.ArgumentParser(description=desc)
parser.add_argument(
"-u",
"--user",
default=f"{DEFAULT_USER_NAME}",
help=f"Username for ssh access. Default: {DEFAULT_USER_NAME}",
)
parser.add_argument(
"-a",
"--address",
default=f"{DEFAULT_ADDRESS}",
help=f"Remote SSH address. Default: {DEFAULT_ADDRESS}",
)
parser.add_argument(
"--tc",
default=f"{DEFAULT_TOOLCHAIN}",
help=f"Target toolchain. Default: {DEFAULT_TOOLCHAIN}",
)
parser.add_argument(
"--app",
default=f"{DEFAULT_APP_NAME}",
help=f"Target appname. Default: {DEFAULT_APP_NAME}",
)
parser.add_argument(
"--source",
help="Target destination path. Default: Built from other arguments",
)
parser.add_argument(
"--dest",
default=f"{DEFAULT_TARGET_FOLDER}",
help=f"Target destination path. Default: {DEFAULT_TARGET_FOLDER}",
)
parser.add_argument(
"other", nargs=argparse.REMAINDER, help="Argument forwarded to cargo build"
)
parser.add_argument(
"-b",
"--build",
action="store_true",
help="Build application",
)
parser.add_argument(
"-t",
"--transfer",
action="store_true",
help="Transfer application to remote machine",
)
parser.add_argument(
"-r",
"--run",
action="store_true",
help="Run application on remote machine",
)
parser.add_argument(
"-d",
"--debug",
action="store_true",
help="Run gdbserver on remote machine for remote debugging"
)
parser.add_argument(
"-s",
"--start",
action="store_true",
help="Start local GDB session, connecting to the remote GDB server"
)
parser.add_argument(
"--gdb",
default="gdb-multiarch",
help="GDB application to use"
)
parser.add_argument(
"-p",
"--port",
default=f"{DEFAULT_DEBUG_PORT}",
help="Port to use for remote debugging"
)
parser.add_argument(
"-e",
"--sshenv",
action="store_true",
help="Take password from environmental variable",
)
parser.add_argument(
"--release",
action="store_true",
help="Supply --release to build command",
)
parser.add_argument(
"-f",
"--sshfile",
help="SSH key file. Otherwise, use password from environmental variable SSHPASS",
)
return parser.parse_args()
def bld_deploy_run(args):
cargo_opts = ""
build_folder = "debug"
if args.release:
cargo_opts += "--release"
build_folder = "release"
for other in args.other:
cargo_opts += f"{other}"
sshpass_args = ""
if args.sshfile:
sshpass_args = f"-f {args.sshfile}"
elif args.sshenv:
sshpass_args = "-e"
ssh_target_ident = f"{args.user}@{args.address}"
sshpass_cmd = ""
if platform.system() != "Windows":
sshpass_cmd = f"sshpass {sshpass_args}"
dest_path = f"{args.dest}/{args.app}"
if not args.source:
source_path = f"{os.getcwd()}/target/{args.tc}/{build_folder}/{args.app}"
else:
source_path = args.source
build_cmd = f"cargo build {cargo_opts}"
if args.build:
print(f"Running build command: {build_cmd}")
os.system(build_cmd)
if args.transfer:
if not os.path.exists(source_path):
print(f"No application found at {source_path}")
sys.exit(1)
scp_target_dest = f'{ssh_target_ident}:"{dest_path}"'
transfer_cmd = f"{sshpass_cmd} scp {source_path} {scp_target_dest}"
print(f"Running transfer command: {transfer_cmd}")
os.system(transfer_cmd)
if args.run:
run_cmd = f"{sshpass_cmd} ssh {ssh_target_ident} {dest_path}"
print(f"Running target application: {run_cmd}")
os.system(run_cmd)
elif args.debug:
# Kill all running gdbserver applications first
# Then start the GDB server
debug_shell_cmd = f"sh -c 'killall -q gdbserver; gdbserver *:{args.port} {dest_path}'"
# Execute the command above and also set up port forwarding. This allows to connect
# to localhost:17777 on the local development machine
ssh_flags = "-L"
if args.start:
ssh_flags += " -f"
debug_cmd = (
f"{sshpass_cmd} ssh {ssh_flags} {args.port}:localhost:{args.port} {ssh_target_ident} "
f'"{debug_shell_cmd}"'
)
print(f"Running debug command: {debug_cmd}")
os.system(debug_cmd)
if args.start:
time.sleep(0.2)
start_cmd = f"{args.gdb} -q -x gdb.gdb {source_path}"
print(f"Running start command: {start_cmd}")
os.system(start_cmd)
if __name__ == "__main__":
main()