• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:meta/meta.dart';
6
7import 'base/config.dart';
8import 'base/context.dart';
9import 'base/platform.dart';
10import 'version.dart';
11
12/// The current [FeatureFlags] implementation.
13///
14/// If not injected, a default implementation is provided.
15FeatureFlags get featureFlags => context.get<FeatureFlags>();
16
17/// The interface used to determine if a particular [Feature] is enabled.
18///
19/// The rest of the tools code should use this class instead of looking up
20/// features directly. To faciliate rolls to google3 and other clients, all
21/// flags should be provided with a default implementation here. Clients that
22/// use this class should extent instead of implement, so that new flags are
23/// picked up automatically.
24class FeatureFlags {
25  const FeatureFlags();
26
27  /// Whether flutter desktop for linux is enabled.
28  bool get isLinuxEnabled => _isEnabled(flutterLinuxDesktopFeature);
29
30  /// Whether flutter desktop for macOS is enabled.
31  bool get isMacOSEnabled => _isEnabled(flutterMacOSDesktopFeature);
32
33  /// Whether flutter web is enabled.
34  bool get isWebEnabled => _isEnabled(flutterWebFeature);
35
36  /// Whether flutter desktop for Windows is enabled.
37  bool get isWindowsEnabled => _isEnabled(flutterWindowsDesktopFeature);
38
39  /// Whether plugins are built as AARs in app projects.
40  bool get isPluginAsAarEnabled => _isEnabled(flutterBuildPluginAsAarFeature);
41
42  // Calculate whether a particular feature is enabled for the current channel.
43  static bool _isEnabled(Feature feature) {
44    final String currentChannel = FlutterVersion.instance.channel;
45    final FeatureChannelSetting featureSetting = feature.getSettingForChannel(currentChannel);
46    if (!featureSetting.available) {
47      return false;
48    }
49    bool isEnabled = featureSetting.enabledByDefault;
50    if (feature.configSetting != null) {
51      final bool configOverride = Config.instance.getValue(feature.configSetting);
52      if (configOverride != null) {
53        isEnabled = configOverride;
54      }
55    }
56    if (feature.environmentOverride != null) {
57      if (platform.environment[feature.environmentOverride]?.toLowerCase() == 'true') {
58        isEnabled = true;
59      }
60    }
61    return isEnabled;
62  }
63}
64
65/// All current Flutter feature flags.
66const List<Feature> allFeatures = <Feature>[
67  flutterWebFeature,
68  flutterLinuxDesktopFeature,
69  flutterMacOSDesktopFeature,
70  flutterWindowsDesktopFeature,
71  flutterBuildPluginAsAarFeature,
72];
73
74/// The [Feature] for flutter web.
75const Feature flutterWebFeature = Feature(
76  name: 'Flutter for web',
77  configSetting: 'enable-web',
78  environmentOverride: 'FLUTTER_WEB',
79  master: FeatureChannelSetting(
80    available: true,
81    enabledByDefault: false,
82  ),
83  dev: FeatureChannelSetting(
84    available: true,
85    enabledByDefault: false,
86  ),
87);
88
89/// The [Feature] for macOS desktop.
90const Feature flutterMacOSDesktopFeature = Feature(
91  name: 'Flutter for desktop on macOS',
92  configSetting: 'enable-macos-desktop',
93  environmentOverride: 'ENABLE_FLUTTER_DESKTOP',
94  master: FeatureChannelSetting(
95    available: true,
96    enabledByDefault: false,
97  ),
98);
99
100/// The [Feature] for Linux desktop.
101const Feature flutterLinuxDesktopFeature = Feature(
102  name: 'Flutter for desktop on Linux',
103  configSetting: 'enable-linux-desktop',
104  environmentOverride: 'ENABLE_FLUTTER_DESKTOP',
105  master: FeatureChannelSetting(
106    available: true,
107    enabledByDefault: false,
108  ),
109);
110
111/// The [Feature] for Windows desktop.
112const Feature flutterWindowsDesktopFeature = Feature(
113  name: 'Flutter for desktop on Windows',
114  configSetting: 'enable-windows-desktop',
115  environmentOverride: 'ENABLE_FLUTTER_DESKTOP',
116  master: FeatureChannelSetting(
117    available: true,
118    enabledByDefault: false,
119  ),
120);
121
122/// The [Feature] for building plugins as AARs in an app project.
123const Feature flutterBuildPluginAsAarFeature = Feature(
124  name: 'Build plugins independently as AARs in app projects',
125  configSetting: 'enable-build-plugin-as-aar',
126  master: FeatureChannelSetting(
127    available: true,
128    enabledByDefault: false,
129  ),
130);
131
132/// A [Feature] is a process for conditionally enabling tool features.
133///
134/// All settings are optional, and if not provided will generally default to
135/// a "safe" value, such as being off.
136///
137/// The top level feature settings can be provided to apply to all channels.
138/// Otherwise, more specific settings take precedence over higher level
139/// settings.
140class Feature {
141  /// Creates a [Feature].
142  const Feature({
143    @required this.name,
144    this.environmentOverride,
145    this.configSetting,
146    this.master = const FeatureChannelSetting(),
147    this.dev = const FeatureChannelSetting(),
148    this.beta = const FeatureChannelSetting(),
149    this.stable = const FeatureChannelSetting(),
150  });
151
152  /// The user visible name for this feature.
153  final String name;
154
155  /// The settings for the master branch and other unknown channels.
156  final FeatureChannelSetting master;
157
158  /// The settings for the dev branch.
159  final FeatureChannelSetting dev;
160
161  /// The settings for the beta branch.
162  final FeatureChannelSetting beta;
163
164  /// The settings for the stable branch.
165  final FeatureChannelSetting stable;
166
167  /// The name of an environment variable that can override the setting.
168  ///
169  /// The environment variable needs to be set to the value 'true'. This is
170  /// only intended for usage by CI and not as an advertised method to enable
171  /// a feature.
172  ///
173  /// If not provided, defaults to `null` meaning there is no override.
174  final String environmentOverride;
175
176  /// The name of a setting that can be used to enable this feature.
177  ///
178  /// If not provided, defaults to `null` meaning there is no config setting.
179  final String configSetting;
180
181  /// A help message for the `flutter config` command, or null if unsupported.
182  String generateHelpMessage() {
183    if (configSetting == null) {
184      return null;
185    }
186    final StringBuffer buffer = StringBuffer('Enable or disable $name. '
187        'This setting will take effect on ');
188    final List<String> channels = <String>[
189      if (master.available) 'master',
190      if (dev.available) 'dev',
191      if (beta.available) 'beta',
192      if (stable.available) 'stable',
193    ];
194    if (channels.length == 1) {
195      buffer.write('the ${channels.single} channel.');
196    } else if (channels.length == 2) {
197      buffer.write('the ${channels.join(' and ')} channels.');
198    } else {
199      final String prefix = (channels.toList()
200        ..removeLast()).join(', ');
201      buffer.write('the $prefix, and ${channels.last} channels.');
202    }
203    return buffer.toString();
204  }
205
206  /// Retrieve the correct setting for the provided `channel`.
207  FeatureChannelSetting getSettingForChannel(String channel) {
208    switch (channel) {
209      case 'stable':
210        return stable;
211      case 'beta':
212        return beta;
213      case 'dev':
214        return dev;
215      case 'master':
216      default:
217        return master;
218    }
219  }
220}
221
222/// A description of the conditions to enable a feature for a particular channel.
223class FeatureChannelSetting {
224  const FeatureChannelSetting({
225    this.available = false,
226    this.enabledByDefault = false,
227  });
228
229  /// Whether the feature is available on this channel.
230  ///
231  /// If not provded, defaults to `false`. This implies that the feature
232  /// cannot be enabled even by the settings below.
233  final bool available;
234
235  /// Whether the feature is enabled by default.
236  ///
237  /// If not provided, defaults to `false`.
238  final bool enabledByDefault;
239}
240