Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: pkg/analysis_server/test/stress/replay/replay.dart

Issue 2611593002: Rework the replay test to be more correct (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * A stress test for the analysis server. 6 * A stress test for the analysis server.
7 */ 7 */
8 library analysis_server.test.stress.replay.replay;
9
10 import 'dart:async'; 8 import 'dart:async';
11 import 'dart:io'; 9 import 'dart:io';
12 import 'dart:math' as math; 10 import 'dart:math' as math;
13 11
14 import 'package:analysis_server/plugin/protocol/protocol.dart'; 12 import 'package:analysis_server/plugin/protocol/protocol.dart';
15 import 'package:analyzer/dart/ast/token.dart'; 13 import 'package:analyzer/dart/ast/token.dart';
16 import 'package:analyzer/error/listener.dart' as error; 14 import 'package:analyzer/error/listener.dart' as error;
17 import 'package:analyzer/src/dart/scanner/reader.dart'; 15 import 'package:analyzer/src/dart/scanner/reader.dart';
18 import 'package:analyzer/src/dart/scanner/scanner.dart'; 16 import 'package:analyzer/src/dart/scanner/scanner.dart';
19 import 'package:analyzer/src/generated/java_engine.dart'; 17 import 'package:analyzer/src/generated/java_engine.dart';
20 import 'package:analyzer/src/generated/source.dart'; 18 import 'package:analyzer/src/generated/source.dart';
21 import 'package:analyzer/src/util/glob.dart'; 19 import 'package:analyzer/src/util/glob.dart';
22 import 'package:args/args.dart'; 20 import 'package:args/args.dart';
23 import 'package:path/path.dart' as path; 21 import 'package:path/path.dart' as path;
24 22
25 import '../utilities/git.dart'; 23 import '../utilities/git.dart';
24 import '../utilities/logger.dart';
26 import '../utilities/server.dart'; 25 import '../utilities/server.dart';
27 import 'operation.dart'; 26 import 'operation.dart';
28 27
29 /** 28 /**
30 * Run the simulation based on the given command-line [arguments]. 29 * Run the simulation based on the given command-line [arguments].
31 */ 30 */
32 Future main(List<String> arguments) async { 31 Future<Null> main(List<String> arguments) async {
33 Driver driver = new Driver(); 32 Driver driver = new Driver();
34 await driver.run(arguments); 33 await driver.run(arguments);
35 } 34 }
36 35
37 /** 36 /**
38 * The driver class that runs the simulation. 37 * The driver class that runs the simulation.
39 */ 38 */
40 class Driver { 39 class Driver {
41 /** 40 /**
42 * The value of the [OVERLAY_STYLE_OPTION_NAME] indicating that modifications 41 * The value of the [OVERLAY_STYLE_OPTION_NAME] indicating that modifications
(...skipping 24 matching lines...) Expand all
67 * The name of the pubspec file. 66 * The name of the pubspec file.
68 */ 67 */
69 static const String PUBSPEC_FILE_NAME = 'pubspec.yaml'; 68 static const String PUBSPEC_FILE_NAME = 'pubspec.yaml';
70 69
71 /** 70 /**
72 * The name of the branch used to clean-up after making temporary changes. 71 * The name of the branch used to clean-up after making temporary changes.
73 */ 72 */
74 static const String TEMP_BRANCH_NAME = 'temp'; 73 static const String TEMP_BRANCH_NAME = 'temp';
75 74
76 /** 75 /**
76 * The name of the command-line flag that will cause verbose output to be
77 * produced.
78 */
79 static String VERBOSE_FLAG_NAME = 'verbose';
80
81 /**
77 * The style of interaction to use for analysis.updateContent requests. 82 * The style of interaction to use for analysis.updateContent requests.
78 */ 83 */
79 OverlayStyle overlayStyle; 84 OverlayStyle overlayStyle;
80 85
81 /** 86 /**
82 * The absolute path of the repository. 87 * The absolute path of the repository.
83 */ 88 */
84 String repositoryPath; 89 String repositoryPath;
85 90
86 /** 91 /**
87 * The absolute paths to the analysis roots. 92 * The absolute paths to the analysis roots.
88 */ 93 */
89 List<String> analysisRoots; 94 List<String> analysisRoots;
90 95
91 /** 96 /**
92 * The git repository. 97 * The git repository.
93 */ 98 */
94 GitRepository repository; 99 GitRepository repository;
95 100
96 /** 101 /**
97 * The connection to the analysis server. 102 * The connection to the analysis server.
98 */ 103 */
99 Server server = new Server(); 104 Server server;
100 105
101 /** 106 /**
102 * A list of the glob patterns used to identify the files being analyzed by 107 * A list of the glob patterns used to identify the files being analyzed by
103 * the server. 108 * the server.
104 */ 109 */
105 List<Glob> fileGlobs; 110 List<Glob> fileGlobs;
106 111
107 /** 112 /**
108 * An object gathering statistics about the simulation. 113 * An object gathering statistics about the simulation.
109 */ 114 */
110 Statistics statistics; 115 Statistics statistics;
111 116
112 /** 117 /**
118 * A flag indicating whether verbose output should be provided.
119 */
120 bool verbose = false;
121
122 /**
123 * The logger to which verbose logging data will be written.
124 */
125 Logger logger;
126
127 /**
113 * Initialize a newly created driver. 128 * Initialize a newly created driver.
114 */ 129 */
115 Driver() { 130 Driver() {
116 statistics = new Statistics(this); 131 statistics = new Statistics(this);
117 } 132 }
118 133
119 /** 134 /**
135 * Allow the output from the server to be read and processed.
136 */
137 Future<Null> readServerOutput() async {
138 await new Future.delayed(new Duration(milliseconds: 2));
139 }
140
141 /**
120 * Run the simulation based on the given command-line arguments ([args]). 142 * Run the simulation based on the given command-line arguments ([args]).
121 */ 143 */
122 Future run(List<String> args) async { 144 Future<Null> run(List<String> args) async {
123 // 145 //
124 // Process the command-line arguments. 146 // Process the command-line arguments.
125 // 147 //
126 if (!_processCommandLine(args)) { 148 if (!_processCommandLine(args)) {
127 return null; 149 return null;
128 } 150 }
151 if (verbose) {
152 stdout.writeln();
153 stdout.writeln('-' * 80);
154 stdout.writeln();
155 }
129 // 156 //
130 // Simulate interactions with the server. 157 // Simulate interactions with the server.
131 // 158 //
132 await _runSimulation(); 159 await _runSimulation();
133 // 160 //
134 // Print out statistics gathered while performing the simulation. 161 // Print out statistics gathered while performing the simulation.
135 // 162 //
163 if (verbose) {
164 stdout.writeln();
165 stdout.writeln('-' * 80);
166 }
167 stdout.writeln();
136 statistics.print(); 168 statistics.print();
169 if (verbose) {
170 stdout.writeln();
171 server.printStatistics();
172 }
137 exit(0); 173 exit(0);
138 return null; 174 return null;
139 } 175 }
140 176
141 /** 177 /**
142 * Create and return a parser that can be used to parse the command-line 178 * Create and return a parser that can be used to parse the command-line
143 * arguments. 179 * arguments.
144 */ 180 */
145 ArgParser _createArgParser() { 181 ArgParser _createArgParser() {
146 ArgParser parser = new ArgParser(); 182 ArgParser parser = new ArgParser();
147 parser.addFlag(HELP_FLAG_NAME, 183 parser.addFlag(HELP_FLAG_NAME,
148 abbr: 'h', 184 abbr: 'h',
149 help: 'Print usage information', 185 help: 'Print usage information',
150 defaultsTo: false, 186 defaultsTo: false,
151 negatable: false); 187 negatable: false);
152
153 parser.addOption(OVERLAY_STYLE_OPTION_NAME, 188 parser.addOption(OVERLAY_STYLE_OPTION_NAME,
154 help: 189 help:
155 'The style of interaction to use for analysis.updateContent requests ', 190 'The style of interaction to use for analysis.updateContent requests ',
156 allowed: [CHANGE_OVERLAY_STYLE, MULTIPLE_ADD_OVERLAY_STYLE], 191 allowed: [CHANGE_OVERLAY_STYLE, MULTIPLE_ADD_OVERLAY_STYLE],
157 allowedHelp: { 192 allowedHelp: {
158 CHANGE_OVERLAY_STYLE: '<add> <change>* <remove>', 193 CHANGE_OVERLAY_STYLE: '<add> <change>* <remove>',
159 MULTIPLE_ADD_OVERLAY_STYLE: '<add>+ <remove>' 194 MULTIPLE_ADD_OVERLAY_STYLE: '<add>+ <remove>'
160 }, 195 },
161 defaultsTo: 'change'); 196 defaultsTo: 'change');
197 parser.addFlag(VERBOSE_FLAG_NAME,
198 abbr: 'v',
199 help: 'Produce verbose output for debugging',
200 defaultsTo: false,
201 negatable: false);
162 return parser; 202 return parser;
163 } 203 }
164 204
165 /** 205 /**
166 * Add source edits to the given [fileEdit] based on the given [blobDiff]. 206 * Add source edits to the given [fileEdit] based on the given [blobDiff].
167 */ 207 */
168 void _createSourceEdits(FileEdit fileEdit, BlobDiff blobDiff) { 208 void _createSourceEdits(FileEdit fileEdit, BlobDiff blobDiff) {
169 LineInfo info = fileEdit.lineInfo; 209 LineInfo info = fileEdit.lineInfo;
170 for (DiffHunk hunk in blobDiff.hunks) { 210 for (DiffHunk hunk in blobDiff.hunks) {
171 int srcStart = info.getOffsetOfLine(hunk.srcLine); 211 int srcStart = info.getOffsetOfLine(hunk.srcLine);
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 return false; 319 return false;
280 } 320 }
281 321
282 String overlayStyleValue = results[OVERLAY_STYLE_OPTION_NAME]; 322 String overlayStyleValue = results[OVERLAY_STYLE_OPTION_NAME];
283 if (overlayStyleValue == CHANGE_OVERLAY_STYLE) { 323 if (overlayStyleValue == CHANGE_OVERLAY_STYLE) {
284 overlayStyle = OverlayStyle.change; 324 overlayStyle = OverlayStyle.change;
285 } else if (overlayStyleValue == MULTIPLE_ADD_OVERLAY_STYLE) { 325 } else if (overlayStyleValue == MULTIPLE_ADD_OVERLAY_STYLE) {
286 overlayStyle = OverlayStyle.multipleAdd; 326 overlayStyle = OverlayStyle.multipleAdd;
287 } 327 }
288 328
289 List<String> arguments = results.arguments; 329 if (results[VERBOSE_FLAG_NAME]) {
330 verbose = true;
331 logger = new Logger(stdout);
332 }
333
334 List<String> arguments = results.rest;
290 if (arguments.length < 2) { 335 if (arguments.length < 2) {
291 _showUsage(parser); 336 _showUsage(parser);
292 return false; 337 return false;
293 } 338 }
294 repositoryPath = path.normalize(arguments[0]); 339 repositoryPath = path.normalize(arguments[0]);
295 repository = new GitRepository(repositoryPath); 340 repository = new GitRepository(repositoryPath, logger: logger);
296 341
297 analysisRoots = arguments 342 analysisRoots = arguments
298 .sublist(1) 343 .sublist(1)
299 .map((String analysisRoot) => path.normalize(analysisRoot)) 344 .map((String analysisRoot) => path.normalize(analysisRoot))
300 .toList(); 345 .toList();
301 for (String analysisRoot in analysisRoots) { 346 for (String analysisRoot in analysisRoots) {
302 if (repositoryPath != analysisRoot && 347 if (repositoryPath != analysisRoot &&
303 !path.isWithin(repositoryPath, analysisRoot)) { 348 !path.isWithin(repositoryPath, analysisRoot)) {
304 _showUsage(parser, 349 _showUsage(parser,
305 'Analysis roots must be contained within the repository: $analysisRo ot'); 350 'Analysis roots must be contained within the repository: $analysisRo ot');
306 return false; 351 return false;
307 } 352 }
308 } 353 }
309 return true; 354 return true;
310 } 355 }
311 356
312 /** 357 /**
313 * Replay the changes in each commit. 358 * Replay the changes in each commit.
314 */ 359 */
315 Future _replayChanges() async { 360 Future<Null> _replayChanges() async {
316 // 361 //
317 // Get the revision history of the repo. 362 // Get the revision history of the repo.
318 // 363 //
319 LinearCommitHistory history = repository.getCommitHistory(); 364 LinearCommitHistory history = repository.getCommitHistory();
320 statistics.commitCount = history.commitIds.length; 365 statistics.commitCount = history.commitIds.length;
321 LinearCommitHistoryIterator iterator = history.iterator(); 366 LinearCommitHistoryIterator iterator = history.iterator();
322 // 367 try {
323 // Iterate over the history, applying changes.
324 //
325 int dotCount = 0;
326 bool firstCheckout = true;
327 ErrorMap expectedErrors = null;
328 Iterable<String> changedPubspecs;
329 while (iterator.moveNext()) {
330 // 368 //
331 // Checkout the commit on which the changes are based. 369 // Iterate over the history, applying changes.
332 // 370 //
333 String commit = iterator.srcCommit; 371 bool firstCheckout = true;
334 repository.checkout(commit); 372 ErrorMap expectedErrors = null;
335 if (expectedErrors != null) { 373 Iterable<String> changedPubspecs;
336 ErrorMap actualErrors = 374 while (iterator.moveNext()) {
337 await server.computeErrorMap(server.analyzedDartFiles); 375 //
338 String difference = expectedErrors.expectErrorMap(actualErrors); 376 // Checkout the commit on which the changes are based.
339 if (difference != null) { 377 //
340 stdout.write('Mismatched errors after commit '); 378 String commit = iterator.srcCommit;
341 stdout.writeln(commit); 379 repository.checkout(commit);
342 stdout.writeln(); 380 if (expectedErrors != null) {
343 stdout.writeln(difference); 381 // ErrorMap actualErrors =
344 return; 382 await server.computeErrorMap(server.analyzedDartFiles);
383 // String difference = expectedErrors.expectErrorMap(actualErrors);
384 // if (difference != null) {
385 // stdout.write('Mismatched errors after commit ');
386 // stdout.writeln(commit);
387 // stdout.writeln();
388 // stdout.writeln(difference);
389 // return;
390 // }
345 } 391 }
392 if (firstCheckout) {
393 changedPubspecs = _findPubspecsInAnalysisRoots();
394 server.sendAnalysisSetAnalysisRoots(analysisRoots, []);
395 firstCheckout = false;
396 } else {
397 server.removeAllOverlays();
398 }
399 await readServerOutput();
400 expectedErrors = await server.computeErrorMap(server.analyzedDartFiles);
401 for (String filePath in changedPubspecs) {
402 _runPub(filePath);
403 }
404 //
405 // Apply the changes.
406 //
407 CommitDelta commitDelta = iterator.next();
408 commitDelta.filterDiffs(analysisRoots, fileGlobs);
409 if (commitDelta.hasDiffs) {
410 statistics.commitsWithChangeInRootCount++;
411 await _replayDiff(commitDelta);
412 }
413 changedPubspecs = commitDelta.filesMatching(PUBSPEC_FILE_NAME);
346 } 414 }
347 if (firstCheckout) { 415 } finally {
348 changedPubspecs = _findPubspecsInAnalysisRoots(); 416 // Ensure that the repository is left at the most recent commit.
349 server.sendAnalysisSetAnalysisRoots(analysisRoots, []); 417 if (history.commitIds.length > 0) {
350 firstCheckout = false; 418 repository.checkout(history.commitIds[0]);
351 } else {
352 server.removeAllOverlays();
353 }
354 expectedErrors = await server.computeErrorMap(server.analyzedDartFiles);
355 for (String filePath in changedPubspecs) {
356 _runPub(filePath);
357 }
358 //
359 // Apply the changes.
360 //
361 CommitDelta commitDelta = iterator.next();
362 commitDelta.filterDiffs(analysisRoots, fileGlobs);
363 if (commitDelta.hasDiffs) {
364 statistics.commitsWithChangeInRootCount++;
365 _replayDiff(commitDelta);
366 }
367 changedPubspecs = commitDelta.filesMatching(PUBSPEC_FILE_NAME);
368 stdout.write('.');
369 if (dotCount++ > 100) {
370 stdout.writeln();
371 dotCount = 0;
372 } 419 }
373 } 420 }
374 server.removeAllOverlays(); 421 server.removeAllOverlays();
422 await readServerOutput();
375 stdout.writeln(); 423 stdout.writeln();
376 } 424 }
377 425
378 /** 426 /**
379 * Replay the changes between two commits, as represented by the given 427 * Replay the changes between two commits, as represented by the given
380 * [commitDelta]. 428 * [commitDelta].
381 */ 429 */
382 void _replayDiff(CommitDelta commitDelta) { 430 Future<Null> _replayDiff(CommitDelta commitDelta) async {
383 List<FileEdit> editList = <FileEdit>[]; 431 List<FileEdit> editList = <FileEdit>[];
384 for (DiffRecord record in commitDelta.diffRecords) { 432 for (DiffRecord record in commitDelta.diffRecords) {
385 FileEdit edit = new FileEdit(overlayStyle, record); 433 FileEdit edit = new FileEdit(overlayStyle, record);
386 _createSourceEdits(edit, record.getBlobDiff()); 434 _createSourceEdits(edit, record.getBlobDiff());
387 editList.add(edit); 435 editList.add(edit);
388 } 436 }
389 // 437 //
390 // TODO(brianwilkerson) Randomize. 438 // TODO(brianwilkerson) Randomize.
391 // Randomly select operations from different files to simulate a user 439 // Randomly select operations from different files to simulate a user
392 // editing multiple files simultaneously. 440 // editing multiple files simultaneously.
393 // 441 //
394 for (FileEdit edit in editList) { 442 for (FileEdit edit in editList) {
395 List<String> currentFile = <String>[edit.filePath]; 443 List<String> currentFile = <String>[edit.filePath];
396 server.sendAnalysisSetPriorityFiles(currentFile); 444 server.sendAnalysisSetPriorityFiles(currentFile);
397 server.sendAnalysisSetSubscriptions({ 445 server.sendAnalysisSetSubscriptions({
398 AnalysisService.FOLDING: currentFile, 446 AnalysisService.FOLDING: currentFile,
399 AnalysisService.HIGHLIGHTS: currentFile, 447 AnalysisService.HIGHLIGHTS: currentFile,
400 AnalysisService.IMPLEMENTED: currentFile, 448 AnalysisService.IMPLEMENTED: currentFile,
401 AnalysisService.NAVIGATION: currentFile, 449 AnalysisService.NAVIGATION: currentFile,
402 AnalysisService.OCCURRENCES: currentFile, 450 AnalysisService.OCCURRENCES: currentFile,
403 AnalysisService.OUTLINE: currentFile, 451 AnalysisService.OUTLINE: currentFile,
404 AnalysisService.OVERRIDES: currentFile 452 AnalysisService.OVERRIDES: currentFile
405 }); 453 });
406 for (ServerOperation operation in edit.getOperations()) { 454 for (ServerOperation operation in edit.getOperations()) {
455 statistics.editCount++;
407 operation.perform(server); 456 operation.perform(server);
457 await readServerOutput();
408 } 458 }
409 } 459 }
410 } 460 }
411 461
412 /** 462 /**
413 * Run `pub` on the pubspec with the given [filePath]. 463 * Run `pub` on the pubspec with the given [filePath].
414 */ 464 */
415 void _runPub(String filePath) { 465 void _runPub(String filePath) {
416 String directoryPath = path.dirname(filePath); 466 String directoryPath = path.dirname(filePath);
417 if (new Directory(directoryPath).existsSync()) { 467 if (new Directory(directoryPath).existsSync()) {
418 Process.runSync( 468 Process.runSync(
419 '/Users/brianwilkerson/Dev/dart/dart-sdk/bin/pub', ['get'], 469 '/Users/brianwilkerson/Dev/dart/dart-sdk/bin/pub', ['get'],
420 workingDirectory: directoryPath); 470 workingDirectory: directoryPath);
421 } 471 }
422 } 472 }
423 473
424 /** 474 /**
425 * Run the simulation by starting up a server and sending it requests. 475 * Run the simulation by starting up a server and sending it requests.
426 */ 476 */
427 Future _runSimulation() async { 477 Future<Null> _runSimulation() async {
478 server = new Server(logger: logger);
428 Stopwatch stopwatch = new Stopwatch(); 479 Stopwatch stopwatch = new Stopwatch();
429 statistics.stopwatch = stopwatch; 480 statistics.stopwatch = stopwatch;
430 stopwatch.start(); 481 stopwatch.start();
431 await server.start(); 482 await server.start();
432 server.sendServerSetSubscriptions([ServerService.STATUS]); 483 server.sendServerSetSubscriptions([ServerService.STATUS]);
433 server.sendAnalysisSetGeneralSubscriptions( 484 server.sendAnalysisSetGeneralSubscriptions(
434 [GeneralAnalysisService.ANALYZED_FILES]); 485 [GeneralAnalysisService.ANALYZED_FILES]);
435 // TODO(brianwilkerson) Get the list of glob patterns from the server after 486 // TODO(brianwilkerson) Get the list of glob patterns from the server after
436 // an API for getting them has been implemented. 487 // an API for getting them has been implemented.
437 fileGlobs = <Glob>[ 488 fileGlobs = <Glob>[
438 new Glob(path.context.separator, '**.dart'), 489 new Glob(path.context.separator, '**.dart'),
439 new Glob(path.context.separator, '**.html'), 490 new Glob(path.context.separator, '**.html'),
440 new Glob(path.context.separator, '**.htm'), 491 new Glob(path.context.separator, '**.htm'),
441 new Glob(path.context.separator, '**/.analysisOptions') 492 new Glob(path.context.separator, '**/.analysisOptions')
442 ]; 493 ];
443 try { 494 try {
444 await _replayChanges(); 495 await _replayChanges();
445 } finally { 496 } finally {
497 // TODO(brianwilkerson) This needs to be moved into a Zone in order to
498 // ensure that it is always run.
446 server.sendServerShutdown(); 499 server.sendServerShutdown();
447 repository.checkout('master'); 500 repository.checkout('master');
448 } 501 }
449 stopwatch.stop(); 502 stopwatch.stop();
450 } 503 }
451 504
452 /** 505 /**
453 * Display usage information, preceeded by the [errorMessage] if one is given. 506 * Display usage information, preceded by the [errorMessage] if one is given.
454 */ 507 */
455 void _showUsage(ArgParser parser, [String errorMessage = null]) { 508 void _showUsage(ArgParser parser, [String errorMessage = null]) {
456 if (errorMessage != null) { 509 if (errorMessage != null) {
457 stderr.writeln(errorMessage); 510 stderr.writeln(errorMessage);
458 stderr.writeln(); 511 stderr.writeln();
459 } 512 }
460 stderr.writeln(''' 513 stderr.writeln('''
461 Usage: replay [options...] repositoryPath analysisRoot... 514 Usage: replay [options...] repositoryPath analysisRoot...
462 515
463 Uses the commit history of the git repository at the given repository path to 516 Uses the commit history of the git repository at the given repository path to
464 simulate the development of a code base while using the analysis server to 517 simulate the development of a code base while using the analysis server to
465 analyze the code base. 518 analyze the code base.
466 519
467 The repository path must be the absolute path of a directory containing a git 520 The repository path must be the absolute path of a directory containing a git
468 repository. 521 repository.
469 522
470 There must be at least one analysis root, and all of the analysis roots must be 523 There must be at least one analysis root, and all of the analysis roots must be
471 the absolute path of a directory contained within the repository directory. The 524 the absolute path of a directory contained within the repository directory. The
472 analysis roots represent the portion of the repository that will be analyzed by 525 analysis roots represent the portions of the repository that will be analyzed by
473 the analysis server. 526 the analysis server.
474 527
475 OPTIONS:'''); 528 OPTIONS:''');
476 stderr.writeln(parser.usage); 529 stderr.writeln(parser.usage);
477 } 530 }
478 } 531 }
479 532
480 /** 533 /**
481 * A representation of the edits to be applied to a single file. 534 * A representation of the edits to be applied to a single file.
482 */ 535 */
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 */ 650 */
598 int commitCount; 651 int commitCount;
599 652
600 /** 653 /**
601 * The number of commits in the repository that touched one of the files in 654 * The number of commits in the repository that touched one of the files in
602 * one of the analysis roots. 655 * one of the analysis roots.
603 */ 656 */
604 int commitsWithChangeInRootCount = 0; 657 int commitsWithChangeInRootCount = 0;
605 658
606 /** 659 /**
660 * The total number of edits that were applied.
661 */
662 int editCount = 0;
663
664 /**
607 * Initialize a newly created set of statistics. 665 * Initialize a newly created set of statistics.
608 */ 666 */
609 Statistics(this.driver); 667 Statistics(this.driver);
610 668
611 /** 669 /**
612 * Print the statistics to [stdout]. 670 * Print the statistics to [stdout].
613 */ 671 */
614 void print() { 672 void print() {
615 stdout.write('Replay commits in '); 673 stdout.write('Replay commits in ');
616 stdout.writeln(driver.repositoryPath); 674 stdout.writeln(driver.repositoryPath);
617 stdout.write(' replay took '); 675 stdout.write(' replay took ');
618 stdout.writeln(_printTime(stopwatch.elapsedMilliseconds)); 676 stdout.writeln(_printTime(stopwatch.elapsedMilliseconds));
619 stdout.write(' analysis roots = '); 677 stdout.write(' analysis roots = ');
620 stdout.writeln(driver.analysisRoots); 678 stdout.writeln(driver.analysisRoots);
621 stdout.write(' number of commits = '); 679 stdout.write(' number of commits = ');
622 stdout.writeln(commitCount); 680 stdout.writeln(commitCount);
623 stdout.write(' number of commits with a change in an analysis root = '); 681 stdout.write(' number of commits with a change in an analysis root = ');
624 stdout.writeln(commitsWithChangeInRootCount); 682 stdout.writeln(commitsWithChangeInRootCount);
683 stdout.write(' number of edits = ');
684 stdout.writeln(editCount);
625 } 685 }
626 686
627 /** 687 /**
628 * Return a textual representation of the given duration, represented in 688 * Return a textual representation of the given duration, represented in
629 * [milliseconds]. 689 * [milliseconds].
630 */ 690 */
631 String _printTime(int milliseconds) { 691 String _printTime(int milliseconds) {
632 int seconds = milliseconds ~/ 1000; 692 int seconds = milliseconds ~/ 1000;
633 milliseconds -= seconds * 1000; 693 milliseconds -= seconds * 1000;
634 int minutes = seconds ~/ 60; 694 int minutes = seconds ~/ 60;
635 seconds -= minutes * 60; 695 seconds -= minutes * 60;
636 int hours = minutes ~/ 60; 696 int hours = minutes ~/ 60;
637 minutes -= hours * 60; 697 minutes -= hours * 60;
638 698
639 if (hours > 0) { 699 if (hours > 0) {
640 return '$hours:$minutes:$seconds.$milliseconds'; 700 return '$hours:$minutes:$seconds.$milliseconds';
641 } else if (minutes > 0) { 701 } else if (minutes > 0) {
642 return '$minutes:$seconds.$milliseconds'; 702 return '$minutes:$seconds.$milliseconds';
643 } 703 }
644 return '$seconds.$milliseconds'; 704 return '$seconds.$milliseconds';
645 } 705 }
646 } 706 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/plugin/protocol/protocol.dart ('k') | pkg/analysis_server/test/stress/utilities/git.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698