Add --template=<type> option to create command. (#11105)

Allows the user to specify the kind of project to create. The default is 'app'. Other choices are 'plugin' (the old '--plugin' behavior), and 'package'.

A Flutter 'package' is a Dart package that depends on Flutter, but does not contain native code.

Fixes #10377.
This commit is contained in:
Jakob Andersen 2017-08-23 13:29:31 +02:00 committed by GitHub
parent 32ab3dbee0
commit 5d0d6126a1
11 changed files with 159 additions and 34 deletions

View file

@ -36,11 +36,26 @@ class CreateCommand extends FlutterCommand {
defaultsTo: false,
help: 'Also add a flutter_driver dependency and generate a sample \'flutter drive\' test.'
);
argParser.addOption(
'template',
abbr: 't',
allowed: <String>['app', 'package', 'plugin'],
help: 'Specify the type of project to create.',
valueHelp: 'type',
allowedHelp: <String, String>{
'app': '(default) Generate a Flutter application.',
'package': 'Generate a shareable Flutter project containing modular Dart code.',
'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.',
},
defaultsTo: 'app',
);
argParser.addFlag(
'plugin',
negatable: true,
defaultsTo: false,
help: 'Generate a Flutter plugin project.'
'plugin',
negatable: false,
defaultsTo: false,
hide: true,
);
argParser.addOption(
'description',
@ -110,7 +125,11 @@ class CreateCommand extends FlutterCommand {
if (!fs.isFileSync(fs.path.join(flutterDriverPackagePath, 'pubspec.yaml')))
throwToolExit('Unable to find package:flutter_driver in $flutterDriverPackagePath', exitCode: 2);
final bool generatePlugin = argResults['plugin'];
String template = argResults['template'];
if (argResults['plugin'])
template = 'plugin';
final bool generatePlugin = template == 'plugin';
final bool generatePackage = template == 'package';
final Directory projectDir = fs.directory(argResults.rest.first);
String dirPath = fs.path.normalize(projectDir.absolute.path);
@ -142,6 +161,23 @@ class CreateCommand extends FlutterCommand {
printStatus('Creating project ${fs.path.relative(dirPath)}...');
int generatedCount = 0;
if (generatePackage) {
final String description = argResults.wasParsed('description')
? argResults['description']
: 'A new flutter package project.';
templateContext['description'] = description;
generatedCount += _renderTemplate('package', dirPath, templateContext);
if (argResults['pub'])
await pubGet(directory: dirPath);
final String relativePath = fs.path.relative(dirPath);
printStatus('Wrote $generatedCount files.');
printStatus('');
printStatus('Your plugin code is in lib/$projectName.dart in the $relativePath directory.');
return;
}
String appPath = dirPath;
if (generatePlugin) {
final String description = argResults.wasParsed('description')

View file

@ -0,0 +1,7 @@
.DS_Store
.atom/
.idea
.packages
.pub/
packages
pubspec.lock

View file

@ -0,0 +1,3 @@
## [0.0.1] - TODO: Add release date.
* TODO: Describe initial release.

View file

@ -0,0 +1 @@
TODO: Add your license here.

View file

@ -0,0 +1,9 @@
# {{projectName}}
{{description}}
## Getting Started
For help getting started with Flutter, view our online [documentation](http://flutter.io/).
For help on editing package code, view the [documentation](https://flutter.io/developing-packages/).

View file

@ -0,0 +1,7 @@
library {{projectName}};
/// A Calculator.
class Calculator {
/// Returns [value] plus 1.
int addOne(int value) => value + 1;
}

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.idea" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/packages" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart Packages" level="project" />
<orderEntry type="library" name="Dart SDK" level="project" />
</component>
</module>

View file

@ -0,0 +1,14 @@
name: {{projectName}}
description: {{description}}
version: 0.0.1
author:
homepage:
flutter:
dependencies:
flutter:
sdk: flutter
dev_dependencies:
test: ^0.12.0

View file

@ -0,0 +1,13 @@
import 'package:test/test.dart';
import 'package:{{projectName}}/{{projectName}}.dart';
void main() {
test('adds one to input values', () {
final calculator = new Calculator();
expect(calculator.addOne(2), 3);
expect(calculator.addOne(-7), -6);
expect(calculator.addOne(0), 1);
expect(() => calculator.addOne(null), throwsNoSuchMethodError);
});
}

View file

@ -1,27 +1 @@
// Copyright 2017 Your Company. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Your Company nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
TODO: Add your license here.

View file

@ -70,7 +70,53 @@ void main() {
);
});
testUsingContext('package project', () async {
return _createAndAnalyzeProject(
projectDir,
<String>['--template=package'],
<String>[
'lib/flutter_project.dart',
'test/flutter_project_test.dart',
],
unexpectedPaths: <String>[
'android/app/src/main/java/com/yourcompany/flutterproject/MainActivity.java',
'android/src/main/java/com/yourcompany/flutterproject/FlutterProjectPlugin.java',
'ios/Classes/FlutterProjectPlugin.h',
'ios/Classes/FlutterProjectPlugin.m',
'ios/Runner/AppDelegate.h',
'ios/Runner/AppDelegate.m',
'ios/Runner/main.m',
'lib/main.dart',
'example/android/app/src/main/java/com/yourcompany/flutterprojectexample/MainActivity.java',
'example/ios/Runner/AppDelegate.h',
'example/ios/Runner/AppDelegate.m',
'example/ios/Runner/main.m',
'example/lib/main.dart',
'test/widget_test.dart',
],
);
});
testUsingContext('plugin project', () async {
return _createAndAnalyzeProject(
projectDir,
<String>['--template=plugin'],
<String>[
'android/src/main/java/com/yourcompany/flutterproject/FlutterProjectPlugin.java',
'ios/Classes/FlutterProjectPlugin.h',
'ios/Classes/FlutterProjectPlugin.m',
'lib/flutter_project.dart',
'example/android/app/src/main/java/com/yourcompany/flutterprojectexample/MainActivity.java',
'example/ios/Runner/AppDelegate.h',
'example/ios/Runner/AppDelegate.m',
'example/ios/Runner/main.m',
'example/lib/main.dart',
],
plugin: true,
);
});
testUsingContext('plugin project (legacy)', () async {
return _createAndAnalyzeProject(
projectDir,
<String>['--plugin'],
@ -92,7 +138,7 @@ void main() {
testUsingContext('kotlin/swift plugin project', () async {
return _createAndAnalyzeProject(
projectDir,
<String>['--plugin', '-a', 'kotlin', '--ios-language', 'swift'],
<String>['--template=plugin', '-a', 'kotlin', '--ios-language', 'swift'],
<String>[
'android/src/main/kotlin/com/yourcompany/flutterproject/FlutterProjectPlugin.kt',
'ios/Classes/FlutterProjectPlugin.h',
@ -118,7 +164,7 @@ void main() {
testUsingContext('plugin project with custom org', () async {
return _createAndAnalyzeProject(
projectDir,
<String>['--plugin', '--org', 'com.bar.foo'],
<String>['--template=plugin', '--org', 'com.bar.foo'],
<String>[
'android/src/main/java/com/bar/foo/flutterproject/FlutterProjectPlugin.java',
'example/android/app/src/main/java/com/bar/foo/flutterprojectexample/MainActivity.java',