From 685e9d1e47d80bd3bd22d97e1774fa264930434c Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 23 Mar 2020 10:42:26 -0700 Subject: [PATCH] Add pre-stable support for create on Windows (#51895) Adds initial support for flutter create of apps and plugins. This is derived from the current FDE example app and sample plugin, adding template values where relevant. Since the APIs/tooling/template aren't stable yet, the app template includes a version marker, which will be updated each time there's a breaking change. The build now checks that the template version matches the version known by that version of the tool, and gives a specific error message when there's a mismatch, which improves over the current breaking change experience of hitting whatever build failure the breaking change causes and having to figure out that the problem is that the runner is out of date. It also adds a warning to the create output about the fact that it won't be stable. Plugins don't currently have a version marker since in practice this is not a significant problem for plugins yet the way it is for runners; we can add it later if that changes. Fixes #30704 --- .gitattributes | 13 +- dev/bots/analyze.dart | 9 +- packages/flutter_tools/lib/src/asset.dart | 2 +- .../lib/src/commands/create.dart | 24 +- .../lib/src/commands/ide_config.dart | 2 +- packages/flutter_tools/lib/src/compile.dart | 2 +- .../lib/src/dart/package_map.dart | 34 ++- packages/flutter_tools/lib/src/plugins.dart | 2 +- packages/flutter_tools/lib/src/project.dart | 46 ++-- .../lib/src/runner/flutter_command.dart | 2 +- .../src/runner/flutter_command_runner.dart | 4 +- packages/flutter_tools/lib/src/template.dart | 106 ++++++-- .../lib/src/test/flutter_web_platform.dart | 2 +- .../lib/src/windows/build_windows.dart | 36 +++ packages/flutter_tools/pubspec.yaml | 3 +- .../templates/app/windows.tmpl/.gitignore | 17 ++ .../windows.tmpl/AppConfiguration.props.tmpl | 6 + .../app/windows.tmpl/FlutterBuild.vcxproj | 50 ++++ .../templates/app/windows.tmpl/Runner.rc | 70 +++++ .../templates/app/windows.tmpl/Runner.sln | 39 +++ .../app/windows.tmpl/Runner.vcxproj.filters | 70 +++++ .../app/windows.tmpl/Runner.vcxproj.tmpl | 256 ++++++++++++++++++ .../windows.tmpl/flutter/.template_version | 1 + .../templates/app/windows.tmpl/main.cpp | 100 +++++++ .../templates/app/windows.tmpl/resource.h | 16 ++ .../resources/app_icon.ico.img.tmpl | 0 .../app/windows.tmpl/runner.exe.manifest | 20 ++ .../scripts/bundle_assets_and_deps.bat | 37 +++ .../scripts/prepare_dependencies.bat | 5 + .../app/windows.tmpl/win32_window.cc | 177 ++++++++++++ .../templates/app/windows.tmpl/win32_window.h | 86 ++++++ .../window_configuration.cpp.tmpl | 7 + .../app/windows.tmpl/window_configuration.h | 18 ++ .../linux.tmpl/projectName_plugin.cc.tmpl | 2 +- .../templates/plugin/windows.tmpl/.gitignore | 17 ++ .../plugin/windows.tmpl/PluginInfo.props.tmpl | 14 + .../windows.tmpl/plugin.vcxproj.filters | 45 +++ .../plugin/windows.tmpl/plugin.vcxproj.tmpl | 247 +++++++++++++++++ .../windows.tmpl/projectName_plugin.cpp.tmpl | 95 +++++++ .../windows.tmpl/projectName_plugin.h.tmpl | 23 ++ .../hermetic/build_windows_test.dart | 106 ++++++-- .../hermetic/create_usage_test.dart | 9 + .../commands.shard/permeable/create_test.dart | 60 ++++ .../general.shard/license_collector_test.dart | 2 +- .../test/general.shard/project_test.dart | 9 + .../flutter_tools/test/src/throwing_pub.dart | 6 +- .../flutter_tools/test/template_test.dart | 60 +++- 47 files changed, 1847 insertions(+), 110 deletions(-) create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/.gitignore create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/AppConfiguration.props.tmpl create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/FlutterBuild.vcxproj create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/Runner.rc create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/Runner.sln create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.filters create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/Runner.vcxproj.tmpl create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/flutter/.template_version create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/main.cpp create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/resource.h create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/resources/app_icon.ico.img.tmpl create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/runner.exe.manifest create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/scripts/bundle_assets_and_deps.bat create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/scripts/prepare_dependencies.bat create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/win32_window.cc create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/win32_window.h create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/window_configuration.cpp.tmpl create mode 100644 packages/flutter_tools/templates/app/windows.tmpl/window_configuration.h create mode 100644 packages/flutter_tools/templates/plugin/windows.tmpl/.gitignore create mode 100644 packages/flutter_tools/templates/plugin/windows.tmpl/PluginInfo.props.tmpl create mode 100644 packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.filters create mode 100644 packages/flutter_tools/templates/plugin/windows.tmpl/plugin.vcxproj.tmpl create mode 100644 packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.cpp.tmpl create mode 100644 packages/flutter_tools/templates/plugin/windows.tmpl/projectName_plugin.h.tmpl diff --git a/.gitattributes b/.gitattributes index 31fda4bf1c8628..1f9dafd2b3939e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,8 +15,17 @@ *.yaml text # Make sure that these Windows files always have CRLF line endings in checkout -*.bat text eol=crlf -*.ps1 text eol=crlf +*.bat text eol=crlf +*.ps1 text eol=crlf +*.rc text eol=crlf +*.sln text eol=crlf +*.props text eol=crlf +*.vcxproj text eol=crlf +*.vcxproj.filters text eol=crlf +# Including templatized versions. +*.sln.tmpl text eol=crlf +*.props.tmpl text eol=crlf +*.vcxproj.tmpl text eol=crlf # Never perform LF normalization on these files *.ico binary diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index 20f65e93dcffb9..7a852d96b7d6b7 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart @@ -603,6 +603,7 @@ Future verifyNoTrailingSpaces(String workingDirectory, { int minimumMatche .where((File file) => path.extension(file.path) != '.snapshot') .where((File file) => path.extension(file.path) != '.png') .where((File file) => path.extension(file.path) != '.jpg') + .where((File file) => path.extension(file.path) != '.ico') .where((File file) => path.extension(file.path) != '.jar') .toList(); final List problems = []; @@ -685,7 +686,9 @@ class Hash256 { // DO NOT ADD ANY ENTRIES TO THIS LIST. // We have a policy of not checking in binaries into this repository. -// If you have binaries to add, please consult Hixie for advice. +// If you are adding/changing template images, use the flutter_template_images +// package and a .img.tmpl placeholder instead. +// If you have other binaries to add, please consult Hixie for advice. final Set _grandfatheredBinaries = { // DEFAULT ICON IMAGES @@ -1044,7 +1047,9 @@ final Set _grandfatheredBinaries = { Future verifyNoBinaries(String workingDirectory, { Set grandfatheredBinaries }) async { // Please do not add anything to the _grandfatheredBinaries set above. // We have a policy of not checking in binaries into this repository. - // If you have binaries to add, please consult Hixie for advice. + // If you are adding/changing template images, use the flutter_template_images + // package and a .img.tmpl placeholder instead. + // If you have other binaries to add, please consult Hixie for advice. assert( _grandfatheredBinaries .expand((Hash256 hash) => [hash.a, hash.b, hash.c, hash.d]) diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index e0e28ed79ccd4f..d8db4e086062dc 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart @@ -148,7 +148,7 @@ class _ManifestAssetBundle implements AssetBundle { final String assetBasePath = globals.fs.path.dirname(globals.fs.path.absolute(manifestPath)); - final PackageMap packageMap = PackageMap(packagesPath); + final PackageMap packageMap = PackageMap(packagesPath, fileSystem: globals.fs); final List wildcardDirectories = []; // The _assetVariants map contains an entry for each asset listed diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index c5ad2c3e7d1c00..81e117a4e2b39b 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -407,6 +407,7 @@ class CreateCommand extends FlutterCommand { web: featureFlags.isWebEnabled, linux: featureFlags.isLinuxEnabled, macos: featureFlags.isMacOSEnabled, + windows: featureFlags.isWindowsEnabled, ); final String relativeDirPath = globals.fs.path.relative(projectDirPath); @@ -507,6 +508,12 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi 'You will likely need to re-create the "linux" directory after future ' 'Flutter updates.'); } + if (featureFlags.isWindowsEnabled) { + globals.printStatus(''); + globals.printStatus('WARNING: The Windows tooling and APIs are not yet stable. ' + 'You will likely need to re-create the "windows" directory after future ' + 'Flutter updates.'); + } } return FlutterCommandResult.success(); } @@ -517,7 +524,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ? stringArg('description') : 'A new flutter module project.'; templateContext['description'] = description; - generatedCount += _renderTemplate(globals.fs.path.join('module', 'common'), directory, templateContext, overwrite: overwrite); + generatedCount += await _renderTemplate(globals.fs.path.join('module', 'common'), directory, templateContext, overwrite: overwrite); if (boolArg('pub')) { await pub.get( context: PubContext.create, @@ -536,7 +543,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ? stringArg('description') : 'A new Flutter package project.'; templateContext['description'] = description; - generatedCount += _renderTemplate('package', directory, templateContext, overwrite: overwrite); + generatedCount += await _renderTemplate('package', directory, templateContext, overwrite: overwrite); if (boolArg('pub')) { await pub.get( context: PubContext.createPackage, @@ -553,7 +560,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi ? stringArg('description') : 'A new flutter plugin project.'; templateContext['description'] = description; - generatedCount += _renderTemplate('plugin', directory, templateContext, overwrite: overwrite); + generatedCount += await _renderTemplate('plugin', directory, templateContext, overwrite: overwrite); if (boolArg('pub')) { await pub.get( context: PubContext.createPlugin, @@ -581,13 +588,13 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi Future _generateApp(Directory directory, Map templateContext, { bool overwrite = false }) async { int generatedCount = 0; - generatedCount += _renderTemplate('app', directory, templateContext, overwrite: overwrite); + generatedCount += await _renderTemplate('app', directory, templateContext, overwrite: overwrite); final FlutterProject project = FlutterProject.fromDirectory(directory); generatedCount += _injectGradleWrapper(project); if (boolArg('with-driver-test')) { final Directory testDirectory = directory.childDirectory('test_driver'); - generatedCount += _renderTemplate('driver', testDirectory, templateContext, overwrite: overwrite); + generatedCount += await _renderTemplate('driver', testDirectory, templateContext, overwrite: overwrite); } if (boolArg('pub')) { @@ -626,6 +633,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi bool web = false, bool linux = false, bool macos = false, + bool windows = false, }) { flutterRoot = globals.fs.path.normalize(flutterRoot); @@ -651,6 +659,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi 'pluginClass': pluginClass, 'pluginDartClass': pluginDartClass, 'pluginCppHeaderGuard': projectName.toUpperCase(), + 'pluginProjectUUID': Uuid().generateV4().toUpperCase(), 'withPluginHook': withPluginHook, 'androidLanguage': androidLanguage, 'iosLanguage': iosLanguage, @@ -659,12 +668,13 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi 'web': web, 'linux': linux, 'macos': macos, + 'windows': windows, 'year': DateTime.now().year, }; } - int _renderTemplate(String templateName, Directory directory, Map context, { bool overwrite = false }) { - final Template template = Template.fromName(templateName); + Future _renderTemplate(String templateName, Directory directory, Map context, { bool overwrite = false }) async { + final Template template = await Template.fromName(templateName, fileSystem: globals.fs); return template.render(directory, context, overwriteExisting: overwrite); } diff --git a/packages/flutter_tools/lib/src/commands/ide_config.dart b/packages/flutter_tools/lib/src/commands/ide_config.dart index 91b78b83712b55..ae341c7e34a193 100644 --- a/packages/flutter_tools/lib/src/commands/ide_config.dart +++ b/packages/flutter_tools/lib/src/commands/ide_config.dart @@ -247,7 +247,7 @@ class IdeConfigCommand extends FlutterCommand { } int _renderTemplate(String templateName, String dirPath, Map context) { - final Template template = Template(_templateDirectory, _templateDirectory); + final Template template = Template(_templateDirectory, _templateDirectory, null, fileSystem: globals.fs); return template.render( globals.fs.directory(dirPath), context, diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index a845bc5f199a67..2694ab00fa1ac2 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -196,7 +196,7 @@ class StdoutHandler { /// Converts filesystem paths to package URIs. class PackageUriMapper { PackageUriMapper(String scriptPath, String packagesPath, String fileSystemScheme, List fileSystemRoots) { - final Map packageMap = PackageMap(globals.fs.path.absolute(packagesPath)).map; + final Map packageMap = PackageMap(globals.fs.path.absolute(packagesPath), fileSystem: globals.fs).map; final bool isWindowsPath = globals.platform.isWindows && !scriptPath.startsWith('org-dartlang-app'); final String scriptUri = Uri.file(scriptPath, windows: isWindowsPath).toString(); for (final String packageName in packageMap.keys) { diff --git a/packages/flutter_tools/lib/src/dart/package_map.dart b/packages/flutter_tools/lib/src/dart/package_map.dart index ddb072cfe7c71d..316aae4b5859c1 100644 --- a/packages/flutter_tools/lib/src/dart/package_map.dart +++ b/packages/flutter_tools/lib/src/dart/package_map.dart @@ -2,27 +2,35 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:meta/meta.dart'; // TODO(bkonyi): remove deprecated member usage, https://github.com/flutter/flutter/issues/51951 // ignore: deprecated_member_use import 'package:package_config/packages_file.dart' as packages_file; -import '../globals.dart' as globals; +import '../base/file_system.dart'; +import '../globals.dart' as globals hide fs; const String kPackagesFileName = '.packages'; -Map _parse(String packagesPath) { - final List source = globals.fs.file(packagesPath).readAsBytesSync(); +Map _parse(String packagesPath, FileSystem fileSystem) { + final List source = fileSystem.file(packagesPath).readAsBytesSync(); return packages_file.parse(source, Uri.file(packagesPath, windows: globals.platform.isWindows)); } class PackageMap { - PackageMap(this.packagesPath); + PackageMap(this.packagesPath, { + @required FileSystem fileSystem, + }) : _fileSystem = fileSystem; /// Create a [PackageMap] for testing. - PackageMap.test(Map input) - : packagesPath = '.packages', - _map = input; + PackageMap.test(Map input, { + @required FileSystem fileSystem, + }) : packagesPath = '.packages', + _map = input, + _fileSystem = fileSystem; + + final FileSystem _fileSystem; static String get globalPackagesPath => _globalPackagesPath ?? kPackagesFileName; @@ -38,7 +46,7 @@ class PackageMap { /// Load and parses the .packages file. void load() { - _map ??= _parse(packagesPath); + _map ??= _parse(packagesPath, _fileSystem); } Map get map { @@ -59,17 +67,17 @@ class PackageMap { if (packageBase == null) { return null; } - final String packageRelativePath = globals.fs.path.joinAll(pathSegments); - return packageBase.resolveUri(globals.fs.path.toUri(packageRelativePath)); + final String packageRelativePath = _fileSystem.path.joinAll(pathSegments); + return packageBase.resolveUri(_fileSystem.path.toUri(packageRelativePath)); } String checkValid() { - if (globals.fs.isFileSync(packagesPath)) { + if (_fileSystem.isFileSync(packagesPath)) { return null; } String message = '$packagesPath does not exist.'; - final String pubspecPath = globals.fs.path.absolute(globals.fs.path.dirname(packagesPath), 'pubspec.yaml'); - if (globals.fs.isFileSync(pubspecPath)) { + final String pubspecPath = _fileSystem.path.absolute(_fileSystem.path.dirname(packagesPath), 'pubspec.yaml'); + if (_fileSystem.isFileSync(pubspecPath)) { message += '\nDid you run "flutter pub get" in this directory?'; } else { message += '\nDid you run this command from the same directory as your pubspec.yaml file?'; diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index 2b1d41d55df12c..b73b42db16d1b2 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -307,7 +307,7 @@ List findPlugins(FlutterProject project) { project.directory.path, PackageMap.globalPackagesPath, ); - packages = PackageMap(packagesFile).map; + packages = PackageMap(packagesFile, fileSystem: globals.fs).map; } on FormatException catch (e) { globals.printTrace('Invalid .packages file: $e'); return plugins; diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 9bd80fa412baad..2926a182c6f726 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -460,7 +460,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { Map _buildSettings; Future ensureReadyForPlatformSpecificTooling() async { - _regenerateFromTemplateIfNeeded(); + await _regenerateFromTemplateIfNeeded(); if (!_flutterLibRoot.existsSync()) { return; } @@ -477,7 +477,7 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { } } - void _regenerateFromTemplateIfNeeded() { + Future _regenerateFromTemplateIfNeeded() async { if (!isModule) { return; } @@ -491,18 +491,18 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { } _deleteIfExistsSync(ephemeralDirectory); - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'library'), ephemeralDirectory, ); // Add ephemeral host app, if a editable host app does not already exist. if (!_editableDirectory.existsSync()) { - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'host_app_ephemeral'), ephemeralDirectory, ); if (hasPlugins(parent)) { - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), ephemeralDirectory, ); @@ -542,19 +542,19 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { throwToolExit('iOS host app is already editable. To start fresh, delete the ios/ folder.'); } _deleteIfExistsSync(ephemeralDirectory); - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'library'), ephemeralDirectory, ); - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'host_app_ephemeral'), _editableDirectory, ); - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'host_app_ephemeral_cocoapods'), _editableDirectory, ); - _overwriteFromTemplate( + await _overwriteFromTemplate( globals.fs.path.join('module', 'ios', 'host_app_editable_cocoapods'), _editableDirectory, ); @@ -579,8 +579,8 @@ class IosProject extends FlutterProjectPlatform implements XcodeBasedProject { : hostAppRoot.childDirectory(_hostAppBundleName); } - void _overwriteFromTemplate(String path, Directory target) { - final Template template = Template.fromName(path); + Future _overwriteFromTemplate(String path, Directory target) async { + final Template template = await Template.fromName(path, fileSystem: globals.fs); template.render( target, { @@ -679,11 +679,11 @@ class AndroidProject extends FlutterProjectPlatform { Future ensureReadyForPlatformSpecificTooling() async { if (isModule && _shouldRegenerateFromTemplate()) { - _regenerateLibrary(); + await _regenerateLibrary(); // Add ephemeral host app, if an editable host app does not already exist. if (!_editableHostAppDirectory.existsSync()) { - _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_common'), ephemeralDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_ephemeral'), ephemeralDirectory); + await _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_common'), ephemeralDirectory); + await _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_ephemeral'), ephemeralDirectory); } } if (!hostAppGradleRoot.existsSync()) { @@ -704,10 +704,10 @@ class AndroidProject extends FlutterProjectPlatform { if (_editableHostAppDirectory.existsSync()) { throwToolExit('Android host app is already editable. To start fresh, delete the android/ folder.'); } - _regenerateLibrary(); - _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_common'), _editableHostAppDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_editable'), _editableHostAppDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'gradle'), _editableHostAppDirectory); + await _regenerateLibrary(); + await _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_common'), _editableHostAppDirectory); + await _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'host_app_editable'), _editableHostAppDirectory); + await _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'gradle'), _editableHostAppDirectory); gradle.gradleUtils.injectGradleWrapperIfNeeded(_editableHostAppDirectory); gradle.writeLocalProperties(_editableHostAppDirectory.childFile('local.properties')); await injectPlugins(parent); @@ -717,19 +717,19 @@ class AndroidProject extends FlutterProjectPlatform { Directory get pluginRegistrantHost => _flutterLibGradleRoot.childDirectory(isModule ? 'Flutter' : 'app'); - void _regenerateLibrary() { + Future _regenerateLibrary() async { _deleteIfExistsSync(ephemeralDirectory); - _overwriteFromTemplate(globals.fs.path.join( + await _overwriteFromTemplate(globals.fs.path.join( 'module', 'android', featureFlags.isAndroidEmbeddingV2Enabled ? 'library_new_embedding' : 'library', ), ephemeralDirectory); - _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'gradle'), ephemeralDirectory); + await _overwriteFromTemplate(globals.fs.path.join('module', 'android', 'gradle'), ephemeralDirectory); gradle.gradleUtils.injectGradleWrapperIfNeeded(ephemeralDirectory); } - void _overwriteFromTemplate(String path, Directory target) { - final Template template = Template.fromName(path); + Future _overwriteFromTemplate(String path, Directory target) async { + final Template template = await Template.fromName(path, fileSystem: globals.fs); template.render( target, { diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index c417200e463eb1..208a34ba8b703d 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -803,7 +803,7 @@ abstract class FlutterCommand extends Command { // Validate the current package map only if we will not be running "pub get" later. if (parent?.name != 'pub' && !(_usesPubOption && boolArg('pub'))) { - final String error = PackageMap(PackageMap.globalPackagesPath).checkValid(); + final String error = PackageMap(PackageMap.globalPackagesPath, fileSystem: globals.fs).checkValid(); if (error != null) { throw ToolExit(error); } diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index ac37ea0571af66..b3e69714fd7659 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -354,7 +354,7 @@ class FlutterCommandRunner extends CommandRunner { if (engineSourcePath == null && globalResults['local-engine'] != null) { try { - Uri engineUri = PackageMap(PackageMap.globalPackagesPath).map[kFlutterEnginePackageName]; + Uri engineUri = PackageMap(PackageMap.globalPackagesPath, fileSystem: globals.fs).map[kFlutterEnginePackageName]; // Skip if sky_engine is the self-contained one. if (engineUri != null && globals.fs.identicalSync(globals.fs.path.join(Cache.flutterRoot, 'bin', 'cache', 'pkg', kFlutterEnginePackageName, 'lib'), engineUri.path)) { engineUri = null; @@ -491,7 +491,7 @@ class FlutterCommandRunner extends CommandRunner { // Check that the flutter running is that same as the one referenced in the pubspec. if (globals.fs.isFileSync(kPackagesFileName)) { - final PackageMap packageMap = PackageMap(kPackagesFileName); + final PackageMap packageMap = PackageMap(kPackagesFileName, fileSystem: globals.fs); Uri flutterUri; try { flutterUri = packageMap.map['flutter']; diff --git a/packages/flutter_tools/lib/src/template.dart b/packages/flutter_tools/lib/src/template.dart index b9beecc8b3e2e4..499c8aba183935 100644 --- a/packages/flutter_tools/lib/src/template.dart +++ b/packages/flutter_tools/lib/src/template.dart @@ -2,27 +2,35 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:meta/meta.dart'; + import 'base/common.dart'; import 'base/file_system.dart'; import 'cache.dart'; -import 'globals.dart' as globals; +import 'dart/package_map.dart'; +import 'dart/pub.dart'; +import 'globals.dart' as globals hide fs; /// Expands templates in a directory to a destination. All files that must -/// undergo template expansion should end with the '.tmpl' extension. All other +/// 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' extension and will be -/// considered for expansion. In case certain files need to be copied but -/// without template expansion (images, data files, etc.), the '.copy.tmpl' +/// 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. /// /// Folders with platform/language-specific content must be named /// '-.tmpl'. /// -/// Files in the destination will contain none of the '.tmpl', '.copy.tmpl' -/// or '-.tmpl' extensions. +/// Files in the destination will contain none of the '.tmpl', '.copy.tmpl', +/// 'img.tmpl', or '-.tmpl' extensions. class Template { - Template(Directory templateSource, Directory baseDir) { + Template(Directory templateSource, Directory baseDir, this.imageSourceDir, { + @required FileSystem fileSystem, + }) : _fileSystem = fileSystem { _templateFilePaths = {}; if (!templateSource.existsSync()) { @@ -37,27 +45,31 @@ class Template { continue; } - final String relativePath = globals.fs.path.relative(entity.path, + final String relativePath = fileSystem.path.relative(entity.path, from: baseDir.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] = globals.fs.path.absolute(entity.path); + _templateFilePaths[relativePath] = fileSystem.path.absolute(entity.path); } } } - factory Template.fromName(String name) { + static Future