Unverified Commit beec6106 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate template to null safety (#80016)

parent ec14cef0
...@@ -267,7 +267,7 @@ class _DeferredComponentAndroidFiles { ...@@ -267,7 +267,7 @@ class _DeferredComponentAndroidFiles {
templateRenderer: globals.templateRenderer, templateRenderer: globals.templateRenderer,
); );
} }
final Map<String, dynamic> context = <String, dynamic>{ final Map<String, Object> context = <String, Object>{
'androidIdentifier': FlutterProject.current().manifest.androidPackage ?? 'com.example.${FlutterProject.current().manifest.appName}', 'androidIdentifier': FlutterProject.current().manifest.androidPackage ?? 'com.example.${FlutterProject.current().manifest.appName}',
'componentName': name, 'componentName': name,
}; };
......
...@@ -227,7 +227,7 @@ class CreateCommand extends CreateBase { ...@@ -227,7 +227,7 @@ class CreateCommand extends CreateBase {
); );
} }
final Map<String, dynamic> templateContext = createTemplateContext( final Map<String, Object> templateContext = createTemplateContext(
organization: organization, organization: organization,
projectName: projectName, projectName: projectName,
projectDescription: stringArg('description'), projectDescription: stringArg('description'),
......
...@@ -312,7 +312,7 @@ abstract class CreateBase extends FlutterCommand { ...@@ -312,7 +312,7 @@ abstract class CreateBase extends FlutterCommand {
/// Creates a template to use for [renderTemplate]. /// Creates a template to use for [renderTemplate].
@protected @protected
Map<String, dynamic> createTemplateContext({ Map<String, Object> createTemplateContext({
String organization, String organization,
String projectName, String projectName,
String projectDescription, String projectDescription,
...@@ -344,7 +344,7 @@ abstract class CreateBase extends FlutterCommand { ...@@ -344,7 +344,7 @@ abstract class CreateBase extends FlutterCommand {
// https://developer.gnome.org/gio/stable/GApplication.html#g-application-id-is-valid // https://developer.gnome.org/gio/stable/GApplication.html#g-application-id-is-valid
final String linuxIdentifier = androidIdentifier; final String linuxIdentifier = androidIdentifier;
return <String, dynamic>{ return <String, Object>{
'organization': organization, 'organization': organization,
'projectName': projectName, 'projectName': projectName,
'androidIdentifier': androidIdentifier, 'androidIdentifier': androidIdentifier,
...@@ -385,7 +385,7 @@ abstract class CreateBase extends FlutterCommand { ...@@ -385,7 +385,7 @@ abstract class CreateBase extends FlutterCommand {
/// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`.
@protected @protected
Future<int> renderTemplate( Future<int> renderTemplate(
String templateName, Directory directory, Map<String, dynamic> context, String templateName, Directory directory, Map<String, Object> context,
{bool overwrite = false}) async { {bool overwrite = false}) async {
final Template template = await Template.fromName( final Template template = await Template.fromName(
templateName, templateName,
...@@ -402,7 +402,7 @@ abstract class CreateBase extends FlutterCommand { ...@@ -402,7 +402,7 @@ abstract class CreateBase extends FlutterCommand {
/// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`. /// If `overwrite` is true, overwrites existing files, `overwrite` defaults to `false`.
@protected @protected
Future<int> generateApp( Future<int> generateApp(
Directory directory, Map<String, dynamic> templateContext, Directory directory, Map<String, Object> templateContext,
{bool overwrite = false, bool pluginExampleApp = false}) async { {bool overwrite = false, bool pluginExampleApp = false}) async {
int generatedCount = 0; int generatedCount = 0;
generatedCount += await renderTemplate( generatedCount += await renderTemplate(
......
...@@ -234,7 +234,7 @@ class IdeConfigCommand extends FlutterCommand { ...@@ -234,7 +234,7 @@ class IdeConfigCommand extends FlutterCommand {
globals.printStatus('Updating IDE configuration for Flutter tree at $dirPath...'); globals.printStatus('Updating IDE configuration for Flutter tree at $dirPath...');
int generatedCount = 0; int generatedCount = 0;
generatedCount += _renderTemplate(_ideName, dirPath, <String, dynamic>{ generatedCount += _renderTemplate(_ideName, dirPath, <String, Object>{
'withRootModule': boolArg('with-root-module'), 'withRootModule': boolArg('with-root-module'),
'android': true, 'android': true,
}); });
...@@ -247,7 +247,7 @@ class IdeConfigCommand extends FlutterCommand { ...@@ -247,7 +247,7 @@ class IdeConfigCommand extends FlutterCommand {
return FlutterCommandResult.success(); return FlutterCommandResult.success();
} }
int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) { int _renderTemplate(String templateName, String dirPath, Map<String, Object> context) {
final Template template = Template( final Template template = Template(
_templateDirectory, _templateDirectory,
_templateDirectory, _templateDirectory,
......
...@@ -786,7 +786,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { ...@@ -786,7 +786,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
); );
template.render( template.render(
target, target,
<String, dynamic>{ <String, Object>{
'ios': true, 'ios': true,
'projectName': parent.manifest.appName, 'projectName': parent.manifest.appName,
'iosIdentifier': parent.manifest.iosBundleIdentifier, 'iosIdentifier': parent.manifest.iosBundleIdentifier,
...@@ -970,7 +970,7 @@ to migrate your project. ...@@ -970,7 +970,7 @@ to migrate your project.
); );
template.render( template.render(
target, target,
<String, dynamic>{ <String, Object>{
'android': true, 'android': true,
'projectName': parent.manifest.appName, 'projectName': parent.manifest.appName,
'androidIdentifier': parent.manifest.androidPackage, 'androidIdentifier': parent.manifest.androidPackage,
......
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import 'package:package_config/package_config_types.dart'; import 'package:package_config/package_config_types.dart';
...@@ -33,23 +30,21 @@ import 'dart/package_map.dart'; ...@@ -33,23 +30,21 @@ import 'dart/package_map.dart';
/// 'img.tmpl', or '-<language>.tmpl' extensions. /// 'img.tmpl', or '-<language>.tmpl' extensions.
class Template { class Template {
Template(Directory templateSource, Directory baseDir, this.imageSourceDir, { Template(Directory templateSource, Directory baseDir, this.imageSourceDir, {
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Logger logger, required Logger logger,
@required TemplateRenderer templateRenderer, required TemplateRenderer templateRenderer,
@required Set<Uri> templateManifest, required Set<Uri>? templateManifest,
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_logger = logger, _logger = logger,
_templateRenderer = templateRenderer, _templateRenderer = templateRenderer,
_templateManifest = templateManifest { _templateManifest = templateManifest ?? <Uri>{} {
_templateFilePaths = <String, String>{};
if (!templateSource.existsSync()) { if (!templateSource.existsSync()) {
return; return;
} }
final List<FileSystemEntity> templateFiles = templateSource.listSync(recursive: true); final List<FileSystemEntity> templateFiles = templateSource.listSync(recursive: true);
for (final FileSystemEntity entity in templateFiles.whereType<File>()) { for (final FileSystemEntity entity in templateFiles.whereType<File>()) {
if (_templateManifest != null && !_templateManifest.contains(Uri.file(entity.absolute.path))) { if (_templateManifest.isNotEmpty && !_templateManifest.contains(Uri.file(entity.absolute.path))) {
_logger.printTrace('Skipping ${entity.absolute.path}, missing from the template manifest.'); _logger.printTrace('Skipping ${entity.absolute.path}, missing from the template manifest.');
// Skip stale files in the flutter_tools directory. // Skip stale files in the flutter_tools directory.
continue; continue;
...@@ -67,10 +62,10 @@ class Template { ...@@ -67,10 +62,10 @@ class Template {
} }
static Future<Template> fromName(String name, { static Future<Template> fromName(String name, {
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Set<Uri> templateManifest, required Set<Uri>? templateManifest,
@required Logger logger, required Logger logger,
@required TemplateRenderer templateRenderer, required TemplateRenderer templateRenderer,
}) async { }) async {
// All named templates are placed in the 'templates' directory // All named templates are placed in the 'templates' directory
final Directory templateDir = _templateDirectoryInPackage(name, fileSystem); final Directory templateDir = _templateDirectoryInPackage(name, fileSystem);
...@@ -96,14 +91,14 @@ class Template { ...@@ -96,14 +91,14 @@ class Template {
final Pattern _kTemplateLanguageVariant = RegExp(r'(\w+)-(\w+)\.tmpl.*'); final Pattern _kTemplateLanguageVariant = RegExp(r'(\w+)-(\w+)\.tmpl.*');
final Directory imageSourceDir; final Directory imageSourceDir;
Map<String /* relative */, String /* absolute source */> _templateFilePaths; final Map<String /* relative */, String /* absolute source */> _templateFilePaths = <String, String>{};
/// Render the template into [directory]. /// Render the template into [directory].
/// ///
/// May throw a [ToolExit] if the directory is not writable. /// May throw a [ToolExit] if the directory is not writable.
int render( int render(
Directory destination, Directory destination,
Map<String, dynamic> context, { Map<String, Object> context, {
bool overwriteExisting = true, bool overwriteExisting = true,
bool printStatusWhenWriting = true, bool printStatusWhenWriting = true,
}) { }) {
...@@ -120,57 +115,57 @@ class Template { ...@@ -120,57 +115,57 @@ class Template {
/// expansion on the path itself. /// expansion on the path itself.
/// ///
/// Returns null if the given raw destination path has been filtered. /// Returns null if the given raw destination path has been filtered.
String renderPath(String relativeDestinationPath) { String? renderPath(String relativeDestinationPath) {
final Match match = _kTemplateLanguageVariant.matchAsPrefix(relativeDestinationPath); final Match? match = _kTemplateLanguageVariant.matchAsPrefix(relativeDestinationPath);
if (match != null) { if (match != null) {
final String platform = match.group(1); final String platform = match.group(1)!;
final String language = context['${platform}Language'] as String; final String? language = context['${platform}Language'] as String?;
if (language != match.group(2)) { if (language != match.group(2)) {
return null; return null;
} }
relativeDestinationPath = relativeDestinationPath.replaceAll('$platform-$language.tmpl', platform); relativeDestinationPath = relativeDestinationPath.replaceAll('$platform-$language.tmpl', platform);
} }
final bool android = context['android'] as bool; final bool android = (context['android'] as bool?) == true;
if (relativeDestinationPath.contains('android') && !android) { if (relativeDestinationPath.contains('android') && !android) {
return null; return null;
} }
final bool ios = context['ios'] as bool; final bool ios = (context['ios'] as bool?) == true;
if (relativeDestinationPath.contains('ios') && !ios) { if (relativeDestinationPath.contains('ios') && !ios) {
return null; return null;
} }
// Only build a web project if explicitly asked. // Only build a web project if explicitly asked.
final bool web = context['web'] as bool; final bool web = (context['web'] as bool?) == true;
if (relativeDestinationPath.contains('web') && !web) { if (relativeDestinationPath.contains('web') && !web) {
return null; return null;
} }
// Only build a Linux project if explicitly asked. // Only build a Linux project if explicitly asked.
final bool linux = context['linux'] as bool; final bool linux = (context['linux'] as bool?) == true;
if (relativeDestinationPath.startsWith('linux.tmpl') && !linux) { if (relativeDestinationPath.startsWith('linux.tmpl') && !linux) {
return null; return null;
} }
// Only build a macOS project if explicitly asked. // Only build a macOS project if explicitly asked.
final bool macOS = context['macos'] as bool; final bool macOS = (context['macos'] as bool?) == true;
if (relativeDestinationPath.startsWith('macos.tmpl') && !macOS) { if (relativeDestinationPath.startsWith('macos.tmpl') && !macOS) {
return null; return null;
} }
// Only build a Windows project if explicitly asked. // Only build a Windows project if explicitly asked.
final bool windows = context['windows'] as bool; final bool windows = (context['windows'] as bool?) == true;
if (relativeDestinationPath.startsWith('windows.tmpl') && !windows) { if (relativeDestinationPath.startsWith('windows.tmpl') && !windows) {
return null; return null;
} }
// Only build a Windows UWP project if explicitly asked. // Only build a Windows UWP project if explicitly asked.
final bool windowsUwp = context['winuwp'] as bool; final bool windowsUwp = (context['winuwp'] as bool?) == true;
if (relativeDestinationPath.startsWith('winuwp.tmpl') && !windowsUwp) { if (relativeDestinationPath.startsWith('winuwp.tmpl') && !windowsUwp) {
return null; return null;
} }
final String projectName = context['projectName'] as String; final String? projectName = context['projectName'] as String?;
final String androidIdentifier = context['androidIdentifier'] as String; final String? androidIdentifier = context['androidIdentifier'] as String?;
final String pluginClass = context['pluginClass'] as String; final String? pluginClass = context['pluginClass'] as String?;
final String pluginClassSnakeCase = context['pluginClassSnakeCase'] as String; final String? pluginClassSnakeCase = context['pluginClassSnakeCase'] as String?;
final String destinationDirPath = destination.absolute.path; final String destinationDirPath = destination.absolute.path;
final String pathSeparator = _fileSystem.path.separator; final String pathSeparator = _fileSystem.path.separator;
String finalDestinationPath = _fileSystem.path String finalDestinationPath = _fileSystem.path
...@@ -197,12 +192,12 @@ class Template { ...@@ -197,12 +192,12 @@ class Template {
} }
_templateFilePaths.forEach((String relativeDestinationPath, String absoluteSourcePath) { _templateFilePaths.forEach((String relativeDestinationPath, String absoluteSourcePath) {
final bool withRootModule = context['withRootModule'] as bool ?? false; final bool withRootModule = context['withRootModule'] as bool? ?? false;
if (!withRootModule && absoluteSourcePath.contains('flutter_root')) { if (!withRootModule && absoluteSourcePath.contains('flutter_root')) {
return; return;
} }
final String finalDestinationPath = renderPath(relativeDestinationPath); final String? finalDestinationPath = renderPath(relativeDestinationPath);
if (finalDestinationPath == null) { if (finalDestinationPath == null) {
return; return;
} }
...@@ -277,7 +272,7 @@ class Template { ...@@ -277,7 +272,7 @@ class Template {
} }
Directory _templateDirectoryInPackage(String name, FileSystem fileSystem) { Directory _templateDirectoryInPackage(String name, FileSystem fileSystem) {
final String templatesDir = fileSystem.path.join(Cache.flutterRoot, final String templatesDir = fileSystem.path.join(Cache.flutterRoot!,
'packages', 'flutter_tools', 'templates'); 'packages', 'flutter_tools', 'templates');
return fileSystem.directory(fileSystem.path.join(templatesDir, name)); return fileSystem.directory(fileSystem.path.join(templatesDir, name));
} }
...@@ -286,13 +281,13 @@ Directory _templateDirectoryInPackage(String name, FileSystem fileSystem) { ...@@ -286,13 +281,13 @@ Directory _templateDirectoryInPackage(String name, FileSystem fileSystem) {
// flutter_template_images, to resolve image placeholder against. // flutter_template_images, to resolve image placeholder against.
Future<Directory> _templateImageDirectory(String name, FileSystem fileSystem, Logger logger) async { Future<Directory> _templateImageDirectory(String name, FileSystem fileSystem, Logger logger) async {
final String toolPackagePath = fileSystem.path.join( final String toolPackagePath = fileSystem.path.join(
Cache.flutterRoot, 'packages', 'flutter_tools'); Cache.flutterRoot!, 'packages', 'flutter_tools');
final String packageFilePath = fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json'); final String packageFilePath = fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json');
final PackageConfig packageConfig = await loadPackageConfigWithLogging( final PackageConfig packageConfig = await loadPackageConfigWithLogging(
fileSystem.file(packageFilePath), fileSystem.file(packageFilePath),
logger: logger, logger: logger,
); );
final Uri imagePackageLibDir = packageConfig['flutter_template_images']?.packageUriRoot; final Uri? imagePackageLibDir = packageConfig['flutter_template_images']?.packageUriRoot;
return fileSystem.directory(imagePackageLibDir) return fileSystem.directory(imagePackageLibDir)
.parent .parent
.childDirectory('templates') .childDirectory('templates')
......
...@@ -2,15 +2,13 @@ ...@@ -2,15 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart'; import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/template.dart'; import 'package:flutter_tools/src/base/template.dart';
import 'package:flutter_tools/src/template.dart'; import 'package:flutter_tools/src/template.dart';
import 'src/common.dart'; import '../src/common.dart';
void main() { void main() {
testWithoutContext('Template.render throws ToolExit when FileSystem exception is raised', () { testWithoutContext('Template.render throws ToolExit when FileSystem exception is raised', () {
...@@ -19,7 +17,7 @@ void main() { ...@@ -19,7 +17,7 @@ void main() {
final Template template = Template( final Template template = Template(
fileSystem.directory('examples'), fileSystem.directory('examples'),
fileSystem.currentDirectory, fileSystem.currentDirectory,
null, fileSystem.currentDirectory,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
templateRenderer: FakeTemplateRenderer(), templateRenderer: FakeTemplateRenderer(),
......
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