Version 2.12.0-26.0.dev
Merge commit '7322bc027e43390c86cd84d2f8f720361a74f00c' into 'dev'
diff --git a/pkg/analysis_server/test/edit/bulk_fixes_test.dart b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
index 5ad4e47..7f22771 100644
--- a/pkg/analysis_server/test/edit/bulk_fixes_test.dart
+++ b/pkg/analysis_server/test/edit/bulk_fixes_test.dart
@@ -148,6 +148,30 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/44080')
+ Future<void> test_unnecessaryNew_collectionLiteral_overlap() async {
+ addAnalysisOptionsFile('''
+linter:
+ rules:
+ - prefer_collection_literals
+ - unnecessary_new
+''');
+
+ addTestFile('''
+class A {
+ Map<String, Object> _map = {};
+ Set<String> _set = new Set<String>();
+}
+''');
+
+ await assertEditEquals('''
+class A {
+ Map<String, Object> _map = {};
+ Set<String> _set = <String>{};
+}
+''');
+ }
+
Future<void> test_unnecessaryNew_ignoredInOptions() async {
addAnalysisOptionsFile('''
analyzer:
diff --git a/pkg/dartdev/test/utils.dart b/pkg/dartdev/test/utils.dart
index e1a3cd2..4d67099 100644
--- a/pkg/dartdev/test/utils.dart
+++ b/pkg/dartdev/test/utils.dart
@@ -70,9 +70,6 @@
}) {
var arguments = [
command,
- if (command == 'migrate')
- // TODO(srawlins): Enable `pub outdated` in tests.
- '--skip-pub-outdated',
...?args,
];
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 43a71e6..8f0d07d 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
-import 'dart:convert' show jsonDecode;
-import 'dart:math';
import 'dart:io' hide File;
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
@@ -33,7 +31,7 @@
import 'package:nnbd_migration/src/front_end/migration_state.dart';
import 'package:nnbd_migration/src/front_end/non_nullable_fix.dart';
import 'package:nnbd_migration/src/messages.dart';
-import 'package:nnbd_migration/src/utilities/json.dart' as json;
+import 'package:nnbd_migration/src/utilities/progress_bar.dart';
import 'package:nnbd_migration/src/utilities/source_edit_diff_formatter.dart';
import 'package:path/path.dart' show Context;
@@ -100,6 +98,10 @@
static const previewHostnameOption = 'preview-hostname';
static const previewPortOption = 'preview-port';
static const sdkPathOption = 'sdk-path';
+ static const skipImportCheckFlag = 'skip-import-check';
+
+ /// TODO(paulberry): remove this flag once internal sources have been updated.
+ @Deprecated('The migration tool no longer performs "pub outdated" checks')
static const skipPubOutdatedFlag = 'skip-pub-outdated';
static const summaryOption = 'summary';
static const verboseFlag = 'verbose';
@@ -119,105 +121,43 @@
final String sdkPath;
- final bool skipPubOutdated;
+ final bool skipImportCheck;
final String summary;
final bool webPreview;
CommandLineOptions(
- {@required this.applyChanges,
- @required this.directory,
- @required this.ignoreErrors,
- @required this.ignoreExceptions,
- @required this.previewHostname,
- @required this.previewPort,
- @required this.sdkPath,
- @required this.skipPubOutdated,
- @required this.summary,
- @required this.webPreview});
-}
-
-@visibleForTesting
-class DependencyChecker {
- /// The directory which contains the package being migrated.
- final String _directory;
- final Context _pathContext;
- final Logger _logger;
- final ProcessManager _processManager;
-
- DependencyChecker(
- this._directory, this._pathContext, this._logger, this._processManager);
-
- bool check() {
- var pubPath = _pathContext.join(getSdkPath(), 'bin', 'dart');
- var pubArguments = ['pub', 'outdated', '--mode=null-safety', '--json'];
- var preNullSafetyPackages = <String, String>{};
- try {
- var result = _processManager.runSync(pubPath, pubArguments,
- workingDirectory: _directory);
- if ((result.stderr as String).isNotEmpty) {
- throw FormatException(
- '`dart pub outdated --mode=null-safety` exited with exit code '
- '${result.exitCode} and stderr:\n\n${result.stderr}');
- }
- var outdatedOutput = jsonDecode(result.stdout as String);
- var outdatedMap = json.expectType<Map>(outdatedOutput, 'root');
- var packageList =
- json.expectType<List>(outdatedMap['packages'], 'packages');
- for (var package_ in packageList) {
- var package = json.expectType<Map>(package_, '');
- var current_ = json.expectKey(package, 'current');
- if (current_ == null) {
- continue;
- }
- var current = json.expectType<Map>(current_, 'current');
- if (json.expectType<bool>(current['nullSafety'], 'nullSafety')) {
- // For whatever reason, there is no "current" version of this package.
- // TODO(srawlins): We may want to report this to the user. But it may
- // be inconsequential.
- continue;
- }
-
- json.expectKey(package, 'package');
- json.expectKey(current, 'version');
- var name = json.expectType<String>(package['package'], 'package');
- // A version will be given, even if a package was provided with a local
- // or git path.
- var version = json.expectType<String>(current['version'], 'version');
- preNullSafetyPackages[name] = version;
- }
- } on ProcessException catch (e) {
- _logger.stderr(
- 'Warning: Could not execute `$pubPath ${pubArguments.join(' ')}`: '
- '"${e.message}"');
- // Allow the program to continue; users should be allowed to attempt to
- // migrate when `pub outdated` is misbehaving, or if there is a bug above.
- } on FormatException catch (e) {
- _logger.stderr('Warning: ${e.message}');
- // Allow the program to continue; users should be allowed to attempt to
- // migrate when `pub outdated` is misbehaving, or if there is a bug above.
- }
- if (preNullSafetyPackages.isNotEmpty) {
- _logger.stderr('Warning: not all current dependencies have migrated to '
- 'null safety:');
- _logger.stderr('');
- for (var package in preNullSafetyPackages.entries) {
- _logger.stderr(
- ' package:${package.key} (currently at version ${package.value})');
- }
- _logger.stderr('');
- _logger.stderr('For the best migration experience, please update to null '
- 'safe versions of these packages before migrating your code. You can '
- 'use \'dart pub outdated --mode=null-safety\' to check the status of '
- 'dependencies.');
- _logger.stderr('');
- _logger.stderr('Visit https://dart.dev/tools/pub/cmd/pub-outdated for '
- 'more information.');
- return false;
- }
- return true;
- }
+ {@required
+ this.applyChanges,
+ @required
+ this.directory,
+ @required
+ this.ignoreErrors,
+ @required
+ this.ignoreExceptions,
+ @required
+ this.previewHostname,
+ @required
+ this.previewPort,
+ @required
+ this.sdkPath,
+ // TODO(paulberry): make this parameter required once internal sources
+ // have been updated.
+ bool skipImportCheck,
+ // TODO(paulberry): remove this flag once internal sources have been
+ // updated.
+ @Deprecated('The migration tool no longer performs "pub outdated" checks')
+ bool skipPubOutdated = false,
+ @required
+ this.summary,
+ @required
+ this.webPreview})
+ // `skipImportCheck` has replaced `skipPubOutdated`, so if the caller
+ // specifies the latter but not the former, carry it over.
+ // TODO(paulberry): remove this logic once internal sources have been
+ // updated.
+ : skipImportCheck = skipImportCheck ?? skipPubOutdated;
}
// TODO(devoncarew): Refactor so this class extends DartdevCommand.
@@ -312,15 +252,13 @@
'analysis errors.',
)),
MigrationCliOption(
- CommandLineOptions.skipPubOutdatedFlag,
+ CommandLineOptions.skipImportCheckFlag,
(parser, hide) => parser.addFlag(
- CommandLineOptions.skipPubOutdatedFlag,
+ CommandLineOptions.skipImportCheckFlag,
defaultsTo: false,
negatable: false,
- help:
- 'Skip the `pub outdated --mode=null-safety` check. This allows a '
- 'migration to proceed even if some package dependencies have not yet '
- 'been migrated.',
+ help: 'Go ahead with migration even if some imported files have '
+ 'not yet been migrated.',
)),
MigrationCliOption.separator('Web interface options:'),
MigrationCliOption(
@@ -393,11 +331,6 @@
/// user. Used in testing to allow user feedback messages to be tested.
final Logger Function(bool isVerbose) loggerFactory;
- /// Process manager that should be used to run processes. Used in testing to
- /// redirect to mock processes.
- @visibleForTesting
- final ProcessManager processManager;
-
/// Resource provider that should be used to access the filesystem. Used in
/// testing to redirect to an in-memory filesystem.
final ResourceProvider resourceProvider;
@@ -414,7 +347,6 @@
@visibleForTesting this.loggerFactory = _defaultLoggerFactory,
@visibleForTesting this.defaultSdkPathOverride,
@visibleForTesting ResourceProvider resourceProvider,
- @visibleForTesting this.processManager = const ProcessManager.system(),
@visibleForTesting Map<String, String> environmentVariables,
}) : logger = loggerFactory(false),
resourceProvider =
@@ -491,8 +423,8 @@
sdkPath: argResults[CommandLineOptions.sdkPathOption] as String ??
defaultSdkPathOverride ??
getSdkPath(),
- skipPubOutdated:
- argResults[CommandLineOptions.skipPubOutdatedFlag] as bool,
+ skipImportCheck:
+ argResults[CommandLineOptions.skipImportCheckFlag] as bool,
summary: argResults[CommandLineOptions.summaryOption] as String,
webPreview: webPreview);
return MigrationCliRunner(this, options,
@@ -695,7 +627,8 @@
int preferredPort,
String summaryPath,
@required String sdkPath}) {
- return NonNullableFix(listener, resourceProvider, getLineInfo, bindAddress,
+ return NonNullableFix(
+ listener, resourceProvider, getLineInfo, bindAddress, logger,
included: included,
preferredPort: preferredPort,
summaryPath: summaryPath,
@@ -707,10 +640,6 @@
/// If something goes wrong, a message is printed using the logger configured
/// in the constructor, and [MigrationExit] is thrown.
Future<void> run() async {
- if (!options.skipPubOutdated) {
- _checkDependencies();
- }
-
logger.stdout('Migrating ${options.directory}');
logger.stdout('');
@@ -862,15 +791,6 @@
applyHook();
}
- void _checkDependencies() {
- var successful = DependencyChecker(
- options.directory, pathContext, logger, cli.processManager)
- .check();
- if (!successful) {
- throw MigrationExit(1);
- }
- }
-
void _displayChangeDiff(DartFixListener migrationResults) {
Map<String, List<DartFixSuggestion>> fileSuggestions = {};
for (DartFixSuggestion suggestion in migrationResults.suggestions) {
@@ -1064,7 +984,7 @@
Set<String> pathsToProcess;
- _ProgressBar _progressBar;
+ ProgressBar _progressBar;
final MigrationCliRunner _migrationCli;
@@ -1131,7 +1051,7 @@
var analysisErrors = <AnalysisError>[];
// All tasks should be registered; [numPhases] should be finalized.
- _progressBar = _ProgressBar(_migrationCli.logger, pathsToProcess.length);
+ _progressBar = ProgressBar(_migrationCli.logger, pathsToProcess.length);
// Process each source file.
await processResources((ResolvedUnitResult result) async {
@@ -1148,12 +1068,22 @@
}
});
+ var unmigratedDependencies = _task.migration.unmigratedDependencies;
+ if (unmigratedDependencies.isNotEmpty) {
+ if (_migrationCli.options.skipImportCheck) {
+ _migrationCli.logger.stdout(unmigratedDependenciesWarning);
+ } else {
+ throw ExperimentStatusException.unmigratedDependencies(
+ unmigratedDependencies);
+ }
+ }
+
return AnalysisResult(analysisErrors, _migrationCli.lineInfo,
_migrationCli.pathContext, _migrationCli.options.directory);
}
Future<MigrationState> runLaterPhases() async {
- _progressBar = _ProgressBar(
+ _progressBar = ProgressBar(
_migrationCli.logger, pathsToProcess.length * (numPhases - 1));
await processResources((ResolvedUnitResult result) async {
@@ -1166,11 +1096,13 @@
await _task.finalizeUnit(result);
}
});
+ _progressBar.complete();
+ _migrationCli.logger.stdout(_migrationCli.ansi
+ .emphasized('Compiling instrumentation information...'));
var state = await _task.finish();
if (_migrationCli.options.webPreview) {
await _task.startPreviewServer(state, _migrationCli.applyHook);
}
- _progressBar.complete();
state.previewUrls = _task.previewUrls;
return state;
@@ -1204,83 +1136,6 @@
}
}
-/// A facility for drawing a progress bar in the terminal.
-///
-/// The bar is instantiated with the total number of "ticks" to be completed,
-/// and progress is made by calling [tick]. The bar is drawn across one entire
-/// line, like so:
-///
-/// [---------- ]
-///
-/// The hyphens represent completed progress, and the whitespace represents
-/// remaining progress.
-///
-/// If there is no terminal, the progress bar will not be drawn.
-class _ProgressBar {
- /// Whether the progress bar should be drawn.
- /*late*/ bool _shouldDrawProgress;
-
- /// The width of the terminal, in terms of characters.
- /*late*/
- int _width;
-
- final Logger _logger;
-
- /// The inner width of the terminal, in terms of characters.
- ///
- /// This represents the number of characters available for drawing progress.
- /*late*/
- int _innerWidth;
-
- final int _totalTickCount;
-
- int _tickCount = 0;
-
- _ProgressBar(this._logger, this._totalTickCount) {
- if (!stdout.hasTerminal) {
- _shouldDrawProgress = false;
- } else {
- _shouldDrawProgress = true;
- _width = stdout.terminalColumns;
- _innerWidth = stdout.terminalColumns - 2;
- _logger.write('[' + ' ' * _innerWidth + ']');
- }
- }
-
- /// Clear the progress bar from the terminal, allowing other logging to be
- /// printed.
- void clear() {
- if (!_shouldDrawProgress) {
- return;
- }
- _logger.write('\r' + ' ' * _width + '\r');
- }
-
- /// Draw the progress bar as complete, and print two newlines.
- void complete() {
- if (!_shouldDrawProgress) {
- return;
- }
- _logger.write('\r[' + '-' * _innerWidth + ']\n\n');
- }
-
- /// Progress the bar by one tick.
- void tick() {
- if (!_shouldDrawProgress) {
- return;
- }
- _tickCount++;
- var fractionComplete =
- max(0, _tickCount * _innerWidth ~/ _totalTickCount - 1);
- var remaining = _innerWidth - fractionComplete - 1;
- _logger.write('\r[' + // Bring cursor back to the start of the line.
- '-' * fractionComplete + // Print complete work.
- AnsiProgress.kAnimationItems[_tickCount % 4] + // Print spinner.
- ' ' * remaining + // Print remaining work.
- ']');
- }
-}
-
extension on Severity {
/// Returns the simple name of the Severity, as a String.
String get name {
diff --git a/pkg/nnbd_migration/lib/nnbd_migration.dart b/pkg/nnbd_migration/lib/nnbd_migration.dart
index 087685d..36027a0 100644
--- a/pkg/nnbd_migration/lib/nnbd_migration.dart
+++ b/pkg/nnbd_migration/lib/nnbd_migration.dart
@@ -334,6 +334,11 @@
void finish();
+ /// Use this getter after any calls to [prepareInput] to obtain a list of URIs
+ /// of unmigrated dependencies. Ideally, this list should be empty before the
+ /// user tries to migrate their package.
+ List<String> get unmigratedDependencies;
+
void prepareInput(ResolvedUnitResult result);
void processInput(ResolvedUnitResult result);
diff --git a/pkg/nnbd_migration/lib/src/exceptions.dart b/pkg/nnbd_migration/lib/src/exceptions.dart
index 15e26ed..580fcda 100644
--- a/pkg/nnbd_migration/lib/src/exceptions.dart
+++ b/pkg/nnbd_migration/lib/src/exceptions.dart
@@ -13,6 +13,10 @@
/// The SDK does not contain the NNBD sources, it is the pre-unfork copy.
ExperimentStatusException.sdkPreforkSources() : super(sdkNnbdOff);
+ /// The user's code imports unmigrated dependencies.
+ ExperimentStatusException.unmigratedDependencies(List<String> uris)
+ : super(unmigratedDependenciesError(uris));
+
/// Throw an [ExperimentStatusException] if the [result] seems to have
/// incorrectly configured experiment flags/nnbd sources.
static void sanityCheck(ResolvedUnitResult result) {
diff --git a/pkg/nnbd_migration/lib/src/front_end/info_builder.dart b/pkg/nnbd_migration/lib/src/front_end/info_builder.dart
index b1d3f84..b5b8e56 100644
--- a/pkg/nnbd_migration/lib/src/front_end/info_builder.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/info_builder.dart
@@ -12,6 +12,7 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
+import 'package:cli_util/cli_logging.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/fix_reason_target.dart';
import 'package:nnbd_migration/instrumentation.dart';
@@ -22,12 +23,16 @@
import 'package:nnbd_migration/src/front_end/instrumentation_information.dart';
import 'package:nnbd_migration/src/front_end/migration_info.dart';
import 'package:nnbd_migration/src/front_end/offset_mapper.dart';
+import 'package:nnbd_migration/src/utilities/progress_bar.dart';
/// A builder used to build the migration information for a library.
class InfoBuilder {
/// The node mapper for the migration state.
NodeMapper nodeMapper;
+ /// The logger to use for showing progress when explaining the migration.
+ final Logger _logger;
+
/// The resource provider used to access the file system.
ResourceProvider provider;
@@ -49,7 +54,7 @@
/// Initialize a newly created builder.
InfoBuilder(this.provider, this.includedPath, this.info, this.listener,
- this.migration, this.nodeMapper);
+ this.migration, this.nodeMapper, this._logger);
/// The provider used to get information about libraries.
DriverProviderImpl get driverProvider => listener.server;
@@ -60,7 +65,10 @@
var sourceInfoMap = info.sourceInformation;
Set<UnitInfo> units =
SplayTreeSet<UnitInfo>((u1, u2) => u1.path.compareTo(u2.path));
+ var progressBar = ProgressBar(_logger, sourceInfoMap.length);
+
for (var source in sourceInfoMap.keys) {
+ progressBar.tick();
var filePath = source.fullName;
var session = driverProvider.getAnalysisSession(filePath);
if (!session.getFile(filePath).isPart) {
@@ -86,6 +94,7 @@
}
}
}
+ progressBar.complete();
return units;
}
diff --git a/pkg/nnbd_migration/lib/src/front_end/migration_state.dart b/pkg/nnbd_migration/lib/src/front_end/migration_state.dart
index 8593172..bfbf7cd 100644
--- a/pkg/nnbd_migration/lib/src/front_end/migration_state.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/migration_state.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:cli_util/cli_logging.dart';
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/migration_cli.dart';
import 'package:nnbd_migration/nnbd_migration.dart';
@@ -41,16 +42,18 @@
final AnalysisResult analysisResult;
+ /*late*/ List<String> previewUrls;
+
/// Initialize a newly created migration state with the given values.
MigrationState(this.migration, this.includedRoot, this.listener,
this.instrumentationListener,
[this.analysisResult]);
- bool get hasErrors => analysisResult?.hasErrors ?? false;
-
/// If the migration has been applied to disk.
bool get hasBeenApplied => _hasBeenApplied;
+ bool get hasErrors => analysisResult?.hasErrors ?? false;
+
/// Mark that the migration has been applied to disk.
void markApplied() {
assert(!hasBeenApplied);
@@ -58,17 +61,15 @@
}
/// Refresh the state of the migration after the migration has been updated.
- Future<void> refresh() async {
+ Future<void> refresh(Logger logger) async {
assert(!hasBeenApplied);
var provider = listener.server.resourceProvider;
var infoBuilder = InfoBuilder(provider, includedRoot,
- instrumentationListener.data, listener, migration, nodeMapper);
+ instrumentationListener.data, listener, migration, nodeMapper, logger);
var unitInfos = await infoBuilder.explainMigration();
var pathContext = provider.pathContext;
migrationInfo = MigrationInfo(
unitInfos, infoBuilder.unitMap, pathContext, includedRoot);
pathMapper = PathMapper(provider);
}
-
- /*late*/ List<String> previewUrls;
}
diff --git a/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart b/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
index 6148a95..8a5d668 100644
--- a/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/non_nullable_fix.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:cli_util/cli_logging.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/nnbd_migration.dart';
import 'package:nnbd_migration/src/front_end/charcodes.dart';
@@ -36,6 +37,8 @@
/// [InternetAddress].
final Object bindAddress;
+ final Logger _logger;
+
final int preferredPort;
final DartFixListener listener;
@@ -76,8 +79,8 @@
/// A list of the URLs corresponding to the included roots.
List<String> previewUrls;
- NonNullableFix(
- this.listener, this.resourceProvider, this._getLineInfo, this.bindAddress,
+ NonNullableFix(this.listener, this.resourceProvider, this._getLineInfo,
+ this.bindAddress, this._logger,
{List<String> included = const [],
this.preferredPort,
this.summaryPath,
@@ -113,7 +116,7 @@
migration.finish();
final state = MigrationState(
migration, includedRoot, listener, instrumentationListener);
- await state.refresh();
+ await state.refresh(_logger);
return state;
}
@@ -167,7 +170,7 @@
Future<MigrationState> rerun() async {
reset();
var state = await rerunFunction();
- await state.refresh();
+ await state.refresh(_logger);
return state;
}
diff --git a/pkg/nnbd_migration/lib/src/messages.dart b/pkg/nnbd_migration/lib/src/messages.dart
index 41497f2..1305da4 100644
--- a/pkg/nnbd_migration/lib/src/messages.dart
+++ b/pkg/nnbd_migration/lib/src/messages.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:nnbd_migration/migration_cli.dart';
+
const String migratedAlready =
"Seem to be migrating code that's already migrated";
const String nnbdExperimentOff =
@@ -10,3 +12,29 @@
const String sdkPathEnvironmentVariableSet =
r'Note: $SDK_PATH environment variable is set and may point to outdated '
'dart:core sources';
+const String _skipImportCheckFlag =
+ '--${CommandLineOptions.skipImportCheckFlag}';
+const String unmigratedDependenciesWarning = '''
+Warning: package has unmigrated dependencies.
+
+Continuing due to the presence of `$_skipImportCheckFlag`. To see a complete
+ list of these libraries, re-run without the `$_skipImportCheckFlag` flag.
+''';
+
+String unmigratedDependenciesError(List<String> uris) => '''
+Error: package has unmigrated dependencies.
+
+Before migrating your package, we recommend ensuring that every library it
+imports (either directly or indirectly) has been migrated to null safety, so
+that you will be able to run your unit tests in sound null checking mode. You
+are currently importing the following non-null-safe libraries:
+
+ ${uris.join('\n ')}
+
+Please upgrade the packages containing these libraries to null safe versions
+before continuing. To see what null safe package versions are available, run
+the following command: `dart pub outdated --mode=null-safety --prereleases`.
+
+To skip this check and try to migrate anyway, re-run with the flag
+`$_skipImportCheckFlag`.
+''';
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index 3878f61..f80f4c4 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -4,6 +4,7 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
@@ -63,6 +64,13 @@
/// parameter into their "OrNull" equivalents if possible.
final bool transformWhereOrNull;
+ /// Map from [Source] object to a boolean indicating whether the source is
+ /// opted in to null safety.
+ final Map<Source, bool> _libraryOptInStatus = {};
+
+ /// Indicates whether the client has used the [unmigratedDependencies] getter.
+ bool _queriedUnmigratedDependencies = false;
+
/// Prepares to perform nullability migration.
///
/// If [permissive] is `true`, exception handling logic will try to proceed
@@ -115,6 +123,23 @@
bool get isPermissive => _permissive;
@override
+ List<String> get unmigratedDependencies {
+ _queriedUnmigratedDependencies = true;
+ var unmigratedDependencies = <Source>[];
+ for (var entry in _libraryOptInStatus.entries) {
+ if (_graph.isBeingMigrated(entry.key)) continue;
+ if (!entry.value) {
+ unmigratedDependencies.add(entry.key);
+ }
+ }
+ var badUris = {
+ for (var dependency in unmigratedDependencies) dependency.uri.toString()
+ }.toList();
+ badUris.sort();
+ return badUris;
+ }
+
+ @override
void finalizeInput(ResolvedUnitResult result) {
if (result.unit.featureSet.isEnabled(Feature.non_nullable)) {
// This library has already been migrated; nothing more to do.
@@ -183,11 +208,16 @@
}
void prepareInput(ResolvedUnitResult result) {
+ assert(
+ !_queriedUnmigratedDependencies,
+ 'Should only query unmigratedDependencies after all calls to '
+ 'prepareInput');
if (result.unit.featureSet.isEnabled(Feature.non_nullable)) {
// This library has already been migrated; nothing more to do.
return;
}
ExperimentStatusException.sanityCheck(result);
+ _recordTransitiveImportOptInStatus(result.libraryElement.importedLibraries);
if (_variables == null) {
_variables = Variables(_graph, result.typeProvider, _getLineInfo,
instrumentation: _instrumentation,
@@ -239,6 +269,18 @@
_graph.update(_postmortemFileWriter);
}
+ /// Records the opt in/out status of all libraries in [libraries], and any
+ /// libraries they transitively import, in [_libraryOptInStatus].
+ void _recordTransitiveImportOptInStatus(Iterable<LibraryElement> libraries) {
+ var librariesToCheck = libraries.toList();
+ while (librariesToCheck.isNotEmpty) {
+ var library = librariesToCheck.removeLast();
+ if (_libraryOptInStatus.containsKey(library.source)) continue;
+ _libraryOptInStatus[library.source] = library.isNonNullableByDefault;
+ librariesToCheck.addAll(library.importedLibraries);
+ }
+ }
+
static Location _computeLocation(
LineInfo lineInfo, SourceEdit edit, Source source) {
final locationInfo = lineInfo.getLocation(edit.offset);
diff --git a/pkg/nnbd_migration/lib/src/utilities/progress_bar.dart b/pkg/nnbd_migration/lib/src/utilities/progress_bar.dart
new file mode 100644
index 0000000..e1b7931
--- /dev/null
+++ b/pkg/nnbd_migration/lib/src/utilities/progress_bar.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io' hide File;
+import 'dart:math';
+
+import 'package:cli_util/cli_logging.dart';
+
+/// A facility for drawing a progress bar in the terminal.
+///
+/// The bar is instantiated with the total number of "ticks" to be completed,
+/// and progress is made by calling [tick]. The bar is drawn across one entire
+/// line, like so:
+///
+/// [---------- ]
+///
+/// The hyphens represent completed progress, and the whitespace represents
+/// remaining progress.
+///
+/// If there is no terminal, the progress bar will not be drawn.
+class ProgressBar {
+ /// Whether the progress bar should be drawn.
+ /*late*/ bool _shouldDrawProgress;
+
+ /// The width of the terminal, in terms of characters.
+ /*late*/ int _width;
+
+ final Logger _logger;
+
+ /// The inner width of the terminal, in terms of characters.
+ ///
+ /// This represents the number of characters available for drawing progress.
+ /*late*/ int _innerWidth;
+
+ final int _totalTickCount;
+
+ int _tickCount = 0;
+
+ ProgressBar(this._logger, this._totalTickCount) {
+ if (!stdout.hasTerminal) {
+ _shouldDrawProgress = false;
+ } else {
+ _shouldDrawProgress = true;
+ _width = stdout.terminalColumns;
+ _innerWidth = stdout.terminalColumns - 2;
+ _logger.write('[' + ' ' * _innerWidth + ']');
+ }
+ }
+
+ /// Clear the progress bar from the terminal, allowing other logging to be
+ /// printed.
+ void clear() {
+ if (!_shouldDrawProgress) {
+ return;
+ }
+ _logger.write('\r' + ' ' * _width + '\r');
+ }
+
+ /// Draw the progress bar as complete, and print two newlines.
+ void complete() {
+ if (!_shouldDrawProgress) {
+ return;
+ }
+ _logger.write('\r[' + '-' * _innerWidth + ']\n\n');
+ }
+
+ /// Progress the bar by one tick.
+ void tick() {
+ if (!_shouldDrawProgress) {
+ return;
+ }
+ _tickCount++;
+ var fractionComplete =
+ max(0, _tickCount * _innerWidth ~/ _totalTickCount - 1);
+ var remaining = _innerWidth - fractionComplete - 1;
+ _logger.write('\r[' + // Bring cursor back to the start of the line.
+ '-' * fractionComplete + // Print complete work.
+ AnsiProgress.kAnimationItems[_tickCount % 4] + // Print spinner.
+ ' ' * remaining + // Print remaining work.
+ ']');
+ }
+}
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index bfd7469..1e86235 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -69,6 +69,7 @@
}
}
}
+ expect(migration.unmigratedDependencies, isEmpty);
_betweenStages();
for (var path in input.keys) {
if (!(session.getFile(path)).isPart) {
diff --git a/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart b/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
index 70cf296..6f87f89 100644
--- a/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
+++ b/pkg/nnbd_migration/test/front_end/nnbd_migration_test_base.dart
@@ -18,6 +18,7 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'analysis_abstract.dart';
+import '../utilities/test_logger.dart';
@reflectiveTest
class NnbdMigrationTestBase extends AbstractAnalysisTest {
@@ -218,13 +219,15 @@
}
await _forEachPath(migration.prepareInput);
+ expect(migration.unmigratedDependencies, isEmpty);
await _forEachPath(migration.processInput);
await _forEachPath(migration.finalizeInput);
migration.finish();
// Build the migration info.
var info = instrumentationListener.data;
- var builder = InfoBuilder(
- resourceProvider, includedRoot, info, listener, migration, nodeMapper);
+ var logger = TestLogger(false);
+ var builder = InfoBuilder(resourceProvider, includedRoot, info, listener,
+ migration, nodeMapper, logger);
infos = await builder.explainMigration();
}
diff --git a/pkg/nnbd_migration/test/instrumentation_test.dart b/pkg/nnbd_migration/test/instrumentation_test.dart
index d06a022..6e8cd37 100644
--- a/pkg/nnbd_migration/test/instrumentation_test.dart
+++ b/pkg/nnbd_migration/test/instrumentation_test.dart
@@ -151,6 +151,7 @@
source = result.unit.declaredElement.source;
findNode = FindNode(content, result.unit);
migration.prepareInput(result);
+ expect(migration.unmigratedDependencies, isEmpty);
migration.processInput(result);
migration.finalizeInput(result);
migration.finish();
diff --git a/pkg/nnbd_migration/test/migration_cli_test.dart b/pkg/nnbd_migration/test/migration_cli_test.dart
index 72acffb..c581b6b 100644
--- a/pkg/nnbd_migration/test/migration_cli_test.dart
+++ b/pkg/nnbd_migration/test/migration_cli_test.dart
@@ -33,6 +33,8 @@
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'utilities/test_logger.dart';
+
main() {
defineReflectiveSuite(() {
defineReflectiveTests(_MigrationCliTestPosix);
@@ -65,11 +67,12 @@
ResourceProvider resourceProvider,
LineInfo Function(String) getLineInfo,
Object bindAddress,
+ Logger logger,
{List<String> included = const <String>[],
int preferredPort,
String summaryPath,
@required String sdkPath})
- : super(listener, resourceProvider, getLineInfo, bindAddress,
+ : super(listener, resourceProvider, getLineInfo, bindAddress, logger,
included: included,
preferredPort: preferredPort,
summaryPath: summaryPath,
@@ -92,11 +95,10 @@
_MigrationCli(this._test)
: super(
binaryName: 'nnbd_migration',
- loggerFactory: (isVerbose) => _test.logger = _TestLogger(isVerbose),
+ loggerFactory: (isVerbose) => _test.logger = TestLogger(isVerbose),
defaultSdkPathOverride:
_test.resourceProvider.convertPath(mock_sdk.sdkRoot),
resourceProvider: _test.resourceProvider,
- processManager: _test.processManager,
environmentVariables: _test.environmentVariables);
_MigrationCliRunner decodeCommandLineArgs(ArgResults argResults,
@@ -156,7 +158,7 @@
@required String sdkPath}) {
if (cli._test.injectArtificialException) {
return _ExceptionGeneratingNonNullableFix(
- listener, resourceProvider, getLineInfo, bindAddress,
+ listener, resourceProvider, getLineInfo, bindAddress, logger,
included: included,
preferredPort: preferredPort,
summaryPath: summaryPath,
@@ -198,16 +200,14 @@
bool Function(String) overrideShouldBeMigrated;
- set logger(_TestLogger logger);
-
- _MockProcessManager get processManager;
+ set logger(TestLogger logger);
MemoryResourceProvider get resourceProvider;
}
mixin _MigrationCliTestMethods on _MigrationCliTestBase {
@override
- /*late*/ _TestLogger logger;
+ /*late*/ TestLogger logger;
final hasVerboseHelpMessage = contains('for verbose help output');
@@ -302,36 +302,6 @@
}
}
- void assertPubOutdatedFailure(
- {int pubOutdatedExitCode = 0,
- String pubOutdatedStdout = '',
- String pubOutdatedStderr = ''}) {
- processManager._mockResult = ProcessResult(123 /* pid */,
- pubOutdatedExitCode, pubOutdatedStdout, pubOutdatedStderr);
- logger = _TestLogger(true);
- var projectContents = simpleProject(sourceText: 'int x;');
- var projectDir = createProjectDir(projectContents);
- var success = DependencyChecker(
- projectDir, resourceProvider.pathContext, logger, processManager)
- .check();
- expect(success, isFalse);
- }
-
- void assertPubOutdatedSuccess(
- {int pubOutdatedExitCode = 0,
- String pubOutdatedStdout = '',
- String pubOutdatedStderr = ''}) {
- processManager._mockResult = ProcessResult(123 /* pid */,
- pubOutdatedExitCode, pubOutdatedStdout, pubOutdatedStderr);
- logger = _TestLogger(true);
- var projectContents = simpleProject(sourceText: 'int x;');
- var projectDir = createProjectDir(projectContents);
- var success = DependencyChecker(
- projectDir, resourceProvider.pathContext, logger, processManager)
- .check();
- expect(success, isTrue);
- }
-
Future<String> assertRunFailure(List<String> args,
{MigrationCli cli,
bool withUsage = false,
@@ -404,6 +374,9 @@
http.post(url, headers: headers, body: body, encoding: encoding));
}
+ String packagePath(String path) =>
+ resourceProvider.convertPath('/.pub-cache/$path');
+
Future<void> runWithPreviewServer(_MigrationCli cli, List<String> args,
Future<void> Function(String) callback) async {
String url;
@@ -572,17 +545,17 @@
expect(_getHelpText(verbose: true), contains(flagName));
}
- test_flag_skip_pub_outdated_default() {
- expect(assertParseArgsSuccess([]).skipPubOutdated, isFalse);
+ test_flag_skip_import_check_default() {
+ expect(assertParseArgsSuccess([]).skipImportCheck, isFalse);
}
- test_flag_skip_pub_outdated_disable() async {
- // "--no-skip-pub-outdated" is not an option.
- await assertParseArgsFailure(['--no-skip-pub-outdated']);
+ test_flag_skip_import_check_disable() async {
+ // "--no-skip-import-check" is not an option.
+ await assertParseArgsFailure(['--no-skip-import_check']);
}
- test_flag_skip_pub_outdated_enable() {
- expect(assertParseArgsSuccess(['--skip-pub-outdated']).skipPubOutdated,
+ test_flag_skip_import_check_enable() {
+ expect(assertParseArgsSuccess(['--skip-import-check']).skipImportCheck,
isTrue);
}
@@ -840,8 +813,12 @@
.join(projectDir, 'lib', 'analyze_but_do_not_migrate.dart');
overridePathsToProcess = {testPath, analyzeButDoNotMigratePath};
overrideShouldBeMigrated = (path) => path == testPath;
- var cliRunner = _createCli().decodeCommandLineArgs(
- _parseArgs(['--no-web-preview', '--apply-changes', projectDir]));
+ var cliRunner = _createCli().decodeCommandLineArgs(_parseArgs([
+ '--no-web-preview',
+ '--apply-changes',
+ '--skip-import-check',
+ projectDir
+ ]));
await cliRunner.run();
assertNormalExit(cliRunner);
// Check that a summary was printed
@@ -1309,47 +1286,54 @@
});
}
- test_lifecycle_skip_pub_outdated_disable() async {
- var projectContents = simpleProject(sourceText: '''
+ test_lifecycle_skip_import_check_disable() async {
+ var projectContents = simpleProject(
+ sourceText: '''
+import 'package:foo/foo.dart';
+import 'package:foo/bar.dart';
+
int f() => null;
-''');
+''',
+ packageConfigText: _getPackageConfigText(
+ migrated: false, packagesMigrated: {'foo': false}));
var projectDir = createProjectDir(projectContents);
- processManager._mockResult = ProcessResult(
- 123 /* pid */,
- 0 /* exitCode */,
- '''
-{ "packages":
- [
- { "package": "abc", "current": { "version": "1.0.0", "nullSafety": false } }
- ]
-}
-''' /* stdout */,
- '' /* stderr */);
- var output = await assertRunFailure([projectDir], expectedExitCode: 1);
- expect(output,
- contains('Warning: not all current dependencies have migrated'));
+ resourceProvider.newFile(packagePath('foo/lib/foo.dart'), '');
+ resourceProvider.newFile(packagePath('foo/lib/bar.dart'), '');
+ await assertRunFailure([projectDir], expectedExitCode: 1);
+ var output = logger.stdoutBuffer.toString();
+ expect(output, contains('Error: package has unmigrated dependencies'));
+ // Output should contain an indented, sorted list of all unmigrated
+ // dependencies.
+ expect(
+ output, contains('\n package:foo/bar.dart\n package:foo/foo.dart'));
+ // Output should mention that the user can rerun with `--skip-import-check`.
+ expect(output, contains('`--${CommandLineOptions.skipImportCheckFlag}`'));
}
- test_lifecycle_skip_pub_outdated_enable() async {
- var projectContents = simpleProject(sourceText: '''
+ test_lifecycle_skip_import_check_enable() async {
+ var projectContents = simpleProject(
+ sourceText: '''
+import 'package:foo/foo.dart';
+import 'package:foo/bar.dart';
+
int f() => null;
-''');
+''',
+ packageConfigText: _getPackageConfigText(
+ migrated: false, packagesMigrated: {'foo': false}));
var projectDir = createProjectDir(projectContents);
- processManager._mockResult = ProcessResult(
- 123 /* pid */,
- 0 /* exitCode */,
- '''
-{ "packages":
- [
- { "package": "abc", "current": { "version": "1.0.0", "nullSafety": false } }
- ]
-}
-''' /* stdout */,
- '' /* stderr */);
+ resourceProvider.newFile(packagePath('foo/lib/foo.dart'), '');
+ resourceProvider.newFile(packagePath('foo/lib/bar.dart'), '');
var cli = _createCli();
- await runWithPreviewServer(cli, ['--skip-pub-outdated', projectDir],
+ await runWithPreviewServer(cli, ['--skip-import-check', projectDir],
(url) async {
await assertPreviewServerResponsive(url);
+ var output = logger.stdoutBuffer.toString();
+ expect(output, contains('Warning: package has unmigrated dependencies'));
+ // Output should not mention the particular unmigrated dependencies.
+ expect(output, isNot(contains('package:foo')));
+ // Output should mention that the user can rerun without
+ // `--skip-import-check`.
+ expect(output, contains('`--${CommandLineOptions.skipImportCheckFlag}`'));
});
}
@@ -1639,134 +1623,6 @@
}
}
- test_pub_outdated_has_malformed_json() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '{ "packages": }');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
- test_pub_outdated_has_no_packages() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '{}');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
- test_pub_outdated_has_no_pre_null_safety_packages() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "package": "abc",
- "current": { "version": "1.0.0", "nullSafety": true }
- },
- {
- "package": "def",
- "current": { "version": "2.0.0", "nullSafety": true }
- }
- ]
-}
-''');
- }
-
- test_pub_outdated_has_one_pre_null_safety_package() {
- assertPubOutdatedFailure(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "package": "abc",
- "current": { "version": "1.0.0", "nullSafety": false }
- },
- {
- "package": "def",
- "current": { "version": "2.0.0", "nullSafety": true }
- }
- ]
-}
-''');
- var stderrText = logger.stderrBuffer.toString();
- expect(stderrText, contains('Warning:'));
- expect(stderrText, contains('abc'));
- expect(stderrText, contains('1.0.0'));
- }
-
- test_pub_outdated_has_package_with_missing_current() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "package": "abc"
- }
- ]
-}
-''');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
- test_pub_outdated_has_package_with_missing_name() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "current": {
- "version": "1.0.0",
- "nullSafety": false
- }
- }
- ]
-}
-''');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
- test_pub_outdated_has_package_with_missing_nullSafety() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "package": "abc",
- "current": {
- "version": "1.0.0"
- }
- }
- ]
-}
-''');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
- test_pub_outdated_has_package_with_missing_version() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "package": "abc",
- "current": {
- "nullSafety": false
- }
- }
- ]
-}
-''');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
- test_pub_outdated_has_package_with_null_current() {
- assertPubOutdatedSuccess(pubOutdatedStdout: '''
-{
- "packages": [
- {
- "package": "abc",
- "current": null
- }
- ]
-}
-''');
- expect(logger.stderrBuffer.toString(), isEmpty);
- }
-
- test_pub_outdated_has_stderr() {
- assertPubOutdatedSuccess(pubOutdatedStderr: 'anything');
- expect(logger.stderrBuffer.toString(), startsWith('Warning:'));
- }
-
test_pubspec_does_not_exist() async {
var projectContents = simpleProject()..remove('pubspec.yaml');
var projectDir = createProjectDir(projectContents);
@@ -1979,23 +1835,34 @@
return helpText;
}
+ String _getPackageConfigText(
+ {@required bool migrated,
+ Map<String, bool> packagesMigrated = const {}}) {
+ Object makePackageEntry(String name, bool migrated, {String rootUri}) {
+ rootUri ??=
+ resourceProvider.pathContext.toUri(packagePath(name)).toString();
+ return {
+ 'name': name,
+ 'rootUri': rootUri,
+ 'packageUri': 'lib/',
+ 'languageVersion': migrated ? '2.12' : '2.6'
+ };
+ }
+
+ var json = {
+ 'configVersion': 2,
+ 'packages': [
+ makePackageEntry('test', migrated, rootUri: '../'),
+ for (var entry in packagesMigrated.entries)
+ makePackageEntry(entry.key, entry.value)
+ ]
+ };
+ return JsonEncoder.withIndent(' ').convert(json) + '\n';
+ }
+
ArgResults _parseArgs(List<String> args) {
return MigrationCli.createParser().parse(args);
}
-
- static String _getPackageConfigText({@required bool migrated}) => '''
-{
- "configVersion": 2,
- "packages": [
- {
- "name": "test",
- "rootUri": "../",
- "packageUri": "lib/",
- "languageVersion": "${migrated ? '2.12' : '2.6'}"
- }
- ]
-}
-''';
}
@reflectiveTest
@@ -2004,16 +1871,12 @@
@override
final resourceProvider;
- @override
- final processManager;
-
_MigrationCliTestPosix()
: resourceProvider = MemoryResourceProvider(
context: path.style == path.Style.posix
? null
: path.Context(
- style: path.Style.posix, current: '/working_dir')),
- processManager = _MockProcessManager();
+ style: path.Style.posix, current: '/working_dir'));
}
@reflectiveTest
@@ -2022,79 +1885,10 @@
@override
final resourceProvider;
- @override
- final processManager;
-
_MigrationCliTestWindows()
: resourceProvider = MemoryResourceProvider(
context: path.style == path.Style.windows
? null
: path.Context(
- style: path.Style.windows, current: 'C:\\working_dir')),
- processManager = _MockProcessManager();
-}
-
-class _MockProcessManager implements ProcessManager {
- ProcessResult _mockResult;
-
- dynamic noSuchMethod(Invocation invocation) {}
-
- ProcessResult runSync(String executable, List<String> arguments,
- {String workingDirectory}) =>
- _mockResult ??
- ProcessResult(
- 123 /* pid */,
- 0 /* exitCode */,
- jsonEncode({'packages': []}) /* stdout */,
- '' /* stderr */,
- );
-}
-
-/// TODO(paulberry): move into cli_util
-class _TestLogger implements Logger {
- final stderrBuffer = StringBuffer();
-
- final stdoutBuffer = StringBuffer();
-
- final bool isVerbose;
-
- _TestLogger(this.isVerbose);
-
- @override
- Ansi get ansi => Ansi(false);
-
- @override
- void flush() {
- throw UnimplementedError('TODO(paulberry)');
- }
-
- @override
- Progress progress(String message) {
- return SimpleProgress(this, message);
- }
-
- @override
- void stderr(String message) {
- stderrBuffer.writeln(message);
- }
-
- @override
- void stdout(String message) {
- stdoutBuffer.writeln(message);
- }
-
- @override
- void trace(String message) {
- throw UnimplementedError('TODO(paulberry)');
- }
-
- @override
- void write(String message) {
- stdoutBuffer.write(message);
- }
-
- @override
- void writeCharCode(int charCode) {
- stdoutBuffer.writeCharCode(charCode);
- }
+ style: path.Style.windows, current: 'C:\\working_dir'));
}
diff --git a/pkg/nnbd_migration/test/utilities/test_logger.dart b/pkg/nnbd_migration/test/utilities/test_logger.dart
new file mode 100644
index 0000000..5d997c3
--- /dev/null
+++ b/pkg/nnbd_migration/test/utilities/test_logger.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:cli_util/cli_logging.dart';
+
+/// TODO(paulberry): move into cli_util
+class TestLogger implements Logger {
+ final stderrBuffer = StringBuffer();
+
+ final stdoutBuffer = StringBuffer();
+
+ final bool isVerbose;
+
+ TestLogger(this.isVerbose);
+
+ @override
+ Ansi get ansi => Ansi(false);
+
+ @override
+ void flush() {
+ throw UnimplementedError('TODO(paulberry)');
+ }
+
+ @override
+ Progress progress(String message) {
+ return SimpleProgress(this, message);
+ }
+
+ @override
+ void stderr(String message) {
+ stderrBuffer.writeln(message);
+ }
+
+ @override
+ void stdout(String message) {
+ stdoutBuffer.writeln(message);
+ }
+
+ @override
+ void trace(String message) {
+ throw UnimplementedError('TODO(paulberry)');
+ }
+
+ @override
+ void write(String message) {
+ stdoutBuffer.write(message);
+ }
+
+ @override
+ void writeCharCode(int charCode) {
+ stdoutBuffer.writeCharCode(charCode);
+ }
+}
diff --git a/tools/VERSION b/tools/VERSION
index 27b1b1d..47a9824 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 25
+PRERELEASE 26
PRERELEASE_PATCH 0
\ No newline at end of file