Unverified Commit da27f623 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Make a kReleaseMode constant that is public. (#27502)

Before this, we had several places where an isReleaseMode was defined, all with the same definition. This just makes it more broadly visible to allow our users to use it, as well as creating debug and profile versions, and adding a device lab test for it.

Since this is a const value, this makes it possible for a developer to easily mark blocks that can be removed at AOT compile time.
parent a872514a
// Copyright (c) 2019 The Chromium 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 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:flutter_devicelab/framework/adb.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
Future<String> runFlutterAndQuit(List<String> args, Device device) async {
final Completer<void> ready = Completer<void>();
print('run: starting...');
final Process run = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
<String>['run', '--suppress-analytics']..addAll(args),
isBot: false, // we just want to test the output, not have any debugging info
);
final List<String> stdout = <String>[];
final List<String> stderr = <String>[];
int runExitCode;
run.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(
(String line) {
print('run:stdout: $line');
stdout.add(line);
if (line.contains('>>> FINISHED <<<')) {
ready.complete();
}
},
);
run.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(
(String line) {
print('run:stderr: $line');
stderr.add(line);
},
);
run.exitCode.then<void>((int exitCode) {
runExitCode = exitCode;
});
await Future.any<dynamic>(<Future<dynamic>>[ready.future, run.exitCode]);
if (runExitCode != null) {
throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.';
}
run.stdin.write('q');
await run.exitCode;
if (stderr.isNotEmpty) {
throw 'flutter run ${args.join(' ')} had output on standard error:\n${stderr.join('\n')}';
}
return stdout.join('\n');
}
void main() {
task(() async {
final Device device = await devices.workingDevice;
await device.unlock();
final Directory appDir = dir(path.join(flutterDirectory.path, 'dev/integration_tests/ui'));
Future<void> checkMode(String mode, {bool releaseExpected = false, bool dynamic = false}) async {
await inDirectory(appDir, () async {
print('run: starting $mode test...');
final List<String> args = <String>['--$mode']..addAll(dynamic ? <String>['--dynamic'] : const <String>[]);
args.addAll(<String>['-d', device.deviceId, 'lib/build_mode.dart']);
final String stdout = await runFlutterAndQuit(args, device);
if (!stdout.contains('>>> Release: $releaseExpected <<<')) {
throw "flutter run --$mode ${dynamic ? '--dynamic ' : ''}didn't set kReleaseMode properly";
}
});
}
await checkMode('debug', releaseExpected: false);
await checkMode('profile', releaseExpected: false);
await checkMode('profile', releaseExpected: false, dynamic: true);
await checkMode('release', releaseExpected: true);
await checkMode('release', releaseExpected: true, dynamic: true);
return TaskResult.success(null);
});
}
......@@ -42,7 +42,7 @@ void main() {
.transform<String>(const LineSplitter())
.listen((String line) {
print('run:stderr: $line');
stdout.add(line);
stderr.add(line);
});
run.exitCode.then<void>((int exitCode) { runExitCode = exitCode; });
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
......
// Copyright 2019 The Chromium 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 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
Future<void> main() async {
print('>>> Release: $kReleaseMode <<<');
print('>>> FINISHED <<<');
stdout.flush();
runApp(const Text('Hello, world!', textDirection: TextDirection.ltr));
}
......@@ -38,6 +38,7 @@ export 'src/foundation/binding.dart';
export 'src/foundation/change_notifier.dart';
export 'src/foundation/collections.dart';
export 'src/foundation/consolidate_response.dart';
export 'src/foundation/constants.dart';
export 'src/foundation/debug.dart';
export 'src/foundation/diagnostics.dart';
export 'src/foundation/isolates.dart';
......
......@@ -13,6 +13,7 @@ import 'package:meta/meta.dart';
import 'assertions.dart';
import 'basic_types.dart';
import 'constants.dart';
import 'debug.dart';
import 'platform.dart';
import 'print.dart';
......@@ -131,8 +132,7 @@ abstract class BindingBase {
return true;
}());
const bool isReleaseMode = bool.fromEnvironment('dart.vm.product');
if (!isReleaseMode) {
if (!kReleaseMode) {
registerSignalServiceExtension(
name: 'exit',
callback: _exitApplication,
......@@ -444,27 +444,33 @@ abstract class BindingBase {
/// not wrapped in a guard that allows the tree shaker to remove it (see
/// sample code below).
///
/// ## Sample Code
///
/// {@tool sample}
/// The following code registers a service extension that is only included in
/// debug builds:
/// debug builds.
///
/// ```dart
/// assert(() {
/// // Register your service extension here.
/// return true;
/// }());
///
/// void myRegistrationFunction() {
/// assert(() {
/// // Register your service extension here.
/// return true;
/// }());
/// }
/// ```
/// {@end-tool}
///
/// {@tool sample}
/// A service extension registered with the following code snippet is
/// available in debug and profile mode:
/// available in debug and profile mode.
///
/// ```dart
/// if (!const bool.fromEnvironment('dart.vm.product')) {
// // Register your service extension here.
// }
/// void myRegistrationFunction() {
/// // kReleaseMode is defined in the 'flutter/foundation.dart' package.
/// if (!kReleaseMode) {
/// // Register your service extension here.
/// }
/// }
/// ```
/// {@end-tool}
///
/// Both guards ensure that Dart's tree shaker can remove the code for the
/// service extension in release builds.
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// A constant that is true if the application was compiled in release mode.
///
/// More specifically, this is a constant that is true if the application was
/// compiled in Dart with the '-Ddart.vm.product=true' flag.
///
/// Since this is a const value, it can be used to indicate to the compiler that
/// a particular block of code will not be executed in release mode, and hence
/// can be removed.
const bool kReleaseMode = bool.fromEnvironment('dart.vm.product', defaultValue: false);
......@@ -4,15 +4,14 @@
import 'dart:ui' show VoidCallback;
/// Whether we've been built in release mode.
const bool _kReleaseMode = bool.fromEnvironment('dart.vm.product');
import 'constants.dart';
/// When running in profile mode (or debug mode), invoke the given function.
///
/// In release mode, the function is not invoked.
// TODO(devoncarew): Going forward, we'll want the call to profile() to be tree-shaken out.
void profile(VoidCallback function) {
if (_kReleaseMode)
if (kReleaseMode)
return;
function();
}
......@@ -93,8 +93,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
return true;
}());
const bool isReleaseMode = bool.fromEnvironment('dart.vm.product');
if (!isReleaseMode) {
if (!kReleaseMode) {
// these service extensions work in debug or profile mode
registerSignalServiceExtension(
name: 'debugDumpRenderTree',
......
......@@ -203,8 +203,7 @@ mixin SchedulerBinding on BindingBase, ServicesBinding {
void initServiceExtensions() {
super.initServiceExtensions();
const bool isReleaseMode = bool.fromEnvironment('dart.vm.product');
if (!isReleaseMode) {
if (!kReleaseMode) {
registerNumericServiceExtension(
name: 'timeDilation',
getter: () async => timeDilation,
......
......@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:developer' as developer;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
......@@ -1684,8 +1685,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
}
void _afterNavigation() {
const bool isReleaseMode = bool.fromEnvironment('dart.vm.product');
if (!isReleaseMode) {
if (!kReleaseMode) {
// This event is used by performance tools that show stats for the
// time interval since the last navigation event occurred ensuring that
// stats only reflect the current page.
......
......@@ -5,9 +5,6 @@
import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart';
// We run our tests in debug mode, to this will always evaluate to false...
const bool isReleaseMode = bool.fromEnvironment('dart.vm.product');
void main() {
// TODO(devoncarew): This test - while very nice - isn't testing what we really want to know:
// that the code in the `profile` closure is omitted in release mode.
......@@ -16,6 +13,8 @@ void main() {
profile(() {
count++;
});
expect(count, isReleaseMode ? 0 : 1);
// We run our tests in debug mode, so kReleaseMode will always evaluate to
// false...
expect(count, kReleaseMode ? 0 : 1);
});
}
......@@ -45,7 +45,7 @@ class FlutterDevice {
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
experimentalFlags: experimentalFlags,
experimentalFlags: experimentalFlags,
);
final Device device;
......
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