diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 93e4d1bfe6..b625d7fe0a 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -289,19 +289,46 @@ class CreateCommand extends CreateBase { int generatedFileCount = 0; switch (template) { case FlutterProjectType.app: - generatedFileCount += await generateApp('app', relativeDir, templateContext, overwrite: overwrite); + generatedFileCount += await generateApp( + 'app', + relativeDir, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: !creatingNewProject, + ); break; case FlutterProjectType.skeleton: - generatedFileCount += await generateApp('skeleton', relativeDir, templateContext, overwrite: overwrite); + generatedFileCount += await generateApp( + 'skeleton', + relativeDir, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: !creatingNewProject, + ); break; case FlutterProjectType.module: - generatedFileCount += await _generateModule(relativeDir, templateContext, overwrite: overwrite); + generatedFileCount += await _generateModule( + relativeDir, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: !creatingNewProject, + ); break; case FlutterProjectType.package: - generatedFileCount += await _generatePackage(relativeDir, templateContext, overwrite: overwrite); + generatedFileCount += await _generatePackage( + relativeDir, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: !creatingNewProject, + ); break; case FlutterProjectType.plugin: - generatedFileCount += await _generatePlugin(relativeDir, templateContext, overwrite: overwrite); + generatedFileCount += await _generatePlugin( + relativeDir, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: !creatingNewProject, + ); break; } if (sampleCode != null) { @@ -367,13 +394,24 @@ Your $application code is in $relativeAppMain. return FlutterCommandResult.success(); } - Future _generateModule(Directory directory, Map templateContext, { bool overwrite = false }) async { + Future _generateModule( + Directory directory, + Map templateContext, { + bool overwrite = false, + bool printStatusWhenWriting = true, + }) async { int generatedCount = 0; final String description = argResults.wasParsed('description') ? stringArg('description') : 'A new flutter module project.'; templateContext['description'] = description; - generatedCount += await renderTemplate(globals.fs.path.join('module', 'common'), directory, templateContext, overwrite: overwrite); + generatedCount += await renderTemplate( + globals.fs.path.join('module', 'common'), + directory, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: printStatusWhenWriting, + ); if (boolArg('pub')) { await pub.get( context: PubContext.create, @@ -390,13 +428,24 @@ Your $application code is in $relativeAppMain. return generatedCount; } - Future _generatePackage(Directory directory, Map templateContext, { bool overwrite = false }) async { + Future _generatePackage( + Directory directory, + Map templateContext, { + bool overwrite = false, + bool printStatusWhenWriting = true, + }) async { int generatedCount = 0; final String description = argResults.wasParsed('description') ? stringArg('description') : 'A new Flutter package project.'; templateContext['description'] = description; - generatedCount += await renderTemplate('package', directory, templateContext, overwrite: overwrite); + generatedCount += await renderTemplate( + 'package', + directory, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: printStatusWhenWriting, + ); if (boolArg('pub')) { await pub.get( context: PubContext.createPackage, @@ -408,7 +457,12 @@ Your $application code is in $relativeAppMain. return generatedCount; } - Future _generatePlugin(Directory directory, Map templateContext, { bool overwrite = false }) async { + Future _generatePlugin( + Directory directory, + Map templateContext, { + bool overwrite = false, + bool printStatusWhenWriting = true, + }) async { // Plugins only add a platform if it was requested explicitly by the user. if (!argResults.wasParsed('platforms')) { for (final String platform in kAllCreatePlatforms) { @@ -430,7 +484,13 @@ Your $application code is in $relativeAppMain. ? stringArg('description') : 'A new flutter plugin project.'; templateContext['description'] = description; - generatedCount += await renderTemplate('plugin', directory, templateContext, overwrite: overwrite); + generatedCount += await renderTemplate( + 'plugin', + directory, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: printStatusWhenWriting, + ); if (boolArg('pub')) { await pub.get( @@ -461,7 +521,14 @@ Your $application code is in $relativeAppMain. templateContext['pluginProjectName'] = projectName; templateContext['androidPluginIdentifier'] = androidPluginIdentifier; - generatedCount += await generateApp('app', project.example.directory, templateContext, overwrite: overwrite, pluginExampleApp: true); + generatedCount += await generateApp( + 'app', + project.example.directory, + templateContext, + overwrite: overwrite, + pluginExampleApp: true, + printStatusWhenWriting: printStatusWhenWriting, + ); return generatedCount; } diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index b10b4a09df..5bbe4aaf3c 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -404,8 +404,12 @@ abstract class CreateBase extends FlutterCommand { /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. @protected Future renderTemplate( - String templateName, Directory directory, Map context, - {bool overwrite = false}) async { + String templateName, + Directory directory, + Map context, { + bool overwrite = false, + bool printStatusWhenWriting = true, + }) async { final Template template = await Template.fromName( templateName, fileSystem: globals.fs, @@ -413,7 +417,12 @@ abstract class CreateBase extends FlutterCommand { templateRenderer: globals.templateRenderer, templateManifest: _templateManifest, ); - return template.render(directory, context, overwriteExisting: overwrite); + return template.render( + directory, + context, + overwriteExisting: overwrite, + printStatusWhenWriting: printStatusWhenWriting, + ); } /// Merges named templates into a single template, output to `directory`. @@ -423,8 +432,12 @@ abstract class CreateBase extends FlutterCommand { /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. @protected Future renderMerged( - List names, Directory directory, Map context, - {bool overwrite = false}) async { + List names, + Directory directory, + Map context, { + bool overwrite = false, + bool printStatusWhenWriting = true, + }) async { final Template template = await Template.merged( names, directory, @@ -433,7 +446,12 @@ abstract class CreateBase extends FlutterCommand { templateRenderer: globals.templateRenderer, templateManifest: _templateManifest, ); - return template.render(directory, context, overwriteExisting: overwrite); + return template.render( + directory, + context, + overwriteExisting: overwrite, + printStatusWhenWriting: printStatusWhenWriting, + ); } /// Generate application project in the `directory` using `templateContext`. @@ -441,14 +459,20 @@ abstract class CreateBase extends FlutterCommand { /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. @protected Future generateApp( - String templateName, Directory directory, Map templateContext, - {bool overwrite = false, bool pluginExampleApp = false}) async { + String templateName, + Directory directory, + Map templateContext, { + bool overwrite = false, + bool pluginExampleApp = false, + bool printStatusWhenWriting = true, + }) async { int generatedCount = 0; generatedCount += await renderMerged( [templateName, 'app_shared'], directory, templateContext, overwrite: overwrite, + printStatusWhenWriting: printStatusWhenWriting, ); final FlutterProject project = FlutterProject.fromDirectory(directory); if (templateContext['android'] == true) { diff --git a/packages/flutter_tools/test/general.shard/template_test.dart b/packages/flutter_tools/test/general.shard/template_test.dart index 9d007a7efa..2a66a30d1c 100644 --- a/packages/flutter_tools/test/general.shard/template_test.dart +++ b/packages/flutter_tools/test/general.shard/template_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; + import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -41,29 +43,80 @@ void main() { throwsToolExit()); }); - testWithoutContext('Template.render replaces .img.tmpl files with files from the image source', () { - final MemoryFileSystem fileSystem = MemoryFileSystem.test(); - final Directory templateDir = fileSystem.directory('templates'); - final Directory imageSourceDir = fileSystem.directory('template_images'); - final Directory destination = fileSystem.directory('target'); + group('renders template', () { + late Directory destination; const String imageName = 'some_image.png'; - templateDir.childFile('$imageName.img.tmpl').createSync(recursive: true); - final File sourceImage = imageSourceDir.childFile(imageName); - sourceImage.createSync(recursive: true); - sourceImage.writeAsStringSync("Ceci n'est pas une pipe"); + late File sourceImage; + late BufferLogger logger; + late Template template; - final Template template = Template( - templateDir, - imageSourceDir, - fileSystem: fileSystem, - logger: BufferLogger.test(), - templateRenderer: FakeTemplateRenderer(), - ); - template.render(destination, {}); + setUp(() { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final Directory templateDir = fileSystem.directory('templates'); + final Directory imageSourceDir = fileSystem.directory('template_images'); + destination = fileSystem.directory('target'); + templateDir.childFile('$imageName.img.tmpl').createSync(recursive: true); + sourceImage = imageSourceDir.childFile(imageName); + sourceImage.createSync(recursive: true); + sourceImage.writeAsStringSync("Ceci n'est pas une pipe"); - final File destinationImage = destination.childFile(imageName); - expect(destinationImage, exists); - expect(destinationImage.readAsBytesSync(), equals(sourceImage.readAsBytesSync())); + logger = BufferLogger.test(); + template = Template( + templateDir, + imageSourceDir, + fileSystem: fileSystem, + logger: logger, + templateRenderer: FakeTemplateRenderer(), + ); + }); + + testWithoutContext('overwrites .img.tmpl files with files from the image source', () { + expect(template.render(destination, {}), 1); + + final File destinationImage = destination.childFile(imageName); + final Uint8List sourceImageBytes = sourceImage.readAsBytesSync(); + expect(destinationImage, exists); + expect(destinationImage.readAsBytesSync(), equals(sourceImageBytes)); + + expect(logger.errorText, isEmpty); + expect(logger.statusText, contains('${destinationImage.path} (created)')); + logger.clear(); + + // Run it again to overwrite (returns 1 file updated). + expect(template.render(destination, {}), 1); + + expect(destinationImage.readAsBytesSync(), equals(sourceImageBytes)); + expect(logger.errorText, isEmpty); + expect(logger.statusText, contains('${destinationImage.path} (overwritten)')); + }); + + testWithoutContext('does not overwrite .img.tmpl files with files from the image source', () { + expect(template.render(destination, {}), 1); + + final File destinationImage = destination.childFile(imageName); + expect(destinationImage, exists); + + expect(logger.errorText, isEmpty); + expect(logger.statusText, contains('${destinationImage.path} (created)')); + logger.clear(); + + // Run it again, do not overwrite (returns 0 files updated). + expect(template.render(destination, {}, overwriteExisting: false), 0); + + expect(destinationImage, exists); + expect(logger.errorText, isEmpty); + expect(logger.statusText, isEmpty); + }); + + testWithoutContext('can suppress file printing', () { + template.render(destination, {}, printStatusWhenWriting: false); + + final File destinationImage = destination.childFile(imageName); + expect(destinationImage, exists); + + expect(logger.errorText, isEmpty); + expect(logger.statusText, isEmpty); + }); }); }