Merge pull request #2747 from devoncarew/refactor_build
Refactor the build commands
This commit is contained in:
commit
18c8f57739
@ -12,7 +12,6 @@ import 'src/base/context.dart';
|
|||||||
import 'src/base/logger.dart';
|
import 'src/base/logger.dart';
|
||||||
import 'src/base/process.dart';
|
import 'src/base/process.dart';
|
||||||
import 'src/commands/analyze.dart';
|
import 'src/commands/analyze.dart';
|
||||||
import 'src/commands/apk.dart';
|
|
||||||
import 'src/commands/build.dart';
|
import 'src/commands/build.dart';
|
||||||
import 'src/commands/create.dart';
|
import 'src/commands/create.dart';
|
||||||
import 'src/commands/daemon.dart';
|
import 'src/commands/daemon.dart';
|
||||||
@ -50,7 +49,6 @@ Future<Null> main(List<String> args) async {
|
|||||||
|
|
||||||
FlutterCommandRunner runner = new FlutterCommandRunner(verboseHelp: verboseHelp)
|
FlutterCommandRunner runner = new FlutterCommandRunner(verboseHelp: verboseHelp)
|
||||||
..addCommand(new AnalyzeCommand())
|
..addCommand(new AnalyzeCommand())
|
||||||
..addCommand(new ApkCommand())
|
|
||||||
..addCommand(new BuildCommand())
|
..addCommand(new BuildCommand())
|
||||||
..addCommand(new CreateCommand())
|
..addCommand(new CreateCommand())
|
||||||
..addCommand(new DaemonCommand(hidden: !verboseHelp))
|
..addCommand(new DaemonCommand(hidden: !verboseHelp))
|
||||||
|
@ -1,77 +1,53 @@
|
|||||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import '../flx.dart';
|
|
||||||
import '../dart/pub.dart';
|
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
import '../runner/flutter_command.dart';
|
import '../runner/flutter_command.dart';
|
||||||
import '../toolchain.dart';
|
import 'build_apk.dart';
|
||||||
|
import 'build_flx.dart';
|
||||||
|
|
||||||
class BuildCommand extends FlutterCommand {
|
class BuildCommand extends FlutterCommand {
|
||||||
|
BuildCommand() {
|
||||||
|
addSubcommand(new BuildApkCommand());
|
||||||
|
addSubcommand(new BuildCleanCommand());
|
||||||
|
addSubcommand(new BuildFlxCommand());
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String name = 'build';
|
final String name = 'build';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String description = 'Package your Flutter app into an FLX.';
|
final String description = 'Flutter build commands.';
|
||||||
|
|
||||||
BuildCommand() {
|
|
||||||
argParser.addFlag('precompiled', negatable: false);
|
|
||||||
// This option is still referenced by the iOS build scripts. We should
|
|
||||||
// remove it once we've updated those build scripts.
|
|
||||||
argParser.addOption('asset-base', help: 'Ignored. Will be removed.', hide: true);
|
|
||||||
argParser.addOption('compiler');
|
|
||||||
argParser.addOption('manifest', defaultsTo: defaultManifestPath);
|
|
||||||
argParser.addOption('private-key', defaultsTo: defaultPrivateKeyPath);
|
|
||||||
argParser.addOption('output-file', abbr: 'o', defaultsTo: defaultFlxOutputPath);
|
|
||||||
argParser.addOption('snapshot', defaultsTo: defaultSnapshotPath);
|
|
||||||
argParser.addOption('depfile', defaultsTo: defaultDepfilePath);
|
|
||||||
argParser.addOption('working-dir', defaultsTo: defaultWorkingDirPath);
|
|
||||||
argParser.addFlag('pub',
|
|
||||||
defaultsTo: true,
|
|
||||||
help: 'Whether to run "pub get" before building the app.');
|
|
||||||
addTargetOption();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> run() async {
|
Future<int> runInProject() => new Future<int>.value(0);
|
||||||
if (argResults['pub']) {
|
}
|
||||||
int exitCode = await pubGet();
|
|
||||||
if (exitCode != 0)
|
class BuildCleanCommand extends FlutterCommand {
|
||||||
return exitCode;
|
@override
|
||||||
}
|
final String name = 'clean';
|
||||||
return await super.run();
|
|
||||||
}
|
@override
|
||||||
|
final String description = 'Delete the build/ directory.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> runInProject() async {
|
Future<int> runInProject() async {
|
||||||
String compilerPath = argResults['compiler'];
|
Directory buildDir = new Directory('build');
|
||||||
|
printStatus("Deleting '${buildDir.path}${Platform.pathSeparator}'.");
|
||||||
|
|
||||||
if (compilerPath == null)
|
if (!buildDir.existsSync())
|
||||||
await downloadToolchain();
|
return 0;
|
||||||
else
|
|
||||||
toolchain = new Toolchain(compiler: new Compiler(compilerPath));
|
|
||||||
|
|
||||||
String outputPath = argResults['output-file'];
|
try {
|
||||||
|
buildDir.deleteSync(recursive: true);
|
||||||
return await build(
|
return 0;
|
||||||
toolchain,
|
} catch (error) {
|
||||||
mainPath: argResults['target'],
|
printError(error.toString());
|
||||||
manifestPath: argResults['manifest'],
|
return 1;
|
||||||
outputPath: outputPath,
|
}
|
||||||
snapshotPath: argResults['snapshot'],
|
|
||||||
depfilePath: argResults['depfile'],
|
|
||||||
privateKeyPath: argResults['private-key'],
|
|
||||||
workingDirPath: argResults['working-dir'],
|
|
||||||
precompiledSnapshot: argResults['precompiled']
|
|
||||||
).then((int result) {
|
|
||||||
if (result == 0)
|
|
||||||
printStatus('Built $outputPath.');
|
|
||||||
else
|
|
||||||
printError('Error building $outputPath: $result.');
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,22 +127,19 @@ class _ApkComponents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ApkKeystoreInfo {
|
class ApkKeystoreInfo {
|
||||||
ApkKeystoreInfo({ this.keystore, this.password, this.keyAlias, this.keyPassword });
|
ApkKeystoreInfo({ this.keystore, this.password, this.keyAlias, this.keyPassword }) {
|
||||||
|
assert(keystore != null);
|
||||||
|
}
|
||||||
|
|
||||||
String keystore;
|
final String keystore;
|
||||||
String password;
|
final String password;
|
||||||
String keyAlias;
|
final String keyAlias;
|
||||||
String keyPassword;
|
final String keyPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApkCommand extends FlutterCommand {
|
class BuildApkCommand extends FlutterCommand {
|
||||||
@override
|
BuildApkCommand() {
|
||||||
final String name = 'apk';
|
usesTargetOption();
|
||||||
|
|
||||||
@override
|
|
||||||
final String description = 'Build an Android APK package.';
|
|
||||||
|
|
||||||
ApkCommand() {
|
|
||||||
argParser.addOption('manifest',
|
argParser.addOption('manifest',
|
||||||
abbr: 'm',
|
abbr: 'm',
|
||||||
defaultsTo: _kDefaultAndroidManifestPath,
|
defaultsTo: _kDefaultAndroidManifestPath,
|
||||||
@ -157,23 +154,24 @@ class ApkCommand extends FlutterCommand {
|
|||||||
help: 'Output APK file.');
|
help: 'Output APK file.');
|
||||||
argParser.addOption('flx',
|
argParser.addOption('flx',
|
||||||
abbr: 'f',
|
abbr: 'f',
|
||||||
defaultsTo: '',
|
|
||||||
help: 'Path to the FLX file. If this is not provided, an FLX will be built.');
|
help: 'Path to the FLX file. If this is not provided, an FLX will be built.');
|
||||||
argParser.addOption('keystore',
|
argParser.addOption('keystore',
|
||||||
defaultsTo: '',
|
|
||||||
help: 'Path to the keystore used to sign the app.');
|
help: 'Path to the keystore used to sign the app.');
|
||||||
argParser.addOption('keystore-password',
|
argParser.addOption('keystore-password',
|
||||||
defaultsTo: '',
|
|
||||||
help: 'Password used to access the keystore.');
|
help: 'Password used to access the keystore.');
|
||||||
argParser.addOption('keystore-key-alias',
|
argParser.addOption('keystore-key-alias',
|
||||||
defaultsTo: '',
|
|
||||||
help: 'Alias of the entry within the keystore.');
|
help: 'Alias of the entry within the keystore.');
|
||||||
argParser.addOption('keystore-key-password',
|
argParser.addOption('keystore-key-password',
|
||||||
defaultsTo: '',
|
|
||||||
help: 'Password for the entry within the keystore.');
|
help: 'Password for the entry within the keystore.');
|
||||||
addTargetOption();
|
usesPubOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String name = 'apk';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String description = 'Build an Android APK file from your app.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> runInProject() async {
|
Future<int> runInProject() async {
|
||||||
// Validate that we can find an android sdk.
|
// Validate that we can find an android sdk.
|
||||||
@ -199,7 +197,7 @@ class ApkCommand extends FlutterCommand {
|
|||||||
outputFile: argResults['output-file'],
|
outputFile: argResults['output-file'],
|
||||||
target: argResults['target'],
|
target: argResults['target'],
|
||||||
flxPath: argResults['flx'],
|
flxPath: argResults['flx'],
|
||||||
keystore: argResults['keystore'].isEmpty ? null : new ApkKeystoreInfo(
|
keystore: (argResults['keystore'] ?? '').isEmpty ? null : new ApkKeystoreInfo(
|
||||||
keystore: argResults['keystore'],
|
keystore: argResults['keystore'],
|
||||||
password: argResults['keystore-password'],
|
password: argResults['keystore-password'],
|
||||||
keyAlias: argResults['keystore-key-alias'],
|
keyAlias: argResults['keystore-key-alias'],
|
||||||
@ -324,13 +322,13 @@ int _signApk(
|
|||||||
keyPassword = _kDebugKeystorePassword;
|
keyPassword = _kDebugKeystorePassword;
|
||||||
} else {
|
} else {
|
||||||
keystore = new File(keystoreInfo.keystore);
|
keystore = new File(keystoreInfo.keystore);
|
||||||
keystorePassword = keystoreInfo.password;
|
keystorePassword = keystoreInfo.password ?? '';
|
||||||
keyAlias = keystoreInfo.keyAlias;
|
keyAlias = keystoreInfo.keyAlias ?? '';
|
||||||
if (keystorePassword.isEmpty || keyAlias.isEmpty) {
|
if (keystorePassword.isEmpty || keyAlias.isEmpty) {
|
||||||
printError('Must provide a keystore password and a key alias.');
|
printError('Must provide a keystore password and a key alias.');
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
keyPassword = keystoreInfo.keyPassword;
|
keyPassword = keystoreInfo.keyPassword ?? '';
|
||||||
if (keyPassword.isEmpty)
|
if (keyPassword.isEmpty)
|
||||||
keyPassword = keystorePassword;
|
keyPassword = keystorePassword;
|
||||||
}
|
}
|
||||||
@ -375,7 +373,7 @@ Future<int> buildAndroid({
|
|||||||
String resources: _kDefaultResourcesPath,
|
String resources: _kDefaultResourcesPath,
|
||||||
String outputFile: _kDefaultOutputPath,
|
String outputFile: _kDefaultOutputPath,
|
||||||
String target: '',
|
String target: '',
|
||||||
String flxPath: '',
|
String flxPath,
|
||||||
ApkKeystoreInfo keystore
|
ApkKeystoreInfo keystore
|
||||||
}) async {
|
}) async {
|
||||||
// Validate that we can find an android sdk.
|
// Validate that we can find an android sdk.
|
||||||
@ -405,7 +403,7 @@ Future<int> buildAndroid({
|
|||||||
|
|
||||||
printStatus('Building APK...');
|
printStatus('Building APK...');
|
||||||
|
|
||||||
if (flxPath.isNotEmpty) {
|
if (flxPath != null && flxPath.isNotEmpty) {
|
||||||
if (!FileSystemEntity.isFileSync(flxPath)) {
|
if (!FileSystemEntity.isFileSync(flxPath)) {
|
||||||
printError('FLX does not exist: $flxPath');
|
printError('FLX does not exist: $flxPath');
|
||||||
printError('(Omit the --flx option to build the FLX automatically)');
|
printError('(Omit the --flx option to build the FLX automatically)');
|
68
packages/flutter_tools/lib/src/commands/build_flx.dart
Normal file
68
packages/flutter_tools/lib/src/commands/build_flx.dart
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2015 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 '../flx.dart';
|
||||||
|
import '../globals.dart';
|
||||||
|
import '../runner/flutter_command.dart';
|
||||||
|
import '../toolchain.dart';
|
||||||
|
|
||||||
|
class BuildFlxCommand extends FlutterCommand {
|
||||||
|
BuildFlxCommand() {
|
||||||
|
usesTargetOption();
|
||||||
|
argParser.addFlag('precompiled', negatable: false);
|
||||||
|
// This option is still referenced by the iOS build scripts. We should
|
||||||
|
// remove it once we've updated those build scripts.
|
||||||
|
argParser.addOption('asset-base', help: 'Ignored. Will be removed.', hide: true);
|
||||||
|
argParser.addOption('compiler');
|
||||||
|
argParser.addOption('manifest', defaultsTo: defaultManifestPath);
|
||||||
|
argParser.addOption('private-key', defaultsTo: defaultPrivateKeyPath);
|
||||||
|
argParser.addOption('output-file', abbr: 'o', defaultsTo: defaultFlxOutputPath);
|
||||||
|
argParser.addOption('snapshot', defaultsTo: defaultSnapshotPath);
|
||||||
|
argParser.addOption('depfile', defaultsTo: defaultDepfilePath);
|
||||||
|
argParser.addOption('working-dir', defaultsTo: defaultWorkingDirPath);
|
||||||
|
usesPubOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String name = 'flx';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String description = 'Build a Flutter FLX file from your app.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String usageFooter = 'FLX files are archives of your application code and resources; '
|
||||||
|
'they are used by some Flutter Android and iOS runtimes.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> runInProject() async {
|
||||||
|
String compilerPath = argResults['compiler'];
|
||||||
|
|
||||||
|
if (compilerPath == null)
|
||||||
|
await downloadToolchain();
|
||||||
|
else
|
||||||
|
toolchain = new Toolchain(compiler: new Compiler(compilerPath));
|
||||||
|
|
||||||
|
String outputPath = argResults['output-file'];
|
||||||
|
|
||||||
|
return await build(
|
||||||
|
toolchain,
|
||||||
|
mainPath: argResults['target'],
|
||||||
|
manifestPath: argResults['manifest'],
|
||||||
|
outputPath: outputPath,
|
||||||
|
snapshotPath: argResults['snapshot'],
|
||||||
|
depfilePath: argResults['depfile'],
|
||||||
|
privateKeyPath: argResults['private-key'],
|
||||||
|
workingDirPath: argResults['working-dir'],
|
||||||
|
precompiledSnapshot: argResults['precompiled']
|
||||||
|
).then((int result) {
|
||||||
|
if (result == 0)
|
||||||
|
printStatus('Built $outputPath.');
|
||||||
|
else
|
||||||
|
printError('Error building $outputPath: $result.');
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ import '../base/os.dart';
|
|||||||
import '../device.dart';
|
import '../device.dart';
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
import '../ios/simulators.dart' show SimControl, IOSSimulatorUtils;
|
import '../ios/simulators.dart' show SimControl, IOSSimulatorUtils;
|
||||||
import 'apk.dart' as apk;
|
import 'build_apk.dart' as build_apk;
|
||||||
import 'run.dart';
|
import 'run.dart';
|
||||||
|
|
||||||
/// Runs integration (a.k.a. end-to-end) tests.
|
/// Runs integration (a.k.a. end-to-end) tests.
|
||||||
@ -244,7 +244,7 @@ Future<int> startApp(DriveCommand command) async {
|
|||||||
|
|
||||||
if (command.device is AndroidDevice) {
|
if (command.device is AndroidDevice) {
|
||||||
printTrace('Building an APK.');
|
printTrace('Building an APK.');
|
||||||
int result = await apk.build(command.toolchain, command.buildConfigurations,
|
int result = await build_apk.build(command.toolchain, command.buildConfigurations,
|
||||||
enginePath: command.runner.enginePath, target: command.target);
|
enginePath: command.runner.enginePath, target: command.target);
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
|
@ -19,7 +19,7 @@ class RefreshCommand extends FlutterCommand {
|
|||||||
final String description = 'Build and deploy the Dart code in a Flutter app (Android only).';
|
final String description = 'Build and deploy the Dart code in a Flutter app (Android only).';
|
||||||
|
|
||||||
RefreshCommand() {
|
RefreshCommand() {
|
||||||
addTargetOption();
|
usesTargetOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -15,7 +15,7 @@ import '../device.dart';
|
|||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
import '../runner/flutter_command.dart';
|
import '../runner/flutter_command.dart';
|
||||||
import '../toolchain.dart';
|
import '../toolchain.dart';
|
||||||
import 'apk.dart';
|
import 'build_apk.dart';
|
||||||
import 'install.dart';
|
import 'install.dart';
|
||||||
|
|
||||||
/// Given the value of the --target option, return the path of the Dart file
|
/// Given the value of the --target option, return the path of the Dart file
|
||||||
@ -43,7 +43,7 @@ abstract class RunCommandBase extends FlutterCommand {
|
|||||||
help: 'Start tracing during startup.');
|
help: 'Start tracing during startup.');
|
||||||
argParser.addOption('route',
|
argParser.addOption('route',
|
||||||
help: 'Which route to load when starting the app.');
|
help: 'Which route to load when starting the app.');
|
||||||
addTargetOption();
|
usesTargetOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get checked => argResults['checked'];
|
bool get checked => argResults['checked'];
|
||||||
@ -73,12 +73,10 @@ class RunCommand extends RunCommandBase {
|
|||||||
defaultsTo: false,
|
defaultsTo: false,
|
||||||
negatable: false,
|
negatable: false,
|
||||||
help: 'Start in a paused mode and wait for a debugger to connect.');
|
help: 'Start in a paused mode and wait for a debugger to connect.');
|
||||||
argParser.addFlag('pub',
|
|
||||||
defaultsTo: true,
|
|
||||||
help: 'Whether to run "pub get" before running the app.');
|
|
||||||
argParser.addOption('debug-port',
|
argParser.addOption('debug-port',
|
||||||
defaultsTo: observatoryDefaultPort.toString(),
|
defaultsTo: observatoryDefaultPort.toString(),
|
||||||
help: 'Listen to the given port for a debug connection.');
|
help: 'Listen to the given port for a debug connection.');
|
||||||
|
usesPubOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -7,6 +7,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
import 'package:args/command_runner.dart';
|
||||||
|
|
||||||
|
import '../dart/pub.dart';
|
||||||
import '../application_package.dart';
|
import '../application_package.dart';
|
||||||
import '../build_configuration.dart';
|
import '../build_configuration.dart';
|
||||||
import '../device.dart';
|
import '../device.dart';
|
||||||
@ -18,6 +19,10 @@ import 'flutter_command_runner.dart';
|
|||||||
typedef bool Validator();
|
typedef bool Validator();
|
||||||
|
|
||||||
abstract class FlutterCommand extends Command {
|
abstract class FlutterCommand extends Command {
|
||||||
|
FlutterCommand() {
|
||||||
|
commandValidator = _commandValidator;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FlutterCommandRunner get runner => super.runner;
|
FlutterCommandRunner get runner => super.runner;
|
||||||
|
|
||||||
@ -30,12 +35,28 @@ abstract class FlutterCommand extends Command {
|
|||||||
/// Whether this command only applies to Android devices.
|
/// Whether this command only applies to Android devices.
|
||||||
bool get androidOnly => false;
|
bool get androidOnly => false;
|
||||||
|
|
||||||
/// Whether this command allows usage of the 'target' option.
|
/// Whether this command uses the 'target' option.
|
||||||
bool get allowsTarget => _targetOptionSpecified;
|
bool _usesTargetOption = false;
|
||||||
bool _targetOptionSpecified = false;
|
|
||||||
|
bool _usesPubOption = false;
|
||||||
|
|
||||||
List<BuildConfiguration> get buildConfigurations => runner.buildConfigurations;
|
List<BuildConfiguration> get buildConfigurations => runner.buildConfigurations;
|
||||||
|
|
||||||
|
void usesTargetOption() {
|
||||||
|
argParser.addOption('target',
|
||||||
|
abbr: 't',
|
||||||
|
defaultsTo: flx.defaultMainPath,
|
||||||
|
help: 'Target app path / main entry-point file.');
|
||||||
|
_usesTargetOption = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usesPubOption() {
|
||||||
|
argParser.addFlag('pub',
|
||||||
|
defaultsTo: true,
|
||||||
|
help: 'Whether to run "pub get" before executing this command.');
|
||||||
|
_usesPubOption = true;
|
||||||
|
}
|
||||||
|
|
||||||
Future<Null> downloadToolchain() async {
|
Future<Null> downloadToolchain() async {
|
||||||
toolchain ??= await Toolchain.forConfigs(buildConfigurations);
|
toolchain ??= await Toolchain.forConfigs(buildConfigurations);
|
||||||
}
|
}
|
||||||
@ -56,8 +77,7 @@ abstract class FlutterCommand extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _run() async {
|
Future<int> _run() async {
|
||||||
bool _checkRoot = requiresProjectRoot && allowsTarget && !_targetSpecified;
|
if (requiresProjectRoot && !commandValidator())
|
||||||
if (_checkRoot && !projectRootValidator())
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// Ensure at least one toolchain is installed.
|
// Ensure at least one toolchain is installed.
|
||||||
@ -99,19 +119,36 @@ abstract class FlutterCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_usesPubOption && argResults['pub']) {
|
||||||
|
int exitCode = await pubGet();
|
||||||
|
if (exitCode != 0)
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
return await runInProject();
|
return await runInProject();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a field so that you can modify the value for testing.
|
// This is a field so that you can modify the value for testing.
|
||||||
Validator projectRootValidator = () {
|
Validator commandValidator;
|
||||||
|
|
||||||
|
bool _commandValidator() {
|
||||||
if (!FileSystemEntity.isFileSync('pubspec.yaml')) {
|
if (!FileSystemEntity.isFileSync('pubspec.yaml')) {
|
||||||
printError('Error: No pubspec.yaml file found.\n'
|
printError('Error: No pubspec.yaml file found.\n'
|
||||||
'This command should be run from the root of your Flutter project.\n'
|
'This command should be run from the root of your Flutter project.\n'
|
||||||
'Do not run this command from the root of your git clone of Flutter.');
|
'Do not run this command from the root of your git clone of Flutter.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_usesTargetOption) {
|
||||||
|
String targetPath = argResults['target'];
|
||||||
|
if (!FileSystemEntity.isFileSync(targetPath)) {
|
||||||
|
printError('Target file "$targetPath" not found.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
Future<int> runInProject();
|
Future<int> runInProject();
|
||||||
|
|
||||||
@ -122,15 +159,4 @@ abstract class FlutterCommand extends Command {
|
|||||||
|
|
||||||
ApplicationPackageStore applicationPackages;
|
ApplicationPackageStore applicationPackages;
|
||||||
Toolchain toolchain;
|
Toolchain toolchain;
|
||||||
|
|
||||||
bool _targetSpecified = false;
|
|
||||||
|
|
||||||
void addTargetOption() {
|
|
||||||
argParser.addOption('target',
|
|
||||||
abbr: 't',
|
|
||||||
callback: (dynamic val) => _targetSpecified = true,
|
|
||||||
defaultsTo: flx.defaultMainPath,
|
|
||||||
help: 'Target app path / main entry-point file.');
|
|
||||||
_targetOptionSpecified = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -101,5 +101,5 @@ void applyMocksToCommand(FlutterCommand command) {
|
|||||||
command
|
command
|
||||||
..applicationPackages = new MockApplicationPackageStore()
|
..applicationPackages = new MockApplicationPackageStore()
|
||||||
..toolchain = new MockToolchain()
|
..toolchain = new MockToolchain()
|
||||||
..projectRootValidator = () => true;
|
..commandValidator = () => true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user