/home/runner/work/chrme/chrme/_build/test/cover/ct/chrme_cli.html

1 -module(chrme_cli).
2
3 -export([main/1]).
4
5 -define(EXIT_OK, 0).
6 -define(EXIT_USAGE_ERROR, 1).
7 -define(EXIT_ERROR, 2).
8
9 main(Args) ->
10
:-(
case Args of
11 [] ->
12
:-(
print_usage(),
13
:-(
halt(?EXIT_OK);
14 ["-h"] ->
15
:-(
print_usage(),
16
:-(
halt(?EXIT_OK);
17 ["--help"] ->
18
:-(
print_usage(),
19
:-(
halt(?EXIT_OK);
20 ["-V"] ->
21
:-(
print_version(),
22
:-(
halt(?EXIT_OK);
23 ["--version"] ->
24
:-(
print_version(),
25
:-(
halt(?EXIT_OK);
26 ["help" | Rest] ->
27
:-(
do_help(Rest),
28
:-(
halt(?EXIT_OK);
29 _ ->
30
:-(
case parse_args(Args) of
31 {ok, Opts, CmdArgs} ->
32
:-(
dispatch(Opts, CmdArgs);
33 {error, Msg} ->
34
:-(
io:format("Error: ~s~n", [Msg]),
35
:-(
print_usage(),
36
:-(
halt(?EXIT_USAGE_ERROR)
37 end
38 end.
39
40 do_navigate(Opts, ["--id", IdStr, UrlStr]) ->
41
:-(
Host = maps:get(host, Opts),
42
:-(
Port = maps:get(port, Opts),
43
:-(
Name = cli_nav,
44
:-(
TargetId = list_to_binary(IdStr),
45
:-(
case chrme_session:attach(Name, Host, Port, TargetId) of
46 {ok, _Session} ->
47
:-(
chrme_session:await_start(Name),
48
:-(
_ = chrme_page:enable(Name),
49
:-(
case chrme_page:navigate(Name, list_to_binary(UrlStr)) of
50 {ok, Nav} ->
51
:-(
Frame = maps:get(frame_id, Nav),
52
:-(
Loader = maps:get(loader_id, Nav),
53
:-(
io:format("Navigated existing target ~ts to ~ts. FrameId=~ts loaderId=~p~n",
54 [TargetId, UrlStr, Frame, Loader]),
55
:-(
halt(?EXIT_OK);
56 Err ->
57
:-(
io:format("Navigation error: ~p~n", [Err]),
58
:-(
halt(?EXIT_ERROR)
59 end;
60 {error, Err} ->
61
:-(
io:format("Error attaching to target ~ts: ~p~n", [TargetId, Err]),
62
:-(
halt(?EXIT_ERROR)
63 end;
64 do_navigate(Opts, ["-i", IdStr, UrlStr]) ->
65
:-(
do_navigate(Opts, ["--id", IdStr, UrlStr]);
66 do_navigate(Opts, [UrlStr]) ->
67
:-(
Host = maps:get(host, Opts),
68
:-(
Port = maps:get(port, Opts),
69
:-(
Name = cli_nav,
70
:-(
Url = list_to_binary(UrlStr),
71
:-(
case chrme_session:start(Name, Host, Port, Url) of
72 {ok, _Session} ->
73
:-(
chrme_session:await_start(Name),
74
:-(
_ = chrme_page:enable(Name),
75
:-(
case chrme_page:navigate(Name, Url) of
76 {ok, Nav} ->
77
:-(
Frame = maps:get(frame_id, Nav),
78
:-(
Loader = maps:get(loader_id, Nav),
79
:-(
io:format("Navigated to ~ts. FrameId=~ts loaderId=~p~n", [Url, Frame, Loader]),
80
:-(
halt(?EXIT_OK);
81 Err ->
82
:-(
io:format("Navigation error: ~p~n", [Err]),
83
:-(
halt(?EXIT_ERROR)
84 end;
85 {error, Err} ->
86
:-(
io:format("Error starting session: ~p~n", [Err]),
87
:-(
halt(?EXIT_ERROR)
88 end;
89 do_navigate(_, _) ->
90
:-(
io:format("Usage: chrme navigate <url> | --id <target-id> <url>~n", []),
91
:-(
halt(?EXIT_USAGE_ERROR).
92
93 %% Evaluate JavaScript expression on a new or existing target
94 do_evaluate(Opts, ["--id", IdStr | ExprParts]) ->
95
:-(
Host = maps:get(host, Opts),
96
:-(
Port = maps:get(port, Opts),
97
:-(
Name = cli_eval,
98
:-(
TargetId = list_to_binary(IdStr),
99
:-(
case chrme_session:attach(Name, Host, Port, TargetId) of
100 {ok, _Session} ->
101
:-(
chrme_session:await_start(Name),
102
:-(
_ = chrme_cdp:call(Name, <<"Runtime.enable">>, #{}),
103
:-(
Expr = list_to_binary(string:join(ExprParts, " ")),
104
:-(
case chrme_runtime:evaluate(Name, Expr) of
105
:-(
{ok, Result} -> io:format("~p~n", [Result]), halt(?EXIT_OK);
106
:-(
{error, Err} -> io:format("Evaluation error: ~p~n", [Err]), halt(?EXIT_ERROR)
107 end;
108 {error, Err} ->
109
:-(
io:format("Error attaching to target ~ts: ~p~n", [TargetId, Err]),
110
:-(
halt(?EXIT_ERROR)
111 end;
112 do_evaluate(Opts, ["-i", IdStr | ExprParts]) ->
113
:-(
do_evaluate(Opts, ["--id", IdStr | ExprParts]);
114 do_evaluate(Opts, ExprParts) when is_list(ExprParts) ->
115
:-(
Host = maps:get(host, Opts),
116
:-(
Port = maps:get(port, Opts),
117
:-(
Name = cli_eval,
118 %% Open a blank page by default
119
:-(
case chrme_session:start(Name, Host, Port, list_to_binary("about:blank")) of
120 {ok, _Session} ->
121
:-(
chrme_session:await_start(Name),
122
:-(
_ = chrme_cdp:call(Name, <<"Runtime.enable">>, #{}),
123
:-(
Expr = list_to_binary(string:join(ExprParts, " ")),
124
:-(
case chrme_runtime:evaluate(Name, Expr) of
125
:-(
{ok, Result} -> io:format("~p~n", [Result]), halt(?EXIT_OK);
126
:-(
{error, Err} -> io:format("Evaluation error: ~p~n", [Err]), halt(?EXIT_ERROR)
127 end;
128 {error, Err} ->
129
:-(
io:format("Error creating session: ~p~n", [Err]),
130
:-(
halt(?EXIT_ERROR)
131 end;
132 do_evaluate(_, _) ->
133
:-(
io:format("Usage: chrme evaluate [--id <target-id>] <expression>~n", []),
134
:-(
halt(?EXIT_USAGE_ERROR).
135
136 %% Dump the DOM of a target (new or existing)
137 do_dom(Opts, ["--id", IdStr]) ->
138
:-(
Host = maps:get(host, Opts),
139
:-(
Port = maps:get(port, Opts),
140
:-(
Name = cli_dom,
141
:-(
TargetId = list_to_binary(IdStr),
142
:-(
case chrme_session:attach(Name, Host, Port, TargetId) of
143 {ok, _Session} ->
144
:-(
chrme_session:await_start(Name),
145
:-(
_ = chrme_cdp:call(Name, <<"DOM.enable">>, #{}),
146
:-(
case chrme_dom:get_document(Name) of
147 {ok, Doc} ->
148
:-(
NodeId = maps:get(<<"nodeId">>, Doc),
149
:-(
case chrme_dom:get_outer_html(Name, NodeId) of
150 {ok, Html} ->
151
:-(
io:format("~ts~n", [Html]),
152
:-(
halt(?EXIT_OK);
153 {error, Err} ->
154
:-(
io:format("DOM dump error: ~p~n", [Err]),
155
:-(
halt(?EXIT_ERROR)
156 end;
157 {error, Err} ->
158
:-(
io:format("Error getting document: ~p~n", [Err]),
159
:-(
halt(?EXIT_ERROR)
160 end;
161 {error, Err} ->
162
:-(
io:format("Error attaching to target ~s: ~p~n", [IdStr, Err]),
163
:-(
halt(?EXIT_ERROR)
164 end;
165 do_dom(Opts, ["-i", IdStr]) ->
166
:-(
do_dom(Opts, ["--id", IdStr]);
167 do_dom(Opts, [UrlStr]) ->
168
:-(
Host = maps:get(host, Opts),
169
:-(
Port = maps:get(port, Opts),
170
:-(
Name = cli_dom,
171
:-(
Url = list_to_binary(UrlStr),
172
:-(
case chrme_session:start(Name, Host, Port, Url) of
173 {ok, _Session} ->
174
:-(
chrme_session:await_start(Name),
175
:-(
_ = chrme_cdp:call(Name, <<"Page.enable">>, #{}),
176
:-(
_ = chrme_cdp:call(Name, <<"DOM.enable">>, #{}),
177
:-(
case chrme_page:navigate(Name, Url) of
178 {ok, _Nav} ->
179
:-(
case chrme_dom:get_document(Name) of
180 {ok, Doc} ->
181
:-(
NodeId = maps:get(<<"nodeId">>, Doc),
182
:-(
case chrme_dom:get_outer_html(Name, NodeId) of
183 {ok, Html} ->
184
:-(
io:format("~ts~n", [Html]),
185
:-(
halt(?EXIT_OK);
186 {error, Err} ->
187
:-(
io:format("DOM dump error: ~p~n", [Err]),
188
:-(
halt(?EXIT_ERROR)
189 end;
190 {error, Err} ->
191
:-(
io:format("Error getting document: ~p~n", [Err]),
192
:-(
halt(?EXIT_ERROR)
193 end;
194 {error, Err} ->
195
:-(
io:format("Navigation error: ~p~n", [Err]),
196
:-(
halt(?EXIT_ERROR)
197 end;
198 {error, Err} ->
199
:-(
io:format("Error starting session: ~p~n", [Err]),
200
:-(
halt(?EXIT_ERROR)
201 end;
202 do_dom(_, _) ->
203
:-(
io:format("Usage: chrme dom [--id <target-id>] <url>~n", []),
204
:-(
halt(?EXIT_USAGE_ERROR).
205
206 %% Stream all protocol events for a target (new or existing)
207 do_events(Opts, ["--id", IdStr]) ->
208
:-(
Host = maps:get(host, Opts),
209
:-(
Port = maps:get(port, Opts),
210
:-(
Name = cli_events,
211
:-(
TargetId = list_to_binary(IdStr),
212
:-(
case chrme_session:attach(Name, Host, Port, TargetId) of
213 {ok, _Session} ->
214
:-(
chrme_session:await_start(Name),
215
:-(
_ = chrme_cdp:call(Name, <<"Page.enable">>, #{}),
216
:-(
_ = chrme_cdp:call(Name, <<"Network.enable">>, #{}),
217
:-(
_ = chrme_cdp:call(Name, <<"Runtime.enable">>, #{}),
218
:-(
_ = chrme_cdp:call(Name, <<"DOM.enable">>, #{}),
219
:-(
Ref = make_ref(),
220
:-(
CallbackName = {cli_events, Name, Ref},
221
:-(
CallbackFun = fun
222
:-(
(stop) -> true;
223 (Msg) ->
224
:-(
io:format("~s~n", [jsone:encode(Msg)]),
225
:-(
true
226 end,
227
:-(
chrme_ws_apic:add_callback(Name, {CallbackName, CallbackFun}),
228
:-(
io:format("Streaming events for target ~ts. Press Ctrl+C to quit.~n", [TargetId]),
229
:-(
events_loop();
230 {error, Err} ->
231
:-(
io:format("Error attaching to target ~s: ~p~n", [IdStr, Err]),
232
:-(
halt(?EXIT_ERROR)
233 end;
234 do_events(Opts, ["-i", IdStr]) ->
235
:-(
do_events(Opts, ["--id", IdStr]);
236 do_events(Opts, []) ->
237
:-(
Host = maps:get(host, Opts),
238
:-(
Port = maps:get(port, Opts),
239
:-(
Name = cli_events,
240
:-(
case chrme_session:start(Name, Host, Port, list_to_binary("about:blank")) of
241 {ok, _Session} ->
242
:-(
chrme_session:await_start(Name),
243
:-(
_ = chrme_cdp:call(Name, <<"Page.enable">>, #{}),
244
:-(
_ = chrme_cdp:call(Name, <<"Network.enable">>, #{}),
245
:-(
_ = chrme_cdp:call(Name, <<"Runtime.enable">>, #{}),
246
:-(
_ = chrme_cdp:call(Name, <<"DOM.enable">>, #{}),
247
:-(
Ref = make_ref(),
248
:-(
CallbackName = {cli_events, Name, Ref},
249
:-(
CallbackFun = fun
250
:-(
(stop) -> true;
251 (Msg) ->
252
:-(
io:format("~s~n", [jsone:encode(Msg)]),
253
:-(
true
254 end,
255
:-(
chrme_ws_apic:add_callback(Name, {CallbackName, CallbackFun}),
256
:-(
io:format("Streaming events for new target. Press Ctrl+C to quit.~n", []),
257
:-(
events_loop();
258 _ ->
259
:-(
io:format("Usage: chrme events [--id <target-id>]~n", []),
260
:-(
halt(?EXIT_USAGE_ERROR)
261 end.
262
263 events_loop() ->
264
:-(
receive
265
:-(
_ -> events_loop()
266 end.
267
268 print_usage() ->
269
:-(
io:format("Usage: chrme [OPTIONS] <command> [args]~n~n", []),
270
:-(
io:format("Options:~n", []),
271
:-(
io:format(" -h, --help Show this help message~n", []),
272
:-(
io:format(" -V, --version Show version~n", []),
273
:-(
io:format(" -H, --host <host> Debugging HTTP host (default \"localhost\")~n", []),
274
:-(
io:format(" -P, --port <port> Debugging HTTP port (default 9222)~n", []),
275
:-(
io:format(" -e, --endpoint <ws_url> WebSocket debugger URL (attach only)~n", []),
276
:-(
io:format(" -i, --id <target-id> Attach to an existing target ID~n", []),
277
:-(
io:format(" -b, --chrome-binary <path> Path to Chrome executable (launch only)~n", []),
278
:-(
io:format(" --headless Launch Chrome in headless mode (default true)~n", []),
279
:-(
io:format(" --no-headless Launch Chrome with UI~n", []),
280
:-(
io:format(" --user-data-dir <dir> Chrome user data directory~n", []),
281
:-(
io:format(" -v, --verbose Enable verbose output~n~n", []),
282
:-(
io:format("Commands:~n", []),
283
:-(
io:format(" launch Launch a new Chrome instance~n", []),
284
:-(
io:format(" list List open debugging targets~n", []),
285
:-(
io:format(" new Create a new debugging target~n", []),
286
:-(
io:format(" navigate Navigate a new page to a URL~n", []),
287
:-(
io:format(" screenshot Capture a screenshot (not implemented)~n", []),
288
:-(
io:format(" evaluate Evaluate JavaScript~n", []),
289
:-(
io:format(" dom Dump DOM~n", []),
290
:-(
io:format(" pdf Print to PDF (not implemented)~n", []),
291
:-(
io:format(" events Stream events~n", []),
292
:-(
io:format(" help Show this message or help for a specific command~n", []),
293
:-(
io:format(" version Show version~n", []).
294
295 print_version() ->
296
:-(
_ = case application:load(chrme) of
297
:-(
ok -> ok;
298
:-(
_ -> ok
299 end,
300
:-(
Vsn = case application:get_key(chrme, vsn) of
301
:-(
V when is_list(V); is_binary(V) -> V;
302
:-(
_ -> "unknown"
303 end,
304
:-(
io:format("~s~n", [Vsn]).
305
306 parse_args(Args) ->
307
:-(
Defaults = #{
308 command => undefined,
309 host => list_to_binary("localhost"),
310 port => 9222,
311 endpoint => undefined,
312 chrome_binary => list_to_binary("/usr/bin/google-chrome"),
313 headless => true,
314 user_data_dir => list_to_binary("/tmp/chrme_default_user_data_dir"),
315 verbose => false
316 },
317
:-(
parse_args_loop(Args, Defaults).
318
319 parse_args_loop([], Opts) ->
320
:-(
case maps:get(command, Opts) of
321
:-(
undefined -> {error, "No command specified"};
322
:-(
_ -> {ok, Opts, []}
323 end;
324 parse_args_loop([Arg|Rest], Opts) ->
325
:-(
case Arg of
326 "-H" ->
327
:-(
case Rest of
328
:-(
[Host|T] -> parse_args_loop(T, Opts#{host => list_to_binary(Host)});
329
:-(
_ -> {error, "Missing argument for -H/--host"}
330 end;
331 "--host" ->
332
:-(
case Rest of
333
:-(
[Host|T] -> parse_args_loop(T, Opts#{host => list_to_binary(Host)});
334
:-(
_ -> {error, "Missing argument for -H/--host"}
335 end;
336 "-P" ->
337
:-(
case Rest of
338 [P|T] ->
339
:-(
Opts1 = case catch list_to_integer(P) of
340
:-(
I when is_integer(I) -> Opts#{port => I};
341
:-(
_ -> Opts
342 end,
343
:-(
parse_args_loop(T, Opts1);
344
:-(
_ -> {error, "Missing argument for -P/--port"}
345 end;
346 "--port" ->
347
:-(
case Rest of
348 [P|T] ->
349
:-(
Opts1 = case catch list_to_integer(P) of
350
:-(
I when is_integer(I) -> Opts#{port => I};
351
:-(
_ -> Opts
352 end,
353
:-(
parse_args_loop(T, Opts1);
354
:-(
_ -> {error, "Missing argument for -P/--port"}
355 end;
356 "-e" ->
357
:-(
case Rest of
358
:-(
[EP|T] -> parse_args_loop(T, Opts#{endpoint => list_to_binary(EP)});
359
:-(
_ -> {error, "Missing argument for -e/--endpoint"}
360 end;
361 "--endpoint" ->
362
:-(
case Rest of
363
:-(
[EP|T] -> parse_args_loop(T, Opts#{endpoint => list_to_binary(EP)});
364
:-(
_ -> {error, "Missing argument for -e/--endpoint"}
365 end;
366 "-b" ->
367
:-(
case Rest of
368
:-(
[Bin|T] -> parse_args_loop(T, Opts#{chrome_binary => list_to_binary(Bin)});
369
:-(
_ -> {error, "Missing argument for -b/--chrome-binary"}
370 end;
371 "--chrome-binary" ->
372
:-(
case Rest of
373
:-(
[Bin|T] -> parse_args_loop(T, Opts#{chrome_binary => list_to_binary(Bin)});
374
:-(
_ -> {error, "Missing argument for -b/--chrome-binary"}
375 end;
376
:-(
"--headless" -> parse_args_loop(Rest, Opts#{headless => true});
377
:-(
"--no-headless" -> parse_args_loop(Rest, Opts#{headless => false});
378 "--user-data-dir" ->
379
:-(
case Rest of
380
:-(
[Dir|T] -> parse_args_loop(T, Opts#{user_data_dir => list_to_binary(Dir)});
381
:-(
_ -> {error, "Missing argument for --user-data-dir"}
382 end;
383
:-(
"-v" -> parse_args_loop(Rest, Opts#{verbose => true});
384
:-(
"--verbose" -> parse_args_loop(Rest, Opts#{verbose => true});
385 Cmd when is_list(Cmd), Cmd =/= [], hd(Cmd) =:= $- ->
386
:-(
{error, ["Unknown flag: ", Cmd]};
387
:-(
Cmd -> {ok, Opts#{command => Cmd}, Rest}
388 end.
389
390 dispatch(Opts, CmdArgs) ->
391
:-(
Cmd = maps:get(command, Opts),
392
:-(
CmdAtom = list_to_atom(Cmd),
393
:-(
case CmdAtom of
394
:-(
launch -> do_launch(Opts, CmdArgs);
395
:-(
list -> do_list(Opts, CmdArgs);
396
:-(
new -> do_new(Opts, CmdArgs);
397
:-(
navigate -> do_navigate(Opts, CmdArgs);
398
:-(
evaluate -> do_evaluate(Opts, CmdArgs);
399
:-(
dom -> do_dom(Opts, CmdArgs);
400
:-(
help -> do_help(CmdArgs), halt(?EXIT_OK);
401
:-(
version -> print_version(), halt(?EXIT_OK);
402
:-(
events -> do_events(Opts, CmdArgs);
403 _ ->
404
:-(
io:format("Unknown command: ~s~n", [Cmd]),
405
:-(
print_usage(),
406
:-(
halt(?EXIT_USAGE_ERROR)
407 end.
408
409 do_launch(Opts, CmdArgs) ->
410
:-(
Host = maps:get(host, Opts),
411
:-(
Port = maps:get(port, Opts),
412
:-(
Exe = maps:get(chrome_binary, Opts),
413
:-(
Headless = maps:get(headless, Opts),
414
:-(
DataDir = maps:get(user_data_dir, Opts),
415
:-(
Extra = case CmdArgs of
416
:-(
["--" | Rest] -> [list_to_binary(X) || X <- Rest];
417
:-(
_ -> [list_to_binary(X) || X <- CmdArgs]
418 end,
419
:-(
Name = cli_chrome,
420
:-(
LOpts = #{name => Name,
421 executable => Exe,
422 remote_port => Port,
423 user_data_dir => DataDir,
424 headless => Headless,
425 extra_args => Extra},
426
:-(
case chrme_launcher:start(LOpts) of
427
:-(
{ok, _} -> ok;
428 {error, LaunchErr} ->
429
:-(
io:format("Error launching Chrome: ~p~n", [LaunchErr]),
430
:-(
halt(?EXIT_ERROR)
431 end,
432
:-(
chrme_launcher:await_start(Name),
433
:-(
case chrme_http_apic:version(Host, Port) of
434 {ok, V} ->
435
:-(
io:format("HTTP debug endpoint: http://~ts:~p~n", [Host, Port]),
436
:-(
case maps:find(<<"webSocketDebuggerUrl">>, V) of
437
:-(
{ok, Ws} -> io:format("WebSocket debugger URL: ~ts~n", [Ws]);
438
:-(
error -> ok
439 end;
440 {error, VersionErr} ->
441
:-(
io:format("Error fetching version: ~p~n", [VersionErr])
442 end,
443
:-(
halt(?EXIT_OK).
444
445 do_list(Opts, _Args) ->
446
:-(
Host = maps:get(host, Opts),
447
:-(
Port = maps:get(port, Opts),
448
:-(
case chrme_http_apic:list_targets(Host, Port) of
449 {ok, Targets} ->
450
:-(
io:format("id\ttype\ttitle\turl\n", []),
451
:-(
lists:foreach(fun(T) ->
452
:-(
Id = maps:get(<<"id">>, T),
453
:-(
Type = maps:get(<<"type">>, T),
454
:-(
Title = maps:get(<<"title">>, T),
455
:-(
Url = maps:get(<<"url">>, T),
456
:-(
io:format("~ts\t~ts\t~ts\t~ts\n", [Id, Type, Title, Url])
457 end, Targets),
458
:-(
halt(?EXIT_OK);
459 {error, Reason} ->
460
:-(
io:format("Error listing targets: ~p~n", [Reason]),
461
:-(
halt(?EXIT_ERROR)
462 end.
463
464 do_new(Opts, CmdArgs) ->
465
:-(
case CmdArgs of
466 [UrlStr] ->
467
:-(
Host = maps:get(host, Opts),
468
:-(
Port = maps:get(port, Opts),
469
:-(
Url = list_to_binary(UrlStr),
470
:-(
case chrme_http_apic:new_target(Host, Port, Url) of
471 {ok, M} ->
472
:-(
Id = maps:get(<<"id">>, M),
473
:-(
Ws = maps:get(<<"webSocketDebuggerUrl">>, M),
474
:-(
io:format("Target id: ~ts~n", [Id]),
475
:-(
io:format("WebSocket URL: ~ts~n", [Ws]),
476
:-(
halt(?EXIT_OK);
477 {error, Reason} ->
478
:-(
io:format("Error creating target: ~p~n", [Reason]),
479
:-(
halt(?EXIT_ERROR)
480 end;
481 _ ->
482
:-(
io:format("Usage: chrme new <url>~n", []),
483
:-(
halt(?EXIT_USAGE_ERROR)
484 end.
485
486 do_help([]) ->
487
:-(
print_usage();
488 do_help([Cmd|_]) ->
489
:-(
CA = list_to_atom(Cmd),
490
:-(
case CA of
491
:-(
launch -> io:format("Usage: chrme launch [options] [-- <extra args>]\n", []);
492
:-(
list -> io:format("Usage: chrme list [options]\n", []);
493
:-(
new -> io:format("Usage: chrme new <url> [options]\n", []);
494
:-(
navigate -> io:format("Usage: chrme navigate <url> [options]\n", []);
495
:-(
evaluate -> io:format("Usage: chrme evaluate [--id <target-id>] <expression>\n", []);
496
:-(
dom -> io:format("Usage: chrme dom [--id <target-id>] <url>\n", []);
497
:-(
events -> io:format("Usage: chrme events [--id <target-id>]\n", []);
498
:-(
help -> io:format("Usage: chrme help [command]\n", []);
499
:-(
version -> io:format("Usage: chrme version\n", []);
500
:-(
_ -> io:format("Unknown command: ~s~n", [Cmd])
501 end.
Line Hits Source