| // 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 '../base/common.dart'; |
| import '../base/context.dart'; |
| import '../base/file_system.dart'; |
| import '../build_info.dart'; |
| import '../build_system/build_system.dart'; |
| import '../convert.dart'; |
| import '../globals.dart'; |
| import '../project.dart'; |
| import '../runner/flutter_command.dart'; |
| |
| /// The [BuildSystem] instance. |
| BuildSystem get buildSystem => context.get<BuildSystem>(); |
| |
| /// Assemble provides a low level API to interact with the flutter tool build |
| /// system. |
| class AssembleCommand extends FlutterCommand { |
| AssembleCommand() { |
| addSubcommand(AssembleRun()); |
| addSubcommand(AssembleDescribe()); |
| addSubcommand(AssembleListInputs()); |
| addSubcommand(AssembleBuildDirectory()); |
| } |
| @override |
| String get description => 'Assemble and build flutter resources.'; |
| |
| @override |
| String get name => 'assemble'; |
| |
| @override |
| bool get isExperimental => true; |
| |
| @override |
| Future<FlutterCommandResult> runCommand() { |
| return null; |
| } |
| } |
| |
| abstract class AssembleBase extends FlutterCommand { |
| AssembleBase() { |
| argParser.addMultiOption( |
| 'define', |
| abbr: 'd', |
| help: 'Allows passing configuration to a target with --define=target=key=value.' |
| ); |
| argParser.addOption( |
| 'build-mode', |
| allowed: const <String>[ |
| 'debug', |
| 'profile', |
| 'release', |
| ], |
| ); |
| argParser.addOption( |
| 'resource-pool-size', |
| help: 'The maximum number of concurrent tasks the build system will run.' |
| ); |
| } |
| |
| /// Returns the provided target platform. |
| /// |
| /// Throws a [ToolExit] if none is provided. This intentionally has no |
| /// default. |
| TargetPlatform get targetPlatform { |
| final String value = argResults['target-platform'] ?? 'darwin-x64'; |
| if (value == null) { |
| throwToolExit('--target-platform is required for flutter assemble.'); |
| } |
| return getTargetPlatformForName(value); |
| } |
| |
| /// Returns the provided build mode. |
| /// |
| /// Throws a [ToolExit] if none is provided. This intentionally has no |
| /// default. |
| BuildMode get buildMode { |
| final String value = argResults['build-mode'] ?? 'debug'; |
| if (value == null) { |
| throwToolExit('--build-mode is required for flutter assemble.'); |
| } |
| return getBuildModeForName(value); |
| } |
| |
| /// The name of the target we are describing or building. |
| String get targetName { |
| if (argResults.rest.isEmpty) { |
| throwToolExit('missing target name for flutter assemble.'); |
| } |
| return argResults.rest.first; |
| } |
| |
| /// The environmental configuration for a build invocation. |
| Environment get environment { |
| final FlutterProject flutterProject = FlutterProject.current(); |
| final Environment result = Environment( |
| buildDir: fs.directory(getBuildDirectory()), |
| projectDir: flutterProject.directory, |
| defines: _parseDefines(argResults['define']), |
| ); |
| return result; |
| } |
| |
| static Map<String, String> _parseDefines(List<String> values) { |
| final Map<String, String> results = <String, String>{}; |
| for (String chunk in values) { |
| final List<String> parts = chunk.split('='); |
| if (parts.length != 2) { |
| throwToolExit('Improperly formatted define flag: $chunk'); |
| } |
| final String key = parts[0]; |
| final String value = parts[1]; |
| results[key] = value; |
| } |
| return results; |
| } |
| } |
| |
| /// Execute a build starting from a target action. |
| class AssembleRun extends AssembleBase { |
| @override |
| String get description => 'Execute the stages for a specified target.'; |
| |
| @override |
| String get name => 'run'; |
| |
| @override |
| bool get isExperimental => true; |
| |
| @override |
| Future<FlutterCommandResult> runCommand() async { |
| final BuildResult result = await buildSystem.build(targetName, environment, BuildSystemConfig( |
| resourcePoolSize: argResults['resource-pool-size'], |
| )); |
| if (!result.success) { |
| for (MapEntry<String, ExceptionMeasurement> data in result.exceptions.entries) { |
| printError('Target ${data.key} failed: ${data.value.exception}'); |
| printError('${data.value.exception}'); |
| } |
| throwToolExit('build failed'); |
| } else { |
| printStatus('build succeeded'); |
| } |
| return null; |
| } |
| } |
| |
| /// Fully describe a target and its dependencies. |
| class AssembleDescribe extends AssembleBase { |
| @override |
| String get description => 'List the stages for a specified target.'; |
| |
| @override |
| String get name => 'describe'; |
| |
| @override |
| bool get isExperimental => true; |
| |
| @override |
| Future<FlutterCommandResult> runCommand() { |
| try { |
| printStatus( |
| json.encode(buildSystem.describe(targetName, environment)) |
| ); |
| } on Exception catch (err, stackTrace) { |
| printTrace(stackTrace.toString()); |
| throwToolExit(err.toString()); |
| } |
| return null; |
| } |
| } |
| |
| /// List input files for a target. |
| class AssembleListInputs extends AssembleBase { |
| @override |
| String get description => 'List the inputs for a particular target.'; |
| |
| @override |
| String get name => 'inputs'; |
| |
| @override |
| bool get isExperimental => true; |
| |
| @override |
| Future<FlutterCommandResult> runCommand() { |
| try { |
| final List<Map<String, Object>> results = buildSystem.describe(targetName, environment); |
| for (Map<String, Object> result in results) { |
| if (result['name'] == targetName) { |
| final List<String> inputs = result['inputs']; |
| inputs.forEach(printStatus); |
| } |
| } |
| } on Exception catch (err, stackTrace) { |
| printTrace(stackTrace.toString()); |
| throwToolExit(err.toString()); |
| } |
| return null; |
| } |
| } |
| |
| /// Return the build directory for a configuiration. |
| class AssembleBuildDirectory extends AssembleBase { |
| @override |
| String get description => 'List the inputs for a particular target.'; |
| |
| @override |
| String get name => 'build-dir'; |
| |
| @override |
| bool get isExperimental => true; |
| |
| @override |
| Future<FlutterCommandResult> runCommand() { |
| printStatus(environment.buildDir.path); |
| return null; |
| } |
| } |
| |