-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfx
executable file
·325 lines (294 loc) · 9.63 KB
/
fx
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#!/bin/bash
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
function help_options {
cat <<END
fx help flags: fx help [OPTION]
--no-contrib Hide contrib commands (see //tools/devshell/README.md)
--deprecated Do not hide deprecated commands
END
}
function help_global_options {
cat <<END
Global fx options: fx [OPTION] ${cmd} ...
--dir=BUILD_DIR Path to the build directory to use when running COMMAND.
--disable=FEATURE Disable a feature (non-persistent).
Valid values for FEATURE: [${_FX_OPTIONAL_FEATURES[@]}]
-d=DEVICE[:SSH_PORT] Target a specific device.
DEVICE may be a Fuchsia device name to be resolved using
device-finder or an IP address.
An IPv4 address must be specified directly, while an IPv6
need to be surrounded by brackets.
SSH_PORT, if specified, will be used for all commands
that rely on SSH to connect to the device instead of the
default SSH port (22).
Note: See "fx help set-device" for more help and to set
the default device for a BUILD_DIR.
-i Iterative mode. Repeat the command whenever a file is
modified under your Fuchsia directory, not including
out/.
-x Print commands and their arguments as they are executed.
-xx Print extra logging of the fx tool itself (implies -x)
END
}
function help_list_commands {
local hide_contrib=0
local show_deprecated=0
while [[ $# -ne 0 ]]; do
if [[ "$1" == "--deprecated" ]]; then
show_deprecated=1
elif [[ "$1" == "--no-contrib" ]]; then
hide_contrib=1
fi
shift
done
# list all subcommands with summaries, grouped by categories
commands | xargs awk \
-v hide_contrib=${hide_contrib} \
-v show_deprecated=${show_deprecated} \
-f "${fuchsia_dir}/scripts/fx-help.awk"
# list host tools build artifacts without corresponding metadata
host_tools="$(find_host_tools)"
if [[ -n "${host_tools}" ]]; then
echo "Host binaries produced by the build with no metadata (more info at //tools/devshell/README.md):"
for i in ${host_tools}; do
echo -n " "
basename $i
done
fi
help_options
help_global_options
}
function help_command {
local cmd="$@"
local cmd_path="$(commands ${cmd} | head -1)"
if [[ -z "${cmd_path}" ]]; then
local cmd_path="$(find_host_tools ${cmd} | head -1)"
if [[ -z "${cmd_path}" ]]; then
echo "Command ${cmd} not found. Try \`fx help\`"
else
echo "'$(_relative "${cmd_path}")' is a host tool and no metadata" \
"was found. Try running \`fx ${cmd} -h\`"
fi
elif [[ $(file -b --mime "${cmd_path}" | cut -d / -f 1) == "text" ]]; then
fx-print-command-help "${cmd_path}"
help_global_options
else
echo "No help found. Try \`fx ${cmd} -h\`"
fi
}
function usage {
cat <<END
usage: fx [--dir BUILD_DIR] [-d DEVICE_NAME] [-i] [-x] COMMAND [...]
Run Fuchsia development commands. Must be run either from a directory
that is contained in a Platform Source Tree or with the FUCHSIA_DIR
environment variable set to the root of a Platform Source Tree.
host shell extensions: (requires "source scripts/fx-env.sh")
fx-update-path add useful tools to the PATH
fx-set-prompt display the current configuration in the shell prompt
END
help_list_commands "$@"
}
fuchsia_dir="${FUCHSIA_DIR}"
if [[ -z "${fuchsia_dir}" ]]; then
# We walk the parent directories looking for .jiri_root rather than using
# BASH_SOURCE so that we find the fuchsia_dir enclosing the current working
# directory instead of the one containing this file in case the user has
# multiple source trees and is picking up this file from another one.
fuchsia_dir="$(pwd)"
while [[ ! -d "${fuchsia_dir}/.jiri_root" ]]; do
fuchsia_dir="$(dirname "${fuchsia_dir}")"
if [[ "${fuchsia_dir}" == "/" ]]; then
echo "Cannot find Platform Source Tree containing $(pwd)"
exit 1
fi
done
fi
declare -r vars_sh="${fuchsia_dir}/tools/devshell/lib/vars.sh"
source "${vars_sh}" || exit $?
declare -r metrics_sh="${fuchsia_dir}/tools/devshell/lib/metrics.sh"
source "${metrics_sh}" || exit $?
declare -r cmd_locator_sh="${fuchsia_dir}/tools/devshell/lib/fx-cmd-locator.sh"
source "${cmd_locator_sh}" || exit $?
declare -r features_sh="${fuchsia_dir}/tools/devshell/lib/fx-optional-features.sh"
source "${features_sh}" || exit $?
while [[ $# -ne 0 ]]; do
case $1 in
--config=*|--dir=*|-d=*|--disable=*)
# Turn --switch=value into --switch value.
arg="$1"
shift
set -- "${arg%%=*}" "${arg#*=}" "$@"
continue
;;
--config)
fx-warn "DEPRECATION NOTICE: --config is deprecated, use --dir instead."
sleep 5
if [[ $# -lt 2 ]]; then
usage
fx-error "Missing path to config file for --config argument"
exit 1
fi
shift # Removes --config.
export _FX_BUILD_DIR="$(source "$1"; echo "${FUCHSIA_BUILD_DIR}")"
;;
--dir)
if [[ $# -lt 2 ]]; then
usage
fx-error "Missing path to build directory for --dir argument"
exit 1
fi
shift # Removes --dir.
export _FX_BUILD_DIR="$1"
if [[ "$_FX_BUILD_DIR" == //* ]]; then
_FX_BUILD_DIR="${fuchsia_dir}/${_FX_BUILD_DIR#//}"
fi
;;
--disable)
if [[ $# -lt 2 ]]; then
usage
fx-error "Missing argument to --disable"
exit 1
fi
shift # Removes --disable.
feature="$1"
if ! is_valid_feature "${feature}"; then
fx-error "Unknown feature \"${feature}\". Valid values are: ${_FX_OPTIONAL_FEATURES[@]}"
exit 1
fi
env_name="$(get_disable_feature_env_name "${feature}")"
export ${env_name}=1
;;
-d)
if [[ $# -lt 2 ]]; then
usage
fx-error "Missing device name for -d argument"
exit 1
fi
shift # removes -d
if ! is-valid-device "$1"; then
fx-error "Invalid device: $1. See valid values in 'fx help set-device'"
exit 1
fi
export FUCHSIA_DEVICE_NAME="$1"
;;
-i)
declare iterative=1
;;
-x)
export FUCHSIA_DEVSHELL_VERBOSITY=1
;;
-xx)
set -x
;;
--)
shift
break
;;
help|--help)
if [[ $# -lt 2 || "$2" =~ ^\-\-.* ]]; then
shift
usage "$@"
else
shift
help_command "$@"
fi
exit 0
;;
-*)
usage
fx-error "Unknown global argument $1"
exit 1
;;
*)
break
;;
esac
shift
done
if [[ $# -lt 1 ]]; then
usage
fx-error "Missing command name"
exit 1
fi
command_name="$1"
command_path="$(find_executable ${command_name})"
if [[ $? -ne 0 || ! -x "${command_path}" ]]; then
if [[ -n "${command_path}" ]]; then
_path_message=" in the expected location $(_relative "${command_path}")"
fi
fx-error "Cannot find executable for ${command_name}${_path_message}."\
"If this is a tool produced by the build, make sure your"\
"\`fx set\` config produces it in the $(_relative "$(get_host_tools_dir)") directory."
exit 1
fi
declare -r cmd_and_args="$@"
shift # Removes the command name.
if [[ "${command_name}" != "vendor" || $# -lt 2 ]]; then
metric_name="${command_name}"
else
metric_name="vendor/$1/$2"
fi
track-command-execution "${metric_name}" "$@" &
declare -r start_time="$SECONDS"
"${command_path}" "$@"
declare -r retval=$?
declare -r end_time="$SECONDS"
declare -r elapsed_time=$(( 1000 * (end_time - start_time) )) # milliseconds
if [ -z "${iterative}" ]; then
track-command-finished "${elapsed_time}" "${retval}" "${command_name}" "$@" &
exit ${retval}
elif which inotifywait >/dev/null; then
monitor_source_changes() {
# Watch everything except out/ and files/directories beginning with "."
# such as lock files, swap files, .git, etc'.
inotifywait -qrme modify \
--exclude "/(\.|lock|compile_commands.json)" \
"${fuchsia_dir}" \
@"${fuchsia_dir}"/out \
@"${fuchsia_dir}"/zircon/public
}
elif which apt-get >/dev/null; then
echo "Missing inotifywait"
echo "Try: sudo apt-get install inotify-tools"
exit 1
elif which fswatch >/dev/null; then
monitor_source_changes() {
fswatch --one-per-batch --event=Updated \
-e "${fuchsia_dir}"/out/ \
-e "${fuchsia_dir}"/zircon/public/ \
-e "/\." \
-e "/lock" \
-e "/compile_commands.json" \
.
}
else
echo "Missing fswatch"
echo "Try: brew install fswatch"
exit 1
fi
monitor_and_run() {
local -r event_pipe="$1"
local -r display_name="$2"
shift 2
# Explicitly bind $event_pipe to a numbered FD so read behaves consistently
# on Linux and Mac shells ("read <$event_pipe" closes $event_pipe after the
# first read on Mac bash).
exec 3<"${event_pipe}"
while read -u 3; do
if [[ "$(uname -s)" != "Darwin" ]]; then
# Drain all subsequent events in a batch.
# Otherwise when multiple files are changes at once we'd run multiple
# times.
read -u 3 -d "" -t .01
fi
# Allow at most one fx -i invocation per Fuchsia dir at a time.
# Otherwise multiple concurrent fx -i invocations can trigger each other
# and cause a storm.
echo "---------------------------------- fx -i ${display_name} ---------------------------------------"
"$@"
echo "--- Done!"
done
}
monitor_and_run <(monitor_source_changes) "${cmd_and_args}" "${command_path}" "$@"