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