blob: 4fa62de720abd3cfd16e5a8fd5f38d3f005c3d5e [file] [log] [blame]
// 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.
import 'package:args/args.dart';
import 'package:dwds/dwds.dart';
import 'package:logging/logging.dart';
import '../logging.dart';
import 'shared.dart';
const autoOption = 'auto';
const chromeDebugPortFlag = 'chrome-debug-port';
const debugExtensionFlag = 'debug-extension';
const debugFlag = 'debug';
const enableInjectedClientFlag = 'injected-client';
const hostnameFlag = 'hostname';
const tlsCertChainFlag = 'tls-cert-chain';
const tlsCertKeyFlag = 'tls-cert-key';
const hotReloadFlag = 'hot-reload';
const hotRestartFlag = 'hot-restart';
const launchInChromeFlag = 'launch-in-chrome';
const liveReloadFlag = 'live-reload';
const logRequestsFlag = 'log-requests';
const outputFlag = 'output';
const outputNone = 'NONE';
const releaseFlag = 'release';
const requireBuildWebCompilersFlag = 'build-web-compilers';
const verboseFlag = 'verbose';
ReloadConfiguration _parseReloadConfiguration(ArgResults argResults) {
var auto = argResults.options.contains(autoOption)
? argResults[autoOption] as String
: null;
void _handleDeprecatedFlag(String flag, String autoFallback) {
if (argResults.options.contains(flag) &&
argResults.wasParsed(flag) &&
argResults[flag] as bool == true) {
logWriter(
Level.WARNING,
'--$flag is deprecated please use --auto=$autoFallback instead '
'(this has been automatically selected).');
if (auto != null) {
logWriter(
Level.WARNING,
'Only one --auto option is allowed, got $flag which corresponds '
'to --auto=$autoFallback, but already got --auto=$auto');
} else {
auto = autoFallback;
}
}
}
_handleDeprecatedFlag(hotReloadFlag, 'reload');
_handleDeprecatedFlag(hotRestartFlag, 'restart');
_handleDeprecatedFlag(liveReloadFlag, 'refresh');
switch (auto) {
case 'reload':
logWriter(
Level.WARNING,
'Hot reload is not yet supported for web projects. '
'Please try --auto=restart instead.');
return ReloadConfiguration.none;
case 'restart':
return ReloadConfiguration.hotRestart;
case 'refresh':
return ReloadConfiguration.liveReload;
default:
return ReloadConfiguration.none;
}
}
class Configuration {
final bool _autoRun;
final int _chromeDebugPort;
final bool _debugExtension;
final bool _debug;
final bool _enableInjectedClient;
final String _hostname;
final String _tlsCertChain;
final String _tlsCertKey;
final bool _launchInChrome;
final bool _logRequests;
final String _output;
final String outputInput;
final String outputPath;
final bool _release;
final ReloadConfiguration _reload;
final bool _requireBuildWebCompilers;
final bool _verbose;
Configuration({
bool autoRun,
int chromeDebugPort,
bool debugExtension,
bool debug,
bool enableInjectedClient,
String hostname,
String tlsCertChain,
String tlsCertKey,
bool launchInChrome,
bool logRequests,
String output,
this.outputInput,
this.outputPath,
ReloadConfiguration reload,
bool release,
bool requireBuildWebCompilers,
bool verbose,
}) : _autoRun = autoRun,
_chromeDebugPort = chromeDebugPort,
_debugExtension = debugExtension,
_debug = debug,
_enableInjectedClient = enableInjectedClient,
_hostname = hostname,
_tlsCertChain = tlsCertChain,
_tlsCertKey = tlsCertKey,
_launchInChrome = launchInChrome,
_logRequests = logRequests,
_output = output,
_release = release,
_reload = reload,
_requireBuildWebCompilers = requireBuildWebCompilers,
_verbose = verbose {
_validateConfiguration();
}
void _validateConfiguration() {
if (outputInput != null) ensureIsTopLevelDir(outputInput);
if ((tlsCertKey != null && tlsCertChain == null) ||
(tlsCertKey == null && tlsCertChain != null)) {
throw InvalidConfiguration(
'Must use --$tlsCertKey with --$tlsCertChain.');
}
if (debug && chromeDebugPort == 0 && !launchInChrome) {
throw InvalidConfiguration(
'Must either use --$chromeDebugPortFlag or --$launchInChromeFlag '
'with --$debugFlag.');
}
// Check that no debugging options were passed if the injected client is
// disabled.
if (!enableInjectedClient) {
if (debug) {
throw InvalidConfiguration(
'--$debugFlag cannot be used with --no-$enableInjectedClientFlag');
}
if (debugExtension) {
throw InvalidConfiguration('--$debugExtensionFlag cannot be used with '
'--no-$enableInjectedClientFlag');
}
if (chromeDebugPort != 0) {
throw InvalidConfiguration('--$chromeDebugPortFlag cannot be used '
'with --no-$enableInjectedClientFlag');
}
}
}
factory Configuration.noInjectedClientDefaults() =>
Configuration(autoRun: false, debug: false, debugExtension: false);
// Whether the application should automatically run when loaded.
bool get autoRun => _autoRun ?? true;
int get chromeDebugPort => _chromeDebugPort ?? 0;
bool get debugExtension => _debugExtension ?? false;
bool get debug => _debug ?? false;
bool get enableInjectedClient => _enableInjectedClient ?? true;
String get hostname => _hostname ?? 'localhost';
String get tlsCertChain => _tlsCertChain;
String get tlsCertKey => _tlsCertKey;
bool get launchInChrome => _launchInChrome ?? false;
bool get logRequests => _logRequests ?? false;
String get output => _output ?? outputNone;
bool get release => _release ?? false;
ReloadConfiguration get reload => _reload ?? ReloadConfiguration.none;
bool get requireBuildWebCompilers => _requireBuildWebCompilers ?? true;
bool get verbose => _verbose ?? false;
/// Returns a new configuration with values updated from the parsed args.
static Configuration fromArgs(ArgResults argResults) {
var defaultConfiguration = Configuration();
if (argResults == null) return defaultConfiguration;
var enableInjectedClient =
argResults.options.contains(enableInjectedClientFlag)
? argResults[enableInjectedClientFlag] as bool
: defaultConfiguration.enableInjectedClient;
// Change the defaults when we have no injected client to disable all
// debugging features.
//
// After parsing we check these defaults weren't overridden as well.
if (!enableInjectedClient) {
defaultConfiguration = Configuration.noInjectedClientDefaults();
}
var chromeDebugPort = argResults.options.contains(chromeDebugPortFlag)
? int.parse(argResults[chromeDebugPortFlag] as String)
: defaultConfiguration.chromeDebugPort;
var debugExtension = argResults.options.contains(debugExtensionFlag)
? argResults[debugExtensionFlag] as bool
: defaultConfiguration.debugExtension;
var debug = argResults.options.contains(debugFlag)
? argResults[debugFlag] as bool
: defaultConfiguration.debug;
var hostname = argResults.options.contains(hostnameFlag)
? argResults[hostnameFlag] as String
: defaultConfiguration.hostname;
var tlsCertChain = argResults.options.contains(tlsCertChainFlag)
? argResults[tlsCertChainFlag] as String
: defaultConfiguration.tlsCertChain;
var tlsCertKey = argResults.options.contains(tlsCertKeyFlag)
? argResults[tlsCertKeyFlag] as String
: defaultConfiguration.tlsCertKey;
var launchInChrome = argResults.options.contains(launchInChromeFlag) &&
argResults.wasParsed(launchInChromeFlag)
? argResults[launchInChromeFlag] as bool
// We want to default to launch chrome if the user provides just --debug
// and not --chrome-debug-port.
: debug && !argResults.wasParsed(chromeDebugPortFlag)
? true
: defaultConfiguration.launchInChrome;
var logRequests = argResults.options.contains(logRequestsFlag)
? argResults[logRequestsFlag] as bool
: defaultConfiguration.logRequests;
var output = argResults.options.contains(outputFlag)
? argResults[outputFlag] as String
: defaultConfiguration.output;
String outputPath;
String outputInput;
if (output != 'NONE') {
var splitOutput = output.split(':');
if (splitOutput.length == 1) {
outputInput = '';
outputPath = output;
} else {
outputInput = splitOutput.first;
outputPath = splitOutput.skip(1).join(':');
}
}
var release = argResults.options.contains(releaseFlag)
? argResults[releaseFlag] as bool
: defaultConfiguration.release;
var requireBuildWebCompilers =
argResults.options.contains(requireBuildWebCompilersFlag)
? argResults[requireBuildWebCompilersFlag] as bool
: defaultConfiguration.requireBuildWebCompilers;
var verbose = argResults.options.contains(verboseFlag)
? argResults[verboseFlag] as bool
: defaultConfiguration.verbose;
return Configuration(
chromeDebugPort: chromeDebugPort,
debugExtension: debugExtension,
debug: debug,
enableInjectedClient: enableInjectedClient,
hostname: hostname,
tlsCertChain: tlsCertChain,
tlsCertKey: tlsCertKey,
launchInChrome: launchInChrome,
logRequests: logRequests,
output: output,
outputInput: outputInput,
outputPath: outputPath,
release: release,
reload: _parseReloadConfiguration(argResults),
requireBuildWebCompilers: requireBuildWebCompilers,
verbose: verbose);
}
}
class InvalidConfiguration implements Exception {
final String details;
InvalidConfiguration(this.details);
@override
String toString() {
return 'Invalid configuration: $details';
}
}