@@ -32,34 +32,129 @@ import 'src/vm_interop_handler.dart';
3232/// analytics logic, it has been moved here.
3333Future <void > runDartdev (List <String > args, SendPort port) async {
3434 VmInteropHandler .initialize (port);
35- if (args.contains ('run' )) {
36- // These flags have a format that can't be handled by package:args, so while
37- // they are valid flags we'll assume the VM has verified them by this point.
38- args = args
39- .where (
40- (element) => ! (element.contains ('--observe' ) ||
41- element.contains ('--enable-vm-service' )),
42- )
43- .toList ();
35+
36+ int result;
37+
38+ // The exit code for the dartdev process; null indicates that it has not been
39+ // set yet. The value is set in the catch and finally blocks below.
40+ int exitCode;
41+
42+ // Any caught non-UsageExceptions when running the sub command.
43+ Object exception;
44+ StackTrace stackTrace;
45+
46+ // The Analytics instance used to report information back to Google Analytics;
47+ // see lib/src/analytics.dart.
48+ final analytics = createAnalyticsInstance (
49+ args.contains ('--disable-dartdev-analytics' ),
50+ );
51+
52+ // If we have not printed the analyticsNoticeOnFirstRunMessage to stdout,
53+ // the user is on a terminal, and the machine is not a bot, then print the
54+ // disclosure and set analytics.disclosureShownOnTerminal to true.
55+ if (analytics is DartdevAnalytics &&
56+ ! analytics.disclosureShownOnTerminal &&
57+ io.stdout.hasTerminal &&
58+ ! isBot ()) {
59+ print (analyticsNoticeOnFirstRunMessage);
60+ analytics.disclosureShownOnTerminal = true ;
4461 }
4562
46- // Finally, call the runner to execute the command; see DartdevRunner.
63+ // When `--disable-analytics` or `--enable-analytics` are called we perform
64+ // the respective intention and print any notices to standard out and exit.
65+ if (args.contains ('--disable-analytics' )) {
66+ // This block also potentially catches the case of (disableAnalytics &&
67+ // enableAnalytics), in which we favor the disabling of analytics.
68+ analytics.enabled = false ;
69+
70+ // Alert the user that analytics has been disabled.
71+ print (analyticsDisabledNoticeMessage);
72+ VmInteropHandler .exit (0 );
73+ return ;
74+ } else if (args.contains ('--enable-analytics' )) {
75+ analytics.enabled = true ;
76+
77+ // Alert the user again that anonymous data will be collected.
78+ print (analyticsNoticeOnFirstRunMessage);
79+ VmInteropHandler .exit (0 );
80+ return ;
81+ }
4782
48- final runner = DartdevRunner (args);
49- var exitCode = 1 ;
5083 try {
51- exitCode = await runner.run (args);
52- } on UsageException catch (e) {
53- // TODO(sigurdm): It is unclear when a UsageException gets to here, and
54- // when it is in DartdevRunner.runCommand.
55- io.stderr.writeln ('$e ' );
56- exitCode = 64 ;
84+ final runner = DartdevRunner (args, analytics);
85+
86+ // Run can't be called with the '--disable-dartdev-analytics' flag; remove
87+ // it if it is contained in args.
88+ if (args.contains ('--disable-dartdev-analytics' )) {
89+ args = List .from (args)..remove ('--disable-dartdev-analytics' );
90+ }
91+
92+ if (args.contains ('run' )) {
93+ // These flags have a format that can't be handled by package:args, so while
94+ // they are valid flags we'll assume the VM has verified them by this point.
95+ args = args
96+ .where (
97+ (element) => ! (element.contains ('--observe' ) ||
98+ element.contains ('--enable-vm-service' )),
99+ )
100+ .toList ();
101+ }
102+
103+ // If ... help pub ... is in the args list, remove 'help', and add '--help'
104+ // to the end of the list. This will make it possible to use the help
105+ // command to access subcommands of pub such as `dart help pub publish`; see
106+ // https://github.com/dart-lang/sdk/issues/42965.
107+ if (PubUtils .shouldModifyArgs (args, runner.commands.keys.toList ())) {
108+ args = PubUtils .modifyArgs (args);
109+ }
110+
111+ // Finally, call the runner to execute the command; see DartdevRunner.
112+ result = await runner.run (args);
113+ } catch (e, st) {
114+ if (e is UsageException ) {
115+ io.stderr.writeln ('$e ' );
116+ exitCode = 64 ;
117+ } else {
118+ // Set the exception and stack trace only for non-UsageException cases:
119+ exception = e;
120+ stackTrace = st;
121+ io.stderr.writeln ('$e ' );
122+ io.stderr.writeln ('$st ' );
123+ exitCode = 1 ;
124+ }
57125 } finally {
126+ // Set the exitCode, if it wasn't set in the catch block above.
127+ exitCode ?? = result ?? 0 ;
128+
129+ // Send analytics before exiting
130+ if (analytics.enabled) {
131+ // And now send the exceptions and events to Google Analytics:
132+ if (exception != null ) {
133+ unawaited (
134+ analytics.sendException (
135+ '${exception .runtimeType }\n ${sanitizeStacktrace (stackTrace )}' ,
136+ fatal: true ),
137+ );
138+ }
139+
140+ await analytics.waitForLastPing (
141+ timeout: const Duration (milliseconds: 200 ));
142+ }
143+
144+ // Set the enabled flag in the analytics object to true. Note: this will not
145+ // enable the analytics unless the disclosure was shown (terminal detected),
146+ // and the machine is not detected to be a bot.
147+ if (analytics.firstRun) {
148+ analytics.enabled = true ;
149+ }
150+ analytics.close ();
58151 VmInteropHandler .exit (exitCode);
59152 }
60153}
61154
62155class DartdevRunner extends CommandRunner <int > {
156+ final Analytics analytics;
157+
63158 @override
64159 final ArgParser argParser = ArgParser (
65160 usageLineLength: dartdevUsageLineLength,
@@ -69,7 +164,8 @@ class DartdevRunner extends CommandRunner<int> {
69164 static const String dartdevDescription =
70165 'A command-line utility for Dart development' ;
71166
72- DartdevRunner (List <String > args) : super ('dart' , '$dartdevDescription .' ) {
167+ DartdevRunner (List <String > args, this .analytics)
168+ : super ('dart' , '$dartdevDescription .' ) {
73169 final bool verbose = args.contains ('-v' ) || args.contains ('--verbose' );
74170
75171 argParser.addFlag ('verbose' ,
@@ -84,9 +180,12 @@ class DartdevRunner extends CommandRunner<int> {
84180 argParser.addFlag ('diagnostics' ,
85181 negatable: false , help: 'Show tool diagnostic output.' , hide: ! verbose);
86182
183+ // A hidden flag to disable analytics on this run, this constructor can be
184+ // called with this flag, but should be removed before run() is called as
185+ // the flag has not been added to all sub-commands.
87186 argParser.addFlag (
88- 'analytics' ,
89- negatable: true ,
187+ 'disable-dartdev- analytics' ,
188+ negatable: false ,
90189 help: 'Disable anonymous analytics for this `dart *` run' ,
91190 hide: true ,
92191 );
@@ -113,38 +212,7 @@ class DartdevRunner extends CommandRunner<int> {
113212 @override
114213 Future <int > runCommand (ArgResults topLevelResults) async {
115214 final stopwatch = Stopwatch ()..start ();
116- // The Analytics instance used to report information back to Google Analytics;
117- // see lib/src/analytics.dart.
118- final analytics = createAnalyticsInstance (! topLevelResults['analytics' ]);
119-
120- // If we have not printed the analyticsNoticeOnFirstRunMessage to stdout,
121- // the user is on a terminal, and the machine is not a bot, then print the
122- // disclosure and set analytics.disclosureShownOnTerminal to true.
123- if (analytics is DartdevAnalytics &&
124- ! analytics.disclosureShownOnTerminal &&
125- io.stdout.hasTerminal &&
126- ! isBot ()) {
127- print (analyticsNoticeOnFirstRunMessage);
128- analytics.disclosureShownOnTerminal = true ;
129- }
130-
131- // When `--disable-analytics` or `--enable-analytics` are called we perform
132- // the respective intention and print any notices to standard out and exit.
133- if (topLevelResults['disable-analytics' ]) {
134- // This block also potentially catches the case of (disableAnalytics &&
135- // enableAnalytics), in which we favor the disabling of analytics.
136- analytics.enabled = false ;
137-
138- // Alert the user that analytics has been disabled.
139- print (analyticsDisabledNoticeMessage);
140- return 0 ;
141- } else if (topLevelResults['enable-analytics' ]) {
142- analytics.enabled = true ;
143-
144- // Alert the user again that anonymous data will be collected.
145- print (analyticsNoticeOnFirstRunMessage);
146- return 0 ;
147- }
215+ assert (! topLevelResults.arguments.contains ('--disable-dartdev-analytics' ));
148216
149217 if (topLevelResults.command == null &&
150218 topLevelResults.arguments.isNotEmpty) {
@@ -154,12 +222,14 @@ class DartdevRunner extends CommandRunner<int> {
154222 io.stderr.writeln (
155223 "Error when reading '$firstArg ': No such file or directory." );
156224 // This is the exit code used by the frontend.
157- return 254 ;
225+ VmInteropHandler . exit ( 254 ) ;
158226 }
159227 }
160228
229+ isDiagnostics = topLevelResults['diagnostics' ];
230+
161231 final Ansi ansi = Ansi (Ansi .terminalSupportsAnsi);
162- log = topLevelResults[ 'diagnostics' ]
232+ log = isDiagnostics
163233 ? Logger .verbose (ansi: ansi)
164234 : Logger .standard (ansi: ansi);
165235
@@ -177,15 +247,8 @@ class DartdevRunner extends CommandRunner<int> {
177247 analytics.sendScreenView (path),
178248 );
179249
180- // The exit code for the dartdev process; null indicates that it has not been
181- // set yet. The value is set in the catch and finally blocks below.
182- int exitCode;
183-
184- // Any caught non-UsageExceptions when running the sub command.
185- Object exception;
186- StackTrace stackTrace;
187250 try {
188- exitCode = await super .runCommand (topLevelResults);
251+ final exitCode = await super .runCommand (topLevelResults);
189252
190253 if (path != null && analytics.enabled) {
191254 // Send the event to analytics
@@ -205,16 +268,8 @@ class DartdevRunner extends CommandRunner<int> {
205268 ),
206269 );
207270 }
208- } on UsageException catch (e) {
209- io.stderr.writeln ('$e ' );
210- exitCode = 64 ;
211- } catch (e, st) {
212- // Set the exception and stack trace only for non-UsageException cases:
213- exception = e;
214- stackTrace = st;
215- io.stderr.writeln ('$e ' );
216- io.stderr.writeln ('$st ' );
217- exitCode = 1 ;
271+
272+ return exitCode;
218273 } finally {
219274 stopwatch.stop ();
220275 if (analytics.enabled) {
@@ -226,32 +281,6 @@ class DartdevRunner extends CommandRunner<int> {
226281 ),
227282 );
228283 }
229- // Set the exitCode, if it wasn't set in the catch block above.
230- exitCode ?? = 0 ;
231-
232- // Send analytics before exiting
233- if (analytics.enabled) {
234- // And now send the exceptions and events to Google Analytics:
235- if (exception != null ) {
236- unawaited (
237- analytics.sendException (
238- '${exception .runtimeType }\n ${sanitizeStacktrace (stackTrace )}' ,
239- fatal: true ),
240- );
241- }
242-
243- await analytics.waitForLastPing (
244- timeout: const Duration (milliseconds: 200 ));
245- }
246-
247- // Set the enabled flag in the analytics object to true. Note: this will not
248- // enable the analytics unless the disclosure was shown (terminal detected),
249- // and the machine is not detected to be a bot.
250- if (analytics.firstRun) {
251- analytics.enabled = true ;
252- }
253- analytics.close ();
254- return exitCode;
255284 }
256285 }
257286}
0 commit comments