Unverified Commit 0ff9e8a9 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Rename 'application' back to 'module', and make 'app' the default again for templates. (#22888)

We decided that redefining the default for templates was premature. We're going to go back to having "module" in experimental land again, and we'll try again when we have the feature set fully baked.

This keeps the writing of the .metadata files, and writing the template type to them, because that was a good improvement, and there are still a bunch of added tests that improve our coverage.
parent e58e4732
......@@ -9,7 +9,7 @@ import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
/// Tests that the Flutter application project template works and supports
/// Tests that the Flutter module project template works and supports
/// adding Flutter to an existing Android app.
Future<void> main() async {
await task(() async {
......@@ -21,15 +21,15 @@ Future<void> main() async {
return TaskResult.failure('Could not find Java');
print('\nUsing JAVA_HOME=$javaHome');
section('Create Flutter application project');
section('Create Flutter module project');
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_application_test.');
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
try {
await inDirectory(tempDir, () async {
await flutter(
'create',
options: <String>['--org', 'io.flutter.devicelab', '--template=application', 'hello'],
options: <String>['--org', 'io.flutter.devicelab', '--template=module', 'hello'],
);
});
......@@ -49,7 +49,7 @@ Future<void> main() async {
);
});
section('Build Flutter application library archive');
section('Build Flutter module library archive');
await inDirectory(Directory(path.join(projectDir.path, '.android')), () async {
await exec(
......
......@@ -10,20 +10,20 @@ import 'package:flutter_devicelab/framework/ios.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:path/path.dart' as path;
/// Tests that the Flutter application project template works and supports
/// Tests that the Flutter module project template works and supports
/// adding Flutter to an existing iOS app.
Future<void> main() async {
await task(() async {
section('Create Flutter application project');
section('Create Flutter module project');
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_application_test.');
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_module_test.');
final Directory projectDir = Directory(path.join(tempDir.path, 'hello'));
try {
await inDirectory(tempDir, () async {
await flutter(
'create',
options: <String>['--org', 'io.flutter.devicelab', '--template=application', 'hello'],
options: <String>['--org', 'io.flutter.devicelab', '--template=module', 'hello'],
);
});
await prepareProvisioningCertificates(projectDir.path);
......
......@@ -263,9 +263,9 @@ tasks:
stage: devicelab
required_agent_capabilities: ["linux/android"]
application_test:
module_test:
description: >
Checks that the application project template works and supports add2app on Android.
Checks that the module project template works and supports add2app on Android.
stage: devicelab
required_agent_capabilities: ["linux/android"]
......@@ -297,9 +297,9 @@ tasks:
stage: devicelab_ios
required_agent_capabilities: ["mac/ios"]
application_test_ios:
module_test_ios:
description: >
Checks that the application project template works and supports add2app on iOS.
Checks that the module project template works and supports add2app on iOS.
stage: devicelab
required_agent_capabilities: ["mac/ios"]
......
......@@ -56,7 +56,7 @@ Future<void> main(List<String> args) async {
ChannelCommand(verboseHelp: verboseHelp),
CleanCommand(),
ConfigCommand(verboseHelp: verboseHelp),
CreateCommand(verboseHelp: verboseHelp),
CreateCommand(),
DaemonCommand(hidden: !verboseHelp),
DevicesCommand(),
DoctorCommand(verbose: verbose),
......
......@@ -25,15 +25,13 @@ import '../template.dart';
import '../version.dart';
enum _ProjectType {
/// This is the legacy "app" module type that was created before the default
/// was "application". It is kept around to allow users to recreate files that
/// have been removed in old projects.
/// This is the default project with the user-managed host code.
/// It is different than the "module" template in that it exposes and doesn't
/// manage the platform code.
app,
/// The is the default type of project created. It is an application with
/// The is a project that has managed platform host code. It is an application with
/// ephemeral .ios and .android directories that can be updated automatically.
application,
/// This is the old name for the [application] style project.
module, // TODO(gspencer): deprecated -- should be removed once IntelliJ no longer uses it.
module,
/// This is a Flutter Dart package project. It doesn't have any native
/// components, only Dart.
package,
......@@ -43,11 +41,6 @@ enum _ProjectType {
_ProjectType _stringToProjectType(String value) {
_ProjectType result;
// TODO(gspencer): remove module when it is no longer used by IntelliJ plugin.
// Module is just an alias for application.
if (value == 'module') {
value = 'application';
}
for (_ProjectType type in _ProjectType.values) {
if (value == getEnumName(type)) {
result = type;
......@@ -58,7 +51,7 @@ _ProjectType _stringToProjectType(String value) {
}
class CreateCommand extends FlutterCommand {
CreateCommand({bool verboseHelp = false }) {
CreateCommand() {
argParser.addFlag('pub',
defaultsTo: true,
help: 'Whether to run "flutter packages get" after the project has been created.'
......@@ -82,23 +75,13 @@ class CreateCommand extends FlutterCommand {
help: 'Specify the type of project to create.',
valueHelp: 'type',
allowedHelp: <String, String>{
getEnumName(_ProjectType.application): '(default) Generate a Flutter application.',
getEnumName(_ProjectType.app): '(default) Generate a Flutter application.',
getEnumName(_ProjectType.package): 'Generate a shareable Flutter project containing modular '
'Dart code.',
getEnumName(_ProjectType.plugin): 'Generate a shareable Flutter project containing an API '
'in Dart code with a platform-specific implementation for Android, for iOS code, or '
'for both.',
}..addAll(verboseHelp
? <String, String>{
getEnumName(_ProjectType.app): 'Generate the legacy form of an application project. Use '
'"application" instead, unless you are working with an existing legacy app project. '
'This is not just an alias for the "application" template, it produces different '
'output.',
getEnumName(_ProjectType.module): 'Legacy, deprecated form of an application project. Use '
'"application" instead. This is just an alias for the "application" template, it '
'produces the same output. It will be removed in a future release.',
}
: <String, String>{}),
},
defaultsTo: null,
);
argParser.addOption(
......@@ -227,7 +210,7 @@ class CreateCommand extends FlutterCommand {
}
}
}
template ??= detectedProjectType ?? _ProjectType.application;
template ??= detectedProjectType ?? _ProjectType.app;
if (detectedProjectType != null && template != detectedProjectType && metadataExists) {
// We can only be definitive that this is the wrong type if the .metadata file
// exists and contains a type that doesn't match.
......@@ -235,7 +218,7 @@ class CreateCommand extends FlutterCommand {
"existing template type of '${getEnumName(detectedProjectType)}'.");
}
final bool generateApplication = template == _ProjectType.application;
final bool generateModule = template == _ProjectType.module;
final bool generatePlugin = template == _ProjectType.plugin;
final bool generatePackage = template == _ProjectType.package;
......@@ -283,11 +266,10 @@ class CreateCommand extends FlutterCommand {
int generatedFileCount = 0;
switch (template) {
case _ProjectType.app:
generatedFileCount += await _generateLegacyApp(relativeDir, templateContext);
generatedFileCount += await _generateApp(relativeDir, templateContext);
break;
case _ProjectType.module:
case _ProjectType.application:
generatedFileCount += await _generateApplication(relativeDir, templateContext);
generatedFileCount += await _generateModule(relativeDir, templateContext);
break;
case _ProjectType.package:
generatedFileCount += await _generatePackage(relativeDir, templateContext);
......@@ -305,13 +287,13 @@ class CreateCommand extends FlutterCommand {
'${templateContext['projectName']}.dart',
));
printStatus('Your package code is in $relativeMainPath');
} else if (generateApplication) {
} else if (generateModule) {
final String relativeMainPath = fs.path.normalize(fs.path.join(
relativeDirPath,
'lib',
'main.dart',
));
printStatus('Your application code is in $relativeMainPath.');
printStatus('Your module code is in $relativeMainPath.');
} else {
// Run doctor; tell the user the next steps.
final FlutterProject project = await FlutterProject.fromPath(projectDirPath);
......@@ -359,13 +341,13 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
return null;
}
Future<int> _generateApplication(Directory directory, Map<String, dynamic> templateContext) async {
Future<int> _generateModule(Directory directory, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter application project.';
: 'A new flutter module project.';
templateContext['description'] = description;
generatedCount += _renderTemplate(fs.path.join('application', 'common'), directory, templateContext);
generatedCount += _renderTemplate(fs.path.join('module', 'common'), directory, templateContext);
if (argResults['pub']) {
await pubGet(
context: PubContext.create,
......@@ -382,7 +364,7 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
int generatedCount = 0;
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter package project.';
: 'A new Flutter package project.';
templateContext['description'] = description;
generatedCount += _renderTemplate('package', directory, templateContext);
if (argResults['pub']) {
......@@ -423,11 +405,11 @@ To edit platform code in an IDE see https://flutter.io/developing-packages/#edit
templateContext['pluginProjectName'] = projectName;
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
generatedCount += await _generateLegacyApp(project.example.directory, templateContext);
generatedCount += await _generateApp(project.example.directory, templateContext);
return generatedCount;
}
Future<int> _generateLegacyApp(Directory directory, Map<String, dynamic> templateContext) async {
Future<int> _generateApp(Directory directory, Map<String, dynamic> templateContext) async {
int generatedCount = 0;
generatedCount += _renderTemplate('app', directory, templateContext);
final FlutterProject project = await FlutterProject.fromDirectory(directory);
......
......@@ -37,8 +37,8 @@ class MakeHostAppEditableCommand extends FlutterCommand {
Future<void> validateCommand() async {
await super.validateCommand();
_project = await FlutterProject.current();
if (!_project.isApplication)
throw ToolExit("Only projects created using 'flutter create -t application' can have their host apps made editable.");
if (!_project.isModule)
throw ToolExit("Only projects created using 'flutter create -t module' can have their host apps made editable.");
}
@override
......
......@@ -110,14 +110,14 @@ class FlutterManifest {
return _flutterDescriptor['uses-material-design'] ?? false;
}
/// True if this manifest declares a Flutter application project.
/// True if this manifest declares a Flutter module project.
///
/// A Flutter project is considered an application when it has a `application:`
/// descriptor. A Flutter application project supports integration into an
/// existing host app.
/// A Flutter project is considered a module when it has a `module:`
/// descriptor. A Flutter module project supports integration into an
/// existing host app, and has managed platform host code.
///
/// Such a project can be created using `flutter create -t application`.
bool get isApplication => _flutterDescriptor.containsKey('application');
/// Such a project can be created using `flutter create -t module`.
bool get isModule => _flutterDescriptor.containsKey('module');
/// True if this manifest declares a Flutter plugin project.
///
......@@ -130,21 +130,21 @@ class FlutterManifest {
bool get isPlugin => _flutterDescriptor.containsKey('plugin');
/// Returns the Android package declared by this manifest in its
/// application or plugin descriptor. Returns null, if there is no
/// module or plugin descriptor. Returns null, if there is no
/// such declaration.
String get androidPackage {
if (isApplication)
return _flutterDescriptor['application']['androidPackage'];
if (isModule)
return _flutterDescriptor['module']['androidPackage'];
if (isPlugin)
return _flutterDescriptor['plugin']['androidPackage'];
return null;
}
/// Returns the iOS bundle identifier declared by this manifest in its
/// application descriptor. Returns null, if there is no such declaration.
/// module descriptor. Returns null if there is no such declaration.
String get iosBundleIdentifier {
if (isApplication)
return _flutterDescriptor['application']['iosBundleIdentifier'];
if (isModule)
return _flutterDescriptor['module']['iosBundleIdentifier'];
return null;
}
......
......@@ -335,7 +335,7 @@ Future<XcodeBuildResult> buildXcodeProject({
buildInfo: buildInfo,
);
refreshPluginsList(project);
if (hasPlugins(project) || (project.isApplication && project.ios.podfile.existsSync())) {
if (hasPlugins(project) || (project.isModule && project.ios.podfile.existsSync())) {
// If the Xcode project, Podfile, or Generated.xcconfig have changed since
// last run, pods should be updated.
final Fingerprinter fingerprinter = Fingerprinter(
......
......@@ -57,8 +57,8 @@ Future<void> updateGeneratedXcodeProperties({
localsBuffer.writeln('SYMROOT=\${SOURCE_ROOT}/../${getIosBuildDirectory()}');
if (!project.isApplication) {
// For application projects we do not want to write the FLUTTER_FRAMEWORK_DIR
if (!project.isModule) {
// For module projects we do not want to write the FLUTTER_FRAMEWORK_DIR
// explicitly. Rather we rely on the xcode backend script and the Podfile
// logic to derive it from FLUTTER_ROOT and FLUTTER_BUILD_MODE.
localsBuffer.writeln('FLUTTER_FRAMEWORK_DIR=${flutterFrameworkDir(buildInfo.mode)}');
......
......@@ -248,7 +248,7 @@ Future<void> _writeIOSPluginRegistrant(FlutterProject project, List<Plugin> plug
};
final String registryDirectory = project.ios.pluginRegistrantHost.path;
if (project.isApplication) {
if (project.isModule) {
final String registryClassesDirectory = fs.path.join(registryDirectory, 'Classes');
_renderTemplateToFile(
_iosPluginRegistrantPodspecTemplate,
......@@ -297,7 +297,7 @@ Future<void> injectPlugins(FlutterProject project) async {
final List<Plugin> plugins = findPlugins(project);
await _writeAndroidPluginRegistrant(project, plugins);
await _writeIOSPluginRegistrant(project, plugins);
if (!project.isApplication && project.ios.hostAppRoot.existsSync()) {
if (!project.isModule && project.ios.hostAppRoot.existsSync()) {
final CocoaPods cocoaPods = CocoaPods();
if (plugins.isNotEmpty)
cocoaPods.setupPodfile(project.ios);
......
......@@ -110,10 +110,10 @@ class FlutterProject {
FlutterManifest.empty(),
);
/// True, if this project is a Flutter application.
bool get isApplication => manifest.isApplication;
/// True if this project is a Flutter module project.
bool get isModule => manifest.isModule;
/// True, if this project has an example application.
/// True if this project has an example application.
bool get hasExampleApp => _exampleDirectory(directory).existsSync();
/// The directory that will contain the example if an example exists.
......@@ -132,7 +132,7 @@ class FlutterProject {
}
/// Generates project files necessary to make Gradle builds work on Android
/// and CocoaPods+Xcode work on iOS, for app and application projects only.
/// and CocoaPods+Xcode work on iOS, for app and module projects only.
Future<void> ensureReadyForPlatformSpecificTooling() async {
if (!directory.existsSync() || hasExampleApp)
return;
......@@ -146,7 +146,7 @@ class FlutterProject {
/// Represents the iOS sub-project of a Flutter project.
///
/// Instances will reflect the contents of the `ios/` sub-folder of
/// Flutter applications and the `.ios/` sub-folder of Flutter applications.
/// Flutter applications and the `.ios/` sub-folder of Flutter module projects.
class IosProject {
IosProject._(this.parent);
......@@ -162,7 +162,7 @@ class IosProject {
/// This parent folder of `Runner.xcodeproj`.
Directory get hostAppRoot {
if (!isApplication || _editableDirectory.existsSync())
if (!isModule || _editableDirectory.existsSync())
return _editableDirectory;
return _ephemeralDirectory;
}
......@@ -172,14 +172,14 @@ class IosProject {
/// during build.
///
/// This is the same as [hostAppRoot] except when the project is
/// a Flutter application with an editable host app.
Directory get _flutterLibRoot => isApplication ? _ephemeralDirectory : _editableDirectory;
/// a Flutter module with an editable host app.
Directory get _flutterLibRoot => isModule ? _ephemeralDirectory : _editableDirectory;
/// The bundle name of the host app, `Runner.app`.
String get hostAppBundleName => '$_hostAppBundleName.app';
/// True, if the parent Flutter project is an application.
bool get isApplication => parent.isApplication;
/// True, if the parent Flutter project is a module project.
bool get isModule => parent.isModule;
/// The xcode config file for [mode].
File xcodeConfigFor(String mode) => _flutterLibRoot.childDirectory('Flutter').childFile('$mode.xcconfig');
......@@ -264,32 +264,32 @@ class IosProject {
}
void _regenerateFromTemplateIfNeeded() {
if (!isApplication)
if (!isModule)
return;
final bool pubspecChanged = isOlderThanReference(entity: _ephemeralDirectory, referenceFile: parent.pubspecFile);
final bool toolingChanged = Cache.instance.isOlderThanToolsStamp(_ephemeralDirectory);
if (!pubspecChanged && !toolingChanged)
return;
_deleteIfExistsSync(_ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('application', 'ios', 'library'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'library'), _ephemeralDirectory);
// Add ephemeral host app, if a editable host app does not already exist.
if (!_editableDirectory.existsSync()) {
_overwriteFromTemplate(fs.path.join('application', 'ios', 'host_app_ephemeral'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral'), _ephemeralDirectory);
if (hasPlugins(parent)) {
_overwriteFromTemplate(fs.path.join('application', 'ios', 'host_app_ephemeral_cocoapods'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), _ephemeralDirectory);
}
}
}
Future<void> makeHostAppEditable() async {
assert(isApplication);
assert(isModule);
if (_editableDirectory.existsSync())
throwToolExit('iOS host app is already editable. To start fresh, delete the ios/ folder.');
_deleteIfExistsSync(_ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('application', 'ios', 'library'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('application', 'ios', 'host_app_ephemeral'), _editableDirectory);
_overwriteFromTemplate(fs.path.join('application', 'ios', 'host_app_ephemeral_cocoapods'), _editableDirectory);
_overwriteFromTemplate(fs.path.join('application', 'ios', 'host_app_editable_cocoapods'), _editableDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'library'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral'), _editableDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), _editableDirectory);
_overwriteFromTemplate(fs.path.join('module', 'ios', 'host_app_editable_cocoapods'), _editableDirectory);
await _updateGeneratedXcodeConfigIfNeeded();
await injectPlugins(parent);
}
......@@ -297,7 +297,7 @@ class IosProject {
File get generatedXcodePropertiesFile => _flutterLibRoot.childDirectory('Flutter').childFile('Generated.xcconfig');
Directory get pluginRegistrantHost {
return isApplication
return isModule
? _flutterLibRoot.childDirectory('Flutter').childDirectory('FlutterPluginRegistrant')
: hostAppRoot.childDirectory(_hostAppBundleName);
}
......@@ -319,7 +319,7 @@ class IosProject {
/// Represents the Android sub-project of a Flutter project.
///
/// Instances will reflect the contents of the `android/` sub-folder of
/// Flutter applications and the `.android/` sub-folder of Flutter applications.
/// Flutter applications and the `.android/` sub-folder of Flutter module projects.
class AndroidProject {
AndroidProject._(this.parent);
......@@ -333,21 +333,21 @@ class AndroidProject {
/// containing the `app/` subdirectory and the `settings.gradle` file that
/// includes it in the overall Gradle project.
Directory get hostAppGradleRoot {
if (!isApplication || _editableHostAppDirectory.existsSync())
if (!isModule || _editableHostAppDirectory.existsSync())
return _editableHostAppDirectory;
return _ephemeralDirectory;
}
/// The Gradle root directory of the Android wrapping of Flutter and plugins.
/// This is the same as [hostAppGradleRoot] except when the project is
/// a Flutter application with an editable host app.
Directory get _flutterLibGradleRoot => isApplication ? _ephemeralDirectory : _editableHostAppDirectory;
/// a Flutter module with an editable host app.
Directory get _flutterLibGradleRoot => isModule ? _ephemeralDirectory : _editableHostAppDirectory;
Directory get _ephemeralDirectory => parent.directory.childDirectory('.android');
Directory get _editableHostAppDirectory => parent.directory.childDirectory('android');
/// True, if the parent Flutter project is an application.
bool get isApplication => parent.isApplication;
/// True if the parent Flutter project is a module.
bool get isModule => parent.isModule;
File get appManifestFile {
return isUsingGradle
......@@ -376,12 +376,12 @@ class AndroidProject {
}
Future<void> ensureReadyForPlatformSpecificTooling() async {
if (isApplication && _shouldRegenerateFromTemplate()) {
if (isModule && _shouldRegenerateFromTemplate()) {
_regenerateLibrary();
// Add ephemeral host app, if an editable host app does not already exist.
if (!_editableHostAppDirectory.existsSync()) {
_overwriteFromTemplate(fs.path.join('application', 'android', 'host_app_common'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('application', 'android', 'host_app_ephemeral'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'host_app_common'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'host_app_ephemeral'), _ephemeralDirectory);
}
}
if (!hostAppGradleRoot.existsSync()) {
......@@ -396,13 +396,13 @@ class AndroidProject {
}
Future<void> makeHostAppEditable() async {
assert(isApplication);
assert(isModule);
if (_editableHostAppDirectory.existsSync())
throwToolExit('Android host app is already editable. To start fresh, delete the android/ folder.');
_regenerateLibrary();
_overwriteFromTemplate(fs.path.join('application', 'android', 'host_app_common'), _editableHostAppDirectory);
_overwriteFromTemplate(fs.path.join('application', 'android', 'host_app_editable'), _editableHostAppDirectory);
_overwriteFromTemplate(fs.path.join('application', 'android', 'gradle'), _editableHostAppDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'host_app_common'), _editableHostAppDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'host_app_editable'), _editableHostAppDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'gradle'), _editableHostAppDirectory);
gradle.injectGradleWrapper(_editableHostAppDirectory);
gradle.writeLocalProperties(_editableHostAppDirectory.childFile('local.properties'));
await injectPlugins(parent);
......@@ -410,12 +410,12 @@ class AndroidProject {
File get localPropertiesFile => _flutterLibGradleRoot.childFile('local.properties');
Directory get pluginRegistrantHost => _flutterLibGradleRoot.childDirectory(isApplication ? 'Flutter' : 'app');
Directory get pluginRegistrantHost => _flutterLibGradleRoot.childDirectory(isModule ? 'Flutter' : 'app');
void _regenerateLibrary() {
_deleteIfExistsSync(_ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('application', 'android', 'library'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('application', 'android', 'gradle'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'library'), _ephemeralDirectory);
_overwriteFromTemplate(fs.path.join('module', 'android', 'gradle'), _ephemeralDirectory);
gradle.injectGradleWrapper(_ephemeralDirectory);
}
......
......@@ -43,7 +43,7 @@
}
}
},
"application": {
"module": {
"type": "object",
"additionalProperties": false,
"properties": {
......
......@@ -7,4 +7,4 @@ version:
revision: {{flutterRevision}}
channel: {{flutterChannel}}
project_type: application
project_type: module
......@@ -20,6 +20,6 @@ dev_dependencies:
flutter:
uses-material-design: true
application:
module:
androidPackage: {{androidIdentifier}}
iosBundleIdentifier: {{iosIdentifier}}
......@@ -45,8 +45,8 @@ void main() {
tryToDelete(tempDir);
});
Future<String> createProjectWithPlugin(String plugin) async {
final String projectPath = await createProject(tempDir);
Future<String> createProjectWithPlugin(String plugin, {List<String> arguments}) async {
final String projectPath = await createProject(tempDir, arguments: arguments);
final File pubspec = fs.file(fs.path.join(projectPath, 'pubspec.yaml'));
String content = await pubspec.readAsString();
content = content.replaceFirst(
......@@ -114,7 +114,7 @@ void main() {
'android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
];
const List<String> applicationPluginRegistrants = <String>[
const List<String> modulePluginRegistrants = <String>[
'.ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.h',
'.ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.m',
'.android/Flutter/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
......@@ -125,7 +125,7 @@ void main() {
'ios/Podfile',
];
const List<String> applicationPluginWitnesses = <String>[
const List<String> modulePluginWitnesses = <String>[
'.flutter-plugins',
'.ios/Podfile',
];
......@@ -135,7 +135,7 @@ void main() {
'ios/Flutter/Release.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"',
};
const Map<String, String> applicationPluginContentWitnesses = <String, String>{
const Map<String, String> modulePluginContentWitnesses = <String, String>{
'.ios/Config/Debug.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"',
'.ios/Config/Release.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"',
};
......@@ -147,13 +147,13 @@ void main() {
}
void expectZeroPluginsInjected(String projectPath) {
for (final String registrant in applicationPluginRegistrants) {
for (final String registrant in modulePluginRegistrants) {
expectExists(projectPath, registrant);
}
for (final String witness in pluginWitnesses) {
expectNotExists(projectPath, witness);
}
applicationPluginContentWitnesses.forEach((String witness, String content) {
modulePluginContentWitnesses.forEach((String witness, String content) {
expectNotContains(projectPath, witness, content);
});
}
......@@ -170,14 +170,14 @@ void main() {
});
}
void expectApplicationPluginInjected(String projectPath) {
for (final String registrant in applicationPluginRegistrants) {
void expectModulePluginInjected(String projectPath) {
for (final String registrant in modulePluginRegistrants) {
expectExists(projectPath, registrant);
}
for (final String witness in applicationPluginWitnesses) {
for (final String witness in modulePluginWitnesses) {
expectExists(projectPath, witness);
}
applicationPluginContentWitnesses.forEach((String witness, String content) {
modulePluginContentWitnesses.forEach((String witness, String content) {
expectContains(projectPath, witness, content);
});
}
......@@ -185,7 +185,7 @@ void main() {
void removeGeneratedFiles(String projectPath) {
final Iterable<String> allFiles = <List<String>>[
pubOutput,
applicationPluginRegistrants,
modulePluginRegistrants,
pluginWitnesses,
].expand<String>((List<String> list) => list);
for (String path in allFiles) {
......@@ -196,7 +196,8 @@ void main() {
}
testUsingContext('get fetches packages', () async {
final String projectPath = await createProject(tempDir);
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=module']);
removeGeneratedFiles(projectPath);
await runCommandIn(projectPath, 'get');
......@@ -206,7 +207,8 @@ void main() {
}, timeout: allowForRemotePubInvocation);
testUsingContext('get --offline fetches packages', () async {
final String projectPath = await createProject(tempDir);
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=module']);
removeGeneratedFiles(projectPath);
await runCommandIn(projectPath, 'get', args: <String>['--offline']);
......@@ -216,7 +218,8 @@ void main() {
}, timeout: allowForCreateFlutterProject);
testUsingContext('upgrade fetches packages', () async {
final String projectPath = await createProject(tempDir);
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=module']);
removeGeneratedFiles(projectPath);
await runCommandIn(projectPath, 'upgrade');
......@@ -226,13 +229,14 @@ void main() {
}, timeout: allowForRemotePubInvocation);
testUsingContext('get fetches packages and injects plugin', () async {
final String projectPath = await createProjectWithPlugin('path_provider');
final String projectPath = await createProjectWithPlugin('path_provider',
arguments: <String>['--no-pub', '--template=module']);
removeGeneratedFiles(projectPath);
await runCommandIn(projectPath, 'get');
expectDependenciesResolved(projectPath);
expectApplicationPluginInjected(projectPath);
expectModulePluginInjected(projectPath);
}, timeout: allowForRemotePubInvocation);
testUsingContext('get fetches packages and injects plugin in plugin project', () async {
......
......@@ -355,20 +355,20 @@ flutter:
''';
final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest);
expect(flutterManifest.isEmpty, false);
expect(flutterManifest.isApplication, false);
expect(flutterManifest.isModule, false);
expect(flutterManifest.isPlugin, false);
expect(flutterManifest.androidPackage, null);
});
test('allows an application declaration', () async {
test('allows a module declaration', () async {
const String manifest = '''
name: test
flutter:
application:
module:
androidPackage: com.example
''';
final FlutterManifest flutterManifest = await FlutterManifest.createFromString(manifest);
expect(flutterManifest.isApplication, true);
expect(flutterManifest.isModule, true);
expect(flutterManifest.androidPackage, 'com.example');
});
......
......@@ -90,20 +90,20 @@ void main() {
});
group('editable Android host app', () {
testInMemory('fails on non-application', () async {
testInMemory('fails on non-module', () async {
final FlutterProject project = await someProject();
await expectLater(
project.android.makeHostAppEditable(),
throwsA(isInstanceOf<AssertionError>()),
);
});
testInMemory('exits on already editable application', () async {
final FlutterProject project = await anApplicationProject();
testInMemory('exits on already editable module', () async {
final FlutterProject project = await aModuleProject();
await project.android.makeHostAppEditable();
return expectToolExitLater(project.android.makeHostAppEditable(), contains('already editable'));
});
testInMemory('creates android/app folder in place of .android/app', () async {
final FlutterProject project = await anApplicationProject();
final FlutterProject project = await aModuleProject();
await project.android.makeHostAppEditable();
expectNotExists(project.directory.childDirectory('.android').childDirectory('app'));
expect(
......@@ -118,7 +118,7 @@ void main() {
);
});
testInMemory('retains .android/Flutter folder and references it', () async {
final FlutterProject project = await anApplicationProject();
final FlutterProject project = await aModuleProject();
await project.android.makeHostAppEditable();
expectExists(project.directory.childDirectory('.android').childDirectory('Flutter'));
expect(
......@@ -127,7 +127,7 @@ void main() {
);
});
testInMemory('can be redone after deletion', () async {
final FlutterProject project = await anApplicationProject();
final FlutterProject project = await aModuleProject();
await project.android.makeHostAppEditable();
project.directory.childDirectory('android').deleteSync(recursive: true);
await project.android.makeHostAppEditable();
......@@ -173,15 +173,15 @@ void main() {
await project.ensureReadyForPlatformSpecificTooling();
expectExists(project.android.hostAppGradleRoot.childFile('local.properties'));
});
testInMemory('creates Android library in application', () async {
final FlutterProject project = await anApplicationProject();
testInMemory('creates Android library in module', () async {
final FlutterProject project = await aModuleProject();
await project.ensureReadyForPlatformSpecificTooling();
expectExists(project.android.hostAppGradleRoot.childFile('settings.gradle'));
expectExists(project.android.hostAppGradleRoot.childFile('local.properties'));
expectExists(androidPluginRegistrant(project.android.hostAppGradleRoot.childDirectory('Flutter')));
});
testInMemory('creates iOS pod in application', () async {
final FlutterProject project = await anApplicationProject();
testInMemory('creates iOS pod in module', () async {
final FlutterProject project = await aModuleProject();
await project.ensureReadyForPlatformSpecificTooling();
final Directory flutter = project.ios.hostAppRoot.childDirectory('Flutter');
expectExists(flutter.childFile('podhelper.rb'));
......@@ -194,20 +194,20 @@ void main() {
});
});
group('application status', () {
testInMemory('is known for application', () async {
final FlutterProject project = await anApplicationProject();
expect(project.isApplication, isTrue);
expect(project.android.isApplication, isTrue);
expect(project.ios.isApplication, isTrue);
group('module status', () {
testInMemory('is known for module', () async {
final FlutterProject project = await aModuleProject();
expect(project.isModule, isTrue);
expect(project.android.isModule, isTrue);
expect(project.ios.isModule, isTrue);
expect(project.android.hostAppGradleRoot.basename, '.android');
expect(project.ios.hostAppRoot.basename, '.ios');
});
testInMemory('is known for non-application', () async {
testInMemory('is known for non-module', () async {
final FlutterProject project = await someProject();
expect(project.isApplication, isFalse);
expect(project.android.isApplication, isFalse);
expect(project.ios.isApplication, isFalse);
expect(project.isModule, isFalse);
expect(project.android.isModule, isFalse);
expect(project.ios.isModule, isFalse);
expect(project.android.hostAppGradleRoot.basename, 'android');
expect(project.ios.hostAppRoot.basename, 'ios');
});
......@@ -351,13 +351,13 @@ flutter:
return FlutterProject.fromDirectory(directory);
}
Future<FlutterProject> anApplicationProject() async {
final Directory directory = fs.directory('application_project');
Future<FlutterProject> aModuleProject() async {
final Directory directory = fs.directory('module_project');
directory.childFile('.packages').createSync(recursive: true);
directory.childFile('pubspec.yaml').writeAsStringSync('''
name: my_application
name: my_module
flutter:
application:
module:
androidPackage: com.example
''');
return FlutterProject.fromDirectory(directory);
......
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