Unverified Commit d9c19629 authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Instrument usage of include_flutter.groovy and xcode_backend.sh (#34189)

This is done via `flutter build bundle`.   As a consequence, this PR introduces a new way to disable analytics via the `FLUTTER_SUPPRESS_ANALYTICS` env flag.
parent 1eb8c640
......@@ -249,7 +249,7 @@ BuildApp() {
fi
StreamOutput " ├─Assembling Flutter resources..."
RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \
RunCommand "${FLUTTER_ROOT}/bin/flutter" \
${verbose_flag} \
build bundle \
--target-platform=ios \
......
......@@ -717,7 +717,6 @@ abstract class BaseFlutterTask extends DefaultTask {
args "--local-engine-src-path", localEngineSrcPath
}
args "build", "bundle"
args "--suppress-analytics"
args "--target", targetPath
args "--target-platform", "${targetPlatform}"
if (verbose) {
......
......@@ -601,6 +601,10 @@ Map<String, String> get _gradleEnv {
// Use java bundled with Android Studio.
env['JAVA_HOME'] = javaPath;
}
// Don't log analytics for downstream Flutter commands.
// e.g. `flutter build bundle`.
env['FLUTTER_SUPPRESS_ANALYTICS'] = 'true';
return env;
}
......
......@@ -48,114 +48,121 @@ const String _kVMSnapshotData = 'vm_snapshot_data';
const String _kIsolateSnapshotData = 'isolate_snapshot_data';
const String _kIsolateSnapshotInstr = 'isolate_snapshot_instr';
Future<void> build({
TargetPlatform platform,
BuildMode buildMode,
String mainPath = defaultMainPath,
String manifestPath = defaultManifestPath,
String applicationKernelFilePath,
String depfilePath,
String privateKeyPath = defaultPrivateKeyPath,
String assetDirPath,
String packagesPath,
bool precompiledSnapshot = false,
bool reportLicensedPackages = false,
bool trackWidgetCreation = false,
String compilationTraceFilePath,
List<String> extraFrontEndOptions = const <String>[],
List<String> extraGenSnapshotOptions = const <String>[],
List<String> fileSystemRoots,
String fileSystemScheme,
}) async {
depfilePath ??= defaultDepfilePath;
assetDirPath ??= getAssetBuildDirectory();
packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
applicationKernelFilePath ??= getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation);
final FlutterProject flutterProject = FlutterProject.current();
/// Provides a `build` method that builds the bundle.
class BundleBuilder {
/// Builds the bundle for the given target platform.
///
/// The default `mainPath` is `lib/main.dart`.
/// The default `manifestPath` is `pubspec.yaml`
Future<void> build({
TargetPlatform platform,
BuildMode buildMode,
String mainPath = defaultMainPath,
String manifestPath = defaultManifestPath,
String applicationKernelFilePath,
String depfilePath,
String privateKeyPath = defaultPrivateKeyPath,
String assetDirPath,
String packagesPath,
bool precompiledSnapshot = false,
bool reportLicensedPackages = false,
bool trackWidgetCreation = false,
String compilationTraceFilePath,
List<String> extraFrontEndOptions = const <String>[],
List<String> extraGenSnapshotOptions = const <String>[],
List<String> fileSystemRoots,
String fileSystemScheme,
}) async {
depfilePath ??= defaultDepfilePath;
assetDirPath ??= getAssetBuildDirectory();
packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
applicationKernelFilePath ??= getDefaultApplicationKernelPath(trackWidgetCreation: trackWidgetCreation);
final FlutterProject flutterProject = FlutterProject.current();
if (compilationTraceFilePath != null) {
if (buildMode != BuildMode.dynamicProfile && buildMode != BuildMode.dynamicRelease) {
// Silently ignore JIT snapshotting for those builds that don't support it.
compilationTraceFilePath = null;
} else if (compilationTraceFilePath.isEmpty) {
// Disable JIT snapshotting if flag is empty.
printStatus('Code snapshot will be disabled for this build.');
compilationTraceFilePath = null;
} else if (!fs.file(compilationTraceFilePath).existsSync()) {
// Be forgiving if compilation trace file is missing.
printStatus('No compilation trace available. To optimize performance, consider using --train.');
final File tmp = fs.systemTempDirectory.childFile('flutterEmptyCompilationTrace.txt');
compilationTraceFilePath = (tmp..createSync(recursive: true)).path;
} else {
printStatus('Code snapshot will use compilation training file $compilationTraceFilePath.');
}
}
DevFSContent kernelContent;
if (!precompiledSnapshot) {
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
printTrace('Extra front-end options: $extraFrontEndOptions');
ensureDirectoryExists(applicationKernelFilePath);
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject);
final CompilerOutput compilerOutput = await kernelCompiler.compile(
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode),
incrementalCompilerByteStorePath: compilationTraceFilePath != null ? null :
fs.path.absolute(getIncrementalCompilerByteStoreDirectory()),
mainPath: fs.file(mainPath).absolute.path,
outputFilePath: applicationKernelFilePath,
depFilePath: depfilePath,
trackWidgetCreation: trackWidgetCreation,
extraFrontEndOptions: extraFrontEndOptions,
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
packagesPath: packagesPath,
linkPlatformKernelIn: compilationTraceFilePath != null,
);
if (compilerOutput?.outputFilename == null) {
throwToolExit('Compiler failed on $mainPath');
if (compilationTraceFilePath != null) {
if (buildMode != BuildMode.dynamicProfile && buildMode != BuildMode.dynamicRelease) {
// Silently ignore JIT snapshotting for those builds that don't support it.
compilationTraceFilePath = null;
} else if (compilationTraceFilePath.isEmpty) {
// Disable JIT snapshotting if flag is empty.
printStatus('Code snapshot will be disabled for this build.');
compilationTraceFilePath = null;
} else if (!fs.file(compilationTraceFilePath).existsSync()) {
// Be forgiving if compilation trace file is missing.
printStatus('No compilation trace available. To optimize performance, consider using --train.');
final File tmp = fs.systemTempDirectory.childFile('flutterEmptyCompilationTrace.txt');
compilationTraceFilePath = (tmp..createSync(recursive: true)).path;
} else {
printStatus('Code snapshot will use compilation training file $compilationTraceFilePath.');
}
}
kernelContent = DevFSFileContent(fs.file(compilerOutput.outputFilename));
await fs.directory(getBuildDirectory()).childFile('frontend_server.d')
.writeAsString('frontend_server.d: ${artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk)}\n');
if (compilationTraceFilePath != null) {
final JITSnapshotter snapshotter = JITSnapshotter();
final int snapshotExitCode = await snapshotter.build(
platform: platform,
buildMode: buildMode,
mainPath: applicationKernelFilePath,
outputPath: getBuildDirectory(),
DevFSContent kernelContent;
if (!precompiledSnapshot) {
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
printTrace('Extra front-end options: $extraFrontEndOptions');
ensureDirectoryExists(applicationKernelFilePath);
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject);
final CompilerOutput compilerOutput = await kernelCompiler.compile(
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode),
incrementalCompilerByteStorePath: compilationTraceFilePath != null ? null :
fs.path.absolute(getIncrementalCompilerByteStoreDirectory()),
mainPath: fs.file(mainPath).absolute.path,
outputFilePath: applicationKernelFilePath,
depFilePath: depfilePath,
trackWidgetCreation: trackWidgetCreation,
extraFrontEndOptions: extraFrontEndOptions,
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
packagesPath: packagesPath,
compilationTraceFilePath: compilationTraceFilePath,
extraGenSnapshotOptions: extraGenSnapshotOptions,
linkPlatformKernelIn: compilationTraceFilePath != null,
);
if (snapshotExitCode != 0) {
throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode');
if (compilerOutput?.outputFilename == null) {
throwToolExit('Compiler failed on $mainPath');
}
kernelContent = DevFSFileContent(fs.file(compilerOutput.outputFilename));
await fs.directory(getBuildDirectory()).childFile('frontend_server.d')
.writeAsString('frontend_server.d: ${artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk)}\n');
if (compilationTraceFilePath != null) {
final JITSnapshotter snapshotter = JITSnapshotter();
final int snapshotExitCode = await snapshotter.build(
platform: platform,
buildMode: buildMode,
mainPath: applicationKernelFilePath,
outputPath: getBuildDirectory(),
packagesPath: packagesPath,
compilationTraceFilePath: compilationTraceFilePath,
extraGenSnapshotOptions: extraGenSnapshotOptions,
);
if (snapshotExitCode != 0) {
throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode');
}
}
}
}
final AssetBundle assets = await buildAssets(
manifestPath: manifestPath,
assetDirPath: assetDirPath,
packagesPath: packagesPath,
reportLicensedPackages: reportLicensedPackages,
);
if (assets == null)
throwToolExit('Error building assets', exitCode: 1);
await assemble(
buildMode: buildMode,
assetBundle: assets,
kernelContent: kernelContent,
privateKeyPath: privateKeyPath,
assetDirPath: assetDirPath,
compilationTraceFilePath: compilationTraceFilePath,
);
final AssetBundle assets = await buildAssets(
manifestPath: manifestPath,
assetDirPath: assetDirPath,
packagesPath: packagesPath,
reportLicensedPackages: reportLicensedPackages,
);
if (assets == null)
throwToolExit('Error building assets', exitCode: 1);
await assemble(
buildMode: buildMode,
assetBundle: assets,
kernelContent: kernelContent,
privateKeyPath: privateKeyPath,
assetDirPath: assetDirPath,
compilationTraceFilePath: compilationTraceFilePath,
);
}
}
Future<AssetBundle> buildAssets({
......
......@@ -5,14 +5,17 @@
import 'dart:async';
import '../base/common.dart';
import '../base/file_system.dart';
import '../build_info.dart';
import '../bundle.dart';
import '../project.dart';
import '../runner/flutter_command.dart' show FlutterOptions, FlutterCommandResult;
import '../usage.dart';
import '../version.dart';
import 'build.dart';
class BuildBundleCommand extends BuildSubCommand {
BuildBundleCommand({bool verboseHelp = false}) {
BuildBundleCommand({bool verboseHelp = false, this.bundleBuilder}) {
usesTargetOption();
usesFilesystemOptions(hide: !verboseHelp);
usesBuildNumberOption();
......@@ -57,8 +60,12 @@ class BuildBundleCommand extends BuildSubCommand {
'in the application\'s LICENSE file.',
defaultsTo: false);
usesPubOption();
bundleBuilder ??= BundleBuilder();
}
BundleBuilder bundleBuilder;
@override
final String name = 'bundle';
......@@ -70,6 +77,21 @@ class BuildBundleCommand extends BuildSubCommand {
'application code and resources; they are used by some Flutter Android and'
' iOS runtimes.';
@override
Future<Map<String, String>> get usageValues async {
final String projectDir = fs.file(targetFile).parent.parent.path;
final FlutterProject futterProject = FlutterProject.fromPath(projectDir);
if (futterProject == null) {
return const <String, String>{};
}
return <String, String>{
kCommandBuildBundleTargetPlatform: argResults['target-platform'],
kCommandBuildBundleIsModule: '${futterProject.isModule}'
};
}
@override
Future<FlutterCommandResult> runCommand() async {
final String targetPlatform = argResults['target-platform'];
......@@ -92,7 +114,7 @@ class BuildBundleCommand extends BuildSubCommand {
final BuildMode buildMode = getBuildMode();
await build(
await bundleBuilder.build(
platform: platform,
buildMode: buildMode,
mainPath: targetFile,
......
......@@ -279,6 +279,10 @@ Future<XcodeBuildResult> buildXcodeProject({
buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}');
}
// Don't log analytics for downstream Flutter commands.
// e.g. `flutter build bundle`.
buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true');
final Stopwatch sw = Stopwatch()..start();
initialBuildStatus = logger.startProgress('Running Xcode build...', timeout: timeoutConfiguration.fastOperation);
final RunResult buildResult = await runAsync(
......
......@@ -15,7 +15,7 @@ import '../base/process.dart';
import '../base/process_manager.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../bundle.dart' as bundle;
import '../bundle.dart';
import '../convert.dart';
import '../device.dart';
import '../globals.dart';
......@@ -412,7 +412,7 @@ class IOSSimulator extends Device {
Future<void> _sideloadUpdatedAssetsForInstalledApplicationBundle(ApplicationPackage app, BuildInfo buildInfo, String mainPath) {
// Run compiler to produce kernel file for the application.
return bundle.build(
return BundleBuilder().build(
mainPath: mainPath,
precompiledSnapshot: false,
trackWidgetCreation: buildInfo.trackWidgetCreation,
......
......@@ -13,7 +13,7 @@ import '../base/file_system.dart';
import '../base/io.dart';
import '../base/process_manager.dart';
import '../build_info.dart';
import '../bundle.dart' as bundle;
import '../bundle.dart';
import '../convert.dart';
import '../dart/package_map.dart';
import '../device.dart';
......@@ -129,11 +129,11 @@ class FlutterTesterDevice extends Device {
// Build assets and perform initial compilation.
final String assetDirPath = getAssetBuildDirectory();
final String applicationKernelFilePath = bundle.getKernelPathForTransformerOptions(
final String applicationKernelFilePath = getKernelPathForTransformerOptions(
fs.path.join(getBuildDirectory(), 'flutter-tester-app.dill'),
trackWidgetCreation: buildInfo.trackWidgetCreation,
);
await bundle.build(
await BundleBuilder().build(
mainPath: mainPath,
assetDirPath: assetDirPath,
applicationKernelFilePath: applicationKernelFilePath,
......
......@@ -45,6 +45,10 @@ const String kCommandCreateProjectType = 'cd19';
const String kCommandPackagesNumberPlugins = 'cd20';
const String kCommandPackagesProjectModule = 'cd21';
const String kCommandBuildBundleTargetPlatform = 'cd24';
const String kCommandBuildBundleIsModule = 'cd25';
// Next ID: cd26
Usage get flutterUsage => Usage.instance;
class Usage {
......@@ -66,8 +70,9 @@ class Usage {
}
_analytics.analyticsOpt = AnalyticsOpt.optOut;
final bool suppressEnvFlag = platform.environment['FLUTTER_SUPPRESS_ANALYTICS'] == 'true';
// Many CI systems don't do a full git checkout.
if (version.endsWith('/unknown') || isRunningOnBot) {
if (version.endsWith('/unknown') || isRunningOnBot || suppressEnvFlag) {
// If we think we're running on a CI system, suppress sending analytics.
suppressAnalytics = true;
}
......
// 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 'package:args/command_runner.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build_bundle.dart';
import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/usage.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/context.dart';
void main() {
Cache.disableLocking();
group('getUsage', () {
Directory tempDir;
MockBundleBuilder mockBundleBuilder;
setUp(() {
tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
mockBundleBuilder = MockBundleBuilder();
when(
mockBundleBuilder.build(
platform: anyNamed('platform'),
buildMode: anyNamed('buildMode'),
mainPath: anyNamed('mainPath'),
manifestPath: anyNamed('manifestPath'),
applicationKernelFilePath: anyNamed('applicationKernelFilePath'),
depfilePath: anyNamed('depfilePath'),
privateKeyPath: anyNamed('privateKeyPath'),
assetDirPath: anyNamed('assetDirPath'),
packagesPath: anyNamed('packagesPath'),
precompiledSnapshot: anyNamed('precompiledSnapshot'),
reportLicensedPackages: anyNamed('reportLicensedPackages'),
trackWidgetCreation: anyNamed('trackWidgetCreation'),
compilationTraceFilePath: anyNamed('compilationTraceFilePath'),
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
extraGenSnapshotOptions: anyNamed('extraGenSnapshotOptions'),
fileSystemRoots: anyNamed('fileSystemRoots'),
fileSystemScheme: anyNamed('fileSystemScheme'),
),
).thenAnswer((_) => Future<void>.value());
});
tearDown(() {
tryToDelete(tempDir);
});
Future<BuildBundleCommand> runCommandIn(String projectPath, { List<String> arguments }) async {
final BuildBundleCommand command = BuildBundleCommand(bundleBuilder: mockBundleBuilder);
final CommandRunner<void> runner = createTestCommandRunner(command);
final List<String> commandArgs = <String>['bundle'];
if (arguments != null)
commandArgs.addAll(arguments);
commandArgs.add('--target=$projectPath/lib/main.dart');
await runner.run(commandArgs);
return command;
}
testUsingContext('indicate that project is a module', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=module']);
final BuildBundleCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildBundleIsModule, 'true'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('indicate that project is not a module', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
final BuildBundleCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildBundleIsModule, 'false'));
}, timeout: allowForCreateFlutterProject);
testUsingContext('indicate the target platform', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
final BuildBundleCommand command = await runCommandIn(projectPath);
expect(await command.usageValues,
containsPair(kCommandBuildBundleTargetPlatform, 'android-arm'));
}, timeout: allowForCreateFlutterProject);
});
}
class MockBundleBuilder extends Mock implements BundleBuilder {}
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