diff --git a/.gitignore b/.gitignore
index 74ae26a0da5..c7f0a565e11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.idea
.history
.DS_Store
+*.iml
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9d0adf14b81..db2baf61501 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -44,14 +44,17 @@ Getting the code and configuring your environment
* Run `flutter update-packages` This will fetch all the Dart packages that
Flutter depends on. You can replicate what this script does by running
`pub get` in each directory that contains a `pubspec.yaml` file.
+ * If you plan on using IntelliJ as your IDE, then also run
+ `flutter ide-config --overwrite` to create all of the IntelliJ configuration
+ files so you can open the main flutter directory as a project and run examples
+ from within the IDE.
Running the examples
--------------------
-To run an example with a prebuilt binary from the cloud, switch to that
-example's directory, run `pub get` to make sure its dependencies have been
-downloaded, and use `flutter run`. Make sure you have a device connected over
-USB and debugging enabled on that device.
+To run an example, switch to that example's directory, and use `flutter run`.
+Make sure you have an emulator running, or a device connected over USB and
+debugging enabled on that device.
* `cd examples/hello_world`
* `flutter run`
diff --git a/examples/flutter_gallery/.idea/libraries/Dart_SDK.xml b/examples/flutter_gallery/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/flutter_gallery/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/flutter_gallery/.idea/modules.xml b/examples/flutter_gallery/.idea/modules.xml
deleted file mode 100644
index 180cda925db..00000000000
--- a/examples/flutter_gallery/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/flutter_gallery/.idea/runConfigurations/main_dart.xml b/examples/flutter_gallery/.idea/runConfigurations/main_dart.xml
deleted file mode 100644
index aab7b5cd832..00000000000
--- a/examples/flutter_gallery/.idea/runConfigurations/main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/flutter_view/.idea/libraries/Dart_SDK.xml b/examples/flutter_view/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/flutter_view/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/flutter_view/.idea/modules.xml b/examples/flutter_view/.idea/modules.xml
deleted file mode 100644
index e26bec79dfb..00000000000
--- a/examples/flutter_view/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/flutter_view/.idea/runConfigurations/main_dart.xml b/examples/flutter_view/.idea/runConfigurations/main_dart.xml
deleted file mode 100644
index aab7b5cd832..00000000000
--- a/examples/flutter_view/.idea/runConfigurations/main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/hello_world/.idea/libraries/Dart_SDK.xml b/examples/hello_world/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/hello_world/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/hello_world/.idea/modules.xml b/examples/hello_world/.idea/modules.xml
deleted file mode 100644
index 6c4ef6201ed..00000000000
--- a/examples/hello_world/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/hello_world/.idea/runConfigurations/main_dart.xml b/examples/hello_world/.idea/runConfigurations/main_dart.xml
deleted file mode 100644
index f94721b31b0..00000000000
--- a/examples/hello_world/.idea/runConfigurations/main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/examples/layers/.idea/libraries/Dart_SDK.xml b/examples/layers/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/layers/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/layers/.idea/modules.xml b/examples/layers/.idea/modules.xml
deleted file mode 100644
index ec44738db89..00000000000
--- a/examples/layers/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/platform_channel/.idea/libraries/Dart_SDK.xml b/examples/platform_channel/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/platform_channel/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/platform_channel/.idea/modules.xml b/examples/platform_channel/.idea/modules.xml
deleted file mode 100644
index 65b2dcbcc16..00000000000
--- a/examples/platform_channel/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/examples/platform_channel/.idea/runConfigurations/main_dart.xml b/examples/platform_channel/.idea/runConfigurations/main_dart.xml
deleted file mode 100644
index aab7b5cd832..00000000000
--- a/examples/platform_channel/.idea/runConfigurations/main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/platform_channel_swift/.idea/libraries/Dart_SDK.xml b/examples/platform_channel_swift/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/platform_channel_swift/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/platform_channel_swift/.idea/modules.xml b/examples/platform_channel_swift/.idea/modules.xml
deleted file mode 100644
index 002f5cb15e9..00000000000
--- a/examples/platform_channel_swift/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/examples/platform_channel_swift/.idea/runConfigurations/main_dart.xml b/examples/platform_channel_swift/.idea/runConfigurations/main_dart.xml
deleted file mode 100644
index aab7b5cd832..00000000000
--- a/examples/platform_channel_swift/.idea/runConfigurations/main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/platform_view/full_platform_view.iml b/examples/platform_view/full_platform_view.iml
deleted file mode 100644
index e75a6371f79..00000000000
--- a/examples/platform_view/full_platform_view.iml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/examples/stocks/.idea/libraries/Dart_SDK.xml b/examples/stocks/.idea/libraries/Dart_SDK.xml
deleted file mode 100644
index 26389a366d2..00000000000
--- a/examples/stocks/.idea/libraries/Dart_SDK.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/stocks/.idea/modules.xml b/examples/stocks/.idea/modules.xml
deleted file mode 100644
index c668e7d46c0..00000000000
--- a/examples/stocks/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/stocks/.idea/runConfigurations/main_dart.xml b/examples/stocks/.idea/runConfigurations/main_dart.xml
deleted file mode 100644
index f94721b31b0..00000000000
--- a/examples/stocks/.idea/runConfigurations/main_dart.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/examples/stocks/stocks.iml b/examples/stocks/stocks.iml
deleted file mode 100644
index e75a6371f79..00000000000
--- a/examples/stocks/stocks.iml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/.name b/packages/flutter_tools/ide_templates/intellij/.idea/.name.copy.tmpl
similarity index 100%
rename from .idea/.name
rename to packages/flutter_tools/ide_templates/intellij/.idea/.name.copy.tmpl
diff --git a/.idea/modules.xml b/packages/flutter_tools/ide_templates/intellij/.idea/modules.xml.copy.tmpl
similarity index 51%
rename from .idea/modules.xml
rename to packages/flutter_tools/ide_templates/intellij/.idea/modules.xml.copy.tmpl
index d57a93f57ba..65465354193 100644
--- a/.idea/modules.xml
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/modules.xml.copy.tmpl
@@ -2,7 +2,10 @@
+
+
+
@@ -10,7 +13,14 @@
+
+
+
+
+
+
+
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/benchmarks___complex_layout.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/benchmarks___complex_layout.xml.copy.tmpl
new file mode 100644
index 00000000000..ad550babd28
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/benchmarks___complex_layout.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/catalog.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/catalog.xml.copy.tmpl
new file mode 100644
index 00000000000..93428232d87
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/catalog.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/flutter_gallery.xml b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_gallery.xml.copy.tmpl
similarity index 100%
rename from .idea/runConfigurations/flutter_gallery.xml
rename to packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_gallery.xml.copy.tmpl
diff --git a/.idea/runConfigurations/flutter_tools.xml b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_tools.xml.copy.tmpl
similarity index 100%
rename from .idea/runConfigurations/flutter_tools.xml
rename to packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_tools.xml.copy.tmpl
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_view.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_view.xml.copy.tmpl
new file mode 100644
index 00000000000..252726a240d
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/flutter_view.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/hello_world.xml b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/hello_world.xml.copy.tmpl
similarity index 100%
rename from .idea/runConfigurations/hello_world.xml
rename to packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/hello_world.xml.copy.tmpl
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___custom_render_box.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___custom_render_box.xml.copy.tmpl
new file mode 100644
index 00000000000..f2ae4241025
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___custom_render_box.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___gestures.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___gestures.xml.copy.tmpl
new file mode 100644
index 00000000000..0cd8785b251
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___gestures.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___hello_world.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___hello_world.xml.copy.tmpl
new file mode 100644
index 00000000000..3aae9f135b7
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___hello_world.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___isolate.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___isolate.xml.copy.tmpl
new file mode 100644
index 00000000000..d0a3d705231
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___isolate.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___lifecycle.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___lifecycle.xml.copy.tmpl
new file mode 100644
index 00000000000..755fe18966a
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___lifecycle.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___sectors.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___sectors.xml.copy.tmpl
new file mode 100644
index 00000000000..7b5ba1a256e
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___sectors.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___spinning_square.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___spinning_square.xml.copy.tmpl
new file mode 100644
index 00000000000..676994cbe42
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___spinning_square.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___styled_text.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___styled_text.xml.copy.tmpl
new file mode 100644
index 00000000000..635a3279b68
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/layers___styled_text.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___card_collection.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___card_collection.xml.copy.tmpl
new file mode 100644
index 00000000000..5d63d14d0a6
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___card_collection.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___color_testing_demo.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___color_testing_demo.xml.copy.tmpl
new file mode 100644
index 00000000000..25d54cb01dc
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___color_testing_demo.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___drag_and_drop.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___drag_and_drop.xml.copy.tmpl
new file mode 100644
index 00000000000..f1d3b034b5e
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___drag_and_drop.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___material_arc.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___material_arc.xml.copy.tmpl
new file mode 100644
index 00000000000..b14c448dcc5
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___material_arc.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___overlay_geometry.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___overlay_geometry.xml.copy.tmpl
new file mode 100644
index 00000000000..230c1cff695
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___overlay_geometry.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___page_view.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___page_view.xml.copy.tmpl
new file mode 100644
index 00000000000..d41e48c073e
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___page_view.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___raw_keyboard.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___raw_keyboard.xml.copy.tmpl
new file mode 100644
index 00000000000..66ad97acc83
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___raw_keyboard.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___text.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___text.xml.copy.tmpl
new file mode 100644
index 00000000000..74fbeb77be2
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/manual_tests___text.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/plaform_view.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/plaform_view.xml.copy.tmpl
new file mode 100644
index 00000000000..bfe7a7db883
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/plaform_view.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/platform_channel.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/platform_channel.xml.copy.tmpl
new file mode 100644
index 00000000000..755c3bebbea
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/platform_channel.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/platform_channel_swift.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/platform_channel_swift.xml.copy.tmpl
new file mode 100644
index 00000000000..1e80ea684b3
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/platform_channel_swift.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/stocks.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/stocks.xml.copy.tmpl
new file mode 100644
index 00000000000..0e4976d2357
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/runConfigurations/stocks.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/.idea/vcs.xml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/.idea/vcs.xml.copy.tmpl
new file mode 100644
index 00000000000..94a25f7f4cb
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/.idea/vcs.xml.copy.tmpl
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/flutter_tools/ide_templates/intellij/dev/benchmarks/complex_layout/complex_layout.iml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/dev/benchmarks/complex_layout/complex_layout.iml.copy.tmpl
new file mode 100644
index 00000000000..65865e3ec94
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/dev/benchmarks/complex_layout/complex_layout.iml.copy.tmpl
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dev/bots/bots.iml b/packages/flutter_tools/ide_templates/intellij/dev/bots/bots.iml.copy.tmpl
similarity index 100%
rename from dev/bots/bots.iml
rename to packages/flutter_tools/ide_templates/intellij/dev/bots/bots.iml.copy.tmpl
diff --git a/dev/devicelab/devicelab.iml b/packages/flutter_tools/ide_templates/intellij/dev/devicelab/devicelab.iml.copy.tmpl
similarity index 100%
rename from dev/devicelab/devicelab.iml
rename to packages/flutter_tools/ide_templates/intellij/dev/devicelab/devicelab.iml.copy.tmpl
diff --git a/dev/manual_tests/android.iml b/packages/flutter_tools/ide_templates/intellij/dev/manual_tests/android.iml.copy.tmpl
similarity index 100%
rename from dev/manual_tests/android.iml
rename to packages/flutter_tools/ide_templates/intellij/dev/manual_tests/android.iml.copy.tmpl
diff --git a/examples/layers/layers.iml b/packages/flutter_tools/ide_templates/intellij/dev/manual_tests/manual_tests.iml.copy.tmpl
similarity index 98%
rename from examples/layers/layers.iml
rename to packages/flutter_tools/ide_templates/intellij/dev/manual_tests/manual_tests.iml.copy.tmpl
index cedac514e4c..cd38844c2d5 100644
--- a/examples/layers/layers.iml
+++ b/packages/flutter_tools/ide_templates/intellij/dev/manual_tests/manual_tests.iml.copy.tmpl
@@ -13,4 +13,4 @@
-
+
\ No newline at end of file
diff --git a/dev/tools/tools.iml b/packages/flutter_tools/ide_templates/intellij/dev/tools/tools.iml.copy.tmpl
similarity index 100%
rename from dev/tools/tools.iml
rename to packages/flutter_tools/ide_templates/intellij/dev/tools/tools.iml.copy.tmpl
diff --git a/packages/flutter_tools/ide_templates/intellij/examples/catalog/catalog.iml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/examples/catalog/catalog.iml.copy.tmpl
new file mode 100644
index 00000000000..ff4051b3b5f
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/examples/catalog/catalog.iml.copy.tmpl
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/flutter_gallery/android.iml b/packages/flutter_tools/ide_templates/intellij/examples/flutter_gallery/android.iml.copy.tmpl
similarity index 100%
rename from examples/flutter_gallery/android.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/flutter_gallery/android.iml.copy.tmpl
diff --git a/examples/flutter_gallery/flutter_gallery.iml b/packages/flutter_tools/ide_templates/intellij/examples/flutter_gallery/flutter_gallery.iml.copy.tmpl
similarity index 100%
rename from examples/flutter_gallery/flutter_gallery.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/flutter_gallery/flutter_gallery.iml.copy.tmpl
diff --git a/examples/flutter_view/flutter_view.iml b/packages/flutter_tools/ide_templates/intellij/examples/flutter_view/flutter_view.iml.copy.tmpl
similarity index 98%
rename from examples/flutter_view/flutter_view.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/flutter_view/flutter_view.iml.copy.tmpl
index f251445ba75..1e956bd50a7 100644
--- a/examples/flutter_view/flutter_view.iml
+++ b/packages/flutter_tools/ide_templates/intellij/examples/flutter_view/flutter_view.iml.copy.tmpl
@@ -12,4 +12,4 @@
-
+
\ No newline at end of file
diff --git a/examples/hello_world/android.iml b/packages/flutter_tools/ide_templates/intellij/examples/hello_world/android.iml.copy.tmpl
similarity index 100%
rename from examples/hello_world/android.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/hello_world/android.iml.copy.tmpl
diff --git a/examples/hello_world/hello_world.iml b/packages/flutter_tools/ide_templates/intellij/examples/hello_world/hello_world.iml.copy.tmpl
similarity index 100%
rename from examples/hello_world/hello_world.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/hello_world/hello_world.iml.copy.tmpl
diff --git a/packages/flutter_tools/ide_templates/intellij/examples/layers/layers.iml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/examples/layers/layers.iml.copy.tmpl
new file mode 100644
index 00000000000..7a21b7757cd
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/examples/layers/layers.iml.copy.tmpl
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/platform_channel/android.iml b/packages/flutter_tools/ide_templates/intellij/examples/platform_channel/android.iml.copy.tmpl
similarity index 100%
rename from examples/platform_channel/android.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/platform_channel/android.iml.copy.tmpl
diff --git a/examples/platform_channel_swift/platform_channel_swift.iml b/packages/flutter_tools/ide_templates/intellij/examples/platform_channel/platform_channel.iml.copy.tmpl
similarity index 89%
rename from examples/platform_channel_swift/platform_channel_swift.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/platform_channel/platform_channel.iml.copy.tmpl
index e75a6371f79..6beca6a0689 100644
--- a/examples/platform_channel_swift/platform_channel_swift.iml
+++ b/packages/flutter_tools/ide_templates/intellij/examples/platform_channel/platform_channel.iml.copy.tmpl
@@ -6,10 +6,9 @@
-
-
+
-
+
\ No newline at end of file
diff --git a/examples/platform_channel/platform_channel.iml b/packages/flutter_tools/ide_templates/intellij/examples/platform_channel_swift/platform_channel_swift.iml.copy.tmpl
similarity index 89%
rename from examples/platform_channel/platform_channel.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/platform_channel_swift/platform_channel_swift.iml.copy.tmpl
index e75a6371f79..6beca6a0689 100644
--- a/examples/platform_channel/platform_channel.iml
+++ b/packages/flutter_tools/ide_templates/intellij/examples/platform_channel_swift/platform_channel_swift.iml.copy.tmpl
@@ -6,10 +6,9 @@
-
-
+
-
+
\ No newline at end of file
diff --git a/examples/platform_view/android.iml b/packages/flutter_tools/ide_templates/intellij/examples/platform_view/android.iml.copy.tmpl
similarity index 100%
rename from examples/platform_view/android.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/platform_view/android.iml.copy.tmpl
diff --git a/packages/flutter_tools/ide_templates/intellij/examples/platform_view/full_platform_view.iml.copy.tmpl b/packages/flutter_tools/ide_templates/intellij/examples/platform_view/full_platform_view.iml.copy.tmpl
new file mode 100644
index 00000000000..6beca6a0689
--- /dev/null
+++ b/packages/flutter_tools/ide_templates/intellij/examples/platform_view/full_platform_view.iml.copy.tmpl
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/stocks/android.iml b/packages/flutter_tools/ide_templates/intellij/examples/stocks/android.iml.copy.tmpl
similarity index 100%
rename from examples/stocks/android.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/stocks/android.iml.copy.tmpl
diff --git a/dev/manual_tests/manual_tests.iml b/packages/flutter_tools/ide_templates/intellij/examples/stocks/stocks.iml.copy.tmpl
similarity index 90%
rename from dev/manual_tests/manual_tests.iml
rename to packages/flutter_tools/ide_templates/intellij/examples/stocks/stocks.iml.copy.tmpl
index e75a6371f79..cd38844c2d5 100644
--- a/dev/manual_tests/manual_tests.iml
+++ b/packages/flutter_tools/ide_templates/intellij/examples/stocks/stocks.iml.copy.tmpl
@@ -7,9 +7,10 @@
+
-
+
-
+
\ No newline at end of file
diff --git a/packages/flutter/flutter.iml b/packages/flutter_tools/ide_templates/intellij/packages/flutter/flutter.iml.copy.tmpl
similarity index 100%
rename from packages/flutter/flutter.iml
rename to packages/flutter_tools/ide_templates/intellij/packages/flutter/flutter.iml.copy.tmpl
diff --git a/packages/flutter_driver/flutter_driver.iml b/packages/flutter_tools/ide_templates/intellij/packages/flutter_driver/flutter_driver.iml.copy.tmpl
similarity index 100%
rename from packages/flutter_driver/flutter_driver.iml
rename to packages/flutter_tools/ide_templates/intellij/packages/flutter_driver/flutter_driver.iml.copy.tmpl
diff --git a/packages/flutter_localizations/flutter_localizations.iml b/packages/flutter_tools/ide_templates/intellij/packages/flutter_localizations/flutter_localizations.iml.copy.tmpl
similarity index 100%
rename from packages/flutter_localizations/flutter_localizations.iml
rename to packages/flutter_tools/ide_templates/intellij/packages/flutter_localizations/flutter_localizations.iml.copy.tmpl
diff --git a/packages/flutter_test/flutter_test.iml b/packages/flutter_tools/ide_templates/intellij/packages/flutter_test/flutter_test.iml.copy.tmpl
similarity index 100%
rename from packages/flutter_test/flutter_test.iml
rename to packages/flutter_tools/ide_templates/intellij/packages/flutter_test/flutter_test.iml.copy.tmpl
diff --git a/packages/flutter_tools/flutter_tools.iml b/packages/flutter_tools/ide_templates/intellij/packages/flutter_tools/flutter_tools.iml.copy.tmpl
similarity index 99%
rename from packages/flutter_tools/flutter_tools.iml
rename to packages/flutter_tools/ide_templates/intellij/packages/flutter_tools/flutter_tools.iml.copy.tmpl
index 1b442a90ec8..a534a0a0ee6 100644
--- a/packages/flutter_tools/flutter_tools.iml
+++ b/packages/flutter_tools/ide_templates/intellij/packages/flutter_tools/flutter_tools.iml.copy.tmpl
@@ -22,7 +22,7 @@
-
+
\ No newline at end of file
diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart
index 5e890400f3f..43ca13b5259 100644
--- a/packages/flutter_tools/lib/executable.dart
+++ b/packages/flutter_tools/lib/executable.dart
@@ -17,6 +17,7 @@ import 'src/commands/doctor.dart';
import 'src/commands/drive.dart';
import 'src/commands/format.dart';
import 'src/commands/fuchsia_reload.dart';
+import 'src/commands/ide_config.dart';
import 'src/commands/install.dart';
import 'src/commands/logs.dart';
import 'src/commands/packages.dart';
@@ -52,6 +53,7 @@ Future main(List args) async {
new DriveCommand(),
new FormatCommand(),
new FuchsiaReloadCommand(),
+ new IdeConfigCommand(hidden: !verboseHelp),
new InstallCommand(),
new LogsCommand(),
new PackagesCommand(),
diff --git a/packages/flutter_tools/lib/src/commands/ide_config.dart b/packages/flutter_tools/lib/src/commands/ide_config.dart
new file mode 100644
index 00000000000..1a7ee40f322
--- /dev/null
+++ b/packages/flutter_tools/lib/src/commands/ide_config.dart
@@ -0,0 +1,273 @@
+// Copyright 2017 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 '../base/common.dart';
+import '../base/file_system.dart';
+import '../cache.dart';
+import '../globals.dart';
+import '../runner/flutter_command.dart';
+import '../template.dart';
+
+class IdeConfigCommand extends FlutterCommand {
+ IdeConfigCommand({this.hidden: false}) {
+ argParser.addFlag(
+ 'overwrite',
+ negatable: true,
+ defaultsTo: false,
+ help: 'When performing operations, overwrite existing files.',
+ );
+ argParser.addFlag(
+ 'update-templates',
+ negatable: false,
+ help: 'Update the templates in the template directory from the current '
+ 'configuration files. This is the opposite of what $name usually does. '
+ 'Will search the flutter tree for .iml files and copy any missing ones '
+ 'into the template directory. If --overwrite is also specified, it will '
+ 'update any out-of-date files, and remove any deleted files from the '
+ 'template directory.',
+ );
+ }
+
+ @override
+ final String name = 'ide-config';
+
+ @override
+ final String description = 'Configure the IDE for use in the Flutter tree.\n\n'
+ 'If run on a Flutter tree that is already configured for the IDE, this '
+ 'command will add any new configurations, recreate any files that are '
+ 'missing. If --overwrite is specified, will revert existing files to '
+ 'the template versions, reset the module list, and return configuration '
+ 'settings to the template versions.\n\n'
+ 'This command is intended for Flutter developers to help them set up the'
+ "Flutter tree for development in an IDE. It doesn't affect other projects.\n\n"
+ 'Currently, IntelliJ is the default (and only) IDE that may be configured.';
+
+ @override
+ final bool hidden;
+
+ @override
+ String get invocation => '${runner.executableName} $name';
+
+ static const String _ideName = 'intellij';
+ Directory get _templateDirectory {
+ return fs.directory(fs.path.join(
+ Cache.flutterRoot,
+ 'packages',
+ 'flutter_tools',
+ 'ide_templates',
+ _ideName,
+ ));
+ }
+
+ Directory get _createTemplatesDirectory {
+ return fs.directory(fs.path.join(
+ Cache.flutterRoot,
+ 'packages',
+ 'flutter_tools',
+ 'templates',
+ ));
+ }
+
+ Directory get _flutterRoot => fs.directory(fs.path.absolute(Cache.flutterRoot));
+
+ // Returns true if any entire path element is equal to dir.
+ bool _hasDirectoryInPath(FileSystemEntity entity, String dir) {
+ String path = entity.absolute.path;
+ while (path.isNotEmpty && fs.path.dirname(path) != path) {
+ if (fs.path.basename(path) == dir) {
+ return true;
+ }
+ path = fs.path.dirname(path);
+ }
+ return false;
+ }
+
+ // Returns true if child is anywhere underneath parent.
+ bool _isChildDirectoryOf(FileSystemEntity parent, FileSystemEntity child) {
+ return child.absolute.path.startsWith(parent.absolute.path);
+ }
+
+ // Checks the contents of the two files to see if they have changes.
+ bool _fileIsIdentical(File src, File dest) {
+ if (src.lengthSync() != dest.lengthSync()) {
+ return false;
+ }
+
+ // Test byte by byte. We're assuming that these are small files.
+ final List srcBytes = src.readAsBytesSync();
+ final List destBytes = dest.readAsBytesSync();
+ for (int i = 0; i < srcBytes.length; ++i) {
+ if (srcBytes[i] != destBytes[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Discovers and syncs with existing configuration files in the Flutter tree.
+ void _handleTemplateUpdate() {
+ if (!_flutterRoot.existsSync()) {
+ return;
+ }
+
+ final Set manifest = new Set();
+ final List flutterFiles = _flutterRoot.listSync(recursive: true);
+ for (FileSystemEntity entity in flutterFiles) {
+ final String relativePath = fs.path.relative(entity.path, from: _flutterRoot.absolute.path);
+ if (entity is! File) {
+ continue;
+ }
+
+ final File srcFile = entity;
+
+ // Skip template files in both the ide_templates and templates
+ // directories to avoid copying onto themselves.
+ if (_isChildDirectoryOf(_templateDirectory, srcFile) ||
+ _isChildDirectoryOf(_createTemplatesDirectory, srcFile)) {
+ continue;
+ }
+
+ // Skip files we aren't interested in.
+ final RegExp _trackedIdeaFileRegExp = new RegExp(
+ r'(\.name|modules.xml|vcs.xml)$',
+ );
+ final bool isATrackedIdeaFile = _hasDirectoryInPath(srcFile, '.idea') &&
+ (_trackedIdeaFileRegExp.hasMatch(relativePath) ||
+ _hasDirectoryInPath(srcFile, 'runConfigurations'));
+ final bool isAnImlOutsideIdea = !isATrackedIdeaFile && srcFile.path.endsWith('.iml');
+ if (!isATrackedIdeaFile && !isAnImlOutsideIdea) {
+ continue;
+ }
+
+ final File finalDestinationFile = fs.file(fs.path.absolute(
+ _templateDirectory.absolute.path, '$relativePath${Template.copyTemplateExtension}'));
+ final String relativeDestination =
+ fs.path.relative(finalDestinationFile.path, from: _flutterRoot.absolute.path);
+ if (finalDestinationFile.existsSync()) {
+ if (_fileIsIdentical(srcFile, finalDestinationFile)) {
+ printTrace(' $relativeDestination (identical)');
+ manifest.add('$relativePath${Template.copyTemplateExtension}');
+ continue;
+ }
+ if (argResults['overwrite']) {
+ finalDestinationFile.deleteSync();
+ printStatus(' $relativeDestination (overwritten)');
+ } else {
+ printTrace(' $relativeDestination (existing - skipped)');
+ manifest.add('$relativePath${Template.copyTemplateExtension}');
+ continue;
+ }
+ } else {
+ printStatus(' $relativeDestination (added)');
+ }
+ final Directory finalDestinationDir = fs.directory(finalDestinationFile.dirname);
+ if (!finalDestinationDir.existsSync()) {
+ printTrace(" ${finalDestinationDir.path} doesn't exist, creating.");
+ finalDestinationDir.createSync(recursive: true);
+ }
+ srcFile.copySync(finalDestinationFile.path);
+ manifest.add('$relativePath${Template.copyTemplateExtension}');
+ }
+
+ // If we're not overwriting, then we're not going to remove missing items either.
+ if (!argResults['overwrite']) {
+ return;
+ }
+
+ // Look for any files under the template dir that don't exist in the manifest and remove
+ // them.
+ final List templateFiles = _templateDirectory.listSync(recursive: true);
+ for (FileSystemEntity entity in templateFiles) {
+ if (entity is! File) {
+ continue;
+ }
+ final File templateFile = entity;
+ final String relativePath = fs.path.relative(
+ templateFile.absolute.path,
+ from: _templateDirectory.absolute.path,
+ );
+ if (!manifest.contains(relativePath)) {
+ templateFile.deleteSync();
+ final String relativeDestination =
+ fs.path.relative(templateFile.path, from: _flutterRoot.absolute.path);
+ printStatus(' $relativeDestination (removed)');
+ }
+ // If the directory is now empty, then remove it, and do the same for its parent,
+ // until we escape to the template directory.
+ Directory parentDir = fs.directory(templateFile.dirname);
+ while (parentDir.listSync().isEmpty) {
+ parentDir.deleteSync();
+ printTrace(' ${fs.path.relative(parentDir.absolute.path)} (empty directory - removed)');
+ parentDir = fs.directory(parentDir.dirname);
+ if (fs.path.isWithin(_templateDirectory.absolute.path, parentDir.absolute.path)) {
+ break;
+ }
+ }
+ }
+ }
+
+ @override
+ Future runCommand() async {
+ if (argResults.rest.isNotEmpty) {
+ throwToolExit('Currently, the only supported IDE is IntelliJ\n$usage', exitCode: 2);
+ }
+
+ await Cache.instance.updateAll();
+
+ if (argResults['update-templates']) {
+ _handleTemplateUpdate();
+ return;
+ }
+
+ final String flutterRoot = fs.path.absolute(Cache.flutterRoot);
+ String dirPath = fs.path.normalize(
+ fs.directory(fs.path.absolute(Cache.flutterRoot)).absolute.path,
+ );
+ // TODO(goderbauer): Work-around for: https://github.com/dart-lang/path/issues/24
+ if (fs.path.basename(dirPath) == '.') {
+ dirPath = fs.path.dirname(dirPath);
+ }
+
+ final String error = _validateFlutterDir(dirPath, flutterRoot: flutterRoot);
+ if (error != null) {
+ throwToolExit(error);
+ }
+
+ printStatus('Updating IDE configuration for Flutter tree at $dirPath...');
+ int generatedCount = 0;
+ generatedCount += _renderTemplate(_ideName, dirPath, {});
+
+ printStatus('Wrote $generatedCount files.');
+ printStatus('');
+ printStatus('Your IntelliJ configuration is now up to date. It is prudent to '
+ 'restart IntelliJ, if running.');
+ }
+
+ int _renderTemplate(String templateName, String dirPath, Map context) {
+ final Template template = new Template(_templateDirectory, _templateDirectory);
+ return template.render(
+ fs.directory(dirPath),
+ context,
+ overwriteExisting: argResults['overwrite'],
+ );
+ }
+}
+
+/// Return null if the flutter root directory is a valid destination. Return a
+/// validation message if we should disallow the directory.
+String _validateFlutterDir(String dirPath, {String flutterRoot}) {
+ final FileSystemEntityType type = fs.typeSync(dirPath);
+
+ if (type != FileSystemEntityType.NOT_FOUND) {
+ switch (type) {
+ case FileSystemEntityType.LINK:
+ // Do not overwrite links.
+ return "Invalid project root dir: '$dirPath' - refers to a link.";
+ }
+ }
+
+ return null;
+}
diff --git a/packages/flutter_tools/lib/src/template.dart b/packages/flutter_tools/lib/src/template.dart
index 5d96db7656d..a2fa206ddcd 100644
--- a/packages/flutter_tools/lib/src/template.dart
+++ b/packages/flutter_tools/lib/src/template.dart
@@ -8,10 +8,6 @@ import 'base/file_system.dart';
import 'cache.dart';
import 'globals.dart';
-const String _kTemplateExtension = '.tmpl';
-const String _kCopyTemplateExtension = '.copy.tmpl';
-final Pattern _kTemplateLanguageVariant = new RegExp(r'(\w+)-(\w+)\.tmpl.*');
-
/// Expands templates in a directory to a destination. All files that must
/// undergo template expansion should end with the '.tmpl' extension. All other
/// files are ignored. In case the contents of entire directories must be copied
@@ -45,7 +41,7 @@ class Template {
final String relativePath = fs.path.relative(entity.path,
from: baseDir.absolute.path);
- if (relativePath.contains(_kTemplateExtension)) {
+ if (relativePath.contains(templateExtension)) {
// If '.tmpl' appears anywhere within the path of this entity, it is
// is a candidate for rendering. This catches cases where the folder
// itself is a template.
@@ -56,10 +52,14 @@ class Template {
factory Template.fromName(String name) {
// All named templates are placed in the 'templates' directory
- final Directory templateDir = _templateDirectoryInPackage(name);
+ final Directory templateDir = templateDirectoryInPackage(name);
return new Template(templateDir, templateDir);
}
+ static const String templateExtension = '.tmpl';
+ static const String copyTemplateExtension = '.copy.tmpl';
+ final Pattern _kTemplateLanguageVariant = new RegExp(r'(\w+)-(\w+)\.tmpl.*');
+
Map _templateFilePaths;
int render(
@@ -91,8 +91,8 @@ class Template {
final String pathSeparator = fs.path.separator;
String finalDestinationPath = fs.path
.join(destinationDirPath, relativeDestinationPath)
- .replaceAll(_kCopyTemplateExtension, '')
- .replaceAll(_kTemplateExtension, '');
+ .replaceAll(copyTemplateExtension, '')
+ .replaceAll(templateExtension, '');
if (androidIdentifier != null) {
finalDestinationPath = finalDestinationPath
@@ -116,7 +116,7 @@ class Template {
if (finalDestinationFile.existsSync()) {
if (overwriteExisting) {
- finalDestinationFile.delete(recursive: true);
+ finalDestinationFile.deleteSync(recursive: true);
printStatus(' $relativePathForLogging (overwritten)');
} else {
// The file exists but we cannot overwrite it, move on.
@@ -124,7 +124,7 @@ class Template {
return;
}
} else {
- printTrace(' $relativePathForLogging');
+ printStatus(' $relativePathForLogging (created)');
}
fileCount++;
@@ -132,11 +132,11 @@ class Template {
finalDestinationFile.createSync(recursive: true);
final File sourceFile = fs.file(absoluteSourcePath);
- // Step 2: If the absolute paths ends with a 'copy.tmpl', this file does
+ // Step 2: If the absolute paths ends with a '.copy.tmpl', this file does
// not need mustache rendering but needs to be directly copied.
- if (sourceFile.path.endsWith(_kCopyTemplateExtension)) {
- finalDestinationFile.writeAsBytesSync(sourceFile.readAsBytesSync());
+ if (sourceFile.path.endsWith(copyTemplateExtension)) {
+ sourceFile.copySync(finalDestinationFile.path);
return;
}
@@ -144,7 +144,7 @@ class Template {
// Step 3: If the absolute path ends with a '.tmpl', this file needs
// rendering via mustache.
- if (sourceFile.path.endsWith(_kTemplateExtension)) {
+ if (sourceFile.path.endsWith(templateExtension)) {
final String templateContents = sourceFile.readAsStringSync();
final String renderedContents = new mustache.Template(templateContents).renderString(context);
@@ -163,7 +163,7 @@ class Template {
}
}
-Directory _templateDirectoryInPackage(String name) {
+Directory templateDirectoryInPackage(String name) {
final String templatesDir = fs.path.join(Cache.flutterRoot,
'packages', 'flutter_tools', 'templates');
return fs.directory(fs.path.join(templatesDir, name));
diff --git a/packages/flutter_tools/test/commands/ide_config_test.dart b/packages/flutter_tools/test/commands/ide_config_test.dart
new file mode 100644
index 00000000000..4cc0a512996
--- /dev/null
+++ b/packages/flutter_tools/test/commands/ide_config_test.dart
@@ -0,0 +1,311 @@
+// Copyright 2017 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 'package:args/command_runner.dart';
+import 'package:flutter_tools/src/base/file_system.dart';
+import 'package:flutter_tools/src/cache.dart';
+import 'package:flutter_tools/src/template.dart';
+import 'package:flutter_tools/src/commands/ide_config.dart';
+import 'package:test/test.dart';
+
+import '../src/common.dart';
+import '../src/context.dart';
+
+void main() {
+ group('ide_config', () {
+ Directory temp;
+ Directory templateDir;
+ Directory intellijDir;
+ Directory toolsDir;
+
+ Map _getFilesystemContents([Directory root]) {
+ final String tempPath = temp.absolute.path;
+ final List paths =
+ (root ?? temp).listSync(recursive: true).map((FileSystemEntity entity) {
+ final String relativePath = fs.path.relative(entity.path, from: tempPath);
+ return relativePath;
+ }).toList();
+ final Map contents = {};
+ for (String path in paths) {
+ final String absPath = fs.path.join(tempPath, path);
+ if (fs.isDirectorySync(absPath)) {
+ contents[path] = 'dir';
+ } else if (fs.isFileSync(absPath)) {
+ contents[path] = fs.file(absPath).readAsStringSync();
+ }
+ }
+ return contents;
+ }
+
+ Map _getManifest(Directory base, String marker, {bool isTemplate: false}) {
+ final String basePath = fs.path.relative(base.path, from: temp.absolute.path);
+ final String suffix = isTemplate ? Template.copyTemplateExtension : '';
+ return {
+ fs.path.join(basePath, '.idea'): 'dir',
+ fs.path.join(basePath, '.idea', 'modules.xml$suffix'): 'modules $marker',
+ fs.path.join(basePath, '.idea', 'vcs.xml$suffix'): 'vcs $marker',
+ fs.path.join(basePath, '.idea', '.name$suffix'):
+ 'codeStyleSettings $marker',
+ fs.path.join(basePath, '.idea', 'runConfigurations'): 'dir',
+ fs.path.join(basePath, '.idea', 'runConfigurations', 'hello_world.xml$suffix'):
+ 'hello_world $marker',
+ fs.path.join(basePath, 'flutter.iml$suffix'): 'flutter $marker',
+ fs.path.join(basePath, 'packages', 'new', 'deep.iml$suffix'): 'deep $marker',
+ };
+ }
+
+ void _populateDir(Map manifest) {
+ for (String key in manifest.keys) {
+ if (manifest[key] == 'dir') {
+ temp.childDirectory(key)..createSync(recursive: true);
+ }
+ }
+ for (String key in manifest.keys) {
+ if (manifest[key] != 'dir') {
+ temp.childFile(key)
+ ..createSync(recursive: true)
+ ..writeAsStringSync(manifest[key]);
+ }
+ }
+ }
+
+ bool _fileOrDirectoryExists(String path) {
+ final String absPath = fs.path.join(temp.absolute.path, path);
+ return fs.file(absPath).existsSync() || fs.directory(absPath).existsSync();
+ }
+
+ Future _updateIdeConfig({
+ Directory dir,
+ List args = const [],
+ Map expectedContents = const {},
+ List unexpectedPaths = const [],
+ }) async {
+ dir ??= temp;
+ final IdeConfigCommand command = new IdeConfigCommand();
+ final CommandRunner runner = createTestCommandRunner(command);
+ final List finalArgs = ['--flutter-root=${temp.absolute.path}', 'ide-config'];
+ finalArgs.addAll(args);
+ await runner.run(finalArgs);
+
+ for (String path in expectedContents.keys) {
+ final String absPath = fs.path.join(temp.absolute.path, path);
+ expect(_fileOrDirectoryExists(fs.path.join(dir.path, path)), true,
+ reason: "$path doesn't exist");
+ if (fs.file(absPath).existsSync()) {
+ expect(fs.file(absPath).readAsStringSync(), equals(expectedContents[path]),
+ reason: "$path contents don't match");
+ }
+ }
+ for (String path in unexpectedPaths) {
+ expect(_fileOrDirectoryExists(fs.path.join(dir.path, path)), false, reason: '$path exists');
+ }
+ }
+
+ setUpAll(() {
+ Cache.disableLocking();
+ });
+
+ setUp(() {
+ temp = fs.systemTempDirectory.createTempSync('flutter_tools_');
+ final Directory packagesDir = temp.childDirectory('packages')..createSync(recursive: true);
+ toolsDir = packagesDir.childDirectory('flutter_tools')..createSync();
+ templateDir = toolsDir.childDirectory('ide_templates')..createSync();
+ intellijDir = templateDir.childDirectory('intellij')..createSync();
+ });
+
+ tearDown(() {
+ temp.deleteSync(recursive: true);
+ });
+
+ testUsingContext("doesn't touch existing files without --overwrite", () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'existing',
+ );
+ _populateDir(templateManifest);
+ _populateDir(flutterManifest);
+ final Map expectedContents = _getFilesystemContents();
+ return _updateIdeConfig(
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ testUsingContext('creates non-existent files', () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'template',
+ );
+ _populateDir(templateManifest);
+ final Map expectedContents = templateManifest;
+ expectedContents.addAll(flutterManifest);
+ return _updateIdeConfig(
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ testUsingContext('overwrites existing files with --overwrite', () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'existing',
+ );
+ _populateDir(templateManifest);
+ _populateDir(flutterManifest);
+ final Map overwrittenManifest = _getManifest(
+ temp,
+ 'template',
+ );
+ final Map expectedContents = templateManifest;
+ expectedContents.addAll(overwrittenManifest);
+ return _updateIdeConfig(
+ args: ['--overwrite'],
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ testUsingContext('only adds new templates without --overwrite', () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ final String flutterIml = fs.path.join(
+ 'packages',
+ 'flutter_tools',
+ 'ide_templates',
+ 'intellij',
+ 'flutter.iml${Template.copyTemplateExtension}',
+ );
+ templateManifest.remove(flutterIml);
+ _populateDir(templateManifest);
+ templateManifest[flutterIml] = 'flutter existing';
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'existing',
+ );
+ _populateDir(flutterManifest);
+ final Map expectedContents = flutterManifest;
+ expectedContents.addAll(templateManifest);
+ return _updateIdeConfig(
+ args: ['--update-templates'],
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ testUsingContext('update all templates with --overwrite', () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ _populateDir(templateManifest);
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'existing',
+ );
+ _populateDir(flutterManifest);
+ final Map updatedTemplates = _getManifest(
+ intellijDir,
+ 'existing',
+ isTemplate: true,
+ );
+ final Map expectedContents = flutterManifest;
+ expectedContents.addAll(updatedTemplates);
+ return _updateIdeConfig(
+ args: ['--update-templates', '--overwrite'],
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ testUsingContext('removes delted imls with --overwrite', () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ _populateDir(templateManifest);
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'existing',
+ );
+ flutterManifest.remove('flutter.iml');
+ _populateDir(flutterManifest);
+ final Map updatedTemplates = _getManifest(
+ intellijDir,
+ 'existing',
+ isTemplate: true,
+ );
+ final String flutterIml = fs.path.join(
+ 'packages',
+ 'flutter_tools',
+ 'ide_templates',
+ 'intellij',
+ 'flutter.iml${Template.copyTemplateExtension}',
+ );
+ updatedTemplates.remove(flutterIml);
+ final Map expectedContents = flutterManifest;
+ expectedContents.addAll(updatedTemplates);
+ return _updateIdeConfig(
+ args: ['--update-templates', '--overwrite'],
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ testUsingContext('removes delted imls with --overwrite, including empty parent dirs', () async {
+ final Map templateManifest = _getManifest(
+ intellijDir,
+ 'template',
+ isTemplate: true,
+ );
+ _populateDir(templateManifest);
+ final Map flutterManifest = _getManifest(
+ temp,
+ 'existing',
+ );
+ flutterManifest.remove(fs.path.join('packages', 'new', 'deep.iml'));
+ _populateDir(flutterManifest);
+ final Map updatedTemplates = _getManifest(
+ intellijDir,
+ 'existing',
+ isTemplate: true,
+ );
+ String deepIml = fs.path.join(
+ 'packages',
+ 'flutter_tools',
+ 'ide_templates',
+ 'intellij');
+ // Remove the all the dir entries too.
+ updatedTemplates.remove(deepIml);
+ deepIml = fs.path.join(deepIml, 'packages');
+ updatedTemplates.remove(deepIml);
+ deepIml = fs.path.join(deepIml, 'new');
+ updatedTemplates.remove(deepIml);
+ deepIml = fs.path.join(deepIml, 'deep.iml');
+ updatedTemplates.remove(deepIml);
+ final Map expectedContents = flutterManifest;
+ expectedContents.addAll(updatedTemplates);
+ return _updateIdeConfig(
+ args: ['--update-templates', '--overwrite'],
+ expectedContents: expectedContents,
+ );
+ }, timeout: const Timeout.factor(2.0));
+
+ });
+}