Unverified Commit b0a63c4f authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Reland the Dart plugin registry (#79669)

parent 9b0fd423
// 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:flutter_devicelab/tasks/dart_plugin_registry_tests.dart';
import 'package:flutter_devicelab/framework/framework.dart';
Future<void> main() async {
await task(dartPluginRegistryTest());
}
// 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 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/task_result.dart';
import 'package:flutter_devicelab/framework/utils.dart';
TaskFunction dartPluginRegistryTest({
String deviceIdOverride,
Map<String, String> environment,
}) {
final Directory tempDir = Directory.systemTemp
.createTempSync('flutter_devicelab_dart_plugin_test.');
return () async {
try {
section('Create implementation plugin');
await inDirectory(tempDir, () async {
await flutter(
'create',
options: <String>[
'--template=plugin',
'--org',
'io.flutter.devicelab',
'--platforms',
'macos',
'plugin_platform_implementation',
],
environment: environment,
);
});
final File pluginMain = File(path.join(
tempDir.absolute.path,
'plugin_platform_implementation',
'lib',
'plugin_platform_implementation.dart',
));
if (!pluginMain.existsSync()) {
return TaskResult.failure('${pluginMain.path} does not exist');
}
// Patch plugin main dart file.
await pluginMain.writeAsString('''
class PluginPlatformInterfaceMacOS {
static void registerWith() {
print('PluginPlatformInterfaceMacOS.registerWith() was called');
}
}
''', flush: true);
// Patch plugin main pubspec file.
final File pluginImplPubspec = File(path.join(
tempDir.absolute.path,
'plugin_platform_implementation',
'pubspec.yaml',
));
String pluginImplPubspecContent = await pluginImplPubspec.readAsString();
pluginImplPubspecContent = pluginImplPubspecContent.replaceFirst(
' pluginClass: PluginPlatformImplementationPlugin',
' pluginClass: PluginPlatformImplementationPlugin\n'
' dartPluginClass: PluginPlatformInterfaceMacOS\n',
);
pluginImplPubspecContent = pluginImplPubspecContent.replaceFirst(
' platforms:\n',
' implements: plugin_platform_interface\n'
' platforms:\n');
await pluginImplPubspec.writeAsString(pluginImplPubspecContent,
flush: true);
section('Create interface plugin');
await inDirectory(tempDir, () async {
await flutter(
'create',
options: <String>[
'--template=plugin',
'--org',
'io.flutter.devicelab',
'--platforms',
'macos',
'plugin_platform_interface',
],
environment: environment,
);
});
final File pluginInterfacePubspec = File(path.join(
tempDir.absolute.path,
'plugin_platform_interface',
'pubspec.yaml',
));
String pluginInterfacePubspecContent =
await pluginInterfacePubspec.readAsString();
pluginInterfacePubspecContent =
pluginInterfacePubspecContent.replaceFirst(
' pluginClass: PluginPlatformInterfacePlugin',
' default_package: plugin_platform_implementation\n');
pluginInterfacePubspecContent =
pluginInterfacePubspecContent.replaceFirst(
'dependencies:',
'dependencies:\n'
' plugin_platform_implementation:\n'
' path: ../plugin_platform_implementation\n');
await pluginInterfacePubspec.writeAsString(pluginInterfacePubspecContent,
flush: true);
section('Create app');
await inDirectory(tempDir, () async {
await flutter(
'create',
options: <String>[
'--template=app',
'--org',
'io.flutter.devicelab',
'--platforms',
'macos',
'app',
],
environment: environment,
);
});
final File appPubspec = File(path.join(
tempDir.absolute.path,
'app',
'pubspec.yaml',
));
String appPubspecContent = await appPubspec.readAsString();
appPubspecContent = appPubspecContent.replaceFirst(
'dependencies:',
'dependencies:\n'
' plugin_platform_interface:\n'
' path: ../plugin_platform_interface\n');
await appPubspec.writeAsString(appPubspecContent, flush: true);
section('Flutter run for macos');
await inDirectory(path.join(tempDir.path, 'app'), () async {
final Process run = await startProcess(
path.join(flutterDirectory.path, 'bin', 'flutter'),
flutterCommandArgs('run', <String>['-d', 'macos', '-v']),
environment: null,
);
Completer<void> registryExecutedCompleter = Completer<void>();
final StreamSubscription<void> subscription = run.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen((String line) {
if (line.contains(
'PluginPlatformInterfaceMacOS.registerWith() was called')) {
registryExecutedCompleter.complete();
}
print('stdout: $line');
});
section('Wait for registry execution');
await registryExecutedCompleter.future;
// Hot restart.
run.stdin.write('R');
registryExecutedCompleter = Completer<void>();
section('Wait for registry execution after hot restart');
await registryExecutedCompleter.future;
subscription.cancel();
run.kill();
});
return TaskResult.success(null);
} finally {
rmTree(tempDir);
}
};
}
...@@ -332,6 +332,7 @@ class Environment { ...@@ -332,6 +332,7 @@ class Environment {
@required ProcessManager processManager, @required ProcessManager processManager,
@required Platform platform, @required Platform platform,
@required String engineVersion, @required String engineVersion,
@required bool generateDartPluginRegistry,
Directory buildDir, Directory buildDir,
Map<String, String> defines = const <String, String>{}, Map<String, String> defines = const <String, String>{},
Map<String, String> inputs = const <String, String>{}, Map<String, String> inputs = const <String, String>{},
...@@ -372,6 +373,7 @@ class Environment { ...@@ -372,6 +373,7 @@ class Environment {
platform: platform, platform: platform,
engineVersion: engineVersion, engineVersion: engineVersion,
inputs: inputs, inputs: inputs,
generateDartPluginRegistry: generateDartPluginRegistry,
); );
} }
...@@ -389,6 +391,7 @@ class Environment { ...@@ -389,6 +391,7 @@ class Environment {
Map<String, String> inputs = const <String, String>{}, Map<String, String> inputs = const <String, String>{},
String engineVersion, String engineVersion,
Platform platform, Platform platform,
bool generateDartPluginRegistry = false,
@required FileSystem fileSystem, @required FileSystem fileSystem,
@required Logger logger, @required Logger logger,
@required Artifacts artifacts, @required Artifacts artifacts,
...@@ -408,6 +411,7 @@ class Environment { ...@@ -408,6 +411,7 @@ class Environment {
processManager: processManager, processManager: processManager,
platform: platform ?? FakePlatform(), platform: platform ?? FakePlatform(),
engineVersion: engineVersion, engineVersion: engineVersion,
generateDartPluginRegistry: generateDartPluginRegistry,
); );
} }
...@@ -426,6 +430,7 @@ class Environment { ...@@ -426,6 +430,7 @@ class Environment {
@required this.artifacts, @required this.artifacts,
@required this.engineVersion, @required this.engineVersion,
@required this.inputs, @required this.inputs,
@required this.generateDartPluginRegistry,
}); });
/// The [Source] value which is substituted with the path to [projectDir]. /// The [Source] value which is substituted with the path to [projectDir].
...@@ -505,6 +510,11 @@ class Environment { ...@@ -505,6 +510,11 @@ class Environment {
/// The version of the current engine, or `null` if built with a local engine. /// The version of the current engine, or `null` if built with a local engine.
final String engineVersion; final String engineVersion;
/// Whether to generate the Dart plugin registry.
/// When [true], the main entrypoint is wrapped and the wrapper becomes
/// the new entrypoint.
final bool generateDartPluginRegistry;
} }
/// The result information from the build system. /// The result information from the build system.
......
...@@ -17,6 +17,7 @@ import '../build_system.dart'; ...@@ -17,6 +17,7 @@ import '../build_system.dart';
import '../depfile.dart'; import '../depfile.dart';
import '../exceptions.dart'; import '../exceptions.dart';
import 'assets.dart'; import 'assets.dart';
import 'dart_plugin_registrant.dart';
import 'icon_tree_shaker.dart'; import 'icon_tree_shaker.dart';
import 'localizations.dart'; import 'localizations.dart';
...@@ -209,6 +210,7 @@ class KernelSnapshot extends Target { ...@@ -209,6 +210,7 @@ class KernelSnapshot extends Target {
@override @override
List<Target> get dependencies => const <Target>[ List<Target> get dependencies => const <Target>[
GenerateLocalizationsTarget(), GenerateLocalizationsTarget(),
DartPluginRegistrantTarget(),
]; ];
@override @override
...@@ -286,6 +288,8 @@ class KernelSnapshot extends Target { ...@@ -286,6 +288,8 @@ class KernelSnapshot extends Target {
fileSystemScheme: fileSystemScheme, fileSystemScheme: fileSystemScheme,
dartDefines: decodeDartDefines(environment.defines, kDartDefines), dartDefines: decodeDartDefines(environment.defines, kDartDefines),
packageConfig: packageConfig, packageConfig: packageConfig,
buildDir: environment.buildDir,
checkDartPluginRegistry: environment.generateDartPluginRegistry,
); );
if (output == null || output.errorCount != 0) { if (output == null || output.errorCount != 0) {
throw Exception(); throw Exception();
......
// 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.
// @dart = 2.8
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart';
import '../../base/file_system.dart';
import '../../dart/package_map.dart';
import '../../flutter_plugins.dart';
import '../../project.dart';
import '../build_system.dart';
import 'common.dart';
/// Generates a new `./dart_tool/flutter_build/generated_main.dart`
/// based on the current dependency map in `pubspec.lock`.
class DartPluginRegistrantTarget extends Target {
/// Construct a [DartPluginRegistrantTarget].
const DartPluginRegistrantTarget() : _project = null;
/// Construct a [DartPluginRegistrantTarget].
///
/// If `project` is unset, a [FlutterProject] based on environment is used.
@visibleForTesting
factory DartPluginRegistrantTarget.test(FlutterProject project) {
return DartPluginRegistrantTarget._(project);
}
DartPluginRegistrantTarget._(this._project);
final FlutterProject _project;
@override
Future<void> build(Environment environment) async {
assert(environment.generateDartPluginRegistry);
final File packagesFile = environment.projectDir
.childDirectory('.dart_tool')
.childFile('package_config.json');
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
packagesFile,
logger: environment.logger,
);
final String targetFile = environment.defines[kTargetFile] ??
environment.fileSystem.path.join('lib', 'main.dart');
final File mainFile = environment.fileSystem.file(targetFile);
final Uri mainFileUri = mainFile.uri;
assert(packagesFile.path != null);
final String mainUri = packageConfig.toPackageUri(mainFileUri)?.toString();
final File newMainDart = environment.projectDir
.childDirectory('.dart_tool')
.childDirectory('flutter_build')
.childFile('generated_main.dart');
await generateMainDartWithPluginRegistrant(
_project ?? FlutterProject.fromDirectory(environment.projectDir),
packageConfig,
mainUri,
newMainDart,
mainFile,
throwOnPluginPubspecError: false,
);
}
@override
bool canSkip(Environment environment) {
return !environment.generateDartPluginRegistry;
}
@override
List<Target> get dependencies => <Target>[];
@override
List<Source> get inputs => <Source>[
const Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'),
];
@override
String get name => 'gen_dart_plugin_registrant';
@override
List<Source> get outputs => <Source>[
const Source.pattern(
'{PROJECT_DIR}/.dart_tool/flutter_build/generated_main.dart',
optional: true,
),
];
}
...@@ -137,6 +137,7 @@ class BundleBuilder { ...@@ -137,6 +137,7 @@ class BundleBuilder {
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
generateDartPluginRegistry: true,
); );
final Target target = buildInfo.mode == BuildMode.debug final Target target = buildInfo.mode == BuildMode.debug
? const CopyFlutterBundle() ? const CopyFlutterBundle()
......
...@@ -246,7 +246,8 @@ class AssembleCommand extends FlutterCommand { ...@@ -246,7 +246,8 @@ class AssembleCommand extends FlutterCommand {
platform: globals.platform, platform: globals.platform,
engineVersion: globals.artifacts.isLocalEngine engineVersion: globals.artifacts.isLocalEngine
? null ? null
: globals.flutterVersion.engineRevision : globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true,
); );
return result; return result;
} }
......
...@@ -385,6 +385,7 @@ end ...@@ -385,6 +385,7 @@ end
engineVersion: globals.artifacts.isLocalEngine engineVersion: globals.artifacts.isLocalEngine
? null ? null
: globals.flutterVersion.engineRevision, : globals.flutterVersion.engineRevision,
generateDartPluginRegistry: true,
); );
Target target; Target target;
// Always build debug for simulator. // Always build debug for simulator.
......
...@@ -120,6 +120,7 @@ class PackagesGetCommand extends FlutterCommand { ...@@ -120,6 +120,7 @@ class PackagesGetCommand extends FlutterCommand {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
projectDir: flutterProject.directory, projectDir: flutterProject.directory,
generateDartPluginRegistry: true,
); );
await generateLocalizationsSyntheticPackage( await generateLocalizationsSyntheticPackage(
...@@ -325,6 +326,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand { ...@@ -325,6 +326,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
projectDir: flutterProject.directory, projectDir: flutterProject.directory,
generateDartPluginRegistry: true,
); );
await generateLocalizationsSyntheticPackage( await generateLocalizationsSyntheticPackage(
......
...@@ -229,6 +229,8 @@ class KernelCompiler { ...@@ -229,6 +229,8 @@ class KernelCompiler {
String fileSystemScheme, String fileSystemScheme,
String initializeFromDill, String initializeFromDill,
String platformDill, String platformDill,
Directory buildDir,
bool checkDartPluginRegistry = false,
@required String packagesPath, @required String packagesPath,
@required BuildMode buildMode, @required BuildMode buildMode,
@required bool trackWidgetCreation, @required bool trackWidgetCreation,
...@@ -247,7 +249,8 @@ class KernelCompiler { ...@@ -247,7 +249,8 @@ class KernelCompiler {
throwToolExit('Unable to find Dart binary at $engineDartPath'); throwToolExit('Unable to find Dart binary at $engineDartPath');
} }
String mainUri; String mainUri;
final Uri mainFileUri = _fileSystem.file(mainPath).uri; final File mainFile = _fileSystem.file(mainPath);
final Uri mainFileUri = mainFile.uri;
if (packagesPath != null) { if (packagesPath != null) {
mainUri = packageConfig.toPackageUri(mainFileUri)?.toString(); mainUri = packageConfig.toPackageUri(mainFileUri)?.toString();
} }
...@@ -255,6 +258,15 @@ class KernelCompiler { ...@@ -255,6 +258,15 @@ class KernelCompiler {
if (outputFilePath != null && !_fileSystem.isFileSync(outputFilePath)) { if (outputFilePath != null && !_fileSystem.isFileSync(outputFilePath)) {
_fileSystem.file(outputFilePath).createSync(recursive: true); _fileSystem.file(outputFilePath).createSync(recursive: true);
} }
if (buildDir != null && checkDartPluginRegistry) {
// Check if there's a Dart plugin registrant.
// This is contained in the file `generated_main.dart` under `.dart_tools/flutter_build/`.
final File newMainDart = buildDir.parent.childFile('generated_main.dart');
if (newMainDart.existsSync()) {
mainUri = newMainDart.path;
}
}
final List<String> command = <String>[ final List<String> command = <String>[
engineDartPath, engineDartPath,
'--disable-dart-dev', '--disable-dart-dev',
...@@ -457,6 +469,8 @@ abstract class ResidentCompiler { ...@@ -457,6 +469,8 @@ abstract class ResidentCompiler {
List<Uri> invalidatedFiles, { List<Uri> invalidatedFiles, {
@required String outputPath, @required String outputPath,
@required PackageConfig packageConfig, @required PackageConfig packageConfig,
@required String projectRootPath,
@required FileSystem fs,
bool suppressErrors = false, bool suppressErrors = false,
}); });
...@@ -596,12 +610,27 @@ class DefaultResidentCompiler implements ResidentCompiler { ...@@ -596,12 +610,27 @@ class DefaultResidentCompiler implements ResidentCompiler {
@required String outputPath, @required String outputPath,
@required PackageConfig packageConfig, @required PackageConfig packageConfig,
bool suppressErrors = false, bool suppressErrors = false,
String projectRootPath,
FileSystem fs,
}) async { }) async {
assert(outputPath != null); assert(outputPath != null);
if (!_controller.hasListener) { if (!_controller.hasListener) {
_controller.stream.listen(_handleCompilationRequest); _controller.stream.listen(_handleCompilationRequest);
} }
// `generated_main.dart` contains the Dart plugin registry.
if (projectRootPath != null && fs != null) {
final File generatedMainDart = fs.file(
fs.path.join(
projectRootPath,
'.dart_tool',
'flutter_build',
'generated_main.dart',
),
);
if (generatedMainDart != null && generatedMainDart.existsSync()) {
mainUri = generatedMainDart.uri;
}
}
final Completer<CompilerOutput> completer = Completer<CompilerOutput>(); final Completer<CompilerOutput> completer = Completer<CompilerOutput>();
_controller.add( _controller.add(
_RecompileRequest(completer, mainUri, invalidatedFiles, outputPath, packageConfig, suppressErrors) _RecompileRequest(completer, mainUri, invalidatedFiles, outputPath, packageConfig, suppressErrors)
......
...@@ -524,6 +524,8 @@ class DevFS { ...@@ -524,6 +524,8 @@ class DevFS {
mainUri, mainUri,
invalidatedFiles, invalidatedFiles,
outputPath: dillOutputPath, outputPath: dillOutputPath,
fs: _fileSystem,
projectRootPath: projectRootPath,
packageConfig: packageConfig, packageConfig: packageConfig,
); );
if (bundle != null) { if (bundle != null) {
......
...@@ -75,6 +75,13 @@ class FlutterManifest { ...@@ -75,6 +75,13 @@ class FlutterManifest {
/// The string value of the top-level `name` property in the `pubspec.yaml` file. /// The string value of the top-level `name` property in the `pubspec.yaml` file.
String get appName => _descriptor['name'] as String? ?? ''; String get appName => _descriptor['name'] as String? ?? '';
/// Contains the name of the dependencies.
/// These are the keys specified in the `dependency` map.
Set<String> get dependencies {
final YamlMap? dependencies = _descriptor['dependencies'] as YamlMap?;
return dependencies != null ? <String>{...dependencies.keys.cast<String>()} : <String>{};
}
// Flag to avoid printing multiple invalid version messages. // Flag to avoid printing multiple invalid version messages.
bool _hasShowInvalidVersionMsg = false; bool _hasShowInvalidVersionMsg = false;
......
...@@ -835,6 +835,8 @@ class WebDevFS implements DevFS { ...@@ -835,6 +835,8 @@ class WebDevFS implements DevFS {
invalidatedFiles, invalidatedFiles,
outputPath: dillOutputPath, outputPath: dillOutputPath,
packageConfig: packageConfig, packageConfig: packageConfig,
projectRootPath: projectRootPath,
fs: globals.fs,
); );
if (compilerOutput == null || compilerOutput.errorCount > 0) { if (compilerOutput == null || compilerOutput.errorCount > 0) {
return UpdateFSReport(success: false); return UpdateFSReport(success: false);
......
...@@ -13,6 +13,9 @@ const String kPluginClass = 'pluginClass'; ...@@ -13,6 +13,9 @@ const String kPluginClass = 'pluginClass';
/// Constant for 'pluginClass' key in plugin maps. /// Constant for 'pluginClass' key in plugin maps.
const String kDartPluginClass = 'dartPluginClass'; const String kDartPluginClass = 'dartPluginClass';
// Constant for 'defaultPackage' key in plugin maps.
const String kDefaultPackage = 'default_package';
/// Marker interface for all platform specific plugin config implementations. /// Marker interface for all platform specific plugin config implementations.
abstract class PluginPlatform { abstract class PluginPlatform {
const PluginPlatform(); const PluginPlatform();
...@@ -204,6 +207,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -204,6 +207,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
required this.name, required this.name,
this.pluginClass, this.pluginClass,
this.dartPluginClass, this.dartPluginClass,
this.defaultPackage,
}); });
factory MacOSPlugin.fromYaml(String name, YamlMap yaml) { factory MacOSPlugin.fromYaml(String name, YamlMap yaml) {
...@@ -217,6 +221,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -217,6 +221,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
name: name, name: name,
pluginClass: pluginClass, pluginClass: pluginClass,
dartPluginClass: yaml[kDartPluginClass] as String?, dartPluginClass: yaml[kDartPluginClass] as String?,
defaultPackage: yaml[kDefaultPackage] as String?,
); );
} }
...@@ -224,7 +229,9 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -224,7 +229,9 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
if (yaml == null) { if (yaml == null) {
return false; return false;
} }
return yaml[kPluginClass] is String || yaml[kDartPluginClass] is String; return yaml[kPluginClass] is String ||
yaml[kDartPluginClass] is String ||
yaml[kDefaultPackage] is String;
} }
static const String kConfigKey = 'macos'; static const String kConfigKey = 'macos';
...@@ -232,6 +239,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -232,6 +239,7 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
final String name; final String name;
final String? pluginClass; final String? pluginClass;
final String? dartPluginClass; final String? dartPluginClass;
final String? defaultPackage;
@override @override
bool isNative() => pluginClass != null; bool isNative() => pluginClass != null;
...@@ -241,7 +249,8 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -241,7 +249,8 @@ class MacOSPlugin extends PluginPlatform implements NativeOrDartPlugin {
return <String, dynamic>{ return <String, dynamic>{
'name': name, 'name': name,
if (pluginClass != null) 'class': pluginClass, if (pluginClass != null) 'class': pluginClass,
if (dartPluginClass != null) 'dartPluginClass': dartPluginClass, if (dartPluginClass != null) kDartPluginClass : dartPluginClass,
if (defaultPackage != null) kDefaultPackage : defaultPackage,
}; };
} }
} }
...@@ -255,7 +264,8 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{ ...@@ -255,7 +264,8 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
required this.name, required this.name,
this.pluginClass, this.pluginClass,
this.dartPluginClass, this.dartPluginClass,
}) : assert(pluginClass != null || dartPluginClass != null); this.defaultPackage,
}) : assert(pluginClass != null || dartPluginClass != null || defaultPackage != null);
factory WindowsPlugin.fromYaml(String name, YamlMap yaml) { factory WindowsPlugin.fromYaml(String name, YamlMap yaml) {
assert(validate(yaml)); assert(validate(yaml));
...@@ -268,6 +278,7 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{ ...@@ -268,6 +278,7 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
name: name, name: name,
pluginClass: pluginClass, pluginClass: pluginClass,
dartPluginClass: yaml[kDartPluginClass] as String?, dartPluginClass: yaml[kDartPluginClass] as String?,
defaultPackage: yaml[kDefaultPackage] as String?,
); );
} }
...@@ -275,7 +286,9 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{ ...@@ -275,7 +286,9 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
if (yaml == null) { if (yaml == null) {
return false; return false;
} }
return yaml[kDartPluginClass] is String || yaml[kPluginClass] is String; return yaml[kPluginClass] is String ||
yaml[kDartPluginClass] is String ||
yaml[kDefaultPackage] is String;
} }
static const String kConfigKey = 'windows'; static const String kConfigKey = 'windows';
...@@ -283,6 +296,7 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{ ...@@ -283,6 +296,7 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
final String name; final String name;
final String? pluginClass; final String? pluginClass;
final String? dartPluginClass; final String? dartPluginClass;
final String? defaultPackage;
@override @override
bool isNative() => pluginClass != null; bool isNative() => pluginClass != null;
...@@ -291,9 +305,10 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{ ...@@ -291,9 +305,10 @@ class WindowsPlugin extends PluginPlatform implements NativeOrDartPlugin{
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return <String, dynamic>{ return <String, dynamic>{
'name': name, 'name': name,
if (pluginClass != null) 'class': pluginClass, if (pluginClass != null) 'class': pluginClass!,
if (pluginClass != null) 'filename': _filenameForCppClass(pluginClass!), if (pluginClass != null) 'filename': _filenameForCppClass(pluginClass!),
if (dartPluginClass != null) 'dartPluginClass': dartPluginClass, if (dartPluginClass != null) kDartPluginClass: dartPluginClass!,
if (defaultPackage != null) kDefaultPackage: defaultPackage!,
}; };
} }
} }
...@@ -307,7 +322,8 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -307,7 +322,8 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
required this.name, required this.name,
this.pluginClass, this.pluginClass,
this.dartPluginClass, this.dartPluginClass,
}) : assert(pluginClass != null || dartPluginClass != null); this.defaultPackage,
}) : assert(pluginClass != null || dartPluginClass != null || defaultPackage != null);
factory LinuxPlugin.fromYaml(String name, YamlMap yaml) { factory LinuxPlugin.fromYaml(String name, YamlMap yaml) {
assert(validate(yaml)); assert(validate(yaml));
...@@ -320,6 +336,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -320,6 +336,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
name: name, name: name,
pluginClass: pluginClass, pluginClass: pluginClass,
dartPluginClass: yaml[kDartPluginClass] as String?, dartPluginClass: yaml[kDartPluginClass] as String?,
defaultPackage: yaml[kDefaultPackage] as String?,
); );
} }
...@@ -327,7 +344,9 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -327,7 +344,9 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
if (yaml == null) { if (yaml == null) {
return false; return false;
} }
return yaml[kPluginClass] is String || yaml[kDartPluginClass] is String; return yaml[kPluginClass] is String ||
yaml[kDartPluginClass] is String ||
yaml[kDefaultPackage] is String;
} }
static const String kConfigKey = 'linux'; static const String kConfigKey = 'linux';
...@@ -335,6 +354,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -335,6 +354,7 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
final String name; final String name;
final String? pluginClass; final String? pluginClass;
final String? dartPluginClass; final String? dartPluginClass;
final String? defaultPackage;
@override @override
bool isNative() => pluginClass != null; bool isNative() => pluginClass != null;
...@@ -343,9 +363,10 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin { ...@@ -343,9 +363,10 @@ class LinuxPlugin extends PluginPlatform implements NativeOrDartPlugin {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return <String, dynamic>{ return <String, dynamic>{
'name': name, 'name': name,
if (pluginClass != null) 'class': pluginClass, if (pluginClass != null) 'class': pluginClass!,
if (pluginClass != null) 'filename': _filenameForCppClass(pluginClass!), if (pluginClass != null) 'filename': _filenameForCppClass(pluginClass!),
if (dartPluginClass != null) 'dartPluginClass': dartPluginClass, if (dartPluginClass != null) kDartPluginClass: dartPluginClass!,
if (defaultPackage != null) kDefaultPackage: defaultPackage!,
}; };
} }
} }
......
...@@ -13,11 +13,18 @@ class Plugin { ...@@ -13,11 +13,18 @@ class Plugin {
required this.name, required this.name,
required this.path, required this.path,
required this.platforms, required this.platforms,
required this.defaultPackagePlatforms,
required this.pluginDartClassPlatforms,
required this.dependencies, required this.dependencies,
required this.isDirectDependency,
this.implementsPackage,
}) : assert(name != null), }) : assert(name != null),
assert(path != null), assert(path != null),
assert(platforms != null), assert(platforms != null),
assert(dependencies != null); assert(defaultPackagePlatforms != null),
assert(pluginDartClassPlatforms != null),
assert(dependencies != null),
assert(isDirectDependency != null);
/// Parses [Plugin] specification from the provided pluginYaml. /// Parses [Plugin] specification from the provided pluginYaml.
/// ///
...@@ -53,15 +60,30 @@ class Plugin { ...@@ -53,15 +60,30 @@ class Plugin {
YamlMap? pluginYaml, YamlMap? pluginYaml,
List<String> dependencies, { List<String> dependencies, {
required FileSystem fileSystem, required FileSystem fileSystem,
Set<String>? appDependencies,
}) { }) {
final List<String> errors = validatePluginYaml(pluginYaml); final List<String> errors = validatePluginYaml(pluginYaml);
if (errors.isNotEmpty) { if (errors.isNotEmpty) {
throwToolExit('Invalid plugin specification $name.\n${errors.join('\n')}'); throwToolExit('Invalid plugin specification $name.\n${errors.join('\n')}');
} }
if (pluginYaml != null && pluginYaml['platforms'] != null) { if (pluginYaml != null && pluginYaml['platforms'] != null) {
return Plugin._fromMultiPlatformYaml(name, path, pluginYaml, dependencies, fileSystem); return Plugin._fromMultiPlatformYaml(
name,
path,
pluginYaml,
dependencies,
fileSystem,
appDependencies != null && appDependencies.contains(name),
);
} }
return Plugin._fromLegacyYaml(name, path, pluginYaml, dependencies, fileSystem); return Plugin._fromLegacyYaml(
name,
path,
pluginYaml,
dependencies,
fileSystem,
appDependencies != null && appDependencies.contains(name),
);
} }
factory Plugin._fromMultiPlatformYaml( factory Plugin._fromMultiPlatformYaml(
...@@ -70,6 +92,7 @@ class Plugin { ...@@ -70,6 +92,7 @@ class Plugin {
dynamic pluginYaml, dynamic pluginYaml,
List<String> dependencies, List<String> dependencies,
FileSystem fileSystem, FileSystem fileSystem,
bool isDirectDependency,
) { ) {
assert (pluginYaml != null && pluginYaml['platforms'] != null, assert (pluginYaml != null && pluginYaml['platforms'] != null,
'Invalid multi-platform plugin specification $name.'); 'Invalid multi-platform plugin specification $name.');
...@@ -114,11 +137,47 @@ class Plugin { ...@@ -114,11 +137,47 @@ class Plugin {
WindowsPlugin.fromYaml(name, platformsYaml[WindowsPlugin.kConfigKey] as YamlMap); WindowsPlugin.fromYaml(name, platformsYaml[WindowsPlugin.kConfigKey] as YamlMap);
} }
final String? defaultPackageForLinux =
_getDefaultPackageForPlatform(platformsYaml, LinuxPlugin.kConfigKey);
final String? defaultPackageForMacOS =
_getDefaultPackageForPlatform(platformsYaml, MacOSPlugin.kConfigKey);
final String? defaultPackageForWindows =
_getDefaultPackageForPlatform(platformsYaml, WindowsPlugin.kConfigKey);
final String? defaultPluginDartClassForLinux =
_getPluginDartClassForPlatform(platformsYaml, LinuxPlugin.kConfigKey);
final String? defaultPluginDartClassForMacOS =
_getPluginDartClassForPlatform(platformsYaml, MacOSPlugin.kConfigKey);
final String? defaultPluginDartClassForWindows =
_getPluginDartClassForPlatform(platformsYaml, WindowsPlugin.kConfigKey);
return Plugin( return Plugin(
name: name, name: name,
path: path, path: path,
platforms: platforms, platforms: platforms,
defaultPackagePlatforms: <String, String>{
if (defaultPackageForLinux != null)
LinuxPlugin.kConfigKey : defaultPackageForLinux,
if (defaultPackageForMacOS != null)
MacOSPlugin.kConfigKey : defaultPackageForMacOS,
if (defaultPackageForWindows != null)
WindowsPlugin.kConfigKey : defaultPackageForWindows,
},
pluginDartClassPlatforms: <String, String>{
if (defaultPluginDartClassForLinux != null)
LinuxPlugin.kConfigKey : defaultPluginDartClassForLinux,
if (defaultPluginDartClassForMacOS != null)
MacOSPlugin.kConfigKey : defaultPluginDartClassForMacOS,
if (defaultPluginDartClassForWindows != null)
WindowsPlugin.kConfigKey : defaultPluginDartClassForWindows,
},
dependencies: dependencies, dependencies: dependencies,
isDirectDependency: isDirectDependency,
implementsPackage: pluginYaml['implements'] != null ? pluginYaml['implements'] as String : '',
); );
} }
...@@ -128,6 +187,7 @@ class Plugin { ...@@ -128,6 +187,7 @@ class Plugin {
dynamic pluginYaml, dynamic pluginYaml,
List<String> dependencies, List<String> dependencies,
FileSystem fileSystem, FileSystem fileSystem,
bool isDirectDependency,
) { ) {
final Map<String, PluginPlatform> platforms = <String, PluginPlatform>{}; final Map<String, PluginPlatform> platforms = <String, PluginPlatform>{};
final String pluginClass = pluginYaml['pluginClass'] as String; final String pluginClass = pluginYaml['pluginClass'] as String;
...@@ -155,7 +215,10 @@ class Plugin { ...@@ -155,7 +215,10 @@ class Plugin {
name: name, name: name,
path: path, path: path,
platforms: platforms, platforms: platforms,
defaultPackagePlatforms: <String, String>{},
pluginDartClassPlatforms: <String, String>{},
dependencies: dependencies, dependencies: dependencies,
isDirectDependency: isDirectDependency,
); );
} }
...@@ -271,11 +334,41 @@ class Plugin { ...@@ -271,11 +334,41 @@ class Plugin {
return errors; return errors;
} }
static bool _providesImplementationForPlatform(YamlMap platformsYaml, String platformKey) { static bool _supportsPlatform(YamlMap platformsYaml, String platformKey) {
if (!platformsYaml.containsKey(platformKey)) { if (!platformsYaml.containsKey(platformKey)) {
return false; return false;
} }
if ((platformsYaml[platformKey] as YamlMap).containsKey('default_package')) { if (platformsYaml[platformKey] is YamlMap) {
return true;
}
return false;
}
static String? _getDefaultPackageForPlatform(YamlMap platformsYaml, String platformKey) {
if (!_supportsPlatform(platformsYaml, platformKey)) {
return null;
}
if ((platformsYaml[platformKey] as YamlMap).containsKey(kDefaultPackage)) {
return (platformsYaml[platformKey] as YamlMap)[kDefaultPackage] as String;
}
return null;
}
static String? _getPluginDartClassForPlatform(YamlMap platformsYaml, String platformKey) {
if (!_supportsPlatform(platformsYaml, platformKey)) {
return null;
}
if ((platformsYaml[platformKey] as YamlMap).containsKey(kDartPluginClass)) {
return (platformsYaml[platformKey] as YamlMap)[kDartPluginClass] as String;
}
return null;
}
static bool _providesImplementationForPlatform(YamlMap platformsYaml, String platformKey) {
if (!_supportsPlatform(platformsYaml, platformKey)) {
return false;
}
if ((platformsYaml[platformKey] as YamlMap).containsKey(kDefaultPackage)) {
return false; return false;
} }
return true; return true;
...@@ -284,9 +377,45 @@ class Plugin { ...@@ -284,9 +377,45 @@ class Plugin {
final String name; final String name;
final String path; final String path;
/// The name of the interface package that this plugin implements.
/// If [null], this plugin doesn't implement an interface.
final String? implementsPackage;
/// The name of the packages this plugin depends on. /// The name of the packages this plugin depends on.
final List<String> dependencies; final List<String> dependencies;
/// This is a mapping from platform config key to the plugin platform spec. /// This is a mapping from platform config key to the plugin platform spec.
final Map<String, PluginPlatform> platforms; final Map<String, PluginPlatform> platforms;
/// This is a mapping from platform config key to the default package implementation.
final Map<String, String> defaultPackagePlatforms;
/// This is a mapping from platform config key to the plugin class for the given platform.
final Map<String, String> pluginDartClassPlatforms;
/// Whether this plugin is a direct dependency of the app.
/// If [false], the plugin is a dependency of another plugin.
final bool isDirectDependency;
}
/// Metadata associated with the resolution of a platform interface of a plugin.
class PluginInterfaceResolution {
PluginInterfaceResolution({
required this.plugin,
required this.platform,
}) : assert(plugin != null),
assert(platform != null);
/// The plugin.
final Plugin plugin;
// The name of the platform that this plugin implements.
final String platform;
Map<String, String> toMap() {
return <String, String> {
'pluginName': plugin.name,
'platform': platform,
'dartClass': plugin.pluginDartClassPlatforms[platform] ?? '',
};
}
} }
...@@ -26,6 +26,7 @@ import 'base/terminal.dart'; ...@@ -26,6 +26,7 @@ import 'base/terminal.dart';
import 'base/utils.dart'; import 'base/utils.dart';
import 'build_info.dart'; import 'build_info.dart';
import 'build_system/build_system.dart'; import 'build_system/build_system.dart';
import 'build_system/targets/dart_plugin_registrant.dart';
import 'build_system/targets/localizations.dart'; import 'build_system/targets/localizations.dart';
import 'bundle.dart'; import 'bundle.dart';
import 'cache.dart'; import 'cache.dart';
...@@ -1211,9 +1212,16 @@ abstract class ResidentRunner extends ResidentHandlers { ...@@ -1211,9 +1212,16 @@ abstract class ResidentRunner extends ResidentHandlers {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
projectDir: globals.fs.currentDirectory, projectDir: globals.fs.currentDirectory,
generateDartPluginRegistry: true,
); );
_lastBuild = await globals.buildSystem.buildIncremental(
final CompositeTarget compositeTarget = CompositeTarget(<Target>[
const GenerateLocalizationsTarget(), const GenerateLocalizationsTarget(),
const DartPluginRegistrantTarget(),
]);
_lastBuild = await globals.buildSystem.buildIncremental(
compositeTarget,
_environment, _environment,
_lastBuild, _lastBuild,
); );
......
...@@ -26,6 +26,7 @@ import 'devfs.dart'; ...@@ -26,6 +26,7 @@ import 'devfs.dart';
import 'device.dart'; import 'device.dart';
import 'features.dart'; import 'features.dart';
import 'globals_null_migrated.dart' as globals; import 'globals_null_migrated.dart' as globals;
import 'project.dart';
import 'reporting/reporting.dart'; import 'reporting/reporting.dart';
import 'resident_devtools_handler.dart'; import 'resident_devtools_handler.dart';
import 'resident_runner.dart'; import 'resident_runner.dart';
...@@ -314,6 +315,7 @@ class HotRunner extends ResidentRunner { ...@@ -314,6 +315,7 @@ class HotRunner extends ResidentRunner {
bool enableDevTools = false, bool enableDevTools = false,
String route, String route,
}) async { }) async {
final File mainFile = globals.fs.file(mainPath);
firstBuildTime = DateTime.now(); firstBuildTime = DateTime.now();
final List<Future<bool>> startupTasks = <Future<bool>>[]; final List<Future<bool>> startupTasks = <Future<bool>>[];
...@@ -326,7 +328,7 @@ class HotRunner extends ResidentRunner { ...@@ -326,7 +328,7 @@ class HotRunner extends ResidentRunner {
if (device.generator != null) { if (device.generator != null) {
startupTasks.add( startupTasks.add(
device.generator.recompile( device.generator.recompile(
globals.fs.file(mainPath).uri, mainFile.uri,
<Uri>[], <Uri>[],
// When running without a provided applicationBinary, the tool will // When running without a provided applicationBinary, the tool will
// simultaneously run the initial frontend_server compilation and // simultaneously run the initial frontend_server compilation and
...@@ -338,6 +340,8 @@ class HotRunner extends ResidentRunner { ...@@ -338,6 +340,8 @@ class HotRunner extends ResidentRunner {
trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation, trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation,
), ),
packageConfig: debuggingOptions.buildInfo.packageConfig, packageConfig: debuggingOptions.buildInfo.packageConfig,
projectRootPath: FlutterProject.current().directory.absolute.path,
fs: globals.fs,
).then((CompilerOutput output) => output?.errorCount == 0) ).then((CompilerOutput output) => output?.errorCount == 0)
); );
} }
......
...@@ -1176,6 +1176,7 @@ abstract class FlutterCommand extends Command<void> { ...@@ -1176,6 +1176,7 @@ abstract class FlutterCommand extends Command<void> {
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
projectDir: project.directory, projectDir: project.directory,
generateDartPluginRegistry: true,
); );
await generateLocalizationsSyntheticPackage( await generateLocalizationsSyntheticPackage(
......
...@@ -140,6 +140,8 @@ class TestCompiler { ...@@ -140,6 +140,8 @@ class TestCompiler {
<Uri>[request.mainUri], <Uri>[request.mainUri],
outputPath: outputDill.path, outputPath: outputDill.path,
packageConfig: buildInfo.packageConfig, packageConfig: buildInfo.packageConfig,
projectRootPath: flutterProject.directory.absolute.path,
fs: globals.fs,
); );
final String outputPath = compilerOutput?.outputFilename; final String outputPath = compilerOutput?.outputFilename;
......
...@@ -138,6 +138,8 @@ class WebTestCompiler { ...@@ -138,6 +138,8 @@ class WebTestCompiler {
<Uri>[], <Uri>[],
outputPath: outputDirectory.childFile('out').path, outputPath: outputDirectory.childFile('out').path,
packageConfig: buildInfo.packageConfig, packageConfig: buildInfo.packageConfig,
fs: _fileSystem,
projectRootPath: projectDirectory.absolute.path,
); );
if (output.errorCount > 0) { if (output.errorCount > 0) {
throwToolExit('Failed to compile'); throwToolExit('Failed to compile');
......
...@@ -71,6 +71,9 @@ Future<void> buildWeb( ...@@ -71,6 +71,9 @@ Future<void> buildWeb(
? null ? null
: globals.flutterVersion.engineRevision, : globals.flutterVersion.engineRevision,
flutterRootDir: globals.fs.directory(Cache.flutterRoot), flutterRootDir: globals.fs.directory(Cache.flutterRoot),
// Web uses a different Dart plugin registry.
// https://github.com/flutter/flutter/issues/80406
generateDartPluginRegistry: false,
)); ));
if (!result.success) { if (!result.success) {
for (final ExceptionMeasurement measurement in result.exceptions.values) { for (final ExceptionMeasurement measurement in result.exceptions.values) {
......
...@@ -38,6 +38,7 @@ void main() { ...@@ -38,6 +38,7 @@ void main() {
processManager: globals.processManager, processManager: globals.processManager,
platform: FakePlatform(), platform: FakePlatform(),
engineVersion: 'invalidEngineVersion', engineVersion: 'invalidEngineVersion',
generateDartPluginRegistry: false,
); );
return result; return result;
} }
......
// 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.
// @dart = 2.8
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/common.dart';
import 'package:flutter_tools/src/build_system/targets/dart_plugin_registrant.dart';
import 'package:flutter_tools/src/project.dart';
import '../../../src/common.dart';
import '../../../src/context.dart';
const String _kEmptyPubspecFile = '''
name: app_without_plugins
dependencies:
flutter:
sdk: flutter
''';
const String _kEmptyPackageJson = '''
{
"configVersion": 2,
"packages": [
]
}
''';
const String _kSamplePackageJson = '''
{
"configVersion": 2,
"packages": [
{
"name": "path_provider_linux",
"rootUri": "/path_provider_linux",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "path_provider_example",
"rootUri": "../",
"packageUri": "lib/",
"languageVersion": "2.12"
}
]
}
''';
const String _kSamplePackagesFile = '''
path_provider_linux:/path_provider_linux/lib/
path_provider_example:lib/
''';
const String _kSamplePubspecFile = '''
name: path_provider_example
description: Demonstrates how to use the path_provider plugin.
dependencies:
flutter:
sdk: flutter
path_provider_linux: 1.0.0
''';
const String _kLinuxRegistrant =
'//\n'
'// Generated file. Do not edit.\n'
'// This file is generated from template in file `flutter_tools/lib/src/flutter_plugins.dart`.\n'
'//\n'
'\n'
'// @dart = 2.12\n'
'\n'
'import \'package:path_provider_example/main.dart\' as entrypoint;\n'
'import \'dart:io\'; // flutter_ignore: dart_io_import.\n'
'import \'package:path_provider_linux/path_provider_linux.dart\';\n'
'\n'
'@pragma(\'vm:entry-point\')\n'
'class _PluginRegistrant {\n'
'\n'
' @pragma(\'vm:entry-point\')\n'
' static void register() {\n'
' if (Platform.isLinux) {\n'
' try {\n'
' PathProviderLinux.registerWith();\n'
' } catch (err) {\n'
' print(\n'
' \'`path_provider_linux` threw an error: \$err. \'\n'
' \'The app may not function as expected until you remove this plugin from pubspec.yaml\'\n'
' );\n'
' rethrow;\n'
' }\n'
'\n'
' } else if (Platform.isMacOS) {\n'
' } else if (Platform.isWindows) {\n'
' }\n'
' }\n'
'\n'
'}\n'
'\n'
'typedef _UnaryFunction = dynamic Function(List<String> args);\n'
'typedef _NullaryFunction = dynamic Function();\n'
'\n'
'void main(List<String> args) {\n'
' if (entrypoint.main is _UnaryFunction) {\n'
' (entrypoint.main as _UnaryFunction)(args);\n'
' } else {\n'
' (entrypoint.main as _NullaryFunction)();\n'
' }\n'
'}\n'
'';
const String _kSamplePluginPubspec = '''
name: path_provider_linux
description: linux implementation of the path_provider plugin
// version: 2.0.1
// homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider_linux
flutter:
plugin:
implements: path_provider
platforms:
linux:
dartPluginClass: PathProviderLinux
pluginClass: none
environment:
sdk: ">=2.12.0-259.9.beta <3.0.0"
flutter: ">=1.20.0"
''';
void main() {
group('Dart plugin registrant' , () {
final FileSystem fileSystem = MemoryFileSystem.test();
testWithoutContext('skipped based on environment.generateDartPluginRegistry',
() async {
final Environment environment = Environment.test(
fileSystem.currentDirectory,
artifacts: null,
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
generateDartPluginRegistry: false);
expect(const DartPluginRegistrantTarget().canSkip(environment), true);
final Environment environment2 = Environment.test(
fileSystem.currentDirectory,
artifacts: null,
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
generateDartPluginRegistry: true);
expect(const DartPluginRegistrantTarget().canSkip(environment2), false);
});
testUsingContext("doesn't generate generated_main.dart if there aren't Dart plugins", () async {
final Environment environment = Environment.test(
fileSystem.currentDirectory,
projectDir: fileSystem.directory('project')..createSync(),
artifacts: null,
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
generateDartPluginRegistry: true);
final File config = environment.projectDir
.childDirectory('.dart_tool')
.childFile('package_config.json');
config.createSync(recursive: true);
config.writeAsStringSync(_kSamplePackageJson);
final File pubspec = environment.projectDir.childFile('pubspec.yaml');
pubspec.createSync();
final File packages = environment.projectDir.childFile('.packages');
packages.createSync();
final File generatedMain = environment.projectDir
.childDirectory('.dart_tool')
.childDirectory('flutter_build')
.childFile('generated_main.dart');
final FlutterProject testProject = FlutterProject.fromDirectoryTest(environment.projectDir);
await DartPluginRegistrantTarget.test(testProject).build(environment);
expect(generatedMain.existsSync(), isFalse);
});
testUsingContext('regenerates generated_main.dart', () async {
final Directory projectDir = fileSystem.directory('project')..createSync();
final Environment environment = Environment.test(
fileSystem.currentDirectory,
projectDir: projectDir,
artifacts: null,
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
defines: <String, String>{
kTargetFile: projectDir.childDirectory('lib').childFile('main.dart').absolute.path,
},
generateDartPluginRegistry: true);
final File config = projectDir
.childDirectory('.dart_tool')
.childFile('package_config.json');
config.createSync(recursive: true);
config.writeAsStringSync(_kSamplePackageJson);
final File pubspec = projectDir.childFile('pubspec.yaml');
pubspec.createSync();
pubspec.writeAsStringSync(_kSamplePubspecFile);
final File packages = projectDir.childFile('.packages');
packages.createSync();
packages.writeAsStringSync(_kSamplePackagesFile);
final File generatedMain = projectDir
.childDirectory('.dart_tool')
.childDirectory('flutter_build')
.childFile('generated_main.dart');
generatedMain.createSync(recursive: true);
final File mainEntrypoint = projectDir.childDirectory('lib').childFile('main.dart');
mainEntrypoint.createSync(recursive: true);
final File pluginPubspec = environment.fileSystem.currentDirectory.childDirectory('path_provider_linux').childFile('pubspec.yaml');
pluginPubspec.createSync(recursive: true);
pluginPubspec.writeAsStringSync(_kSamplePluginPubspec);
final FlutterProject testProject = FlutterProject.fromDirectoryTest(environment.projectDir);
await DartPluginRegistrantTarget.test(testProject).build(environment);
final String mainContent = generatedMain.readAsStringSync();
expect(mainContent, equals(_kLinuxRegistrant));
});
testUsingContext('removes generated_main.dart if plugins are removed from pubspec.yaml', () async {
final Environment environment = Environment.test(
fileSystem.currentDirectory,
projectDir: fileSystem.directory('project')..createSync(),
artifacts: null,
fileSystem: fileSystem,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
generateDartPluginRegistry: true);
final File config = environment.projectDir
.childDirectory('.dart_tool')
.childFile('package_config.json');
config.createSync(recursive: true);
config.writeAsStringSync(_kSamplePackageJson);
final File pubspec = environment.projectDir.childFile('pubspec.yaml');
pubspec.createSync();
pubspec.writeAsStringSync(_kSamplePubspecFile);
final File packages = environment.projectDir.childFile('.packages');
packages.createSync();
packages.writeAsStringSync(_kSamplePackagesFile);
final File generatedMain = environment.projectDir
.childDirectory('.dart_tool')
.childDirectory('flutter_build')
.childFile('generated_main.dart');
final File pluginPubspec = environment.fileSystem.currentDirectory
.childDirectory('path_provider_linux')
.childFile('pubspec.yaml');
pluginPubspec.createSync(recursive: true);
pluginPubspec.writeAsStringSync(_kSamplePluginPubspec);
final FlutterProject testProject = FlutterProject.fromDirectoryTest(environment.projectDir);
await DartPluginRegistrantTarget.test(testProject).build(environment);
expect(generatedMain.existsSync(), isTrue);
// Simulate a user removing everything from pubspec.yaml.
pubspec.writeAsStringSync(_kEmptyPubspecFile);
packages.writeAsStringSync(_kEmptyPackageJson);
config.writeAsStringSync(_kEmptyPackageJson);
await DartPluginRegistrantTarget.test(testProject).build(environment);
expect(generatedMain.existsSync(), isFalse);
});
});
}
...@@ -8,6 +8,7 @@ import 'dart:async'; ...@@ -8,6 +8,7 @@ import 'dart:async';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/compile.dart';
...@@ -367,4 +368,60 @@ void main() { ...@@ -367,4 +368,60 @@ void main() {
expect((await output).outputFilename, ''); expect((await output).outputFilename, '');
}); });
testWithoutContext('KernelCompiler uses generated entrypoint', () async {
final BufferLogger logger = BufferLogger.test();
final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test());
final Completer<void> completer = Completer<void>();
final MemoryFileSystem fs = MemoryFileSystem.test();
final KernelCompiler kernelCompiler = KernelCompiler(
artifacts: Artifacts.test(),
fileSystem: fs,
fileSystemRoots: <String>[
'/foo/bar/fizz',
],
fileSystemScheme: 'scheme',
logger: logger,
processManager: FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: const <String>[
'HostArtifact.engineDartBinary',
'--disable-dart-dev',
'Artifact.frontendServerSnapshotForEngineDartSdk',
'--sdk-root',
'/path/to/sdkroot/',
'--target=flutter',
'--no-print-incremental-dependencies',
'-Ddart.vm.profile=false',
'-Ddart.vm.product=false',
'--enable-asserts',
'--no-link-platform',
'--packages',
'.packages',
'.dart_tools/flutter_build/generated_main.dart',
], completer: completer),
]),
stdoutHandler: stdoutHandler,
);
final Directory buildDir = fs.directory('.dart_tools')
.childDirectory('flutter_build')
.childDirectory('test');
buildDir.parent.childFile('generated_main.dart').createSync(recursive: true);
final Future<CompilerOutput> output = kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/foo/bar/fizz/main.dart',
buildMode: BuildMode.debug,
trackWidgetCreation: false,
dartDefines: const <String>[],
packageConfig: PackageConfig.empty,
packagesPath: '.packages',
buildDir: buildDir,
checkDartPluginRegistry: true,
);
stdoutHandler.compilerOutput.complete(const CompilerOutput('', 0, <Uri>[]));
completer.complete();
await output;
});
} }
...@@ -95,6 +95,8 @@ void main() { ...@@ -95,6 +95,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
projectRootPath: '',
fs: fileSystem,
).then((CompilerOutput output) { ).then((CompilerOutput output) {
expect(frontendServerStdIn.getAndClear(), expect(frontendServerStdIn.getAndClear(),
'compile file:///path/to/main.dart\n'); 'compile file:///path/to/main.dart\n');
...@@ -137,6 +139,8 @@ void main() { ...@@ -137,6 +139,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
projectRootPath: '',
fs: MemoryFileSystem(),
).then((CompilerOutput outputCompile) { ).then((CompilerOutput outputCompile) {
expect(testLogger.errorText, expect(testLogger.errorText,
equals('line1\nline2\n')); equals('line1\nline2\n'));
......
...@@ -92,6 +92,8 @@ void main() { ...@@ -92,6 +92,8 @@ void main() {
null /* invalidatedFiles */, null /* invalidatedFiles */,
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
expect(testLogger.errorText, equals('line1\nline2\n')); expect(testLogger.errorText, equals('line1\nline2\n'));
...@@ -117,6 +119,8 @@ void main() { ...@@ -117,6 +119,8 @@ void main() {
null /* invalidatedFiles */, null /* invalidatedFiles */,
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n');
expect(testLogger.errorText, equals('line1\nline2\n')); expect(testLogger.errorText, equals('line1\nline2\n'));
...@@ -135,6 +139,8 @@ void main() { ...@@ -135,6 +139,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
)), throwsToolExit()); )), throwsToolExit());
}); });
...@@ -150,6 +156,8 @@ void main() { ...@@ -150,6 +156,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
)), throwsToolExit(message: 'the Dart compiler exited unexpectedly.')); )), throwsToolExit(message: 'the Dart compiler exited unexpectedly.'));
}); });
...@@ -167,6 +175,8 @@ void main() { ...@@ -167,6 +175,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
projectRootPath: '',
fs: MemoryFileSystem(),
); );
expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
...@@ -213,6 +223,8 @@ void main() { ...@@ -213,6 +223,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n');
...@@ -274,6 +286,8 @@ void main() { ...@@ -274,6 +286,8 @@ void main() {
null, /* invalidatedFiles */ null, /* invalidatedFiles */
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile scheme:///main.dart\n');
...@@ -323,6 +337,8 @@ void main() { ...@@ -323,6 +337,8 @@ void main() {
<Uri>[], <Uri>[],
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
...@@ -359,6 +375,8 @@ void main() { ...@@ -359,6 +375,8 @@ void main() {
null /* invalidatedFiles */, null /* invalidatedFiles */,
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n'); expect(frontendServerStdIn.getAndClear(), 'compile /path/to/main.dart\n');
...@@ -398,6 +416,8 @@ Future<void> _recompile( ...@@ -398,6 +416,8 @@ Future<void> _recompile(
outputPath: '/build/', outputPath: '/build/',
packageConfig: PackageConfig.empty, packageConfig: PackageConfig.empty,
suppressErrors: suppressErrors, suppressErrors: suppressErrors,
fs: MemoryFileSystem(),
projectRootPath: '',
); );
// Put content into the output stream after generator.recompile gets // Put content into the output stream after generator.recompile gets
......
...@@ -170,6 +170,8 @@ void main() { ...@@ -170,6 +170,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
fileSystem.file('lib/foo.dill') fileSystem.file('lib/foo.dill')
..createSync(recursive: true) ..createSync(recursive: true)
...@@ -237,6 +239,8 @@ void main() { ...@@ -237,6 +239,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('lib/foo.dill', 2, <Uri>[]); return const CompilerOutput('lib/foo.dill', 2, <Uri>[]);
}); });
...@@ -281,6 +285,8 @@ void main() { ...@@ -281,6 +285,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
fileSystem.file('example').createSync(); fileSystem.file('example').createSync();
return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]); return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]);
...@@ -327,6 +333,8 @@ void main() { ...@@ -327,6 +333,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
fileSystem.file('lib/foo.txt.dill').createSync(recursive: true); fileSystem.file('lib/foo.txt.dill').createSync(recursive: true);
return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]); return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]);
...@@ -379,6 +387,8 @@ void main() { ...@@ -379,6 +387,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
fileSystem.file('example').createSync(); fileSystem.file('example').createSync();
return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]); return const CompilerOutput('lib/foo.txt.dill', 0, <Uri>[]);
......
...@@ -1444,6 +1444,19 @@ flutter: ...@@ -1444,6 +1444,19 @@ flutter:
expect(deferredComponents[0].assets[1].path, 'path/to/asset2.jpg'); expect(deferredComponents[0].assets[1].path, 'path/to/asset2.jpg');
expect(deferredComponents[0].assets[2].path, 'path/to/asset3.jpg'); expect(deferredComponents[0].assets[2].path, 'path/to/asset3.jpg');
}); });
testWithoutContext('FlutterManifest can parse empty dependencies', () async {
const String manifest = '''
name: test
''';
final FlutterManifest? flutterManifest = FlutterManifest.createFromString(
manifest,
logger: BufferLogger.test(),
);
expect(flutterManifest, isNotNull);
expect(flutterManifest!.dependencies, isEmpty);
});
} }
Matcher matchesManifest({ Matcher matchesManifest({
......
...@@ -218,6 +218,39 @@ void main() { ...@@ -218,6 +218,39 @@ void main() {
); );
expect(plugin.platforms, <String, PluginPlatform>{}); expect(plugin.platforms, <String, PluginPlatform>{});
expect(plugin.defaultPackagePlatforms, <String, String>{
'linux': 'sample_package_linux',
'macos': 'sample_package_macos',
'windows': 'sample_package_windows',
});
expect(plugin.pluginDartClassPlatforms, <String, String>{});
});
testWithoutContext('Desktop plugin parsing allows a dartPluginClass field', () {
final FileSystem fileSystem = MemoryFileSystem.test();
const String pluginYamlRaw =
'platforms:\n'
' linux:\n'
' dartPluginClass: LinuxClass\n'
' macos:\n'
' dartPluginClass: MacOSClass\n'
' windows:\n'
' dartPluginClass: WindowsClass\n';
final YamlMap pluginYaml = loadYaml(pluginYamlRaw) as YamlMap;
final Plugin plugin = Plugin.fromYaml(
_kTestPluginName,
_kTestPluginPath,
pluginYaml,
const <String>[],
fileSystem: fileSystem,
);
expect(plugin.pluginDartClassPlatforms, <String, String>{
'linux': 'LinuxClass',
'macos': 'MacOSClass',
'windows': 'WindowsClass',
});
}); });
testWithoutContext('Plugin parsing throws a fatal error on an empty plugin', () { testWithoutContext('Plugin parsing throws a fatal error on an empty plugin', () {
......
...@@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/platform.dart'; ...@@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/base/utils.dart';
import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/flutter_manifest.dart';
import 'package:flutter_tools/src/flutter_plugins.dart'; import 'package:flutter_tools/src/flutter_plugins.dart';
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
...@@ -33,6 +34,7 @@ void main() { ...@@ -33,6 +34,7 @@ void main() {
group('plugins', () { group('plugins', () {
FileSystem fs; FileSystem fs;
MockFlutterProject flutterProject; MockFlutterProject flutterProject;
MockFlutterManifest flutterManifest;
MockIosProject iosProject; MockIosProject iosProject;
MockMacOSProject macosProject; MockMacOSProject macosProject;
MockAndroidProject androidProject; MockAndroidProject androidProject;
...@@ -49,6 +51,12 @@ void main() { ...@@ -49,6 +51,12 @@ void main() {
// Adds basic properties to the flutterProject and its subprojects. // Adds basic properties to the flutterProject and its subprojects.
void setUpProject(FileSystem fileSystem) { void setUpProject(FileSystem fileSystem) {
flutterProject = MockFlutterProject(); flutterProject = MockFlutterProject();
flutterManifest = MockFlutterManifest();
when(flutterManifest.dependencies).thenReturn(<String>{});
when(flutterProject.manifest).thenReturn(flutterManifest);
when(flutterProject.directory).thenReturn(fileSystem.systemTempDirectory.childDirectory('app')); when(flutterProject.directory).thenReturn(fileSystem.systemTempDirectory.childDirectory('app'));
// TODO(franciscojma): Remove logic for .flutter-plugins once it's deprecated. // TODO(franciscojma): Remove logic for .flutter-plugins once it's deprecated.
when(flutterProject.flutterPluginsFile).thenReturn(flutterProject.directory.childFile('.flutter-plugins')); when(flutterProject.flutterPluginsFile).thenReturn(flutterProject.directory.childFile('.flutter-plugins'));
...@@ -1412,6 +1420,7 @@ flutter: ...@@ -1412,6 +1420,7 @@ flutter:
} }
class MockAndroidProject extends Mock implements AndroidProject {} class MockAndroidProject extends Mock implements AndroidProject {}
class MockFlutterManifest extends Mock implements FlutterManifest {}
class MockFlutterProject extends Mock implements FlutterProject {} class MockFlutterProject extends Mock implements FlutterProject {}
class MockIosProject extends Mock implements IosProject {} class MockIosProject extends Mock implements IosProject {}
class MockMacOSProject extends Mock implements MacOSProject {} class MockMacOSProject extends Mock implements MacOSProject {}
......
...@@ -110,6 +110,17 @@ void main() { ...@@ -110,6 +110,17 @@ void main() {
); );
}); });
_testInMemory('reads dependencies from pubspec.yaml', () async {
final Directory directory = globals.fs.directory('myproject');
directory.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync(validPubspecWithDependencies);
expect(
FlutterProject.fromDirectory(directory).manifest.dependencies,
<String>{'plugin_a', 'plugin_b'},
);
});
_testInMemory('sets up location', () async { _testInMemory('sets up location', () async {
final Directory directory = globals.fs.directory('myproject'); final Directory directory = globals.fs.directory('myproject');
expect( expect(
...@@ -920,6 +931,16 @@ name: hello ...@@ -920,6 +931,16 @@ name: hello
flutter: flutter:
'''; ''';
String get validPubspecWithDependencies => '''
name: hello
flutter:
dependencies:
plugin_a:
plugin_b:
''';
String get invalidPubspec => ''' String get invalidPubspec => '''
name: hello name: hello
flutter: flutter:
......
...@@ -271,6 +271,8 @@ void main() { ...@@ -271,6 +271,8 @@ void main() {
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
suppressErrors: true, suppressErrors: true,
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('foo', 0 ,<Uri>[]); return const CompilerOutput('foo', 0 ,<Uri>[]);
}); });
...@@ -288,6 +290,8 @@ void main() { ...@@ -288,6 +290,8 @@ void main() {
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
suppressErrors: true, suppressErrors: true,
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).called(1); )).called(1);
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
...@@ -316,6 +320,8 @@ void main() { ...@@ -316,6 +320,8 @@ void main() {
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
suppressErrors: true, suppressErrors: true,
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('foo', 1 ,<Uri>[]); return const CompilerOutput('foo', 1 ,<Uri>[]);
}); });
...@@ -408,6 +414,8 @@ void main() { ...@@ -408,6 +414,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
suppressErrors: false, suppressErrors: false,
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('foo', 0, <Uri>[]); return const CompilerOutput('foo', 0, <Uri>[]);
...@@ -426,6 +434,8 @@ void main() { ...@@ -426,6 +434,8 @@ void main() {
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
suppressErrors: false, suppressErrors: false,
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).called(1); )).called(1);
expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(fakeVmServiceHost.hasRemainingExpectations, false);
}), overrides: <Type, Generator>{ }), overrides: <Type, Generator>{
...@@ -1438,6 +1448,26 @@ void main() { ...@@ -1438,6 +1448,26 @@ void main() {
globals.fs.file('l10n.yaml').createSync(); globals.fs.file('l10n.yaml').createSync();
globals.fs.file('pubspec.yaml').writeAsStringSync('flutter:\n generate: true\n'); globals.fs.file('pubspec.yaml').writeAsStringSync('flutter:\n generate: true\n');
// Create necessary files for [DartPluginRegistrantTarget]
final File packageConfig = globals.fs.directory('.dart_tool')
.childFile('package_config.json');
packageConfig.createSync(recursive: true);
packageConfig.writeAsStringSync('''
{
"configVersion": 2,
"packages": [
{
"name": "path_provider_linux",
"rootUri": "../../../path_provider_linux",
"packageUri": "lib/",
"languageVersion": "2.12"
}
]
}
''');
// Start from an empty generated_main.dart file.
globals.fs.directory('.dart_tool').childDirectory('flutter_build').childFile('generated_main.dart').createSync(recursive: true);
await residentRunner.runSourceGenerators(); await residentRunner.runSourceGenerators();
expect(testLogger.errorText, isEmpty); expect(testLogger.errorText, isEmpty);
...@@ -2515,6 +2545,8 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { ...@@ -2515,6 +2545,8 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler {
List<Uri> invalidatedFiles, { List<Uri> invalidatedFiles, {
@required String outputPath, @required String outputPath,
@required PackageConfig packageConfig, @required PackageConfig packageConfig,
@required String projectRootPath,
@required FileSystem fs,
bool suppressErrors = false, bool suppressErrors = false,
}) async { }) async {
return const CompilerOutput('foo.dill', 0, <Uri>[]); return const CompilerOutput('foo.dill', 0, <Uri>[]);
......
...@@ -55,6 +55,8 @@ void main() { ...@@ -55,6 +55,8 @@ void main() {
<Uri>[Uri.parse('test/foo.dart')], <Uri>[Uri.parse('test/foo.dart')],
outputPath: testCompiler.outputDill.path, outputPath: testCompiler.outputDill.path,
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
fileSystem.file('abc.dill').createSync(); fileSystem.file('abc.dill').createSync();
return const CompilerOutput('abc.dill', 0, <Uri>[]); return const CompilerOutput('abc.dill', 0, <Uri>[]);
...@@ -80,6 +82,8 @@ void main() { ...@@ -80,6 +82,8 @@ void main() {
<Uri>[Uri.parse('test/foo.dart')], <Uri>[Uri.parse('test/foo.dart')],
outputPath: testCompiler.outputDill.path, outputPath: testCompiler.outputDill.path,
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
fileSystem.file('abc.dill').createSync(); fileSystem.file('abc.dill').createSync();
return const CompilerOutput('abc.dill', 1, <Uri>[]); return const CompilerOutput('abc.dill', 1, <Uri>[]);
......
...@@ -605,6 +605,8 @@ void main() { ...@@ -605,6 +605,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]); return const CompilerOutput('a', 0, <Uri>[]);
}); });
...@@ -723,6 +725,8 @@ void main() { ...@@ -723,6 +725,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]); return const CompilerOutput('a', 0, <Uri>[]);
}); });
...@@ -838,6 +842,8 @@ void main() { ...@@ -838,6 +842,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]); return const CompilerOutput('a', 0, <Uri>[]);
}); });
...@@ -883,6 +889,8 @@ void main() { ...@@ -883,6 +889,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]); return const CompilerOutput('a', 0, <Uri>[]);
}); });
...@@ -936,6 +944,8 @@ void main() { ...@@ -936,6 +944,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]); return const CompilerOutput('a', 0, <Uri>[]);
}); });
...@@ -1056,6 +1066,8 @@ void main() { ...@@ -1056,6 +1066,8 @@ void main() {
any, any,
outputPath: anyNamed('outputPath'), outputPath: anyNamed('outputPath'),
packageConfig: anyNamed('packageConfig'), packageConfig: anyNamed('packageConfig'),
projectRootPath: anyNamed('projectRootPath'),
fs: anyNamed('fs'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return const CompilerOutput('a', 0, <Uri>[]); return const CompilerOutput('a', 0, <Uri>[]);
}); });
......
...@@ -44,8 +44,11 @@ void main() { ...@@ -44,8 +44,11 @@ void main() {
Plugin( Plugin(
name: 'test', name: 'test',
path: 'foo', path: 'foo',
defaultPackagePlatforms: const <String, String>{},
pluginDartClassPlatforms: const <String, String>{},
platforms: const <String, PluginPlatform>{WindowsPlugin.kConfigKey: WindowsPlugin(name: 'test', pluginClass: 'Foo')}, platforms: const <String, PluginPlatform>{WindowsPlugin.kConfigKey: WindowsPlugin(name: 'test', pluginClass: 'Foo')},
dependencies: <String>[], dependencies: <String>[],
isDirectDependency: true,
), ),
], renderer); ], renderer);
...@@ -67,8 +70,11 @@ void main() { ...@@ -67,8 +70,11 @@ void main() {
Plugin( Plugin(
name: 'test', name: 'test',
path: 'foo', path: 'foo',
defaultPackagePlatforms: const <String, String>{},
pluginDartClassPlatforms: const <String, String>{},
platforms: const <String, PluginPlatform>{WindowsPlugin.kConfigKey: WindowsPlugin(name: 'test', pluginClass: 'Foo')}, platforms: const <String, PluginPlatform>{WindowsPlugin.kConfigKey: WindowsPlugin(name: 'test', pluginClass: 'Foo')},
dependencies: <String>[], dependencies: <String>[],
isDirectDependency: true,
), ),
], renderer); ], renderer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment