diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 75f4795372..cd600ed33b 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -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: ['app', 'package', 'plugin'], + help: 'Specify the type of project to create.', + valueHelp: 'type', + allowedHelp: { + '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') diff --git a/packages/flutter_tools/templates/package/.gitignore.tmpl b/packages/flutter_tools/templates/package/.gitignore.tmpl new file mode 100644 index 0000000000..75e965865e --- /dev/null +++ b/packages/flutter_tools/templates/package/.gitignore.tmpl @@ -0,0 +1,7 @@ +.DS_Store +.atom/ +.idea +.packages +.pub/ +packages +pubspec.lock diff --git a/packages/flutter_tools/templates/package/CHANGELOG.md.tmpl b/packages/flutter_tools/templates/package/CHANGELOG.md.tmpl new file mode 100644 index 0000000000..ac071598e5 --- /dev/null +++ b/packages/flutter_tools/templates/package/CHANGELOG.md.tmpl @@ -0,0 +1,3 @@ +## [0.0.1] - TODO: Add release date. + +* TODO: Describe initial release. diff --git a/packages/flutter_tools/templates/package/LICENSE.tmpl b/packages/flutter_tools/templates/package/LICENSE.tmpl new file mode 100644 index 0000000000..ba75c69f7f --- /dev/null +++ b/packages/flutter_tools/templates/package/LICENSE.tmpl @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/flutter_tools/templates/package/README.md.tmpl b/packages/flutter_tools/templates/package/README.md.tmpl new file mode 100644 index 0000000000..b5d6778b57 --- /dev/null +++ b/packages/flutter_tools/templates/package/README.md.tmpl @@ -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/). diff --git a/packages/flutter_tools/templates/package/lib/projectName.dart.tmpl b/packages/flutter_tools/templates/package/lib/projectName.dart.tmpl new file mode 100644 index 0000000000..4048343a6d --- /dev/null +++ b/packages/flutter_tools/templates/package/lib/projectName.dart.tmpl @@ -0,0 +1,7 @@ +library {{projectName}}; + +/// A Calculator. +class Calculator { + /// Returns [value] plus 1. + int addOne(int value) => value + 1; +} diff --git a/packages/flutter_tools/templates/package/projectName.iml.tmpl b/packages/flutter_tools/templates/package/projectName.iml.tmpl new file mode 100644 index 0000000000..dafb001137 --- /dev/null +++ b/packages/flutter_tools/templates/package/projectName.iml.tmpl @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/flutter_tools/templates/package/pubspec.yaml.tmpl b/packages/flutter_tools/templates/package/pubspec.yaml.tmpl new file mode 100644 index 0000000000..138ae3d313 --- /dev/null +++ b/packages/flutter_tools/templates/package/pubspec.yaml.tmpl @@ -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 diff --git a/packages/flutter_tools/templates/package/test/projectName_test.dart.tmpl b/packages/flutter_tools/templates/package/test/projectName_test.dart.tmpl new file mode 100644 index 0000000000..fbf95715c0 --- /dev/null +++ b/packages/flutter_tools/templates/package/test/projectName_test.dart.tmpl @@ -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); + }); +} diff --git a/packages/flutter_tools/templates/plugin/LICENSE.tmpl b/packages/flutter_tools/templates/plugin/LICENSE.tmpl index 86928f6575..ba75c69f7f 100644 --- a/packages/flutter_tools/templates/plugin/LICENSE.tmpl +++ b/packages/flutter_tools/templates/plugin/LICENSE.tmpl @@ -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. diff --git a/packages/flutter_tools/test/commands/create_test.dart b/packages/flutter_tools/test/commands/create_test.dart index f8240a09e7..065c34444e 100644 --- a/packages/flutter_tools/test/commands/create_test.dart +++ b/packages/flutter_tools/test/commands/create_test.dart @@ -70,7 +70,53 @@ void main() { ); }); + testUsingContext('package project', () async { + return _createAndAnalyzeProject( + projectDir, + ['--template=package'], + [ + 'lib/flutter_project.dart', + 'test/flutter_project_test.dart', + ], + unexpectedPaths: [ + '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, + ['--template=plugin'], + [ + '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, ['--plugin'], @@ -92,7 +138,7 @@ void main() { testUsingContext('kotlin/swift plugin project', () async { return _createAndAnalyzeProject( projectDir, - ['--plugin', '-a', 'kotlin', '--ios-language', 'swift'], + ['--template=plugin', '-a', 'kotlin', '--ios-language', 'swift'], [ '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, - ['--plugin', '--org', 'com.bar.foo'], + ['--template=plugin', '--org', 'com.bar.foo'], [ 'android/src/main/java/com/bar/foo/flutterproject/FlutterProjectPlugin.java', 'example/android/app/src/main/java/com/bar/foo/flutterprojectexample/MainActivity.java',