mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
417 lines
12 KiB
Dart
417 lines
12 KiB
Dart
// Copyright 2014 The Flutter Authors. 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:meta/meta.dart';
|
|
|
|
import 'base/config.dart';
|
|
import 'base/context.dart';
|
|
import 'base/platform.dart';
|
|
import 'version.dart';
|
|
|
|
/// The current [FeatureFlags] implementation.
|
|
///
|
|
/// If not injected, a default implementation is provided.
|
|
FeatureFlags get featureFlags => context.get<FeatureFlags>();
|
|
|
|
/// The interface used to determine if a particular [Feature] is enabled.
|
|
///
|
|
/// The rest of the tools code should use this class instead of looking up
|
|
/// features directly. To facilitate rolls to google3 and other clients, all
|
|
/// flags should be provided with a default implementation here. Clients that
|
|
/// use this class should extent instead of implement, so that new flags are
|
|
/// picked up automatically.
|
|
abstract class FeatureFlags {
|
|
/// const constructor so that subclasses can be const.
|
|
const FeatureFlags();
|
|
|
|
/// Whether flutter desktop for linux is enabled.
|
|
bool get isLinuxEnabled => false;
|
|
|
|
/// Whether flutter desktop for macOS is enabled.
|
|
bool get isMacOSEnabled => false;
|
|
|
|
/// Whether flutter web is enabled.
|
|
bool get isWebEnabled => false;
|
|
|
|
/// Whether flutter desktop for Windows is enabled.
|
|
bool get isWindowsEnabled => false;
|
|
|
|
/// Whether android is enabled.
|
|
bool get isAndroidEnabled => true;
|
|
|
|
/// Whether iOS is enabled.
|
|
bool get isIOSEnabled => true;
|
|
|
|
/// Whether fuchsia is enabled.
|
|
bool get isFuchsiaEnabled => true;
|
|
|
|
/// Whether fast single widget reloads are enabled.
|
|
bool get isSingleWidgetReloadEnabled => false;
|
|
|
|
/// Whether the CFE experimental invalidation strategy is enabled.
|
|
bool get isExperimentalInvalidationStrategyEnabled => false;
|
|
|
|
/// Whether a particular feature is enabled for the current channel.
|
|
///
|
|
/// Prefer using one of the specific getters above instead of this API.
|
|
bool isEnabled(Feature feature) => false;
|
|
}
|
|
|
|
class FlutterFeatureFlags implements FeatureFlags {
|
|
FlutterFeatureFlags({
|
|
@required FlutterVersion flutterVersion,
|
|
@required Config config,
|
|
@required Platform platform,
|
|
}) : _flutterVersion = flutterVersion,
|
|
_config = config,
|
|
_platform = platform;
|
|
|
|
final FlutterVersion _flutterVersion;
|
|
final Config _config;
|
|
final Platform _platform;
|
|
|
|
@override
|
|
bool get isLinuxEnabled => isEnabled(flutterLinuxDesktopFeature);
|
|
|
|
@override
|
|
bool get isMacOSEnabled => isEnabled(flutterMacOSDesktopFeature);
|
|
|
|
@override
|
|
bool get isWebEnabled => isEnabled(flutterWebFeature);
|
|
|
|
@override
|
|
bool get isWindowsEnabled => isEnabled(flutterWindowsDesktopFeature);
|
|
|
|
@override
|
|
bool get isAndroidEnabled => isEnabled(flutterAndroidFeature);
|
|
|
|
@override
|
|
bool get isIOSEnabled => isEnabled(flutterIOSFeature);
|
|
|
|
@override
|
|
bool get isFuchsiaEnabled => isEnabled(flutterFuchsiaFeature);
|
|
|
|
@override
|
|
bool get isSingleWidgetReloadEnabled => isEnabled(singleWidgetReload);
|
|
|
|
@override
|
|
bool get isExperimentalInvalidationStrategyEnabled => isEnabled(experimentalInvalidationStrategy);
|
|
|
|
@override
|
|
bool isEnabled(Feature feature) {
|
|
final String currentChannel = _flutterVersion.channel;
|
|
final FeatureChannelSetting featureSetting = feature.getSettingForChannel(currentChannel);
|
|
if (!featureSetting.available) {
|
|
return false;
|
|
}
|
|
bool isEnabled = featureSetting.enabledByDefault;
|
|
if (feature.configSetting != null) {
|
|
final bool configOverride = _config.getValue(feature.configSetting) as bool;
|
|
if (configOverride != null) {
|
|
isEnabled = configOverride;
|
|
}
|
|
}
|
|
if (feature.environmentOverride != null) {
|
|
if (_platform.environment[feature.environmentOverride]?.toLowerCase() == 'true') {
|
|
isEnabled = true;
|
|
}
|
|
}
|
|
return isEnabled;
|
|
}
|
|
}
|
|
|
|
/// All current Flutter feature flags.
|
|
const List<Feature> allFeatures = <Feature>[
|
|
flutterWebFeature,
|
|
flutterLinuxDesktopFeature,
|
|
flutterMacOSDesktopFeature,
|
|
flutterWindowsDesktopFeature,
|
|
singleWidgetReload,
|
|
flutterAndroidFeature,
|
|
flutterIOSFeature,
|
|
flutterFuchsiaFeature,
|
|
experimentalInvalidationStrategy,
|
|
];
|
|
|
|
/// The [Feature] for flutter web.
|
|
const Feature flutterWebFeature = Feature(
|
|
name: 'Flutter for web',
|
|
configSetting: 'enable-web',
|
|
environmentOverride: 'FLUTTER_WEB',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: flutterNext,
|
|
),
|
|
beta: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: flutterNext,
|
|
),
|
|
stable: FeatureChannelSetting(
|
|
available: flutterNext,
|
|
enabledByDefault: flutterNext,
|
|
),
|
|
);
|
|
|
|
/// The [Feature] for macOS desktop.
|
|
const Feature flutterMacOSDesktopFeature = Feature(
|
|
name: 'Flutter for desktop on macOS',
|
|
configSetting: 'enable-macos-desktop',
|
|
environmentOverride: 'FLUTTER_MACOS',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
);
|
|
|
|
/// The [Feature] for Linux desktop.
|
|
const Feature flutterLinuxDesktopFeature = Feature(
|
|
name: 'Flutter for desktop on Linux',
|
|
configSetting: 'enable-linux-desktop',
|
|
environmentOverride: 'FLUTTER_LINUX',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
);
|
|
|
|
/// The [Feature] for Windows desktop.
|
|
const Feature flutterWindowsDesktopFeature = Feature(
|
|
name: 'Flutter for desktop on Windows',
|
|
configSetting: 'enable-windows-desktop',
|
|
environmentOverride: 'FLUTTER_WINDOWS',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
);
|
|
|
|
/// The [Feature] for Android devices.
|
|
const Feature flutterAndroidFeature = Feature(
|
|
name: 'Flutter for Android',
|
|
configSetting: 'enable-android',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
beta: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
stable: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
);
|
|
|
|
|
|
/// The [Feature] for iOS devices.
|
|
const Feature flutterIOSFeature = Feature(
|
|
name: 'Flutter for iOS',
|
|
configSetting: 'enable-ios',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
beta: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
stable: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
);
|
|
|
|
/// The [Feature] for Fuchsia support.
|
|
const Feature flutterFuchsiaFeature = Feature(
|
|
name: 'Flutter for Fuchsia',
|
|
configSetting: 'enable-fuchsia',
|
|
environmentOverride: 'FLUTTER_FUCHSIA',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
);
|
|
|
|
/// The fast hot reload feature for https://github.com/flutter/flutter/issues/61407.
|
|
const Feature singleWidgetReload = Feature(
|
|
name: 'Hot reload optimization for changes to class body of a single widget',
|
|
configSetting: 'single-widget-reload-optimization',
|
|
environmentOverride: 'FLUTTER_SINGLE_WIDGET_RELOAD',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
beta: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
stable: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
);
|
|
|
|
/// The CFE experimental invalidation strategy.
|
|
const Feature experimentalInvalidationStrategy = Feature(
|
|
name: 'Hot reload optimization that reduces incremental artifact size',
|
|
configSetting: 'experimental-invalidation-strategy',
|
|
environmentOverride: 'FLUTTER_CFE_EXPERIMENTAL_INVALIDATION',
|
|
master: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: true,
|
|
),
|
|
dev: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
beta: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
stable: FeatureChannelSetting(
|
|
available: true,
|
|
enabledByDefault: false,
|
|
),
|
|
);
|
|
|
|
/// A [Feature] is a process for conditionally enabling tool features.
|
|
///
|
|
/// All settings are optional, and if not provided will generally default to
|
|
/// a "safe" value, such as being off.
|
|
///
|
|
/// The top level feature settings can be provided to apply to all channels.
|
|
/// Otherwise, more specific settings take precedence over higher level
|
|
/// settings.
|
|
class Feature {
|
|
/// Creates a [Feature].
|
|
const Feature({
|
|
@required this.name,
|
|
this.environmentOverride,
|
|
this.configSetting,
|
|
this.master = const FeatureChannelSetting(),
|
|
this.dev = const FeatureChannelSetting(),
|
|
this.beta = const FeatureChannelSetting(),
|
|
this.stable = const FeatureChannelSetting(),
|
|
});
|
|
|
|
/// The user visible name for this feature.
|
|
final String name;
|
|
|
|
/// The settings for the master branch and other unknown channels.
|
|
final FeatureChannelSetting master;
|
|
|
|
/// The settings for the dev branch.
|
|
final FeatureChannelSetting dev;
|
|
|
|
/// The settings for the beta branch.
|
|
final FeatureChannelSetting beta;
|
|
|
|
/// The settings for the stable branch.
|
|
final FeatureChannelSetting stable;
|
|
|
|
/// The name of an environment variable that can override the setting.
|
|
///
|
|
/// The environment variable needs to be set to the value 'true'. This is
|
|
/// only intended for usage by CI and not as an advertised method to enable
|
|
/// a feature.
|
|
///
|
|
/// If not provided, defaults to `null` meaning there is no override.
|
|
final String environmentOverride;
|
|
|
|
/// The name of a setting that can be used to enable this feature.
|
|
///
|
|
/// If not provided, defaults to `null` meaning there is no config setting.
|
|
final String configSetting;
|
|
|
|
/// A help message for the `flutter config` command, or null if unsupported.
|
|
String generateHelpMessage() {
|
|
if (configSetting == null) {
|
|
return null;
|
|
}
|
|
final StringBuffer buffer = StringBuffer('Enable or disable $name. '
|
|
'This setting will take effect on ');
|
|
final List<String> channels = <String>[
|
|
if (master.available) 'master',
|
|
if (dev.available) 'dev',
|
|
if (beta.available) 'beta',
|
|
if (stable.available) 'stable',
|
|
];
|
|
if (channels.length == 1) {
|
|
buffer.write('the ${channels.single} channel.');
|
|
} else if (channels.length == 2) {
|
|
buffer.write('the ${channels.join(' and ')} channels.');
|
|
} else {
|
|
final String prefix = (channels.toList()
|
|
..removeLast()).join(', ');
|
|
buffer.write('the $prefix, and ${channels.last} channels.');
|
|
}
|
|
return buffer.toString();
|
|
}
|
|
|
|
/// Retrieve the correct setting for the provided `channel`.
|
|
FeatureChannelSetting getSettingForChannel(String channel) {
|
|
switch (channel) {
|
|
case 'stable':
|
|
return stable;
|
|
case 'beta':
|
|
return beta;
|
|
case 'dev':
|
|
return dev;
|
|
case 'master':
|
|
default:
|
|
return master;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A description of the conditions to enable a feature for a particular channel.
|
|
class FeatureChannelSetting {
|
|
const FeatureChannelSetting({
|
|
this.available = false,
|
|
this.enabledByDefault = false,
|
|
});
|
|
|
|
/// Whether the feature is available on this channel.
|
|
///
|
|
/// If not provided, defaults to `false`. This implies that the feature
|
|
/// cannot be enabled even by the settings below.
|
|
final bool available;
|
|
|
|
/// Whether the feature is enabled by default.
|
|
///
|
|
/// If not provided, defaults to `false`.
|
|
final bool enabledByDefault;
|
|
}
|
|
|
|
const bool flutterNext = false;
|