[flutter_tools] Removes the need of a no-op plugin implementations (#48614)
This commit is contained in:
parent
91f8d3da32
commit
5eb394e084
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
@ -74,10 +75,6 @@ Future<void> main() async {
|
||||
);
|
||||
});
|
||||
|
||||
// https://github.com/flutter/flutter/issues/46898
|
||||
// https://github.com/flutter/flutter/issues/39657
|
||||
File(path.join(pluginCDirectory.path, 'android', 'build.gradle')).deleteSync();
|
||||
|
||||
final File pluginCpubspec = File(path.join(pluginCDirectory.path, 'pubspec.yaml'));
|
||||
await pluginCpubspec.writeAsString('''
|
||||
name: plugin_c
|
||||
@ -177,30 +174,32 @@ public class DummyPluginAClass {
|
||||
}
|
||||
|
||||
final String flutterPluginsDependenciesFileContent = flutterPluginsDependenciesFile.readAsStringSync();
|
||||
const String kExpectedPluginsDependenciesContent =
|
||||
'{'
|
||||
'\"_info\":\"// This is a generated file; do not edit or check into version control.\",'
|
||||
'\"dependencyGraph\":['
|
||||
'{'
|
||||
'\"name\":\"plugin_a\",'
|
||||
'\"dependencies\":[\"plugin_b\",\"plugin_c\"]'
|
||||
'},'
|
||||
'{'
|
||||
'\"name\":\"plugin_b\",'
|
||||
'\"dependencies\":[]'
|
||||
'},'
|
||||
'{'
|
||||
'\"name\":\"plugin_c\",'
|
||||
'\"dependencies\":[]'
|
||||
'}'
|
||||
']'
|
||||
'}';
|
||||
|
||||
if (flutterPluginsDependenciesFileContent != kExpectedPluginsDependenciesContent) {
|
||||
final Map<String, dynamic> jsonContent = json.decode(flutterPluginsDependenciesFileContent) as Map<String, dynamic>;
|
||||
|
||||
// Verify the dependencyGraph object is valid. The rest of the contents of this file are not relevant to the
|
||||
// dependency graph and are tested by unit tests.
|
||||
final List<dynamic> dependencyGraph = jsonContent['dependencyGraph'] as List<dynamic>;
|
||||
const String kExpectedPluginsDependenciesContent =
|
||||
'['
|
||||
'{'
|
||||
'\"name\":\"plugin_a\",'
|
||||
'\"dependencies\":[\"plugin_b\",\"plugin_c\"]'
|
||||
'},'
|
||||
'{'
|
||||
'\"name\":\"plugin_b\",'
|
||||
'\"dependencies\":[]'
|
||||
'},'
|
||||
'{'
|
||||
'\"name\":\"plugin_c\",'
|
||||
'\"dependencies\":[]'
|
||||
'}'
|
||||
']';
|
||||
final String graphString = json.encode(dependencyGraph);
|
||||
if (graphString != kExpectedPluginsDependenciesContent) {
|
||||
return TaskResult.failure(
|
||||
'Unexpected file content in ${flutterPluginsDependenciesFile.path}: '
|
||||
'Found "$flutterPluginsDependenciesFileContent" instead of '
|
||||
'"$kExpectedPluginsDependenciesContent"'
|
||||
'Found "$graphString" instead of "$kExpectedPluginsDependenciesContent"'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import 'package:yaml/yaml.dart';
|
||||
import 'android/gradle.dart';
|
||||
import 'base/common.dart';
|
||||
import 'base/file_system.dart';
|
||||
import 'base/time.dart';
|
||||
import 'convert.dart';
|
||||
import 'dart/package_map.dart';
|
||||
import 'features.dart';
|
||||
@ -18,6 +19,7 @@ import 'globals.dart' as globals;
|
||||
import 'macos/cocoapods.dart';
|
||||
import 'platform_plugins.dart';
|
||||
import 'project.dart';
|
||||
import 'version.dart';
|
||||
|
||||
void _renderTemplateToFile(String template, dynamic context, String filePath) {
|
||||
final String renderedTemplate =
|
||||
@ -263,7 +265,7 @@ class Plugin {
|
||||
final Map<String, PluginPlatform> platforms;
|
||||
}
|
||||
|
||||
Plugin _pluginFromPubspec(String name, Uri packageRoot) {
|
||||
Plugin _pluginFromPackage(String name, Uri packageRoot) {
|
||||
final String pubspecPath = globals.fs.path.fromUri(packageRoot.resolve('pubspec.yaml'));
|
||||
if (!globals.fs.isFileSync(pubspecPath)) {
|
||||
return null;
|
||||
@ -302,7 +304,7 @@ List<Plugin> findPlugins(FlutterProject project) {
|
||||
}
|
||||
packages.forEach((String name, Uri uri) {
|
||||
final Uri packageRoot = uri.resolve('..');
|
||||
final Plugin plugin = _pluginFromPubspec(name, packageRoot);
|
||||
final Plugin plugin = _pluginFromPackage(name, packageRoot);
|
||||
if (plugin != null) {
|
||||
plugins.add(plugin);
|
||||
}
|
||||
@ -310,55 +312,159 @@ List<Plugin> findPlugins(FlutterProject project) {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
/// Writes the .flutter-plugins and .flutter-plugins-dependencies files based on the list of plugins.
|
||||
/// If there aren't any plugins, then the files aren't written to disk.
|
||||
/// Filters [plugins] to those supported by [platformKey].
|
||||
List<Map<String, dynamic>> _filterPluginsByPlatform(List<Plugin>plugins, String platformKey) {
|
||||
final Iterable<Plugin> platformPlugins = plugins.where((Plugin p) {
|
||||
return p.platforms.containsKey(platformKey);
|
||||
});
|
||||
|
||||
final Set<String> pluginNames = platformPlugins.map((Plugin plugin) => plugin.name).toSet();
|
||||
final List<Map<String, dynamic>> list = <Map<String, dynamic>>[];
|
||||
for (final Plugin plugin in platformPlugins) {
|
||||
list.add(<String, dynamic>{
|
||||
'name': plugin.name,
|
||||
'path': fsUtils.escapePath(plugin.path),
|
||||
'dependencies': <String>[...plugin.dependencies.where(pluginNames.contains)],
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// Writes the .flutter-plugins-dependencies file based on the list of plugins.
|
||||
/// If there aren't any plugins, then the files aren't written to disk. The resulting
|
||||
/// file looks something like this (order of keys is not guaranteed):
|
||||
/// {
|
||||
/// "info": "This is a generated file; do not edit or check into version control.",
|
||||
/// "plugins": {
|
||||
/// "ios": [
|
||||
/// {
|
||||
/// "name": "test",
|
||||
/// "path": "test_path",
|
||||
/// "dependencies": [
|
||||
/// "plugin-a",
|
||||
/// "plugin-b"
|
||||
/// ]
|
||||
/// }
|
||||
/// ],
|
||||
/// "android": [],
|
||||
/// "macos": [],
|
||||
/// "linux": [],
|
||||
/// "windows": [],
|
||||
/// "web": []
|
||||
/// },
|
||||
/// "dependencyGraph": [
|
||||
/// {
|
||||
/// "name": "plugin-a",
|
||||
/// "dependencies": [
|
||||
/// "plugin-b",
|
||||
/// "plugin-c"
|
||||
/// ]
|
||||
/// },
|
||||
/// {
|
||||
/// "name": "plugin-b",
|
||||
/// "dependencies": [
|
||||
/// "plugin-c"
|
||||
/// ]
|
||||
/// },
|
||||
/// {
|
||||
/// "name": "plugin-c",
|
||||
/// "dependencies": []
|
||||
/// }
|
||||
/// ],
|
||||
/// "date_created": "1970-01-01 00:00:00.000",
|
||||
/// "version": "0.0.0-unknown"
|
||||
/// }
|
||||
///
|
||||
/// Finally, returns [true] if .flutter-plugins or .flutter-plugins-dependencies have changed,
|
||||
///
|
||||
/// Finally, returns [true] if .flutter-plugins-dependencies has changed,
|
||||
/// otherwise returns [false].
|
||||
bool _writeFlutterPluginsList(FlutterProject project, List<Plugin> plugins) {
|
||||
final List<dynamic> directAppDependencies = <dynamic>[];
|
||||
const String info = 'This is a generated file; do not edit or check into version control.';
|
||||
final StringBuffer flutterPluginsBuffer = StringBuffer('# $info\n');
|
||||
|
||||
final Set<String> pluginNames = <String>{};
|
||||
for (final Plugin plugin in plugins) {
|
||||
pluginNames.add(plugin.name);
|
||||
final File pluginsFile = project.flutterPluginsDependenciesFile;
|
||||
if (plugins.isEmpty) {
|
||||
if (pluginsFile.existsSync()) {
|
||||
pluginsFile.deleteSync();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final String iosKey = project.ios.pluginConfigKey;
|
||||
final String androidKey = project.android.pluginConfigKey;
|
||||
final String macosKey = project.macos.pluginConfigKey;
|
||||
final String linuxKey = project.linux.pluginConfigKey;
|
||||
final String windowsKey = project.windows.pluginConfigKey;
|
||||
final String webKey = project.web.pluginConfigKey;
|
||||
|
||||
final Map<String, dynamic> pluginsMap = <String, dynamic>{};
|
||||
pluginsMap[iosKey] = _filterPluginsByPlatform(plugins, iosKey);
|
||||
pluginsMap[androidKey] = _filterPluginsByPlatform(plugins, androidKey);
|
||||
pluginsMap[macosKey] = _filterPluginsByPlatform(plugins, macosKey);
|
||||
pluginsMap[linuxKey] = _filterPluginsByPlatform(plugins, linuxKey);
|
||||
pluginsMap[windowsKey] = _filterPluginsByPlatform(plugins, windowsKey);
|
||||
pluginsMap[webKey] = _filterPluginsByPlatform(plugins, webKey);
|
||||
|
||||
final Map<String, dynamic> result = <String, dynamic> {};
|
||||
|
||||
result['info'] = 'This is a generated file; do not edit or check into version control.';
|
||||
result['plugins'] = pluginsMap;
|
||||
/// The dependencyGraph object is kept for backwards compatibility, but
|
||||
/// should be removed once migration is complete.
|
||||
/// https://github.com/flutter/flutter/issues/48918
|
||||
result['dependencyGraph'] = _createPluginLegacyDependencyGraph(plugins);
|
||||
result['date_created'] = systemClock.now().toString();
|
||||
result['version'] = flutterVersion.frameworkVersion;
|
||||
|
||||
final String oldPluginFileContent = _readFileContent(pluginsFile);
|
||||
final String pluginFileContent = json.encode(result);
|
||||
pluginsFile.writeAsStringSync(pluginFileContent, flush: true);
|
||||
|
||||
return oldPluginFileContent != pluginFileContent;
|
||||
}
|
||||
|
||||
List<dynamic> _createPluginLegacyDependencyGraph(List<Plugin> plugins) {
|
||||
final List<dynamic> directAppDependencies = <dynamic>[];
|
||||
|
||||
final Set<String> pluginNames = plugins.map((Plugin plugin) => plugin.name).toSet();
|
||||
for (final Plugin plugin in plugins) {
|
||||
flutterPluginsBuffer.write('${plugin.name}=${fsUtils.escapePath(plugin.path)}\n');
|
||||
directAppDependencies.add(<String, dynamic>{
|
||||
'name': plugin.name,
|
||||
// Extract the plugin dependencies which happen to be plugins.
|
||||
'dependencies': <String>[...plugin.dependencies.where(pluginNames.contains)],
|
||||
});
|
||||
}
|
||||
return directAppDependencies;
|
||||
}
|
||||
|
||||
// The .flutter-plugins file will be DEPRECATED in favor of .flutter-plugins-dependencies.
|
||||
// TODO(franciscojma): Remove this method once deprecated.
|
||||
// https://github.com/flutter/flutter/issues/48918
|
||||
//
|
||||
/// Writes the .flutter-plugins files based on the list of plugins.
|
||||
/// If there aren't any plugins, then the files aren't written to disk.
|
||||
///
|
||||
/// Finally, returns [true] if .flutter-plugins has changed, otherwise returns [false].
|
||||
bool _writeFlutterPluginsListLegacy(FlutterProject project, List<Plugin> plugins) {
|
||||
|
||||
final File pluginsFile = project.flutterPluginsFile;
|
||||
final String oldPluginFileContent = _readFileContent(pluginsFile);
|
||||
final String pluginFileContent = flutterPluginsBuffer.toString();
|
||||
if (pluginNames.isNotEmpty) {
|
||||
pluginsFile.writeAsStringSync(pluginFileContent, flush: true);
|
||||
} else {
|
||||
if (plugins.isEmpty) {
|
||||
if (pluginsFile.existsSync()) {
|
||||
pluginsFile.deleteSync();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final File dependenciesFile = project.flutterPluginsDependenciesFile;
|
||||
final String oldDependenciesFileContent = _readFileContent(dependenciesFile);
|
||||
final String dependenciesFileContent = json.encode(<String, dynamic>{
|
||||
'_info': '// $info',
|
||||
'dependencyGraph': directAppDependencies,
|
||||
});
|
||||
if (pluginNames.isNotEmpty) {
|
||||
dependenciesFile.writeAsStringSync(dependenciesFileContent, flush: true);
|
||||
} else {
|
||||
if (dependenciesFile.existsSync()) {
|
||||
dependenciesFile.deleteSync();
|
||||
}
|
||||
}
|
||||
const String info = 'This is a generated file; do not edit or check into version control.';
|
||||
final StringBuffer flutterPluginsBuffer = StringBuffer('# $info\n');
|
||||
|
||||
return oldPluginFileContent != _readFileContent(pluginsFile)
|
||||
|| oldDependenciesFileContent != _readFileContent(dependenciesFile);
|
||||
for (final Plugin plugin in plugins) {
|
||||
flutterPluginsBuffer.write('${plugin.name}=${fsUtils.escapePath(plugin.path)}\n');
|
||||
}
|
||||
final String oldPluginFileContent = _readFileContent(pluginsFile);
|
||||
final String pluginFileContent = flutterPluginsBuffer.toString();
|
||||
pluginsFile.writeAsStringSync(pluginFileContent, flush: true);
|
||||
|
||||
return oldPluginFileContent != _readFileContent(pluginsFile);
|
||||
}
|
||||
|
||||
/// Returns the contents of [File] or [null] if that file does not exist.
|
||||
@ -782,8 +888,13 @@ Future<void> _writeWebPluginRegistrant(FlutterProject project, List<Plugin> plug
|
||||
/// Assumes `pub get` has been executed since last change to `pubspec.yaml`.
|
||||
void refreshPluginsList(FlutterProject project, {bool checkProjects = false}) {
|
||||
final List<Plugin> plugins = findPlugins(project);
|
||||
|
||||
// TODO(franciscojma): Remove once migration is complete.
|
||||
// Write the legacy plugin files to avoid breaking existing apps.
|
||||
final bool legacyChanged = _writeFlutterPluginsListLegacy(project, plugins);
|
||||
|
||||
final bool changed = _writeFlutterPluginsList(project, plugins);
|
||||
if (changed) {
|
||||
if (changed || legacyChanged) {
|
||||
if (!checkProjects || project.ios.existsSync()) {
|
||||
cocoaPods.invalidatePodInstallOutput(project.ios);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import 'flutter_manifest.dart';
|
||||
import 'globals.dart' as globals;
|
||||
import 'ios/plist_parser.dart';
|
||||
import 'ios/xcodeproj.dart' as xcode;
|
||||
import 'platform_plugins.dart';
|
||||
import 'plugins.dart';
|
||||
import 'template.dart';
|
||||
|
||||
@ -251,6 +252,16 @@ class FlutterProject {
|
||||
}
|
||||
}
|
||||
|
||||
/// Base class for projects per platform.
|
||||
abstract class FlutterProjectPlatform {
|
||||
|
||||
/// Plugin's platform config key, e.g., "macos", "ios".
|
||||
String get pluginConfigKey;
|
||||
|
||||
/// Whether the platform exists in the project.
|
||||
bool existsSync();
|
||||
}
|
||||
|
||||
/// Represents an Xcode-based sub-project.
|
||||
///
|
||||
/// This defines interfaces common to iOS and macOS projects.
|
||||
@ -300,12 +311,15 @@ abstract class XcodeBasedProject {
|
||||
///
|
||||
/// Instances will reflect the contents of the `ios/` sub-folder of
|
||||
/// Flutter applications and the `.ios/` sub-folder of Flutter module projects.
|
||||
class IosProject implements XcodeBasedProject {
|
||||
class IosProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
||||
IosProject.fromFlutter(this.parent);
|
||||
|
||||
@override
|
||||
final FlutterProject parent;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => IOSPlugin.kConfigKey;
|
||||
|
||||
static final RegExp _productBundleIdPattern = RegExp(r'''^\s*PRODUCT_BUNDLE_IDENTIFIER\s*=\s*(["']?)(.*?)\1;\s*$''');
|
||||
static const String _productBundleIdVariable = r'$(PRODUCT_BUNDLE_IDENTIFIER)';
|
||||
static const String _hostAppBundleName = 'Runner';
|
||||
@ -574,12 +588,15 @@ class IosProject implements XcodeBasedProject {
|
||||
///
|
||||
/// Instances will reflect the contents of the `android/` sub-folder of
|
||||
/// Flutter applications and the `.android/` sub-folder of Flutter module projects.
|
||||
class AndroidProject {
|
||||
class AndroidProject extends FlutterProjectPlatform {
|
||||
AndroidProject._(this.parent);
|
||||
|
||||
/// The parent of this project.
|
||||
final FlutterProject parent;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => AndroidPlugin.kConfigKey;
|
||||
|
||||
static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\s+[\'\"](.*)[\'\"]\\s*\$');
|
||||
static final RegExp _kotlinPluginPattern = RegExp('^\\s*apply plugin\:\\s+[\'\"]kotlin-android[\'\"]\\s*\$');
|
||||
static final RegExp _groupPattern = RegExp('^\\s*group\\s+[\'\"](.*)[\'\"]\\s*\$');
|
||||
@ -627,6 +644,7 @@ class AndroidProject {
|
||||
}
|
||||
|
||||
/// Whether the current flutter project has an Android sub-project.
|
||||
@override
|
||||
bool existsSync() {
|
||||
return parent.isModule || _editableHostAppDirectory.existsSync();
|
||||
}
|
||||
@ -760,12 +778,16 @@ enum AndroidEmbeddingVersion {
|
||||
}
|
||||
|
||||
/// Represents the web sub-project of a Flutter project.
|
||||
class WebProject {
|
||||
class WebProject extends FlutterProjectPlatform {
|
||||
WebProject._(this.parent);
|
||||
|
||||
final FlutterProject parent;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => WebPlugin.kConfigKey;
|
||||
|
||||
/// Whether this flutter project has a web sub-project.
|
||||
@override
|
||||
bool existsSync() {
|
||||
return parent.directory.childDirectory('web').existsSync()
|
||||
&& indexFile.existsSync();
|
||||
@ -810,12 +832,15 @@ Match _firstMatchInFile(File file, RegExp regExp) {
|
||||
}
|
||||
|
||||
/// The macOS sub project.
|
||||
class MacOSProject implements XcodeBasedProject {
|
||||
class MacOSProject extends FlutterProjectPlatform implements XcodeBasedProject {
|
||||
MacOSProject._(this.parent);
|
||||
|
||||
@override
|
||||
final FlutterProject parent;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => MacOSPlugin.kConfigKey;
|
||||
|
||||
static const String _hostAppBundleName = 'Runner';
|
||||
|
||||
@override
|
||||
@ -895,11 +920,15 @@ class MacOSProject implements XcodeBasedProject {
|
||||
}
|
||||
|
||||
/// The Windows sub project
|
||||
class WindowsProject {
|
||||
class WindowsProject extends FlutterProjectPlatform {
|
||||
WindowsProject._(this.project);
|
||||
|
||||
final FlutterProject project;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => WindowsPlugin.kConfigKey;
|
||||
|
||||
@override
|
||||
bool existsSync() => _editableDirectory.existsSync();
|
||||
|
||||
Directory get _editableDirectory => project.directory.childDirectory('windows');
|
||||
@ -933,11 +962,14 @@ class WindowsProject {
|
||||
}
|
||||
|
||||
/// The Linux sub project.
|
||||
class LinuxProject {
|
||||
class LinuxProject extends FlutterProjectPlatform {
|
||||
LinuxProject._(this.project);
|
||||
|
||||
final FlutterProject project;
|
||||
|
||||
@override
|
||||
String get pluginConfigKey => LinuxPlugin.kConfigKey;
|
||||
|
||||
Directory get _editableDirectory => project.directory.childDirectory('linux');
|
||||
|
||||
/// The directory in the project that is managed by Flutter. As much as
|
||||
@ -950,6 +982,7 @@ class LinuxProject {
|
||||
/// checked in should live here.
|
||||
Directory get ephemeralDirectory => managedDirectory.childDirectory('ephemeral');
|
||||
|
||||
@override
|
||||
bool existsSync() => _editableDirectory.existsSync();
|
||||
|
||||
/// The Linux project makefile.
|
||||
|
@ -16,6 +16,8 @@ import 'cache.dart';
|
||||
import 'convert.dart';
|
||||
import 'globals.dart' as globals;
|
||||
|
||||
FlutterVersion get flutterVersion => context.get<FlutterVersion>();
|
||||
|
||||
class FlutterVersion {
|
||||
FlutterVersion([this._clock = const SystemClock()]) {
|
||||
_frameworkRevision = _runGit(gitLog(<String>['-n', '1', '--pretty=format:%H']).join(' '));
|
||||
|
@ -2,13 +2,17 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/base/time.dart';
|
||||
import 'package:flutter_tools/src/dart/package_map.dart';
|
||||
import 'package:flutter_tools/src/features.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/plugins.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
@ -23,15 +27,22 @@ void main() {
|
||||
MockMacOSProject macosProject;
|
||||
MockAndroidProject androidProject;
|
||||
MockWebProject webProject;
|
||||
MockWindowsProject windowsProject;
|
||||
MockLinuxProject linuxProject;
|
||||
File packagesFile;
|
||||
Directory dummyPackageDirectory;
|
||||
SystemClock mockClock;
|
||||
FlutterVersion mockVersion;
|
||||
|
||||
setUp(() async {
|
||||
fs = MemoryFileSystem();
|
||||
mockClock = MockClock();
|
||||
mockVersion = MockFlutterVersion();
|
||||
|
||||
// Add basic properties to the Flutter project and subprojects
|
||||
flutterProject = MockFlutterProject();
|
||||
when(flutterProject.directory).thenReturn(fs.directory('/'));
|
||||
// TODO(franciscojma): Remove logic for .flutter-plugins it's deprecated.
|
||||
when(flutterProject.flutterPluginsFile).thenReturn(flutterProject.directory.childFile('.flutter-plugins'));
|
||||
when(flutterProject.flutterPluginsDependenciesFile).thenReturn(flutterProject.directory.childFile('.flutter-plugins-dependencies'));
|
||||
iosProject = MockIosProject();
|
||||
@ -39,18 +50,34 @@ void main() {
|
||||
when(iosProject.pluginRegistrantHost).thenReturn(flutterProject.directory.childDirectory('Runner'));
|
||||
when(iosProject.podfile).thenReturn(flutterProject.directory.childDirectory('ios').childFile('Podfile'));
|
||||
when(iosProject.podManifestLock).thenReturn(flutterProject.directory.childDirectory('ios').childFile('Podfile.lock'));
|
||||
when(iosProject.pluginConfigKey).thenReturn('ios');
|
||||
when(iosProject.existsSync()).thenReturn(false);
|
||||
macosProject = MockMacOSProject();
|
||||
when(flutterProject.macos).thenReturn(macosProject);
|
||||
when(macosProject.podfile).thenReturn(flutterProject.directory.childDirectory('macos').childFile('Podfile'));
|
||||
when(macosProject.podManifestLock).thenReturn(flutterProject.directory.childDirectory('macos').childFile('Podfile.lock'));
|
||||
when(macosProject.pluginConfigKey).thenReturn('macos');
|
||||
when(macosProject.existsSync()).thenReturn(false);
|
||||
androidProject = MockAndroidProject();
|
||||
when(flutterProject.android).thenReturn(androidProject);
|
||||
when(androidProject.pluginRegistrantHost).thenReturn(flutterProject.directory.childDirectory('android').childDirectory('app'));
|
||||
when(androidProject.hostAppGradleRoot).thenReturn(flutterProject.directory.childDirectory('android'));
|
||||
when(androidProject.pluginConfigKey).thenReturn('android');
|
||||
when(androidProject.existsSync()).thenReturn(false);
|
||||
webProject = MockWebProject();
|
||||
when(flutterProject.web).thenReturn(webProject);
|
||||
when(webProject.libDirectory).thenReturn(flutterProject.directory.childDirectory('lib'));
|
||||
when(webProject.existsSync()).thenReturn(true);
|
||||
when(webProject.pluginConfigKey).thenReturn('web');
|
||||
when(webProject.existsSync()).thenReturn(false);
|
||||
windowsProject = MockWindowsProject();
|
||||
when(flutterProject.windows).thenReturn(windowsProject);
|
||||
when(windowsProject.pluginConfigKey).thenReturn('windows');
|
||||
when(windowsProject.existsSync()).thenReturn(false);
|
||||
linuxProject = MockLinuxProject();
|
||||
when(flutterProject.linux).thenReturn(linuxProject);
|
||||
when(linuxProject.pluginConfigKey).thenReturn('linux');
|
||||
when(linuxProject.existsSync()).thenReturn(false);
|
||||
|
||||
// Set up a simple .packages file for all the tests to use, pointing to one package.
|
||||
dummyPackageDirectory = fs.directory('/pubcache/apackage/lib/');
|
||||
@ -67,6 +94,18 @@ void main() {
|
||||
platforms:
|
||||
ios:
|
||||
pluginClass: FLESomePlugin
|
||||
macos:
|
||||
pluginClass: FLESomePlugin
|
||||
windows:
|
||||
pluginClass: FLESomePlugin
|
||||
linux:
|
||||
pluginClass: FLESomePlugin
|
||||
web:
|
||||
pluginClass: SomePlugin
|
||||
fileName: lib/SomeFile.dart
|
||||
android:
|
||||
pluginClass: SomePlugin
|
||||
package: AndroidPackage
|
||||
''');
|
||||
}
|
||||
|
||||
@ -239,8 +278,8 @@ dependencies:
|
||||
|
||||
testUsingContext('Refreshing the plugin list deletes the plugin file when there were plugins but no longer are', () {
|
||||
flutterProject.flutterPluginsFile.createSync();
|
||||
when(iosProject.existsSync()).thenReturn(false);
|
||||
when(macosProject.existsSync()).thenReturn(false);
|
||||
flutterProject.flutterPluginsDependenciesFile.createSync();
|
||||
|
||||
refreshPluginsList(flutterProject);
|
||||
expect(flutterProject.flutterPluginsFile.existsSync(), false);
|
||||
expect(flutterProject.flutterPluginsDependenciesFile.existsSync(), false);
|
||||
@ -251,8 +290,8 @@ dependencies:
|
||||
|
||||
testUsingContext('Refreshing the plugin list creates a plugin directory when there are plugins', () {
|
||||
configureDummyPackageAsPlugin();
|
||||
when(iosProject.existsSync()).thenReturn(false);
|
||||
when(macosProject.existsSync()).thenReturn(false);
|
||||
when(iosProject.existsSync()).thenReturn(true);
|
||||
|
||||
refreshPluginsList(flutterProject);
|
||||
expect(flutterProject.flutterPluginsFile.existsSync(), true);
|
||||
expect(flutterProject.flutterPluginsDependenciesFile.existsSync(), true);
|
||||
@ -265,11 +304,20 @@ dependencies:
|
||||
createPluginWithDependencies(name: 'plugin-a', dependencies: const <String>['plugin-b', 'plugin-c', 'random-package']);
|
||||
createPluginWithDependencies(name: 'plugin-b', dependencies: const <String>['plugin-c']);
|
||||
createPluginWithDependencies(name: 'plugin-c', dependencies: const <String>[]);
|
||||
when(iosProject.existsSync()).thenReturn(false);
|
||||
when(macosProject.existsSync()).thenReturn(false);
|
||||
when(iosProject.existsSync()).thenReturn(true);
|
||||
|
||||
final DateTime dateCreated = DateTime(1970, 1, 1);
|
||||
when(mockClock.now()).thenAnswer(
|
||||
(Invocation _) => dateCreated
|
||||
);
|
||||
const String version = '1.0.0';
|
||||
when(mockVersion.frameworkVersion).thenAnswer(
|
||||
(Invocation _) => version
|
||||
);
|
||||
|
||||
refreshPluginsList(flutterProject);
|
||||
|
||||
// Verify .flutter-plugins-dependencies is configured correctly.
|
||||
expect(flutterProject.flutterPluginsFile.existsSync(), true);
|
||||
expect(flutterProject.flutterPluginsDependenciesFile.existsSync(), true);
|
||||
expect(flutterProject.flutterPluginsFile.readAsStringSync(),
|
||||
@ -279,28 +327,79 @@ dependencies:
|
||||
'plugin-c=/.tmp_rand0/plugin.rand2/\n'
|
||||
''
|
||||
);
|
||||
expect(flutterProject.flutterPluginsDependenciesFile.readAsStringSync(),
|
||||
'{'
|
||||
'"_info":"// This is a generated file; do not edit or check into version control.",'
|
||||
'"dependencyGraph":['
|
||||
'{'
|
||||
'"name":"plugin-a",'
|
||||
'"dependencies":["plugin-b","plugin-c"]'
|
||||
'},'
|
||||
'{'
|
||||
'"name":"plugin-b",'
|
||||
'"dependencies":["plugin-c"]'
|
||||
'},'
|
||||
'{'
|
||||
'"name":"plugin-c",'
|
||||
'"dependencies":[]'
|
||||
'}'
|
||||
']'
|
||||
'}'
|
||||
);
|
||||
|
||||
final String pluginsString = flutterProject.flutterPluginsDependenciesFile.readAsStringSync();
|
||||
final Map<String, dynamic> jsonContent = json.decode(pluginsString) as Map<String, dynamic>;
|
||||
expect(jsonContent['info'], 'This is a generated file; do not edit or check into version control.');
|
||||
|
||||
final Map<String, dynamic> plugins = jsonContent['plugins'] as Map<String, dynamic>;
|
||||
final List<dynamic> expectedPlugins = <dynamic>[
|
||||
<String, dynamic> {
|
||||
'name': 'plugin-a',
|
||||
'path': '/.tmp_rand0/plugin.rand0/',
|
||||
'dependencies': <String>[
|
||||
'plugin-b',
|
||||
'plugin-c'
|
||||
]
|
||||
},
|
||||
<String, dynamic> {
|
||||
'name': 'plugin-b',
|
||||
'path': '/.tmp_rand0/plugin.rand1/',
|
||||
'dependencies': <String>[
|
||||
'plugin-c'
|
||||
]
|
||||
},
|
||||
<String, dynamic> {
|
||||
'name': 'plugin-c',
|
||||
'path': '/.tmp_rand0/plugin.rand2/',
|
||||
'dependencies': <String>[]
|
||||
},
|
||||
];
|
||||
expect(plugins['ios'], expectedPlugins);
|
||||
expect(plugins['android'], expectedPlugins);
|
||||
expect(plugins['macos'], <dynamic>[]);
|
||||
expect(plugins['windows'], <dynamic>[]);
|
||||
expect(plugins['linux'], <dynamic>[]);
|
||||
expect(plugins['web'], <dynamic>[]);
|
||||
|
||||
final List<dynamic> expectedDependencyGraph = <dynamic>[
|
||||
<String, dynamic> {
|
||||
'name': 'plugin-a',
|
||||
'dependencies': <String>[
|
||||
'plugin-b',
|
||||
'plugin-c'
|
||||
]
|
||||
},
|
||||
<String, dynamic> {
|
||||
'name': 'plugin-b',
|
||||
'dependencies': <String>[
|
||||
'plugin-c'
|
||||
]
|
||||
},
|
||||
<String, dynamic> {
|
||||
'name': 'plugin-c',
|
||||
'dependencies': <String>[]
|
||||
},
|
||||
];
|
||||
|
||||
expect(jsonContent['dependencyGraph'], expectedDependencyGraph);
|
||||
expect(jsonContent['date_created'], dateCreated.toString());
|
||||
expect(jsonContent['version'], version);
|
||||
|
||||
// Make sure tests are updated if a new object is added/removed.
|
||||
final List<String> expectedKeys = <String>[
|
||||
'info',
|
||||
'plugins',
|
||||
'dependencyGraph',
|
||||
'date_created',
|
||||
'version',
|
||||
];
|
||||
expect(jsonContent.keys, expectedKeys);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
SystemClock: () => mockClock,
|
||||
FlutterVersion: () => mockVersion
|
||||
});
|
||||
|
||||
testUsingContext('Changes to the plugin list invalidates the Cocoapod lockfiles', () {
|
||||
@ -316,8 +415,25 @@ dependencies:
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
|
||||
testUsingContext('Changes to the plugin json list invalidates the Cocoapod lockfiles', () {
|
||||
simulatePodInstallRun(iosProject);
|
||||
simulatePodInstallRun(macosProject);
|
||||
configureDummyPackageAsPlugin();
|
||||
|
||||
when(iosProject.existsSync()).thenReturn(true);
|
||||
when(macosProject.existsSync()).thenReturn(true);
|
||||
|
||||
refreshPluginsList(flutterProject);
|
||||
expect(iosProject.podManifestLock.existsSync(), false);
|
||||
expect(macosProject.podManifestLock.existsSync(), false);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fs,
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
group('injectPlugins', () {
|
||||
MockFeatureFlags featureFlags;
|
||||
MockXcodeProjectInterpreter xcodeProjectInterpreter;
|
||||
@ -600,6 +716,7 @@ dependencies:
|
||||
testUsingContext('Registrant for web doesn\'t escape slashes in imports', () async {
|
||||
when(flutterProject.isModule).thenReturn(true);
|
||||
when(featureFlags.isWebEnabled).thenReturn(true);
|
||||
when(webProject.existsSync()).thenReturn(true);
|
||||
|
||||
final Directory webPluginWithNestedFile =
|
||||
fs.systemTempDirectory.createTempSync('web_plugin_with_nested');
|
||||
@ -648,3 +765,5 @@ class MockIosProject extends Mock implements IosProject {}
|
||||
class MockMacOSProject extends Mock implements MacOSProject {}
|
||||
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
|
||||
class MockWebProject extends Mock implements WebProject {}
|
||||
class MockWindowsProject extends Mock implements WindowsProject {}
|
||||
class MockLinuxProject extends Mock implements LinuxProject {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user