@@ -32,34 +32,129 @@ import 'src/vm_interop_handler.dart';
32
32
/// analytics logic, it has been moved here.
33
33
Future <void > runDartdev (List <String > args, SendPort port) async {
34
34
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 ;
44
61
}
45
62
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
+ }
47
82
48
- final runner = DartdevRunner (args);
49
- var exitCode = 1 ;
50
83
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
+ }
57
125
} 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 ();
58
151
VmInteropHandler .exit (exitCode);
59
152
}
60
153
}
61
154
62
155
class DartdevRunner extends CommandRunner <int > {
156
+ final Analytics analytics;
157
+
63
158
@override
64
159
final ArgParser argParser = ArgParser (
65
160
usageLineLength: dartdevUsageLineLength,
@@ -69,7 +164,8 @@ class DartdevRunner extends CommandRunner<int> {
69
164
static const String dartdevDescription =
70
165
'A command-line utility for Dart development' ;
71
166
72
- DartdevRunner (List <String > args) : super ('dart' , '$dartdevDescription .' ) {
167
+ DartdevRunner (List <String > args, this .analytics)
168
+ : super ('dart' , '$dartdevDescription .' ) {
73
169
final bool verbose = args.contains ('-v' ) || args.contains ('--verbose' );
74
170
75
171
argParser.addFlag ('verbose' ,
@@ -84,9 +180,12 @@ class DartdevRunner extends CommandRunner<int> {
84
180
argParser.addFlag ('diagnostics' ,
85
181
negatable: false , help: 'Show tool diagnostic output.' , hide: ! verbose);
86
182
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.
87
186
argParser.addFlag (
88
- 'analytics' ,
89
- negatable: true ,
187
+ 'disable-dartdev- analytics' ,
188
+ negatable: false ,
90
189
help: 'Disable anonymous analytics for this `dart *` run' ,
91
190
hide: true ,
92
191
);
@@ -113,38 +212,7 @@ class DartdevRunner extends CommandRunner<int> {
113
212
@override
114
213
Future <int > runCommand (ArgResults topLevelResults) async {
115
214
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' ));
148
216
149
217
if (topLevelResults.command == null &&
150
218
topLevelResults.arguments.isNotEmpty) {
@@ -154,12 +222,14 @@ class DartdevRunner extends CommandRunner<int> {
154
222
io.stderr.writeln (
155
223
"Error when reading '$firstArg ': No such file or directory." );
156
224
// This is the exit code used by the frontend.
157
- return 254 ;
225
+ VmInteropHandler . exit ( 254 ) ;
158
226
}
159
227
}
160
228
229
+ isDiagnostics = topLevelResults['diagnostics' ];
230
+
161
231
final Ansi ansi = Ansi (Ansi .terminalSupportsAnsi);
162
- log = topLevelResults[ 'diagnostics' ]
232
+ log = isDiagnostics
163
233
? Logger .verbose (ansi: ansi)
164
234
: Logger .standard (ansi: ansi);
165
235
@@ -177,15 +247,8 @@ class DartdevRunner extends CommandRunner<int> {
177
247
analytics.sendScreenView (path),
178
248
);
179
249
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;
187
250
try {
188
- exitCode = await super .runCommand (topLevelResults);
251
+ final exitCode = await super .runCommand (topLevelResults);
189
252
190
253
if (path != null && analytics.enabled) {
191
254
// Send the event to analytics
@@ -205,16 +268,8 @@ class DartdevRunner extends CommandRunner<int> {
205
268
),
206
269
);
207
270
}
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;
218
273
} finally {
219
274
stopwatch.stop ();
220
275
if (analytics.enabled) {
@@ -226,32 +281,6 @@ class DartdevRunner extends CommandRunner<int> {
226
281
),
227
282
);
228
283
}
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;
255
284
}
256
285
}
257
286
}
0 commit comments