| // Copyright (c) 2019, 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. | |
| /// This executable provides the ability to run the migration tool in process | |
| /// on a single package. It should be invoked with two command-line arguments: | |
| /// a path to a configuration file and the name of a package to migrate. | |
| /// | |
| /// The configuration file format is a JSON map, with the following keys: | |
| /// - `sdk_root`: path to the SDK source code on the user's machine (this is the | |
| /// directory that contains `pkg`, `third_party`, `tests`, etc. | |
| /// - `output_root`: if present, path to the directory on the user's machine | |
| /// where output HTML files should go. A subdirectory will be created for | |
| /// each package that is migrated. | |
| /// - `external_packages`: a map (name => path) of additional non-SDK packages | |
| /// that may need to be migrated. | |
| /// - `port`: if present, the port where a server should be spawned serving HTML | |
| /// pages. | |
| library migration_runner; | |
| import 'dart:convert'; | |
| import 'dart:io' as io; | |
| import 'package:analysis_server/protocol/protocol.dart'; | |
| import 'package:analysis_server/protocol/protocol_constants.dart'; | |
| import 'package:analysis_server/protocol/protocol_generated.dart'; | |
| import 'package:analysis_server/src/analysis_server.dart'; | |
| import 'package:analysis_server/src/server/crash_reporting_attachments.dart'; | |
| import 'package:analysis_server/src/utilities/mocks.dart'; | |
| import 'package:analyzer/file_system/file_system.dart'; | |
| import 'package:analyzer/file_system/physical_file_system.dart'; | |
| import 'package:analyzer/instrumentation/instrumentation.dart'; | |
| import 'package:analyzer/src/dart/sdk/sdk.dart'; | |
| import 'package:analyzer/src/generated/sdk.dart'; | |
| import 'package:path/path.dart' as path; | |
| import 'package:test/test.dart'; | |
| Future<void> main(List<String> args) async { | |
| if (args.length != 2) { | |
| throw StateError( | |
| 'Exactly two arguments are required: the path to a JSON configuration ' | |
| 'file, and the name of the package to migrate'); | |
| } | |
| var testInfoJsonPath = args[0]; | |
| var testInfoJson = json.decode(io.File(testInfoJsonPath).readAsStringSync()); | |
| var packageName = args[1]; | |
| var testInfo = TestInfo(testInfoJson); | |
| var packageRoot = testInfo.packageRoot(packageName); | |
| var port = testInfo.port; | |
| print('Preparing to migrate'); | |
| var migrationTest = MigrationTest(); | |
| migrationTest.setUp(); | |
| print('Migrating'); | |
| await migrationTest.run(packageRoot, port); | |
| if (port == null) { | |
| print('Done'); | |
| io.exit(0); | |
| } else { | |
| print('Done. Please point your browser to localhost:$port/\$filePath'); | |
| } | |
| } | |
| class MigrationBase { | |
| ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; | |
| MockServerChannel serverChannel; | |
| AnalysisServer server; | |
| AnalysisServer createAnalysisServer() { | |
| // | |
| // Create server | |
| // | |
| AnalysisServerOptions options = AnalysisServerOptions(); | |
| String sdkPath = FolderBasedDartSdk.defaultSdkDirectory( | |
| PhysicalResourceProvider.INSTANCE, | |
| ).path; | |
| return AnalysisServer( | |
| serverChannel, | |
| resourceProvider, | |
| options, | |
| DartSdkManager(sdkPath, true), | |
| CrashReportingAttachmentsBuilder.empty, | |
| InstrumentationService.NULL_SERVICE); | |
| } | |
| void processNotification(Notification notification) { | |
| if (notification.event == SERVER_NOTIFICATION_ERROR) { | |
| fail('${notification.toJson()}'); | |
| } | |
| } | |
| Future<Response> sendAnalysisSetAnalysisRoots(List<String> directories) { | |
| var request = | |
| AnalysisSetAnalysisRootsParams(directories, []).toRequest('0'); | |
| return waitResponse(request); | |
| } | |
| Future<Response> sendEditDartfix(List<String> directories, int port) { | |
| var request = EditDartfixParams(directories, | |
| includedFixes: ['non-nullable'], port: port) | |
| .toRequest('1'); | |
| return waitResponse(request); | |
| } | |
| void setUp() { | |
| serverChannel = MockServerChannel(); | |
| server = createAnalysisServer(); | |
| server.pluginManager = TestPluginManager(); | |
| // listen for notifications | |
| Stream<Notification> notificationStream = | |
| serverChannel.notificationController.stream; | |
| notificationStream.listen((Notification notification) { | |
| processNotification(notification); | |
| }); | |
| } | |
| void tearDown() { | |
| server.done(); | |
| server = null; | |
| serverChannel = null; | |
| } | |
| /// Returns a [Future] that completes when the server's analysis is complete. | |
| Future waitForTasksFinished() { | |
| return server.onAnalysisComplete; | |
| } | |
| /// Completes with a successful [Response] for the given [request]. | |
| Future<Response> waitResponse(Request request, | |
| {bool throwOnError = true}) async { | |
| return serverChannel.sendRequest(request, throwOnError: throwOnError); | |
| } | |
| } | |
| class MigrationTest extends MigrationBase { | |
| Future<void> run(String packageRoot, int port) async { | |
| List<String> packageRoots = [packageRoot]; | |
| await sendAnalysisSetAnalysisRoots(packageRoots); | |
| await sendEditDartfix(packageRoots, port); | |
| } | |
| } | |
| class TestInfo { | |
| static const Set<String> thirdPartyPackages = { | |
| 'charcode', | |
| 'collection', | |
| 'logging', | |
| 'meta', | |
| 'pedantic', | |
| 'typed_data' | |
| }; | |
| static const Set<String> builtInPackages = {'meta', 'path'}; | |
| final Map<String, Object> testInfoJson; | |
| TestInfo(this.testInfoJson); | |
| Map<String, String> get externalPackages => | |
| ((testInfoJson['external_packages'] ?? {}) as Map).cast<String, String>(); | |
| String get outputRoot => testInfoJson['output_root']; | |
| int get port => testInfoJson['port']; | |
| String get sdkRoot => testInfoJson['sdk_root']; | |
| String packageRoot(String packageName) { | |
| if (thirdPartyPackages.contains(packageName)) { | |
| return path.join(sdkRoot, 'third_party', 'pkg', packageName); | |
| } else if (builtInPackages.contains(packageName)) { | |
| return path.join(sdkRoot, 'pkg', packageName); | |
| } else if (externalPackages.containsKey(packageName)) { | |
| return externalPackages[packageName]; | |
| } else { | |
| throw StateError('Unrecognized package $packageName'); | |
| } | |
| } | |
| } |