| // Copyright (c) 2022, 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:async'; |
| import 'dart:io' show File; |
| |
| import 'package:args/args.dart'; |
| import 'package:dartdev/src/generate_kernel.dart'; |
| import 'package:frontend_server/resident_frontend_server_utils.dart' |
| show ResidentCompilerInfo; |
| |
| import '../core.dart'; |
| import '../resident_frontend_constants.dart'; |
| import '../resident_frontend_utils.dart'; |
| |
| class CompilationServerCommand extends DartdevCommand { |
| static const commandName = 'compilation-server'; |
| |
| static const commandDescription = 'Control resident frontend compilers.'; |
| |
| static const legacyResidentServerInfoFileFlag = 'resident-server-info-file'; |
| static const residentCompilerInfoFileFlag = residentCompilerInfoFileOption; |
| static const residentCompilerInfoFileFlagDescription = |
| 'The path to an info file that the Dart CLI will use to communicate with ' |
| 'a resident frontend compiler. Each unique info file is associated with ' |
| 'a unique resident frontend compiler. If this flag is ommitted, the ' |
| 'default info file will be used.'; |
| |
| static const inaccessibleDefaultResidentCompilerInfoFileMessage = |
| 'The default resident frontend compiler info file could not be accessed. ' |
| 'Please explicitly provide the path to a resident compiler info file ' |
| 'using the --resident-compiler-info-file option.'; |
| |
| CompilationServerCommand({bool verbose = false}) |
| : super( |
| commandName, |
| commandDescription, |
| false, |
| hidden: !verbose, |
| ) { |
| addSubcommand(CompilationServerStartCommand()); |
| addSubcommand(CompilationServerShutdownCommand()); |
| } |
| |
| @override |
| CommandCategory get commandCategory => CommandCategory.tools; |
| } |
| |
| class CompilationServerStartCommand extends DartdevCommand { |
| static const commandName = 'start'; |
| |
| static const commandDescription = 'Start a resident frontend compiler.'; |
| |
| CompilationServerStartCommand({bool verbose = false}) |
| : super( |
| commandName, |
| commandDescription, |
| false, |
| hidden: !verbose, |
| ) { |
| argParser |
| ..addOption( |
| CompilationServerCommand.residentCompilerInfoFileFlag, |
| help: CompilationServerCommand.residentCompilerInfoFileFlagDescription, |
| ) |
| ..addOption( |
| CompilationServerCommand.legacyResidentServerInfoFileFlag, |
| // This option is only available for backwards compatibility, and should |
| // never be shown in the help message. |
| hide: true, |
| ); |
| } |
| |
| @override |
| FutureOr<int> run() async { |
| final args = argResults!; |
| |
| final File? residentCompilerInfoFile = |
| getResidentCompilerInfoFileConsideringArgs(args); |
| if (residentCompilerInfoFile == null) { |
| log.stderr( |
| CompilationServerCommand |
| .inaccessibleDefaultResidentCompilerInfoFileMessage, |
| ); |
| return DartdevCommand.errorExitCode; |
| } |
| |
| try { |
| await ensureCompilationServerIsRunning( |
| residentCompilerInfoFile, |
| quiet: false, |
| ); |
| } catch (e) { |
| // We already print the error in `ensureCompilationServerIsRunning` when we |
| // throw a state error. |
| if (e is! StateError) { |
| print(e.toString()); |
| } |
| return 64; |
| } |
| return 0; |
| } |
| } |
| |
| class CompilationServerShutdownCommand extends DartdevCommand { |
| static const commandName = 'shutdown'; |
| |
| static const commandDescription = ''' |
| Shut down a resident frontend compiler. |
| |
| Note that this command name and usage could change as we evolve the resident frontend compiler behavior.'''; |
| |
| CompilationServerShutdownCommand({bool verbose = false}) |
| : super(commandName, commandDescription, false, hidden: !verbose) { |
| argParser |
| ..addOption( |
| CompilationServerCommand.residentCompilerInfoFileFlag, |
| help: CompilationServerCommand.residentCompilerInfoFileFlagDescription, |
| ) |
| ..addOption( |
| CompilationServerCommand.legacyResidentServerInfoFileFlag, |
| // This option is only available for backwards compatibility, and should |
| // never be shown in the help message. |
| hide: true, |
| ); |
| } |
| |
| // This argument parser is here solely to ensure that VM specific flags are |
| // provided before any command and to provide a more consistent help message |
| // with the rest of the tool. |
| @override |
| ArgParser createArgParser() { |
| return ArgParser(); |
| } |
| |
| @override |
| FutureOr<int> run() async { |
| final args = argResults!; |
| |
| final File? residentCompilerInfoFile = |
| getResidentCompilerInfoFileConsideringArgs(args); |
| if (residentCompilerInfoFile == null) { |
| log.stderr( |
| CompilationServerCommand |
| .inaccessibleDefaultResidentCompilerInfoFileMessage, |
| ); |
| return DartdevCommand.errorExitCode; |
| } |
| |
| if (!residentCompilerInfoFile.existsSync()) { |
| log.stdout('No resident frontend compiler instance running.'); |
| return 0; |
| } |
| |
| final residentCompilerInfo = |
| ResidentCompilerInfo.fromFile(residentCompilerInfoFile); |
| final address = residentCompilerInfo.address; |
| final port = residentCompilerInfo.port; |
| // There is nothing actionable the user can do in response to an error |
| // occurring when shutting down. So, we call |
| // [shutDownOrForgetResidentFrontendCompiler] here to ensure that when such |
| // an error occurs, we don't report it to the user and instead just forget |
| // about the compiler that couldn't be shut down. |
| await shutDownOrForgetResidentFrontendCompiler(residentCompilerInfoFile); |
| log.stdout( |
| 'The Resident Frontend Compiler instance at ${address.host}:$port was ' |
| 'successfully shutdown.', |
| ); |
| return 0; |
| } |
| } |