import 'package:mustache/mustache.dart' as mustache;
import 'base/common.dart';
import 'base/file_system.dart';
import 'cache.dart';
import 'globals.dart';
class Template {
Template(Directory templateSource, Directory baseDir) {
_templateFilePaths = <String, String>{};
if (!templateSource.existsSync()) {
return;
}
final List<FileSystemEntity> templateFiles = templateSource.listSync(recursive: true);
for (FileSystemEntity entity in templateFiles) {
if (entity is! File) {
continue;
}
final String relativePath = fs.path.relative(entity.path,
from: baseDir.absolute.path);
if (relativePath.contains(templateExtension)) {
_templateFilePaths[relativePath] = fs.path.absolute(entity.path);
}
}
}
factory Template.fromName(String name) {
final Directory templateDir = templateDirectoryInPackage(name);
return Template(templateDir, templateDir);
}
static const String templateExtension = '.tmpl';
static const String copyTemplateExtension = '.copy.tmpl';
final Pattern _kTemplateLanguageVariant = RegExp(r'(\w+)-(\w+)\.tmpl.*');
Map<String , String > _templateFilePaths;
int render(
Directory destination,
Map<String, dynamic> context, {
bool overwriteExisting = true,
bool printStatusWhenWriting = true,
}) {
try {
destination.createSync(recursive: true);
} on FileSystemException catch (err) {
printError(err.toString());
throwToolExit('Failed to flutter create at ${destination.path}.');
return 0;
}
int fileCount = 0;
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'];
if (language != match.group(2))
return null;
relativeDestinationPath = relativeDestinationPath.replaceAll('$platform-$language.tmpl', platform);
}
final bool web = context['web'];
if (relativeDestinationPath.contains('web') && !web) {
return null;
}
final String projectName = context['projectName'];
final String androidIdentifier = context['androidIdentifier'];
final String pluginClass = context['pluginClass'];
final String destinationDirPath = destination.absolute.path;
final String pathSeparator = fs.path.separator;
String finalDestinationPath = fs.path
.join(destinationDirPath, relativeDestinationPath)
.replaceAll(copyTemplateExtension, '')
.replaceAll(templateExtension, '');
if (androidIdentifier != null) {
finalDestinationPath = finalDestinationPath
.replaceAll('androidIdentifier', androidIdentifier.replaceAll('.', pathSeparator));
}
if (projectName != null)
finalDestinationPath = finalDestinationPath.replaceAll('projectName', projectName);
if (pluginClass != null)
finalDestinationPath = finalDestinationPath.replaceAll('pluginClass', pluginClass);
return finalDestinationPath;
}
_templateFilePaths.forEach((String relativeDestinationPath, String absoluteSourcePath) {
final bool withRootModule = context['withRootModule'] ?? false;
if (!withRootModule && absoluteSourcePath.contains('flutter_root'))
return;
final String finalDestinationPath = renderPath(relativeDestinationPath);
if (finalDestinationPath == null)
return;
final File finalDestinationFile = fs.file(finalDestinationPath);
final String relativePathForLogging = fs.path.relative(finalDestinationFile.path);
if (finalDestinationFile.existsSync()) {
if (overwriteExisting) {
finalDestinationFile.deleteSync(recursive: true);
if (printStatusWhenWriting)
printStatus(' $relativePathForLogging (overwritten)');
} else {
if (printStatusWhenWriting)
printTrace(' $relativePathForLogging (existing - skipped)');
return;
}
} else {
if (printStatusWhenWriting)
printStatus(' $relativePathForLogging (created)');
}
fileCount++;
finalDestinationFile.createSync(recursive: true);
final File sourceFile = fs.file(absoluteSourcePath);
if (sourceFile.path.endsWith(copyTemplateExtension)) {
sourceFile.copySync(finalDestinationFile.path);
return;
}
if (sourceFile.path.endsWith(templateExtension)) {
final String templateContents = sourceFile.readAsStringSync();
final String renderedContents = mustache.Template(templateContents).renderString(context);
finalDestinationFile.writeAsStringSync(renderedContents);
return;
}
sourceFile.copySync(finalDestinationFile.path);
});
return fileCount;
}
}
Directory templateDirectoryInPackage(String name) {
final String templatesDir = fs.path.join(Cache.flutterRoot,
'packages', 'flutter_tools', 'templates');
return fs.directory(fs.path.join(templatesDir, name));
}