Unverified Commit 76e587bf authored by Kevin Moore's avatar Kevin Moore Committed by GitHub

flutter-tool: enum cleanup (#124760)

flutter-tool: enum cleanup
parent dca8d7c2
...@@ -109,9 +109,9 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag ...@@ -109,9 +109,9 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag
if (buildInfo == null) { if (buildInfo == null) {
filename = 'app.apk'; filename = 'app.apk';
} else if (buildInfo.flavor == null) { } else if (buildInfo.flavor == null) {
filename = 'app-${buildInfo.mode.name}.apk'; filename = 'app-${buildInfo.mode.cliName}.apk';
} else { } else {
filename = 'app-${buildInfo.lowerCasedFlavor}-${buildInfo.mode.name}.apk'; filename = 'app-${buildInfo.lowerCasedFlavor}-${buildInfo.mode.cliName}.apk';
} }
if (androidProject.isUsingGradle && androidProject.isSupportedVersion) { if (androidProject.isUsingGradle && androidProject.isSupportedVersion) {
...@@ -119,7 +119,7 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag ...@@ -119,7 +119,7 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag
if (androidProject.parent.isModule) { if (androidProject.parent.isModule) {
// Module builds output the apk in a subdirectory that corresponds // Module builds output the apk in a subdirectory that corresponds
// to the buildmode of the apk. // to the buildmode of the apk.
apkDirectory = apkDirectory.childDirectory(buildInfo!.mode.name); apkDirectory = apkDirectory.childDirectory(buildInfo!.mode.cliName);
} }
apkFile = apkDirectory.childFile(filename); apkFile = apkDirectory.childFile(filename);
if (apkFile.existsSync()) { if (apkFile.existsSync()) {
......
...@@ -20,7 +20,7 @@ void validateBuild(AndroidBuildInfo androidBuildInfo) { ...@@ -20,7 +20,7 @@ void validateBuild(AndroidBuildInfo androidBuildInfo) {
} }
if (buildInfo.mode.isPrecompiled && androidBuildInfo.targetArchs.contains(AndroidArch.x86)) { if (buildInfo.mode.isPrecompiled && androidBuildInfo.targetArchs.contains(AndroidArch.x86)) {
throwToolExit( throwToolExit(
'Cannot build ${androidBuildInfo.buildInfo.mode.name} mode for x86 ABI.\n' 'Cannot build ${androidBuildInfo.buildInfo.mode.cliName} mode for x86 ABI.\n'
'For more information see $kSupportedAbis .' 'For more information see $kSupportedAbis .'
); );
} }
......
...@@ -673,7 +673,7 @@ class CachedArtifacts implements Artifacts { ...@@ -673,7 +673,7 @@ class CachedArtifacts implements Artifacts {
// https://github.com/flutter/flutter/issues/38935 // https://github.com/flutter/flutter/issues/38935
String platformDirName = _enginePlatformDirectoryName(platform); String platformDirName = _enginePlatformDirectoryName(platform);
if (mode == BuildMode.profile || mode == BuildMode.release) { if (mode == BuildMode.profile || mode == BuildMode.release) {
platformDirName = '$platformDirName-${getNameForBuildMode(mode!)}'; platformDirName = '$platformDirName-${mode!.cliName}';
} }
final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode)); return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode));
...@@ -713,7 +713,7 @@ class CachedArtifacts implements Artifacts { ...@@ -713,7 +713,7 @@ class CachedArtifacts implements Artifacts {
if (mode == BuildMode.debug || mode == null) { if (mode == BuildMode.debug || mode == null) {
return _fileSystem.path.join(engineDir, platformName); return _fileSystem.path.join(engineDir, platformName);
} }
final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode), '-')}' : ''; final String suffix = mode != BuildMode.debug ? '-${snakeCase(mode.cliName, '-')}' : '';
return _fileSystem.path.join(engineDir, platformName + suffix); return _fileSystem.path.join(engineDir, platformName + suffix);
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
case TargetPlatform.fuchsia_x64: case TargetPlatform.fuchsia_x64:
...@@ -727,7 +727,7 @@ class CachedArtifacts implements Artifacts { ...@@ -727,7 +727,7 @@ class CachedArtifacts implements Artifacts {
case TargetPlatform.android_x64: case TargetPlatform.android_x64:
case TargetPlatform.android_x86: case TargetPlatform.android_x86:
assert(mode != null, 'Need to specify a build mode for platform $platform.'); assert(mode != null, 'Need to specify a build mode for platform $platform.');
final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode!), '-')}' : ''; final String suffix = mode != BuildMode.debug ? '-${snakeCase(mode!.cliName, '-')}' : '';
return _fileSystem.path.join(engineDir, platformName + suffix); return _fileSystem.path.join(engineDir, platformName + suffix);
case TargetPlatform.android: case TargetPlatform.android:
assert(false, 'cannot use TargetPlatform.android to look up artifacts'); assert(false, 'cannot use TargetPlatform.android to look up artifacts');
......
...@@ -34,6 +34,18 @@ String snakeCase(String str, [ String sep = '_' ]) { ...@@ -34,6 +34,18 @@ String snakeCase(String str, [ String sep = '_' ]) {
(Match m) => '${m.start == 0 ? '' : sep}${m[0]!.toLowerCase()}'); (Match m) => '${m.start == 0 ? '' : sep}${m[0]!.toLowerCase()}');
} }
abstract interface class CliEnum implements Enum {
String get cliName;
String get helpText;
static Map<String, String> allowedHelp<T extends CliEnum>(List<T> values) =>
Map<String, String>.fromEntries(
values.map(
(T e) => MapEntry<String, String>(e.cliName, e.helpText),
),
);
}
/// Converts `fooBar` to `FooBar`. /// Converts `fooBar` to `FooBar`.
/// ///
/// This uses [toBeginningOfSentenceCase](https://pub.dev/documentation/intl/latest/intl/toBeginningOfSentenceCase.html), /// This uses [toBeginningOfSentenceCase](https://pub.dev/documentation/intl/latest/intl/toBeginningOfSentenceCase.html),
...@@ -53,13 +65,6 @@ String snakeCaseToTitleCase(String snakeCaseString) { ...@@ -53,13 +65,6 @@ String snakeCaseToTitleCase(String snakeCaseString) {
/// Return the plural of the given word (`cat(s)`). /// Return the plural of the given word (`cat(s)`).
String pluralize(String word, int count) => count == 1 ? word : '${word}s'; String pluralize(String word, int count) => count == 1 ? word : '${word}s';
/// Return the name of an enum item.
String getEnumName(dynamic enumItem) {
final String name = '$enumItem';
final int index = name.indexOf('.');
return index == -1 ? name : name.substring(index + 1);
}
String toPrettyJson(Object jsonable) { String toPrettyJson(Object jsonable) {
final String value = const JsonEncoder.withIndent(' ').convert(jsonable); final String value = const JsonEncoder.withIndent(' ').convert(jsonable);
return '$value\n'; return '$value\n';
......
...@@ -214,7 +214,7 @@ class BuildInfo { ...@@ -214,7 +214,7 @@ class BuildInfo {
bool get usesAot => isAotBuildMode(mode); bool get usesAot => isAotBuildMode(mode);
bool get supportsEmulator => isEmulatorBuildMode(mode); bool get supportsEmulator => isEmulatorBuildMode(mode);
bool get supportsSimulator => isEmulatorBuildMode(mode); bool get supportsSimulator => isEmulatorBuildMode(mode);
String get modeName => getModeName(mode); String get modeName => mode.cliName;
String get friendlyModeName => getFriendlyModeName(mode); String get friendlyModeName => getFriendlyModeName(mode);
/// the flavor name in the output apk files is lower-cased (see flutter.gradle), /// the flavor name in the output apk files is lower-cased (see flutter.gradle),
...@@ -233,7 +233,7 @@ class BuildInfo { ...@@ -233,7 +233,7 @@ class BuildInfo {
// packagesPath and performanceMeasurementFile are not passed into // packagesPath and performanceMeasurementFile are not passed into
// the Environment map. // the Environment map.
return <String, String>{ return <String, String>{
kBuildMode: getNameForBuildMode(mode), kBuildMode: mode.cliName,
if (dartDefines.isNotEmpty) if (dartDefines.isNotEmpty)
kDartDefines: encodeDartDefines(dartDefines), kDartDefines: encodeDartDefines(dartDefines),
kDartObfuscation: dartObfuscation.toString(), kDartObfuscation: dartObfuscation.toString(),
...@@ -377,41 +377,25 @@ class AndroidBuildInfo { ...@@ -377,41 +377,25 @@ class AndroidBuildInfo {
} }
/// A summary of the compilation strategy used for Dart. /// A summary of the compilation strategy used for Dart.
class BuildMode { enum BuildMode {
const BuildMode._(this.name);
factory BuildMode.fromName(String value) {
switch (value) {
case 'debug':
return BuildMode.debug;
case 'profile':
return BuildMode.profile;
case 'release':
return BuildMode.release;
case 'jit_release':
return BuildMode.jitRelease;
}
throw ArgumentError('$value is not a supported build mode');
}
/// Built in JIT mode with no optimizations, enabled asserts, and a VM service. /// Built in JIT mode with no optimizations, enabled asserts, and a VM service.
static const BuildMode debug = BuildMode._('debug'); debug,
/// Built in AOT mode with some optimizations and a VM service. /// Built in AOT mode with some optimizations and a VM service.
static const BuildMode profile = BuildMode._('profile'); profile,
/// Built in AOT mode with all optimizations and no VM service. /// Built in AOT mode with all optimizations and no VM service.
static const BuildMode release = BuildMode._('release'); release,
/// Built in JIT mode with all optimizations and no VM service. /// Built in JIT mode with all optimizations and no VM service.
static const BuildMode jitRelease = BuildMode._('jit_release'); jitRelease;
factory BuildMode.fromCliName(String value) => values.singleWhere(
(BuildMode element) => element.cliName == value,
orElse: () =>
throw ArgumentError('$value is not a supported build mode'),
);
static const List<BuildMode> values = <BuildMode>[
debug,
profile,
release,
jitRelease,
];
static const Set<BuildMode> releaseModes = <BuildMode>{ static const Set<BuildMode> releaseModes = <BuildMode>{
release, release,
jitRelease, jitRelease,
...@@ -433,21 +417,10 @@ class BuildMode { ...@@ -433,21 +417,10 @@ class BuildMode {
/// Whether this mode is using the precompiled runtime. /// Whether this mode is using the precompiled runtime.
bool get isPrecompiled => !isJit; bool get isPrecompiled => !isJit;
/// The name for this build mode. String get cliName => snakeCase(name);
final String name;
@override @override
String toString() => name; String toString() => cliName;
}
/// Return the name for the build mode, or "any" if null.
String getNameForBuildMode(BuildMode buildMode) {
return buildMode.name;
}
/// Returns the [BuildMode] for a particular `name`.
BuildMode getBuildModeForName(String name) {
return BuildMode.fromName(name);
} }
/// Environment type of the target device. /// Environment type of the target device.
...@@ -540,10 +513,8 @@ String? validatedBuildNameForPlatform(TargetPlatform targetPlatform, String? bui ...@@ -540,10 +513,8 @@ String? validatedBuildNameForPlatform(TargetPlatform targetPlatform, String? bui
return buildName; return buildName;
} }
String getModeName(BuildMode mode) => getEnumName(mode);
String getFriendlyModeName(BuildMode mode) { String getFriendlyModeName(BuildMode mode) {
return snakeCase(getModeName(mode)).replaceAll('_', ' '); return snakeCase(mode.cliName).replaceAll('_', ' ');
} }
// Returns true if the selected build mode uses ahead-of-time compilation. // Returns true if the selected build mode uses ahead-of-time compilation.
......
...@@ -46,7 +46,7 @@ abstract class AndroidAssetBundle extends Target { ...@@ -46,7 +46,7 @@ abstract class AndroidAssetBundle extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, name); throw MissingDefineException(kBuildMode, name);
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final Directory outputDirectory = environment.outputDir final Directory outputDirectory = environment.outputDir
.childDirectory('flutter_assets') .childDirectory('flutter_assets')
..createSync(recursive: true); ..createSync(recursive: true);
...@@ -167,7 +167,7 @@ class AndroidAot extends AotElfBase { ...@@ -167,7 +167,7 @@ class AndroidAot extends AotElfBase {
} }
@override @override
String get name => 'android_aot_${getNameForBuildMode(buildMode)}_' String get name => 'android_aot_${buildMode.cliName}_'
'${getNameForTargetPlatform(targetPlatform)}'; '${getNameForTargetPlatform(targetPlatform)}';
/// The specific Android ABI we are building for. /// The specific Android ABI we are building for.
...@@ -229,7 +229,7 @@ class AndroidAot extends AotElfBase { ...@@ -229,7 +229,7 @@ class AndroidAot extends AotElfBase {
extraGenSnapshotOptions.add('--loading_unit_manifest=$manifestPath'); extraGenSnapshotOptions.add('--loading_unit_manifest=$manifestPath');
outputs.add(environment.fileSystem.file(manifestPath)); outputs.add(environment.fileSystem.file(manifestPath));
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true'; final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final String? codeSizeDirectory = environment.defines[kCodeSizeDirectory]; final String? codeSizeDirectory = environment.defines[kCodeSizeDirectory];
...@@ -299,7 +299,7 @@ class AndroidAotBundle extends Target { ...@@ -299,7 +299,7 @@ class AndroidAotBundle extends Target {
} }
@override @override
String get name => 'android_aot_bundle_${getNameForBuildMode(dependency.buildMode)}_' String get name => 'android_aot_bundle_${dependency.buildMode.cliName}_'
'${getNameForTargetPlatform(dependency.targetPlatform)}'; '${getNameForTargetPlatform(dependency.targetPlatform)}';
TargetPlatform get targetPlatform => dependency.targetPlatform; TargetPlatform get targetPlatform => dependency.targetPlatform;
...@@ -390,7 +390,7 @@ class AndroidAotDeferredComponentsBundle extends Target { ...@@ -390,7 +390,7 @@ class AndroidAotDeferredComponentsBundle extends Target {
} }
@override @override
String get name => 'android_aot_deferred_components_bundle_${getNameForBuildMode(dependency.buildMode)}_' String get name => 'android_aot_deferred_components_bundle_${dependency.buildMode.cliName}_'
'${getNameForTargetPlatform(dependency.targetPlatform)}'; '${getNameForTargetPlatform(dependency.targetPlatform)}';
TargetPlatform get targetPlatform => dependency.targetPlatform; TargetPlatform get targetPlatform => dependency.targetPlatform;
...@@ -499,7 +499,7 @@ Depfile copyDeferredComponentSoFiles( ...@@ -499,7 +499,7 @@ Depfile copyDeferredComponentSoFiles(
.childDirectory(component.name) .childDirectory(component.name)
.childDirectory('intermediates') .childDirectory('intermediates')
.childDirectory('flutter') .childDirectory('flutter')
.childDirectory(buildMode.name) .childDirectory(buildMode.cliName)
.childDirectory('deferred_libs') .childDirectory('deferred_libs')
.childDirectory(abi) .childDirectory(abi)
.childFile('libapp.so-${unit.id}.part.so'); .childFile('libapp.so-${unit.id}.part.so');
......
...@@ -178,7 +178,7 @@ Future<Depfile> copyAssets( ...@@ -178,7 +178,7 @@ Future<Depfile> copyAssets(
// If deferred components are disabled, then copy assets to regular location. // If deferred components are disabled, then copy assets to regular location.
final File file = environment.defines[kDeferredComponents] == 'true' final File file = environment.defines[kDeferredComponents] == 'true'
? environment.fileSystem.file( ? environment.fileSystem.file(
environment.fileSystem.path.join(componentOutputDir.path, buildMode.name, 'deferred_assets', 'flutter_assets', entry.key)) environment.fileSystem.path.join(componentOutputDir.path, buildMode.cliName, 'deferred_assets', 'flutter_assets', entry.key))
: environment.fileSystem.file( : environment.fileSystem.file(
environment.fileSystem.path.join(outputDirectory.path, entry.key)); environment.fileSystem.path.join(outputDirectory.path, entry.key));
outputs.add(file); outputs.add(file);
......
...@@ -56,7 +56,7 @@ class CopyFlutterBundle extends Target { ...@@ -56,7 +56,7 @@ class CopyFlutterBundle extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, 'copy_flutter_bundle'); throw MissingDefineException(kBuildMode, 'copy_flutter_bundle');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
environment.outputDir.createSync(recursive: true); environment.outputDir.createSync(recursive: true);
// Only copy the prebuilt runtimes and kernel blob in debug mode. // Only copy the prebuilt runtimes and kernel blob in debug mode.
...@@ -167,7 +167,7 @@ class KernelSnapshot extends Target { ...@@ -167,7 +167,7 @@ class KernelSnapshot extends Target {
if (targetPlatformEnvironment == null) { if (targetPlatformEnvironment == null) {
throw MissingDefineException(kTargetPlatform, 'kernel_snapshot'); throw MissingDefineException(kTargetPlatform, 'kernel_snapshot');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final String targetFile = environment.defines[kTargetFile] ?? environment.fileSystem.path.join('lib', 'main.dart'); final String targetFile = environment.defines[kTargetFile] ?? environment.fileSystem.path.join('lib', 'main.dart');
final File packagesFile = environment.projectDir final File packagesFile = environment.projectDir
.childDirectory('.dart_tool') .childDirectory('.dart_tool')
...@@ -272,7 +272,7 @@ abstract class AotElfBase extends Target { ...@@ -272,7 +272,7 @@ abstract class AotElfBase extends Target {
throw MissingDefineException(kTargetPlatform, 'aot_elf'); throw MissingDefineException(kTargetPlatform, 'aot_elf');
} }
final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions); final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions);
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final TargetPlatform targetPlatform = getTargetPlatformForName(targetPlatformEnvironment); final TargetPlatform targetPlatform = getTargetPlatformForName(targetPlatformEnvironment);
final String? splitDebugInfo = environment.defines[kSplitDebugInfo]; final String? splitDebugInfo = environment.defines[kSplitDebugInfo];
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true'; final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
......
...@@ -56,7 +56,7 @@ abstract class AotAssemblyBase extends Target { ...@@ -56,7 +56,7 @@ abstract class AotAssemblyBase extends Target {
} }
final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions); final List<String> extraGenSnapshotOptions = decodeCommaSeparated(environment.defines, kExtraGenSnapshotOptions);
final BuildMode buildMode = getBuildModeForName(environmentBuildMode); final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode);
final TargetPlatform targetPlatform = getTargetPlatformForName(environmentTargetPlatform); final TargetPlatform targetPlatform = getTargetPlatformForName(environmentTargetPlatform);
final String? splitDebugInfo = environment.defines[kSplitDebugInfo]; final String? splitDebugInfo = environment.defines[kSplitDebugInfo];
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true'; final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
...@@ -461,7 +461,7 @@ abstract class IosAssetBundle extends Target { ...@@ -461,7 +461,7 @@ abstract class IosAssetBundle extends Target {
if (environmentBuildMode == null) { if (environmentBuildMode == null) {
throw MissingDefineException(kBuildMode, name); throw MissingDefineException(kBuildMode, name);
} }
final BuildMode buildMode = getBuildModeForName(environmentBuildMode); final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode);
final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework'); final Directory frameworkDirectory = environment.outputDir.childDirectory('App.framework');
final String frameworkBinaryPath = frameworkDirectory.childFile('App').path; final String frameworkBinaryPath = frameworkDirectory.childFile('App').path;
final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets'); final Directory assetDirectory = frameworkDirectory.childDirectory('flutter_assets');
......
...@@ -53,7 +53,7 @@ class UnpackLinux extends Target { ...@@ -53,7 +53,7 @@ class UnpackLinux extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, name); throw MissingDefineException(kBuildMode, name);
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final String engineSourcePath = environment.artifacts final String engineSourcePath = environment.artifacts
.getArtifactPath( .getArtifactPath(
Artifact.linuxDesktopPath, Artifact.linuxDesktopPath,
...@@ -125,7 +125,7 @@ abstract class BundleLinuxAssets extends Target { ...@@ -125,7 +125,7 @@ abstract class BundleLinuxAssets extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, 'bundle_linux_assets'); throw MissingDefineException(kBuildMode, 'bundle_linux_assets');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final Directory outputDirectory = environment.outputDir final Directory outputDirectory = environment.outputDir
.childDirectory('flutter_assets'); .childDirectory('flutter_assets');
if (!outputDirectory.existsSync()) { if (!outputDirectory.existsSync()) {
......
...@@ -50,7 +50,7 @@ abstract class UnpackMacOS extends Target { ...@@ -50,7 +50,7 @@ abstract class UnpackMacOS extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, 'unpack_macos'); throw MissingDefineException(kBuildMode, 'unpack_macos');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final String basePath = environment.artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: buildMode); final String basePath = environment.artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: buildMode);
final ProcessResult result = environment.processManager.runSync(<String>[ final ProcessResult result = environment.processManager.runSync(<String>[
...@@ -245,7 +245,7 @@ class CompileMacOSFramework extends Target { ...@@ -245,7 +245,7 @@ class CompileMacOSFramework extends Target {
if (targetPlatformEnvironment == null) { if (targetPlatformEnvironment == null) {
throw MissingDefineException(kTargetPlatform, 'kernel_snapshot'); throw MissingDefineException(kTargetPlatform, 'kernel_snapshot');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
if (buildMode == BuildMode.debug) { if (buildMode == BuildMode.debug) {
throw Exception('precompiled macOS framework only supported in release/profile builds.'); throw Exception('precompiled macOS framework only supported in release/profile builds.');
} }
...@@ -372,7 +372,7 @@ abstract class MacOSBundleFlutterAssets extends Target { ...@@ -372,7 +372,7 @@ abstract class MacOSBundleFlutterAssets extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, 'compile_macos_framework'); throw MissingDefineException(kBuildMode, 'compile_macos_framework');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final Directory frameworkRootDirectory = environment final Directory frameworkRootDirectory = environment
.outputDir .outputDir
.childDirectory('App.framework'); .childDirectory('App.framework');
......
...@@ -40,20 +40,6 @@ const String kBaseHref = 'baseHref'; ...@@ -40,20 +40,6 @@ const String kBaseHref = 'baseHref';
/// The caching strategy to use for service worker generation. /// The caching strategy to use for service worker generation.
const String kServiceWorkerStrategy = 'ServiceWorkerStrategy'; const String kServiceWorkerStrategy = 'ServiceWorkerStrategy';
const String kOfflineFirst = 'offline-first';
const String kNoneWorker = 'none';
/// Convert a [value] into a [ServiceWorkerStrategy].
ServiceWorkerStrategy _serviceWorkerStrategyFromString(String? value) {
switch (value) {
case kNoneWorker:
return ServiceWorkerStrategy.none;
// offline-first is the default value for any invalid requests.
default:
return ServiceWorkerStrategy.offlineFirst;
}
}
/// Generates an entry point for a web target. /// Generates an entry point for a web target.
// Keep this in sync with build_runner/resident_web_runner.dart // Keep this in sync with build_runner/resident_web_runner.dart
class WebEntrypointTarget extends Target { class WebEntrypointTarget extends Target {
...@@ -175,7 +161,7 @@ class Dart2JSTarget extends Dart2WebTarget { ...@@ -175,7 +161,7 @@ class Dart2JSTarget extends Dart2WebTarget {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, name); throw MissingDefineException(kBuildMode, name);
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final JsCompilerConfig compilerConfig = JsCompilerConfig.fromBuildSystemEnvironment(environment.defines); final JsCompilerConfig compilerConfig = JsCompilerConfig.fromBuildSystemEnvironment(environment.defines);
final Artifacts artifacts = globals.artifacts!; final Artifacts artifacts = globals.artifacts!;
final String platformBinariesPath = getWebPlatformBinariesDirectory(artifacts, webRenderer).path; final String platformBinariesPath = getWebPlatformBinariesDirectory(artifacts, webRenderer).path;
...@@ -256,7 +242,7 @@ class Dart2WasmTarget extends Dart2WebTarget { ...@@ -256,7 +242,7 @@ class Dart2WasmTarget extends Dart2WebTarget {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, name); throw MissingDefineException(kBuildMode, name);
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final Artifacts artifacts = globals.artifacts!; final Artifacts artifacts = globals.artifacts!;
final File outputWasmFile = environment.buildDir.childFile('main.dart.wasm'); final File outputWasmFile = environment.buildDir.childFile('main.dart.wasm');
final File depFile = environment.buildDir.childFile('dart2wasm.d'); final File depFile = environment.buildDir.childFile('dart2wasm.d');
...@@ -590,9 +576,8 @@ class WebServiceWorker extends Target { ...@@ -590,9 +576,8 @@ class WebServiceWorker extends Target {
final File serviceWorkerFile = environment.outputDir final File serviceWorkerFile = environment.outputDir
.childFile('flutter_service_worker.js'); .childFile('flutter_service_worker.js');
final Depfile depfile = Depfile(contents, <File>[serviceWorkerFile]); final Depfile depfile = Depfile(contents, <File>[serviceWorkerFile]);
final ServiceWorkerStrategy serviceWorkerStrategy = _serviceWorkerStrategyFromString( final ServiceWorkerStrategy serviceWorkerStrategy =
environment.defines[kServiceWorkerStrategy], ServiceWorkerStrategy.fromCliName(environment.defines[kServiceWorkerStrategy]);
);
final String fileGeneratorsPath = final String fileGeneratorsPath =
globals.artifacts!.getArtifactPath(Artifact.flutterToolsFileGenerators); globals.artifacts!.getArtifactPath(Artifact.flutterToolsFileGenerators);
final String serviceWorker = generateServiceWorker( final String serviceWorker = generateServiceWorker(
......
...@@ -56,7 +56,7 @@ class UnpackWindows extends Target { ...@@ -56,7 +56,7 @@ class UnpackWindows extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, name); throw MissingDefineException(kBuildMode, name);
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final String engineSourcePath = environment.artifacts final String engineSourcePath = environment.artifacts
.getArtifactPath( .getArtifactPath(
Artifact.windowsDesktopPath, Artifact.windowsDesktopPath,
...@@ -127,7 +127,7 @@ abstract class BundleWindowsAssets extends Target { ...@@ -127,7 +127,7 @@ abstract class BundleWindowsAssets extends Target {
if (buildModeEnvironment == null) { if (buildModeEnvironment == null) {
throw MissingDefineException(kBuildMode, 'bundle_windows_assets'); throw MissingDefineException(kBuildMode, 'bundle_windows_assets');
} }
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment); final BuildMode buildMode = BuildMode.fromCliName(buildModeEnvironment);
final Directory outputDirectory = environment.outputDir final Directory outputDirectory = environment.outputDir
.childDirectory('flutter_assets'); .childDirectory('flutter_assets');
if (!outputDirectory.existsSync()) { if (!outputDirectory.existsSync()) {
......
...@@ -125,7 +125,7 @@ class BuildAarCommand extends BuildSubCommand { ...@@ -125,7 +125,7 @@ class BuildAarCommand extends BuildSubCommand {
androidBuildInfo.add( androidBuildInfo.add(
AndroidBuildInfo( AndroidBuildInfo(
await getBuildInfo( await getBuildInfo(
forcedBuildMode: BuildMode.fromName(buildMode), forcedBuildMode: BuildMode.fromCliName(buildMode),
forcedTargetFile: targetFile, forcedTargetFile: targetFile,
), ),
targetArchs: targetArchitectures, targetArchs: targetArchitectures,
......
...@@ -139,7 +139,7 @@ class BuildAppBundleCommand extends BuildSubCommand { ...@@ -139,7 +139,7 @@ class BuildAppBundleCommand extends BuildSubCommand {
.childDirectory(component.name) .childDirectory(component.name)
.childDirectory('intermediates') .childDirectory('intermediates')
.childDirectory('flutter') .childDirectory('flutter')
.childDirectory(androidBuildInfo.buildInfo.mode.name) .childDirectory(androidBuildInfo.buildInfo.mode.cliName)
.childDirectory('deferred_libs'); .childDirectory('deferred_libs');
if (deferredLibsIntermediate.existsSync()) { if (deferredLibsIntermediate.existsSync()) {
deferredLibsIntermediate.deleteSync(recursive: true); deferredLibsIntermediate.deleteSync(recursive: true);
......
...@@ -239,8 +239,8 @@ class BuildIOSFrameworkCommand extends BuildFrameworkCommand { ...@@ -239,8 +239,8 @@ class BuildIOSFrameworkCommand extends BuildFrameworkCommand {
displayNullSafetyMode(buildInfos.first); displayNullSafetyMode(buildInfos.first);
for (final BuildInfo buildInfo in buildInfos) { for (final BuildInfo buildInfo in buildInfos) {
final String? productBundleIdentifier = await project.ios.productBundleIdentifier(buildInfo); final String? productBundleIdentifier = await project.ios.productBundleIdentifier(buildInfo);
globals.printStatus('Building frameworks for $productBundleIdentifier in ${getNameForBuildMode(buildInfo.mode)} mode...'); globals.printStatus('Building frameworks for $productBundleIdentifier in ${buildInfo.mode.cliName} mode...');
final String xcodeBuildConfiguration = sentenceCase(getNameForBuildMode(buildInfo.mode)); final String xcodeBuildConfiguration = sentenceCase(buildInfo.mode.cliName);
final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration); final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration);
if (modeDirectory.existsSync()) { if (modeDirectory.existsSync()) {
...@@ -332,7 +332,7 @@ class BuildIOSFrameworkCommand extends BuildFrameworkCommand { ...@@ -332,7 +332,7 @@ class BuildIOSFrameworkCommand extends BuildFrameworkCommand {
throwToolExit('Could not find license at ${license.path}'); throwToolExit('Could not find license at ${license.path}');
} }
final String licenseSource = license.readAsStringSync(); final String licenseSource = license.readAsStringSync();
final String artifactsMode = mode == BuildMode.debug ? 'ios' : 'ios-${mode.name}'; final String artifactsMode = mode == BuildMode.debug ? 'ios' : 'ios-${mode.cliName}';
final String podspecContents = ''' final String podspecContents = '''
Pod::Spec.new do |s| Pod::Spec.new do |s|
...@@ -510,7 +510,7 @@ end ...@@ -510,7 +510,7 @@ end
} }
// Always build debug for simulator. // Always build debug for simulator.
final String simulatorConfiguration = sentenceCase(getNameForBuildMode(BuildMode.debug)); final String simulatorConfiguration = sentenceCase(BuildMode.debug.cliName);
pluginsBuildCommand = <String>[ pluginsBuildCommand = <String>[
...globals.xcode!.xcrunCommand(), ...globals.xcode!.xcrunCommand(),
'xcodebuild', 'xcodebuild',
......
...@@ -72,8 +72,8 @@ class BuildMacOSFrameworkCommand extends BuildFrameworkCommand { ...@@ -72,8 +72,8 @@ class BuildMacOSFrameworkCommand extends BuildFrameworkCommand {
displayNullSafetyMode(buildInfos.first); displayNullSafetyMode(buildInfos.first);
for (final BuildInfo buildInfo in buildInfos) { for (final BuildInfo buildInfo in buildInfos) {
globals.printStatus('Building macOS frameworks in ${getNameForBuildMode(buildInfo.mode)} mode...'); globals.printStatus('Building macOS frameworks in ${buildInfo.mode.cliName} mode...');
final String xcodeBuildConfiguration = sentenceCase(getNameForBuildMode(buildInfo.mode)); final String xcodeBuildConfiguration = sentenceCase(buildInfo.mode.cliName);
final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration); final Directory modeDirectory = outputDirectory.childDirectory(xcodeBuildConfiguration);
if (modeDirectory.existsSync()) { if (modeDirectory.existsSync()) {
...@@ -143,7 +143,7 @@ class BuildMacOSFrameworkCommand extends BuildFrameworkCommand { ...@@ -143,7 +143,7 @@ class BuildMacOSFrameworkCommand extends BuildFrameworkCommand {
throwToolExit('Could not find license at ${license.path}'); throwToolExit('Could not find license at ${license.path}');
} }
final String licenseSource = license.readAsStringSync(); final String licenseSource = license.readAsStringSync();
final String artifactsMode = mode == BuildMode.debug ? 'darwin-x64' : 'darwin-x64-${mode.name}'; final String artifactsMode = mode == BuildMode.debug ? 'darwin-x64' : 'darwin-x64-${mode.cliName}';
final String podspecContents = ''' final String podspecContents = '''
Pod::Spec.new do |s| Pod::Spec.new do |s|
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../build_system/targets/web.dart';
import '../features.dart'; import '../features.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../html_utils.dart'; import '../html_utils.dart';
...@@ -13,6 +13,7 @@ import '../project.dart'; ...@@ -13,6 +13,7 @@ import '../project.dart';
import '../runner/flutter_command.dart' import '../runner/flutter_command.dart'
show DevelopmentArtifact, FlutterCommandResult, FlutterOptions; show DevelopmentArtifact, FlutterCommandResult, FlutterOptions;
import '../web/compile.dart'; import '../web/compile.dart';
import '../web/file_generators/flutter_service_worker_js.dart';
import 'build.dart'; import 'build.dart';
class BuildWebCommand extends BuildSubCommand { class BuildWebCommand extends BuildSubCommand {
...@@ -43,22 +44,12 @@ class BuildWebCommand extends BuildSubCommand { ...@@ -43,22 +44,12 @@ class BuildWebCommand extends BuildSubCommand {
'The value has to start and end with a slash "/". ' 'The value has to start and end with a slash "/". '
'For more information: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base' 'For more information: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base'
); );
argParser.addOption('pwa-strategy', argParser.addOption(
defaultsTo: kOfflineFirst, 'pwa-strategy',
defaultsTo: ServiceWorkerStrategy.offlineFirst.cliName,
help: 'The caching strategy to be used by the PWA service worker.', help: 'The caching strategy to be used by the PWA service worker.',
allowed: <String>[ allowed: ServiceWorkerStrategy.values.map((ServiceWorkerStrategy e) => e.cliName),
kOfflineFirst, allowedHelp: CliEnum.allowedHelp(ServiceWorkerStrategy.values),
kNoneWorker,
],
allowedHelp: <String, String>{
kOfflineFirst: 'Attempt to cache the application shell eagerly and '
'then lazily cache all subsequent assets as they are loaded. When '
'making a network request for an asset, the offline cache will be '
'preferred.',
kNoneWorker: 'Generate a service worker with no body. This is useful for '
'local testing or in cases where the service worker caching functionality '
'is not desirable',
},
); );
usesWebRendererOption(); usesWebRendererOption();
usesWebResourcesCdnFlag(); usesWebResourcesCdnFlag();
...@@ -196,7 +187,7 @@ class BuildWebCommand extends BuildSubCommand { ...@@ -196,7 +187,7 @@ class BuildWebCommand extends BuildSubCommand {
flutterProject, flutterProject,
target, target,
buildInfo, buildInfo,
stringArg('pwa-strategy')!, ServiceWorkerStrategy.fromCliName(stringArg('pwa-strategy')),
compilerConfig: compilerConfig, compilerConfig: compilerConfig,
baseHref: baseHref, baseHref: baseHref,
outputDirectoryPath: outputDirectoryPath, outputDirectoryPath: outputDirectoryPath,
......
...@@ -36,25 +36,10 @@ class CreateCommand extends CreateBase { ...@@ -36,25 +36,10 @@ class CreateCommand extends CreateBase {
argParser.addOption( argParser.addOption(
'template', 'template',
abbr: 't', abbr: 't',
allowed: FlutterProjectType.values.map<String>(flutterProjectTypeToString), allowed: FlutterProjectType.values.map<String>((FlutterProjectType e) => e.cliName),
help: 'Specify the type of project to create.', help: 'Specify the type of project to create.',
valueHelp: 'type', valueHelp: 'type',
allowedHelp: <String, String>{ allowedHelp: CliEnum.allowedHelp(FlutterProjectType.values),
flutterProjectTypeToString(FlutterProjectType.app): '(default) Generate a Flutter application.',
flutterProjectTypeToString(FlutterProjectType.skeleton): 'Generate a List View / Detail View Flutter '
'application that follows community best practices.',
flutterProjectTypeToString(FlutterProjectType.package): 'Generate a shareable Flutter project containing modular '
'Dart code.',
flutterProjectTypeToString(FlutterProjectType.plugin): 'Generate a shareable Flutter project containing an API '
'in Dart code with a platform-specific implementation through method channels for Android, iOS, '
'Linux, macOS, Windows, web, or any combination of these.',
flutterProjectTypeToString(FlutterProjectType.ffiPlugin):
'Generate a shareable Flutter project containing an API '
'in Dart code with a platform-specific implementation through dart:ffi for Android, iOS, '
'Linux, macOS, Windows, or any combination of these.',
flutterProjectTypeToString(FlutterProjectType.module): 'Generate a project to add a Flutter module to an '
'existing Android or iOS application.',
},
); );
argParser.addOption( argParser.addOption(
'sample', 'sample',
...@@ -164,7 +149,7 @@ class CreateCommand extends CreateBase { ...@@ -164,7 +149,7 @@ class CreateCommand extends CreateBase {
final bool metadataExists = projectDir.absolute.childFile('.metadata').existsSync(); final bool metadataExists = projectDir.absolute.childFile('.metadata').existsSync();
final String? templateArgument = stringArg('template'); final String? templateArgument = stringArg('template');
if (templateArgument != null) { if (templateArgument != null) {
template = stringToProjectType(templateArgument); template = FlutterProjectType.fromCliName(templateArgument);
} }
// If the project directory exists and isn't empty, then try to determine the template // If the project directory exists and isn't empty, then try to determine the template
// type from the project directory. // type from the project directory.
...@@ -182,8 +167,8 @@ class CreateCommand extends CreateBase { ...@@ -182,8 +167,8 @@ class CreateCommand extends CreateBase {
if (detectedProjectType != null && template != detectedProjectType && metadataExists) { if (detectedProjectType != null && template != detectedProjectType && metadataExists) {
// We can only be definitive that this is the wrong type if the .metadata file // We can only be definitive that this is the wrong type if the .metadata file
// exists and contains a type that doesn't match. // exists and contains a type that doesn't match.
throwToolExit("The requested template type '${flutterProjectTypeToString(template)}' doesn't match the " throwToolExit("The requested template type '${template.cliName}' doesn't match the "
"existing template type of '${flutterProjectTypeToString(detectedProjectType)}'."); "existing template type of '${detectedProjectType.cliName}'.");
} }
return template; return template;
} }
...@@ -210,9 +195,9 @@ class CreateCommand extends CreateBase { ...@@ -210,9 +195,9 @@ class CreateCommand extends CreateBase {
final bool emptyArgument = boolArg('empty'); final bool emptyArgument = boolArg('empty');
if (sampleArgument != null) { if (sampleArgument != null) {
final String? templateArgument = stringArg('template'); final String? templateArgument = stringArg('template');
if (templateArgument != null && stringToProjectType(templateArgument) != FlutterProjectType.app) { if (templateArgument != null && FlutterProjectType.fromCliName(templateArgument) != FlutterProjectType.app) {
throwToolExit('Cannot specify --sample with a project type other than ' throwToolExit('Cannot specify --sample with a project type other than '
'"${flutterProjectTypeToString(FlutterProjectType.app)}"'); '"${FlutterProjectType.app.cliName}"');
} }
// Fetch the sample from the server. // Fetch the sample from the server.
sampleCode = await _fetchSampleFromServer(sampleArgument); sampleCode = await _fetchSampleFromServer(sampleArgument);
...@@ -221,7 +206,7 @@ class CreateCommand extends CreateBase { ...@@ -221,7 +206,7 @@ class CreateCommand extends CreateBase {
final FlutterProjectType template = _getProjectType(projectDir); final FlutterProjectType template = _getProjectType(projectDir);
final bool generateModule = template == FlutterProjectType.module; final bool generateModule = template == FlutterProjectType.module;
final bool generateMethodChannelsPlugin = template == FlutterProjectType.plugin; final bool generateMethodChannelsPlugin = template == FlutterProjectType.plugin;
final bool generateFfiPlugin = template == FlutterProjectType.ffiPlugin; final bool generateFfiPlugin = template == FlutterProjectType.pluginFfi;
final bool generatePackage = template == FlutterProjectType.package; final bool generatePackage = template == FlutterProjectType.package;
final List<String> platforms = stringsArg('platforms'); final List<String> platforms = stringsArg('platforms');
...@@ -391,7 +376,7 @@ class CreateCommand extends CreateBase { ...@@ -391,7 +376,7 @@ class CreateCommand extends CreateBase {
projectType: template, projectType: template,
); );
pubContext = PubContext.createPlugin; pubContext = PubContext.createPlugin;
case FlutterProjectType.ffiPlugin: case FlutterProjectType.pluginFfi:
generatedFileCount += await _generateFfiPlugin( generatedFileCount += await _generateFfiPlugin(
relativeDir, relativeDir,
templateContext, templateContext,
......
...@@ -954,7 +954,7 @@ class DeviceDomain extends Domain { ...@@ -954,7 +954,7 @@ class DeviceDomain extends Domain {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
final String buildMode = _getStringArg(args, 'buildMode', required: true)!; final String buildMode = _getStringArg(args, 'buildMode', required: true)!;
return await device.supportsRuntimeMode(getBuildModeForName(buildMode)); return await device.supportsRuntimeMode(BuildMode.fromCliName(buildMode));
} }
/// Creates an application package from a file in the temp directory. /// Creates an application package from a file in the temp directory.
......
...@@ -17,10 +17,12 @@ import '../base/io.dart'; ...@@ -17,10 +17,12 @@ import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../base/signals.dart'; import '../base/signals.dart';
import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../device.dart'; import '../device.dart';
import '../drive/drive_service.dart'; import '../drive/drive_service.dart';
import '../drive/web_driver_service.dart' show Browser;
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../ios/devices.dart'; import '../ios/devices.dart';
import '../resident_runner.dart'; import '../resident_runner.dart';
...@@ -111,25 +113,12 @@ class DriveCommand extends RunCommandBase { ...@@ -111,25 +113,12 @@ class DriveCommand extends RunCommandBase {
defaultsTo: true, defaultsTo: true,
help: 'Whether the driver browser is going to be launched in headless mode.', help: 'Whether the driver browser is going to be launched in headless mode.',
) )
..addOption('browser-name', ..addOption(
defaultsTo: 'chrome', 'browser-name',
defaultsTo: Browser.chrome.cliName,
help: 'Name of the browser where tests will be executed.', help: 'Name of the browser where tests will be executed.',
allowed: <String>[ allowed: Browser.values.map((Browser e) => e.cliName),
'android-chrome', allowedHelp: CliEnum.allowedHelp(Browser.values),
'chrome',
'edge',
'firefox',
'ios-safari',
'safari',
],
allowedHelp: <String, String>{
'android-chrome': 'Chrome on Android (see also "--android-emulator").',
'chrome': 'Google Chrome on this computer (see also "--chrome-binary").',
'edge': 'Microsoft Edge on this computer (Windows only).',
'firefox': 'Mozilla Firefox on this computer.',
'ios-safari': 'Apple Safari on an iOS device.',
'safari': 'Apple Safari on this computer (macOS only).',
},
) )
..addOption('browser-dimension', ..addOption('browser-dimension',
defaultsTo: '1600,1024', defaultsTo: '1600,1024',
......
...@@ -774,7 +774,7 @@ class RunCommand extends RunCommandBase { ...@@ -774,7 +774,7 @@ class RunCommand extends RunCommandBase {
ExitStatus.success, ExitStatus.success,
timingLabelParts: <String?>[ timingLabelParts: <String?>[
if (hotMode) 'hot' else 'cold', if (hotMode) 'hot' else 'cold',
getModeName(getBuildMode()), getBuildMode().cliName,
if (devices!.length == 1) if (devices!.length == 1)
getNameForTargetPlatform(await devices![0].targetPlatform) getNameForTargetPlatform(await devices![0].targetPlatform)
else else
......
...@@ -165,37 +165,33 @@ class StdoutHandler { ...@@ -165,37 +165,33 @@ class StdoutHandler {
} }
/// List the preconfigured build options for a given build mode. /// List the preconfigured build options for a given build mode.
List<String> buildModeOptions(BuildMode mode, List<String> dartDefines) { List<String> buildModeOptions(BuildMode mode, List<String> dartDefines) =>
switch (mode) { switch (mode) {
case BuildMode.debug: BuildMode.debug => <String>[
return <String>[ // These checks allow the CLI to override the value of this define for unit
// These checks allow the CLI to override the value of this define for unit // testing the framework.
// testing the framework. if (!dartDefines.any((String define) => define.startsWith('dart.vm.profile')))
if (!dartDefines.any((String define) => define.startsWith('dart.vm.profile'))) '-Ddart.vm.profile=false',
if (!dartDefines.any((String define) => define.startsWith('dart.vm.product')))
'-Ddart.vm.product=false',
'--enable-asserts',
],
BuildMode.profile => <String>[
// These checks allow the CLI to override the value of this define for
// benchmarks with most timeline traces disabled.
if (!dartDefines.any((String define) => define.startsWith('dart.vm.profile')))
'-Ddart.vm.profile=true',
if (!dartDefines.any((String define) => define.startsWith('dart.vm.product')))
'-Ddart.vm.product=false',
...kDartCompilerExperiments,
],
BuildMode.release => <String>[
'-Ddart.vm.profile=false', '-Ddart.vm.profile=false',
if (!dartDefines.any((String define) => define.startsWith('dart.vm.product'))) '-Ddart.vm.product=true',
'-Ddart.vm.product=false', ...kDartCompilerExperiments,
'--enable-asserts', ],
]; _ => throw Exception('Unknown BuildMode: $mode')
case BuildMode.profile: };
return <String>[
// These checks allow the CLI to override the value of this define for
// benchmarks with most timeline traces disabled.
if (!dartDefines.any((String define) => define.startsWith('dart.vm.profile')))
'-Ddart.vm.profile=true',
if (!dartDefines.any((String define) => define.startsWith('dart.vm.product')))
'-Ddart.vm.product=false',
...kDartCompilerExperiments,
];
case BuildMode.release:
return <String>[
'-Ddart.vm.profile=false',
'-Ddart.vm.product=true',
...kDartCompilerExperiments,
];
}
throw Exception('Unknown BuildMode: $mode');
}
/// A compiler interface for producing single (non-incremental) kernel files. /// A compiler interface for producing single (non-incremental) kernel files.
class KernelCompiler { class KernelCompiler {
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
...@@ -16,6 +14,7 @@ import '../base/common.dart'; ...@@ -16,6 +14,7 @@ import '../base/common.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../convert.dart'; import '../convert.dart';
import '../device.dart'; import '../device.dart';
...@@ -140,7 +139,7 @@ class WebDriverService extends DriverService { ...@@ -140,7 +139,7 @@ class WebDriverService extends DriverService {
String? profileMemory, String? profileMemory,
}) async { }) async {
late async_io.WebDriver webDriver; late async_io.WebDriver webDriver;
final Browser browser = _browserNameToEnum(browserName); final Browser browser = Browser.fromCliName(browserName);
try { try {
webDriver = await async_io.createDriver( webDriver = await async_io.createDriver(
uri: Uri.parse('http://localhost:$driverPort/'), uri: Uri.parse('http://localhost:$driverPort/'),
...@@ -211,9 +210,9 @@ class WebDriverService extends DriverService { ...@@ -211,9 +210,9 @@ class WebDriverService extends DriverService {
'DRIVER_SESSION_URI': webDriver.uri.toString(), 'DRIVER_SESSION_URI': webDriver.uri.toString(),
'DRIVER_SESSION_SPEC': webDriver.spec.toString(), 'DRIVER_SESSION_SPEC': webDriver.spec.toString(),
'DRIVER_SESSION_CAPABILITIES': json.encode(webDriver.capabilities), 'DRIVER_SESSION_CAPABILITIES': json.encode(webDriver.capabilities),
'SUPPORT_TIMELINE_ACTION': (_browserNameToEnum(browserName) == Browser.chrome).toString(), 'SUPPORT_TIMELINE_ACTION': (Browser.fromCliName(browserName) == Browser.chrome).toString(),
'FLUTTER_WEB_TEST': 'true', 'FLUTTER_WEB_TEST': 'true',
'ANDROID_CHROME_ON_EMULATOR': (_browserNameToEnum(browserName) == Browser.androidChrome && androidEmulator!).toString(), 'ANDROID_CHROME_ON_EMULATOR': (Browser.fromCliName(browserName) == Browser.androidChrome && androidEmulator!).toString(),
}; };
} }
...@@ -224,19 +223,42 @@ class WebDriverService extends DriverService { ...@@ -224,19 +223,42 @@ class WebDriverService extends DriverService {
} }
/// A list of supported browsers. /// A list of supported browsers.
enum Browser { enum Browser implements CliEnum {
/// Chrome on Android: https://developer.chrome.com/multidevice/android/overview /// Chrome on Android: https://developer.chrome.com/docs/multidevice/android/
androidChrome, androidChrome,
/// Chrome: https://www.google.com/chrome/ /// Chrome: https://www.google.com/chrome/
chrome, chrome,
/// Edge: https://www.microsoft.com/en-us/windows/microsoft-edge
/// Edge: https://www.microsoft.com/edge
edge, edge,
/// Firefox: https://www.mozilla.org/en-US/firefox/ /// Firefox: https://www.mozilla.org/en-US/firefox/
firefox, firefox,
/// Safari in iOS: https://www.apple.com/safari/ /// Safari in iOS: https://www.apple.com/safari/
iosSafari, iosSafari,
/// Safari in macOS: https://www.apple.com/safari/ /// Safari in macOS: https://www.apple.com/safari/
safari, safari;
@override
String get helpText => switch (this) {
Browser.androidChrome => 'Chrome on Android (see also "--android-emulator").',
Browser.chrome => 'Google Chrome on this computer (see also "--chrome-binary").',
Browser.edge => 'Microsoft Edge on this computer (Windows only).',
Browser.firefox => 'Mozilla Firefox on this computer.',
Browser.iosSafari => 'Apple Safari on an iOS device.',
Browser.safari => 'Apple Safari on this computer (macOS only).',
};
@override
String get cliName => snakeCase(name, '-');
static Browser fromCliName(String? value) => Browser.values.singleWhere(
(Browser element) => element.cliName == value,
orElse: () => throw UnsupportedError('Browser $value not supported'),
);
} }
/// Returns desired capabilities for given [browser], [headless], [chromeBinary] /// Returns desired capabilities for given [browser], [headless], [chromeBinary]
...@@ -247,102 +269,80 @@ Map<String, dynamic> getDesiredCapabilities( ...@@ -247,102 +269,80 @@ Map<String, dynamic> getDesiredCapabilities(
bool? headless, { bool? headless, {
List<String> webBrowserFlags = const <String>[], List<String> webBrowserFlags = const <String>[],
String? chromeBinary, String? chromeBinary,
}) { }) =>
switch (browser) { switch (browser) {
case Browser.chrome: Browser.chrome => <String, dynamic>{
return <String, dynamic>{ 'acceptInsecureCerts': true,
'acceptInsecureCerts': true, 'browserName': 'chrome',
'browserName': 'chrome', 'goog:loggingPrefs': <String, String>{
'goog:loggingPrefs': <String, String>{ async_io.LogType.browser: 'INFO',
async_io.LogType.browser: 'INFO', async_io.LogType.performance: 'ALL',
async_io.LogType.performance: 'ALL', },
}, 'goog:chromeOptions': <String, dynamic>{
'goog:chromeOptions': <String, dynamic>{ if (chromeBinary != null) 'binary': chromeBinary,
if (chromeBinary != null) 'w3c': true,
'binary': chromeBinary, 'args': <String>[
'w3c': true, '--bwsi',
'args': <String>[ '--disable-background-timer-throttling',
'--bwsi', '--disable-default-apps',
'--disable-background-timer-throttling', '--disable-extensions',
'--disable-default-apps', '--disable-popup-blocking',
'--disable-extensions', '--disable-translate',
'--disable-popup-blocking', '--no-default-browser-check',
'--disable-translate', '--no-sandbox',
'--no-default-browser-check', '--no-first-run',
'--no-sandbox', if (headless!) '--headless',
'--no-first-run', ...webBrowserFlags,
if (headless!) '--headless', ],
...webBrowserFlags, 'perfLoggingPrefs': <String, String>{
], 'traceCategories': 'devtools.timeline,'
'perfLoggingPrefs': <String, String>{ 'v8,blink.console,benchmark,blink,'
'traceCategories': 'blink.user_timing',
'devtools.timeline,' },
'v8,blink.console,benchmark,blink,'
'blink.user_timing',
}, },
}, },
}; Browser.firefox => <String, dynamic>{
case Browser.firefox: 'acceptInsecureCerts': true,
return <String, dynamic>{ 'browserName': 'firefox',
'acceptInsecureCerts': true, 'moz:firefoxOptions': <String, dynamic>{
'browserName': 'firefox', 'args': <String>[
'moz:firefoxOptions' : <String, dynamic>{ if (headless!) '-headless',
'args': <String>[ ...webBrowserFlags,
if (headless!) '-headless', ],
...webBrowserFlags, 'prefs': <String, dynamic>{
], 'dom.file.createInChild': true,
'prefs': <String, dynamic>{ 'dom.timeout.background_throttling_max_budget': -1,
'dom.file.createInChild': true, 'media.autoplay.default': 0,
'dom.timeout.background_throttling_max_budget': -1, 'media.gmp-manager.url': '',
'media.autoplay.default': 0, 'media.gmp-provider.enabled': false,
'media.gmp-manager.url': '', 'network.captive-portal-service.enabled': false,
'media.gmp-provider.enabled': false, 'security.insecure_field_warning.contextual.enabled': false,
'network.captive-portal-service.enabled': false, 'test.currentTimeOffsetSeconds': 11491200,
'security.insecure_field_warning.contextual.enabled': false, },
'test.currentTimeOffsetSeconds': 11491200, 'log': <String, String>{'level': 'trace'},
}, },
'log': <String, String>{'level': 'trace'},
}, },
}; Browser.edge => <String, dynamic>{
case Browser.edge: 'acceptInsecureCerts': true,
return <String, dynamic>{ 'browserName': 'edge',
'acceptInsecureCerts': true,
'browserName': 'edge',
};
case Browser.safari:
return <String, dynamic>{
'browserName': 'safari',
};
case Browser.iosSafari:
return <String, dynamic>{
'platformName': 'ios',
'browserName': 'safari',
'safari:useSimulator': true,
};
case Browser.androidChrome:
return <String, dynamic>{
'browserName': 'chrome',
'platformName': 'android',
'goog:chromeOptions': <String, dynamic>{
'androidPackage': 'com.android.chrome',
'args': <String>[
'--disable-fullscreen',
...webBrowserFlags,
],
}, },
}; Browser.safari => <String, dynamic>{
} 'browserName': 'safari',
} },
Browser.iosSafari => <String, dynamic>{
/// Converts [browserName] string to [Browser] 'platformName': 'ios',
Browser _browserNameToEnum(String? browserName) { 'browserName': 'safari',
switch (browserName) { 'safari:useSimulator': true,
case 'android-chrome': return Browser.androidChrome; },
case 'chrome': return Browser.chrome; Browser.androidChrome => <String, dynamic>{
case 'edge': return Browser.edge; 'browserName': 'chrome',
case 'firefox': return Browser.firefox; 'platformName': 'android',
case 'ios-safari': return Browser.iosSafari; 'goog:chromeOptions': <String, dynamic>{
case 'safari': return Browser.safari; 'androidPackage': 'com.android.chrome',
} 'args': <String>[
throw UnsupportedError('Browser $browserName not supported'); '--disable-fullscreen',
} ...webBrowserFlags,
],
},
},
};
...@@ -10,44 +10,59 @@ import 'base/utils.dart'; ...@@ -10,44 +10,59 @@ import 'base/utils.dart';
import 'project.dart'; import 'project.dart';
import 'version.dart'; import 'version.dart';
enum FlutterProjectType { enum FlutterProjectType implements CliEnum {
/// This is the default project with the user-managed host code. /// This is the default project with the user-managed host code.
/// It is different than the "module" template in that it exposes and doesn't /// It is different than the "module" template in that it exposes and doesn't
/// manage the platform code. /// manage the platform code.
app, app,
/// A List/Detail app template that follows community best practices. /// A List/Detail app template that follows community best practices.
skeleton, skeleton,
/// The is a project that has managed platform host code. It is an application with /// The is a project that has managed platform host code. It is an application with
/// ephemeral .ios and .android directories that can be updated automatically. /// ephemeral .ios and .android directories that can be updated automatically.
module, module,
/// This is a Flutter Dart package project. It doesn't have any native /// This is a Flutter Dart package project. It doesn't have any native
/// components, only Dart. /// components, only Dart.
package, package,
/// This is a native plugin project. /// This is a native plugin project.
plugin, plugin,
/// This is an FFI native plugin project. /// This is an FFI native plugin project.
ffiPlugin, pluginFfi;
}
String flutterProjectTypeToString(FlutterProjectType? type) { @override
if (type == null) { String get cliName => snakeCase(name);
return '';
}
if (type == FlutterProjectType.ffiPlugin) {
return 'plugin_ffi';
}
return getEnumName(type);
}
FlutterProjectType? stringToProjectType(String value) { @override
FlutterProjectType? result; String get helpText => switch (this) {
for (final FlutterProjectType type in FlutterProjectType.values) { FlutterProjectType.app => '(default) Generate a Flutter application.',
if (value == flutterProjectTypeToString(type)) { FlutterProjectType.skeleton =>
result = type; 'Generate a List View / Detail View Flutter application that follows community best practices.',
break; FlutterProjectType.package =>
'Generate a shareable Flutter project containing modular Dart code.',
FlutterProjectType.plugin =>
'Generate a shareable Flutter project containing an API '
'in Dart code with a platform-specific implementation through method channels for Android, iOS, '
'Linux, macOS, Windows, web, or any combination of these.',
FlutterProjectType.pluginFfi =>
'Generate a shareable Flutter project containing an API '
'in Dart code with a platform-specific implementation through dart:ffi for Android, iOS, '
'Linux, macOS, Windows, or any combination of these.',
FlutterProjectType.module =>
'Generate a project to add a Flutter module to an existing Android or iOS application.',
};
static FlutterProjectType? fromCliName(String value) {
for (final FlutterProjectType type in FlutterProjectType.values) {
if (value == type.cliName) {
return type;
}
} }
return null;
} }
return result;
} }
/// Verifies the expected yaml keys are present in the file. /// Verifies the expected yaml keys are present in the file.
...@@ -100,7 +115,7 @@ class FlutterProjectMetadata { ...@@ -100,7 +115,7 @@ class FlutterProjectMetadata {
} }
} }
if (_validateMetadataMap(yamlRoot, <String, Type>{'project_type': String}, _logger)) { if (_validateMetadataMap(yamlRoot, <String, Type>{'project_type': String}, _logger)) {
_projectType = stringToProjectType(yamlRoot['project_type'] as String); _projectType = FlutterProjectType.fromCliName(yamlRoot['project_type'] as String);
} }
final Object? migrationYaml = yamlRoot['migration']; final Object? migrationYaml = yamlRoot['migration'];
if (migrationYaml is YamlMap) { if (migrationYaml is YamlMap) {
...@@ -163,7 +178,7 @@ version: ...@@ -163,7 +178,7 @@ version:
revision: $_versionRevision revision: $_versionRevision
channel: $_versionChannel channel: $_versionChannel
project_type: ${flutterProjectTypeToString(projectType)} project_type: ${projectType == null ? '' : projectType!.cliName}
${migrateConfig.getOutputFileString()}'''; ${migrateConfig.getOutputFileString()}''';
} }
......
...@@ -22,7 +22,6 @@ import '../base/terminal.dart'; ...@@ -22,7 +22,6 @@ import '../base/terminal.dart';
import '../base/time.dart'; import '../base/time.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../build_system/targets/web.dart';
import '../cache.dart'; import '../cache.dart';
import '../dart/language_version.dart'; import '../dart/language_version.dart';
import '../devfs.dart'; import '../devfs.dart';
...@@ -37,6 +36,7 @@ import '../run_hot.dart'; ...@@ -37,6 +36,7 @@ import '../run_hot.dart';
import '../vmservice.dart'; import '../vmservice.dart';
import '../web/chrome.dart'; import '../web/chrome.dart';
import '../web/compile.dart'; import '../web/compile.dart';
import '../web/file_generators/flutter_service_worker_js.dart';
import '../web/file_generators/main_dart.dart' as main_dart; import '../web/file_generators/main_dart.dart' as main_dart;
import '../web/web_device.dart'; import '../web/web_device.dart';
import '../web/web_runner.dart'; import '../web/web_runner.dart';
...@@ -326,7 +326,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). ...@@ -326,7 +326,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
flutterProject, flutterProject,
target, target,
debuggingOptions.buildInfo, debuggingOptions.buildInfo,
kNoneWorker, ServiceWorkerStrategy.none,
compilerConfig: JsCompilerConfig.run(nativeNullAssertions: debuggingOptions.nativeNullAssertions) compilerConfig: JsCompilerConfig.run(nativeNullAssertions: debuggingOptions.nativeNullAssertions)
); );
} }
...@@ -404,7 +404,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). ...@@ -404,7 +404,7 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
flutterProject, flutterProject,
target, target,
debuggingOptions.buildInfo, debuggingOptions.buildInfo,
kNoneWorker, ServiceWorkerStrategy.none,
compilerConfig: JsCompilerConfig.run(nativeNullAssertions: debuggingOptions.nativeNullAssertions), compilerConfig: JsCompilerConfig.run(nativeNullAssertions: debuggingOptions.nativeNullAssertions),
); );
} on ToolExit { } on ToolExit {
......
...@@ -59,7 +59,7 @@ class BuildableLinuxApp extends LinuxApp { ...@@ -59,7 +59,7 @@ class BuildableLinuxApp extends LinuxApp {
final String? binaryName = getCmakeExecutableName(project); final String? binaryName = getCmakeExecutableName(project);
return globals.fs.path.join( return globals.fs.path.join(
getLinuxBuildDirectory(), getLinuxBuildDirectory(),
getNameForBuildMode(buildMode), buildMode.cliName,
'bundle', 'bundle',
binaryName, binaryName,
); );
......
...@@ -67,7 +67,7 @@ Future<void> buildLinux( ...@@ -67,7 +67,7 @@ Future<void> buildLinux(
'Building Linux application...', 'Building Linux application...',
); );
try { try {
final String buildModeName = getNameForBuildMode(buildInfo.mode); final String buildModeName = buildInfo.mode.cliName;
final Directory buildDirectory = final Directory buildDirectory =
globals.fs.directory(getLinuxBuildDirectory(targetPlatform)).childDirectory(buildModeName); globals.fs.directory(getLinuxBuildDirectory(targetPlatform)).childDirectory(buildModeName);
await _runCmake(buildModeName, linuxProject.cmakeFile.parent, buildDirectory, await _runCmake(buildModeName, linuxProject.cmakeFile.parent, buildDirectory,
......
...@@ -172,7 +172,7 @@ class BuildableMacOSApp extends MacOSApp { ...@@ -172,7 +172,7 @@ class BuildableMacOSApp extends MacOSApp {
} }
String bundleDirectory(BuildInfo buildInfo) { String bundleDirectory(BuildInfo buildInfo) {
return sentenceCase(buildInfo.mode.name) + (buildInfo.flavor != null return sentenceCase(buildInfo.mode.cliName) + (buildInfo.flavor != null
? ' ${sentenceCase(buildInfo.flavor!)}' ? ' ${sentenceCase(buildInfo.flavor!)}'
: ''); : '');
} }
......
...@@ -131,7 +131,7 @@ ${_projectMetadataInformation()} ...@@ -131,7 +131,7 @@ ${_projectMetadataInformation()}
final FlutterProjectMetadata metadata = FlutterProjectMetadata(project.metadataFile, _logger); final FlutterProjectMetadata metadata = FlutterProjectMetadata(project.metadataFile, _logger);
final FlutterProjectType? projectType = metadata.projectType; final FlutterProjectType? projectType = metadata.projectType;
final StringBuffer description = StringBuffer() final StringBuffer description = StringBuffer()
..writeln('**Type**: ${projectType == null ? 'malformed' : flutterProjectTypeToString(projectType)}') ..writeln('**Type**: ${projectType == null ? 'malformed' : projectType.cliName}')
..writeln('**Version**: ${manifest.appVersion}') ..writeln('**Version**: ${manifest.appVersion}')
..writeln('**Material**: ${manifest.usesMaterialDesign}') ..writeln('**Material**: ${manifest.usesMaterialDesign}')
..writeln('**Android X**: ${manifest.usesAndroidX}') ..writeln('**Android X**: ${manifest.usesAndroidX}')
......
...@@ -82,18 +82,7 @@ class FlutterCommandResult { ...@@ -82,18 +82,7 @@ class FlutterCommandResult {
final DateTime? endTimeOverride; final DateTime? endTimeOverride;
@override @override
String toString() { String toString() => exitStatus.name;
switch (exitStatus) {
case ExitStatus.success:
return 'success';
case ExitStatus.warning:
return 'warning';
case ExitStatus.fail:
return 'fail';
case ExitStatus.killed:
return 'killed';
}
}
} }
/// Common flutter command line options. /// Common flutter command line options.
...@@ -130,7 +119,7 @@ abstract final class FlutterOptions { ...@@ -130,7 +119,7 @@ abstract final class FlutterOptions {
} }
/// flutter command categories for usage. /// flutter command categories for usage.
class FlutterCommandCategory { abstract final class FlutterCommandCategory {
static const String sdk = 'Flutter SDK'; static const String sdk = 'Flutter SDK';
static const String project = 'Project'; static const String project = 'Project';
static const String tools = 'Tools & Devices'; static const String tools = 'Tools & Devices';
...@@ -641,7 +630,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -641,7 +630,7 @@ abstract class FlutterCommand extends Command<void> {
defaultsTo: WebRendererMode.auto.name, defaultsTo: WebRendererMode.auto.name,
allowed: WebRendererMode.values.map((WebRendererMode e) => e.name), allowed: WebRendererMode.values.map((WebRendererMode e) => e.name),
help: 'The renderer implementation to use when building for the web.', help: 'The renderer implementation to use when building for the web.',
allowedHelp: Map<String, String>.fromEntries(WebRendererMode.values.map((WebRendererMode e) => MapEntry<String, String>(e.name, e.helpText))) allowedHelp: CliEnum.allowedHelp(WebRendererMode.values)
); );
} }
...@@ -1422,7 +1411,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -1422,7 +1411,7 @@ abstract class FlutterCommand extends Command<void> {
// Send timing. // Send timing.
final List<String?> labels = <String?>[ final List<String?> labels = <String?>[
getEnumName(commandResult.exitStatus), commandResult.exitStatus.name,
if (commandResult.timingLabelParts?.isNotEmpty ?? false) if (commandResult.timingLabelParts?.isNotEmpty ?? false)
...?commandResult.timingLabelParts, ...?commandResult.timingLabelParts,
]; ];
......
...@@ -9,6 +9,7 @@ import '../base/common.dart'; ...@@ -9,6 +9,7 @@ import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/project_migrator.dart'; import '../base/project_migrator.dart';
import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../build_system/build_system.dart'; import '../build_system/build_system.dart';
import '../build_system/targets/web.dart'; import '../build_system/targets/web.dart';
...@@ -21,6 +22,7 @@ import '../project.dart'; ...@@ -21,6 +22,7 @@ import '../project.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../version.dart'; import '../version.dart';
import 'compiler_config.dart'; import 'compiler_config.dart';
import 'file_generators/flutter_service_worker_js.dart';
import 'migrations/scrub_generated_plugin_registrant.dart'; import 'migrations/scrub_generated_plugin_registrant.dart';
export 'compiler_config.dart'; export 'compiler_config.dart';
...@@ -51,7 +53,7 @@ class WebBuilder { ...@@ -51,7 +53,7 @@ class WebBuilder {
FlutterProject flutterProject, FlutterProject flutterProject,
String target, String target,
BuildInfo buildInfo, BuildInfo buildInfo,
String serviceWorkerStrategy, { ServiceWorkerStrategy serviceWorkerStrategy, {
required WebCompilerConfig compilerConfig, required WebCompilerConfig compilerConfig,
String? baseHref, String? baseHref,
String? outputDirectoryPath, String? outputDirectoryPath,
...@@ -93,7 +95,7 @@ class WebBuilder { ...@@ -93,7 +95,7 @@ class WebBuilder {
kTargetFile: target, kTargetFile: target,
kHasWebPlugins: hasWebPlugins.toString(), kHasWebPlugins: hasWebPlugins.toString(),
if (baseHref != null) kBaseHref: baseHref, if (baseHref != null) kBaseHref: baseHref,
kServiceWorkerStrategy: serviceWorkerStrategy, kServiceWorkerStrategy: serviceWorkerStrategy.cliName,
...compilerConfig.toBuildSystemEnvironment(), ...compilerConfig.toBuildSystemEnvironment(),
...buildInfo.toBuildSystemEnvironment(), ...buildInfo.toBuildSystemEnvironment(),
}, },
...@@ -133,7 +135,7 @@ class WebBuilder { ...@@ -133,7 +135,7 @@ class WebBuilder {
} }
/// Web rendering backend mode. /// Web rendering backend mode.
enum WebRendererMode { enum WebRendererMode implements CliEnum {
/// Auto detects which rendering backend to use. /// Auto detects which rendering backend to use.
auto, auto,
...@@ -146,6 +148,10 @@ enum WebRendererMode { ...@@ -146,6 +148,10 @@ enum WebRendererMode {
/// Always use skwasm. /// Always use skwasm.
skwasm; skwasm;
@override
String get cliName => snakeCase(name, '-');
@override
String get helpText => switch (this) { String get helpText => switch (this) {
auto => auto =>
'Use the HTML renderer on mobile devices, and CanvasKit on desktop devices.', 'Use the HTML renderer on mobile devices, and CanvasKit on desktop devices.',
......
...@@ -2,16 +2,41 @@ ...@@ -2,16 +2,41 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import '../../base/utils.dart';
import '../../globals.dart' as globals; import '../../globals.dart' as globals;
/// The caching strategy for the generated service worker. /// The caching strategy for the generated service worker.
enum ServiceWorkerStrategy { enum ServiceWorkerStrategy implements CliEnum {
/// Download the app shell eagerly and all other assets lazily. /// Download the app shell eagerly and all other assets lazily.
/// Prefer the offline cached version. /// Prefer the offline cached version.
offlineFirst, offlineFirst,
/// Do not generate a service worker, /// Do not generate a service worker,
none, none;
@override
String get cliName => snakeCase(name, '-');
static ServiceWorkerStrategy fromCliName(String? value) => value == null
? ServiceWorkerStrategy.offlineFirst
: values.singleWhere(
(ServiceWorkerStrategy element) => element.cliName == value,
orElse: () =>
throw ArgumentError.value(value, 'value', 'Not supported.'),
);
@override
String get helpText => switch (this) {
ServiceWorkerStrategy.offlineFirst =>
'Attempt to cache the application shell eagerly and then lazily '
'cache all subsequent assets as they are loaded. When making a '
'network request for an asset, the offline cache will be '
'preferred.',
ServiceWorkerStrategy.none =>
'Generate a service worker with no body. This is useful for local '
'testing or in cases where the service worker caching '
'functionality is not desirable'
};
} }
/// Generate a service worker with an app-specific cache name a map of /// Generate a service worker with an app-specific cache name a map of
......
...@@ -113,7 +113,7 @@ class BuildableWindowsApp extends WindowsApp { ...@@ -113,7 +113,7 @@ class BuildableWindowsApp extends WindowsApp {
return globals.fs.path.join( return globals.fs.path.join(
getWindowsBuildDirectory(), getWindowsBuildDirectory(),
'runner', 'runner',
sentenceCase(getNameForBuildMode(buildMode)), sentenceCase(buildMode.cliName),
'$binaryName.exe', '$binaryName.exe',
); );
} }
......
...@@ -76,7 +76,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -76,7 +76,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
'Please run `flutter doctor` for more details.'); 'Please run `flutter doctor` for more details.');
} }
final String buildModeName = getNameForBuildMode(buildInfo.mode); final String buildModeName = buildInfo.mode.cliName;
final Directory buildDirectory = globals.fs.directory(getWindowsBuildDirectory()); final Directory buildDirectory = globals.fs.directory(getWindowsBuildDirectory());
final Status status = globals.logger.startProgress( final Status status = globals.logger.startProgress(
'Building Windows application...', 'Building Windows application...',
......
...@@ -74,11 +74,11 @@ void main() { ...@@ -74,11 +74,11 @@ void main() {
expect(BuildMode.jitRelease.isPrecompiled, false); expect(BuildMode.jitRelease.isPrecompiled, false);
expect(BuildMode.jitRelease.isJit, true); expect(BuildMode.jitRelease.isJit, true);
expect(BuildMode.fromName('debug'), BuildMode.debug); expect(BuildMode.fromCliName('debug'), BuildMode.debug);
expect(BuildMode.fromName('profile'), BuildMode.profile); expect(BuildMode.fromCliName('profile'), BuildMode.profile);
expect(BuildMode.fromName('jit_release'), BuildMode.jitRelease); expect(BuildMode.fromCliName('jit_release'), BuildMode.jitRelease);
expect(BuildMode.fromName('release'), BuildMode.release); expect(BuildMode.fromCliName('release'), BuildMode.release);
expect(() => BuildMode.fromName('foo'), throwsArgumentError); expect(() => BuildMode.fromCliName('foo'), throwsArgumentError);
}); });
}); });
......
...@@ -39,7 +39,7 @@ void main() { ...@@ -39,7 +39,7 @@ void main() {
androidEnvironment = Environment.test( androidEnvironment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
defines: <String, String>{ defines: <String, String>{
kBuildMode: getNameForBuildMode(BuildMode.profile), kBuildMode: BuildMode.profile.cliName,
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm), kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
}, },
inputs: <String, String>{}, inputs: <String, String>{},
...@@ -52,7 +52,7 @@ void main() { ...@@ -52,7 +52,7 @@ void main() {
iosEnvironment = Environment.test( iosEnvironment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
defines: <String, String>{ defines: <String, String>{
kBuildMode: getNameForBuildMode(BuildMode.profile), kBuildMode: BuildMode.profile.cliName,
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios), kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
}, },
inputs: <String, String>{}, inputs: <String, String>{},
...@@ -266,7 +266,7 @@ void main() { ...@@ -266,7 +266,7 @@ void main() {
]); ]);
await const KernelSnapshot().build(androidEnvironment await const KernelSnapshot().build(androidEnvironment
..defines[kBuildMode] = getNameForBuildMode(BuildMode.debug) ..defines[kBuildMode] = BuildMode.debug.cliName
..defines[kTrackWidgetCreation] = 'false'); ..defines[kTrackWidgetCreation] = 'false');
expect(processManager, hasNoRemainingExpectations); expect(processManager, hasNoRemainingExpectations);
...@@ -308,7 +308,7 @@ void main() { ...@@ -308,7 +308,7 @@ void main() {
await const KernelSnapshot().build(androidEnvironment await const KernelSnapshot().build(androidEnvironment
..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin) ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin)
..defines[kBuildMode] = getNameForBuildMode(BuildMode.debug) ..defines[kBuildMode] = BuildMode.debug.cliName
..defines[kTrackWidgetCreation] = 'false' ..defines[kTrackWidgetCreation] = 'false'
); );
...@@ -322,7 +322,7 @@ void main() { ...@@ -322,7 +322,7 @@ void main() {
final Environment testEnvironment = Environment.test( final Environment testEnvironment = Environment.test(
fileSystem.currentDirectory, fileSystem.currentDirectory,
defines: <String, String>{ defines: <String, String>{
kBuildMode: getNameForBuildMode(BuildMode.debug), kBuildMode: BuildMode.debug.cliName,
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm), kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
}, },
processManager: processManager, processManager: processManager,
...@@ -553,7 +553,7 @@ void main() { ...@@ -553,7 +553,7 @@ void main() {
testUsingContext('kExtraGenSnapshotOptions passes values to gen_snapshot', () async { testUsingContext('kExtraGenSnapshotOptions passes values to gen_snapshot', () async {
androidEnvironment.defines[kExtraGenSnapshotOptions] = 'foo,bar,baz=2'; androidEnvironment.defines[kExtraGenSnapshotOptions] = 'foo,bar,baz=2';
androidEnvironment.defines[kBuildMode] = getNameForBuildMode(BuildMode.profile); androidEnvironment.defines[kBuildMode] = BuildMode.profile.cliName;
final String build = androidEnvironment.buildDir.path; final String build = androidEnvironment.buildDir.path;
processManager.addCommands(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
......
...@@ -371,7 +371,7 @@ class FakeDesktopDevice extends DesktopDevice { ...@@ -371,7 +371,7 @@ class FakeDesktopDevice extends DesktopDevice {
if (nullExecutablePathForDevice) { if (nullExecutablePathForDevice) {
return null; return null;
} }
return getNameForBuildMode(buildInfo.mode); return buildInfo.mode.cliName;
} }
} }
......
...@@ -170,18 +170,12 @@ FlutterProject setUpFlutterProject(Directory directory) { ...@@ -170,18 +170,12 @@ FlutterProject setUpFlutterProject(Directory directory) {
class FakeLinuxApp extends Fake implements LinuxApp { class FakeLinuxApp extends Fake implements LinuxApp {
@override @override
String executable(BuildMode buildMode) { String executable(BuildMode buildMode) => switch (buildMode) {
switch (buildMode) { BuildMode.debug => 'debug/executable',
case BuildMode.debug: BuildMode.profile => 'profile/executable',
return 'debug/executable'; BuildMode.release => 'release/executable',
case BuildMode.profile: _ => throw StateError('Invalid mode: $buildMode'),
return 'profile/executable'; };
case BuildMode.release:
return 'release/executable';
default:
throw StateError('Invalid mode: $buildMode');
}
}
} }
class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils { class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils {
FakeOperatingSystemUtils({ FakeOperatingSystemUtils({
......
...@@ -1479,6 +1479,8 @@ TerminalHandler setUpTerminalHandler(List<FakeVmServiceRequest> requests, { ...@@ -1479,6 +1479,8 @@ TerminalHandler setUpTerminalHandler(List<FakeVmServiceRequest> requests, {
..isRunningDebug = false ..isRunningDebug = false
..isRunningProfile = false ..isRunningProfile = false
..isRunningRelease = true; ..isRunningRelease = true;
case _:
// NOOP
} }
return TerminalHandler( return TerminalHandler(
residentRunner, residentRunner,
......
...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/project.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/version.dart';
import 'package:flutter_tools/src/web/compile.dart'; import 'package:flutter_tools/src/web/compile.dart';
import 'package:flutter_tools/src/web/file_generators/flutter_service_worker_js.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
...@@ -44,7 +45,7 @@ void main() { ...@@ -44,7 +45,7 @@ void main() {
expect(environment.defines, <String, String>{ expect(environment.defines, <String, String>{
'TargetFile': 'target', 'TargetFile': 'target',
'HasWebPlugins': 'false', 'HasWebPlugins': 'false',
'ServiceWorkerStrategy': 'serviceWorkerStrategy', 'ServiceWorkerStrategy': ServiceWorkerStrategy.offlineFirst.cliName,
'WasmOmitTypeChecks': 'false', 'WasmOmitTypeChecks': 'false',
'BuildMode': 'debug', 'BuildMode': 'debug',
'DartObfuscation': 'false', 'DartObfuscation': 'false',
...@@ -68,7 +69,7 @@ void main() { ...@@ -68,7 +69,7 @@ void main() {
flutterProject, flutterProject,
'target', 'target',
BuildInfo.debug, BuildInfo.debug,
'serviceWorkerStrategy', ServiceWorkerStrategy.offlineFirst,
compilerConfig: const WasmCompilerConfig(omitTypeChecks: false), compilerConfig: const WasmCompilerConfig(omitTypeChecks: false),
); );
...@@ -108,7 +109,7 @@ void main() { ...@@ -108,7 +109,7 @@ void main() {
flutterProject, flutterProject,
'target', 'target',
BuildInfo.debug, BuildInfo.debug,
'serviceWorkerStrategy', ServiceWorkerStrategy.offlineFirst,
compilerConfig: const JsCompilerConfig.run(nativeNullAssertions: true), compilerConfig: const JsCompilerConfig.run(nativeNullAssertions: true),
), ),
throwsToolExit(message: 'Failed to compile application for the Web.')); throwsToolExit(message: 'Failed to compile application for the Web.'));
......
...@@ -130,5 +130,5 @@ WindowsDevice setUpWindowsDevice({ ...@@ -130,5 +130,5 @@ WindowsDevice setUpWindowsDevice({
class FakeWindowsApp extends Fake implements WindowsApp { class FakeWindowsApp extends Fake implements WindowsApp {
@override @override
String executable(BuildMode buildMode) => '${buildMode.name}/executable'; String executable(BuildMode buildMode) => '${buildMode.cliName}/executable';
} }
...@@ -76,7 +76,7 @@ void main() { ...@@ -76,7 +76,7 @@ void main() {
}); });
for (final BuildMode buildMode in <BuildMode>[BuildMode.debug, BuildMode.release]) { for (final BuildMode buildMode in <BuildMode>[BuildMode.debug, BuildMode.release]) {
group('build in ${buildMode.name} mode', () { group('build in ${buildMode.cliName} mode', () {
late Directory outputPath; late Directory outputPath;
late Directory outputApp; late Directory outputApp;
late Directory frameworkDirectory; late Directory frameworkDirectory;
...@@ -98,7 +98,7 @@ void main() { ...@@ -98,7 +98,7 @@ void main() {
'ios', 'ios',
'--verbose', '--verbose',
'--no-codesign', '--no-codesign',
'--${buildMode.name}', '--${buildMode.cliName}',
'--obfuscate', '--obfuscate',
'--split-debug-info=foo debug info/', '--split-debug-info=foo debug info/',
], workingDirectory: projectRoot); ], workingDirectory: projectRoot);
...@@ -125,7 +125,7 @@ void main() { ...@@ -125,7 +125,7 @@ void main() {
projectRoot, projectRoot,
'build', 'build',
'ios', 'ios',
'${sentenceCase(buildMode.name)}-iphoneos', '${sentenceCase(buildMode.cliName)}-iphoneos',
)); ));
buildAppFrameworkDsym = buildPath.childDirectory('App.framework.dSYM'); buildAppFrameworkDsym = buildPath.childDirectory('App.framework.dSYM');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment