blob: 87112bc7a9c9a9d35698dd999c650b8facadc966 [file] [log] [blame] [edit]
// 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;
}
}