// Copyright 2014 The Flutter 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 'package:file/file.dart'; import 'package:package_config/package_config.dart'; import 'package:package_config/package_config_types.dart'; import 'base/common.dart'; import 'base/file_system.dart'; import 'base/logger.dart'; import 'base/template.dart'; import 'cache.dart'; import 'dart/package_map.dart'; /// The Kotlin keywords which are not Java keywords. /// They are escaped in Kotlin files. /// /// https://kotlinlang.org/docs/keyword-reference.html const List kReservedKotlinKeywords = ['when', 'in']; /// Expands templates in a directory to a destination. All files that must /// undergo template expansion should end with the '.tmpl' extension. All files /// that should be replaced with the corresponding image from /// flutter_template_images should end with the '.img.tmpl' extension. All other /// files are ignored. In case the contents of entire directories must be copied /// as is, the directory itself can end with '.tmpl' extension. Files within /// such a directory may also contain the '.tmpl' or '.img.tmpl' extensions and /// will be considered for expansion. In case certain files need to be copied /// but without template expansion (data files, etc.), the '.copy.tmpl' /// extension may be used. Furthermore, templates may contain additional /// test files intended to run on the CI. Test files must end in `.test.tmpl` /// and are only included when the --implementation-tests flag is enabled. /// /// Folders with platform/language-specific content must be named /// '-.tmpl'. /// /// Files in the destination will contain none of the '.tmpl', '.copy.tmpl', /// 'img.tmpl', or '-.tmpl' extensions. class Template { factory Template(Directory templateSource, Directory? imageSourceDir, { required FileSystem fileSystem, required Logger logger, required TemplateRenderer templateRenderer, Set? templateManifest, }) { return Template._( [templateSource], imageSourceDir != null ? [imageSourceDir] : [], fileSystem: fileSystem, logger: logger, templateRenderer: templateRenderer, templateManifest: templateManifest, ); } Template._( List templateSources, this.imageSourceDirectories, { required FileSystem fileSystem, required Logger logger, required TemplateRenderer templateRenderer, required Set? templateManifest, }) : _fileSystem = fileSystem, _logger = logger, _templateRenderer = templateRenderer, _templateManifest = templateManifest ?? {} { for (final Directory sourceDirectory in templateSources) { if (!sourceDirectory.existsSync()) { throwToolExit('Template source directory does not exist: ${sourceDirectory.absolute.path}'); } } final Map templateFiles = { for (final Directory sourceDirectory in templateSources) for (final FileSystemEntity entity in sourceDirectory.listSync(recursive: true)) entity: sourceDirectory, }; for (final FileSystemEntity entity in templateFiles.keys.whereType()) { 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; } final String relativePath = fileSystem.path.relative(entity.path, from: templateFiles[entity]!.absolute.path); 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. _templateFilePaths[relativePath] = fileSystem.path.absolute(entity.path); } } } static Future