Unverified Commit 0a08f8af authored by Chris Yang's avatar Chris Yang Committed by GitHub

[flutter_tools] Display "no platforms" message based on results when creating...

[flutter_tools] Display "no platforms" message based on results when creating plugins project (#70215)
parent 2b85eeed
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:yaml/yaml.dart';
import '../android/gradle_utils.dart' as gradle;
import '../base/common.dart';
import '../base/context.dart';
......@@ -17,19 +15,11 @@ import '../features.dart';
import '../flutter_manifest.dart';
import '../flutter_project_metadata.dart';
import '../globals.dart' as globals;
import '../plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
import 'create_base.dart';
const String _kNoPlatformsErrorMessage = '''
The plugin project was generated without specifying the `--platforms` flag, no new platforms are added.
To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
directory. You can also find detailed instructions on how to add platforms in the `pubspec.yaml`
at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
''';
class CreateCommand extends CreateBase {
CreateCommand() {
addPlatformsOptions(customHelp: 'The platforms supported by this project. '
......@@ -249,7 +239,8 @@ class CreateCommand extends CreateBase {
);
final String relativeDirPath = globals.fs.path.relative(projectDirPath);
if (!projectDir.existsSync() || projectDir.listSync().isEmpty) {
final bool creatingNewProject = !projectDir.existsSync() || projectDir.listSync().isEmpty;
if (creatingNewProject) {
globals.printStatus('Creating project $relativeDirPath...');
} else {
if (sampleCode != null && !overwrite) {
......@@ -295,18 +286,24 @@ class CreateCommand extends CreateBase {
'main.dart',
));
globals.printStatus('Your module code is in $relativeMainPath.');
} else {
} else if (generatePlugin) {
final String relativePluginPath = globals.fs.path.normalize(globals.fs.path.relative(projectDirPath));
final List<String> requestedPlatforms = _getUserRequestedPlatforms();
final String platformsString = requestedPlatforms.join(', ');
_printPluginDirectoryLocationMessage(relativePluginPath, projectName, platformsString);
if (!creatingNewProject && requestedPlatforms.isNotEmpty) {
_printPluginUpdatePubspecMessage(relativePluginPath, platformsString);
} else if (_getSupportedPlatformsInPlugin(projectDir).isEmpty){
globals.printError(_kNoPlatformsArgMessage);
}
} else {
// Tell the user the next steps.
final FlutterProject project = FlutterProject.fromPath(projectDirPath);
final FlutterProject app = project.hasExampleApp ? project.example : project;
final String relativeAppPath = globals.fs.path.normalize(globals.fs.path.relative(app.directory.path));
final String relativeAppMain = globals.fs.path.join(relativeAppPath, 'lib', 'main.dart');
final String relativePluginPath = globals.fs.path.normalize(globals.fs.path.relative(projectDirPath));
final String relativePluginMain = globals.fs.path.join(relativePluginPath, 'lib', '$projectName.dart');
// Let them know a summary of the state of their tooling.
final List<String> platforms = _getSupportedPlatformsFromTemplateContext(templateContext);
final String platformsString = platforms.join(', ');
globals.printStatus('''
In order to run your $application, type:
......@@ -315,14 +312,6 @@ In order to run your $application, type:
Your $application code is in $relativeAppMain.
''');
if (generatePlugin) {
globals.printStatus('''
Your plugin code is in $relativePluginMain.
Host platform code is in the $platformsString directories under $relativePluginPath.
To edit platform code in an IDE see https://flutter.dev/developing-packages/#edit-plugin-package.
''');
}
}
return FlutterCommandResult.success();
}
......@@ -378,19 +367,13 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
templateContext['linux'] = false;
templateContext['macos'] = false;
templateContext['windows'] = false;
globals.printError(_kNoPlatformsErrorMessage);
}
final List<String> platformsToAdd = _getSupportedPlatformsFromTemplateContext(templateContext);
final String pubspecPath = globals.fs.path.join(directory.absolute.path, 'pubspec.yaml');
final FlutterManifest manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger);
List<String> existingPlatforms = <String>[];
if (manifest.supportedPlatforms != null) {
existingPlatforms = manifest.supportedPlatforms.keys.toList();
for (final String existingPlatform in existingPlatforms) {
// re-generate files for existing platforms
templateContext[existingPlatform] = true;
}
final List<String> existingPlatforms = _getSupportedPlatformsInPlugin(directory);
for (final String existingPlatform in existingPlatforms) {
// re-generate files for existing platforms
templateContext[existingPlatform] = true;
}
final bool willAddPlatforms = platformsToAdd.isNotEmpty;
......@@ -411,35 +394,6 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
);
}
final bool addPlatformsToExistingPlugin = willAddPlatforms && existingPlatforms.isNotEmpty;
if (addPlatformsToExistingPlugin) {
// If adding new platforms to an existing plugin project, prints
// a help message containing the platforms maps need to be added to the `platforms` key in the pubspec.
platformsToAdd.removeWhere(existingPlatforms.contains);
final YamlMap platformsMapToPrint = Plugin.createPlatformsYamlMap(platformsToAdd, templateContext['pluginClass'] as String, templateContext['androidIdentifier'] as String);
if (platformsMapToPrint.isNotEmpty) {
String prettyYaml = '';
for (final String platform in platformsMapToPrint.keys.toList().cast<String>()) {
prettyYaml += '$platform:\n';
for (final String key in (platformsMapToPrint[platform] as YamlMap).keys.toList().cast<String>()) {
prettyYaml += ' $key: ${platformsMapToPrint[platform][key] as String}\n';
}
}
globals.printStatus('''
The `pubspec.yaml` under the project directory must be updated to support ${platformsToAdd.join(', ')},
Add below lines to under the `platform:` key:
''', emphasis: true);
globals.printStatus(prettyYaml, emphasis: true, color: TerminalColor.blue);
globals.printStatus('''
If the `platforms` key does not exist in the `pubspec.yaml`, it might because that the plugin project does not
use the multi-platforms plugin format. We highly recommend a migration to the multi-platforms plugin format.
For detailed instructions on how to format the pubspec.yaml to support platforms using the multi-platforms format, see:
https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms
''', emphasis: true);
}
}
final FlutterProject project = FlutterProject.fromDirectory(directory);
final bool generateAndroid = templateContext['android'] == true;
if (generateAndroid) {
......@@ -493,4 +447,57 @@ https://flutter.dev/docs/development/packages-and-plugins/developing-packages#pl
'macos',
];
}
// Returns a list of platforms that are explicitly requested by user via `--platforms`.
List<String> _getUserRequestedPlatforms() {
if (!argResults.wasParsed('platforms')) {
return <String>[];
}
return stringsArg('platforms');
}
}
// Determine what platforms are supported based on generated files.
List<String> _getSupportedPlatformsInPlugin(Directory projectDir) {
final String pubspecPath = globals.fs.path.join(projectDir.absolute.path, 'pubspec.yaml');
final FlutterManifest manifest = FlutterManifest.createFromPath(pubspecPath, fileSystem: globals.fs, logger: globals.logger);
final List<String> platforms = manifest.validSupportedPlatforms == null
? <String>[]
: manifest.validSupportedPlatforms.keys.toList();
return platforms;
}
void _printPluginDirectoryLocationMessage(String pluginPath, String projectName, String platformsString) {
final String relativePluginMain = globals.fs.path.join(pluginPath, 'lib', '$projectName.dart');
final String relativeExampleMain = globals.fs.path.join(pluginPath, 'example', 'lib', 'main.dart');
globals.printStatus('''
Your plugin code is in $relativePluginMain.
You example app code is in $relativeExampleMain.
''');
if (platformsString != null && platformsString.isNotEmpty) {
globals.printStatus('''
Host platform code is in the $platformsString directories under $pluginPath.
To edit platform code in an IDE see https://flutter.dev/developing-packages/#edit-plugin-package.
''');
}
}
void _printPluginUpdatePubspecMessage(String pluginPath, String platformsString) {
globals.printStatus('''
You need to update $pluginPath/pubspec.yaml to support $platformsString.
For more information, see https://flutter.dev/go/developing-plugins.
''', emphasis: true, color: TerminalColor.red);
}
const String _kNoPlatformsArgMessage = '''
Must specify at least one platform using --platforms.
For more information, see https://flutter.dev/go/developing-plugins.
''';
......@@ -12,6 +12,10 @@ import 'base/user_messages.dart';
import 'base/utils.dart';
import 'plugins.dart';
const Set<String> _kValidPluginPlatforms = <String>{
'android', 'ios', 'web', 'windows', 'linux', 'macos'
};
/// A wrapper around the `flutter` section in the `pubspec.yaml` file.
class FlutterManifest {
FlutterManifest._(this._logger);
......@@ -199,6 +203,20 @@ class FlutterManifest {
return null;
}
/// Like [supportedPlatforms], but only returns the valid platforms that are supported in flutter plugins.
Map<String, dynamic> get validSupportedPlatforms {
final Map<String, dynamic> allPlatforms = supportedPlatforms;
if (allPlatforms == null) {
return null;
}
final Map<String, dynamic> platforms = <String, dynamic>{}..addAll(supportedPlatforms);
platforms.removeWhere((String key, dynamic _) => !_kValidPluginPlatforms.contains(key));
if (platforms.isEmpty) {
return null;
}
return platforms;
}
List<Map<String, dynamic>> get fontsDescriptor {
return fonts.map((Font font) => font.descriptor).toList();
}
......
......@@ -33,7 +33,7 @@ flutter:
platforms:
{{#no_platforms}}
# This plugin project was generated without specifying any
# platforms with the `--platform` argument. If you see the `fake_platform` map below, remove it and
# platforms with the `--platform` argument. If you see the `some_platform` map below, remove it and
# then add platforms following the instruction here:
# https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms
# -------------------
......
......@@ -972,6 +972,49 @@ flutter:
expect(flutterManifest.supportedPlatforms, null);
});
testWithoutContext('FlutterManifest validSupportedPlatforms return null if the platform keys are not valid', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
some_platform:
pluginClass: SomeClass
''';
final BufferLogger logger = BufferLogger.test();
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.validSupportedPlatforms, null);
});
testWithoutContext('FlutterManifest validSupportedPlatforms only returns valid platforms', () {
const String manifest = '''
name: test
flutter:
plugin:
platforms:
some_platform:
pluginClass: SomeClass
ios:
pluginClass: SomeClass
''';
final BufferLogger logger = BufferLogger.test();
final FlutterManifest flutterManifest = FlutterManifest.createFromString(
manifest,
logger: logger,
);
expect(flutterManifest.isPlugin, true);
expect(flutterManifest.validSupportedPlatforms['ios'],
<String, dynamic>{'pluginClass': 'SomeClass'});
expect(flutterManifest.validSupportedPlatforms['some_platform'],
isNull);
});
testWithoutContext('FlutterManifest getSupportedPlatforms returns valid platforms.', () {
const String manifest = '''
name: test
......
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