From 5ee4eb52e6cc13611ca8672fe6f73ef78cd10490 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Wed, 11 Sep 2024 16:54:29 +0000 Subject: [PATCH] DAS plugins: Add plugin package generator This generator will be used create shared plugin package entrypoints from plugin configurations. Work towards https://github.com/dart-lang/sdk/issues/53402 Change-Id: If5c6aeb7bc7845311975928fba1cb9c8d273423c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384681 Reviewed-by: Brian Wilkerson Commit-Queue: Samuel Rawlins Reviewed-by: Konstantin Shcheglov --- pkg/analysis_server/lib/src/plugin/README.md | 3 + pkg/analysis_server/lib/src/plugin2/README.md | 8 ++ .../lib/src/plugin2/generator.dart | 79 ++++++++++++++++ .../test/src/plugin/test_all.dart | 2 +- .../test/src/plugin2/README.md | 5 + .../test/src/plugin2/generator_test.dart | 92 +++++++++++++++++++ .../test/src/plugin2/test_all.dart | 13 +++ pkg/analysis_server/test/src/test_all.dart | 2 + 8 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 pkg/analysis_server/lib/src/plugin/README.md create mode 100644 pkg/analysis_server/lib/src/plugin2/README.md create mode 100644 pkg/analysis_server/lib/src/plugin2/generator.dart create mode 100644 pkg/analysis_server/test/src/plugin2/README.md create mode 100644 pkg/analysis_server/test/src/plugin2/generator_test.dart create mode 100644 pkg/analysis_server/test/src/plugin2/test_all.dart diff --git a/pkg/analysis_server/lib/src/plugin/README.md b/pkg/analysis_server/lib/src/plugin/README.md new file mode 100644 index 00000000000..8581454871b --- /dev/null +++ b/pkg/analysis_server/lib/src/plugin/README.md @@ -0,0 +1,3 @@ +This directory contains sources for the "prototype" plugin system introduced +circa 2017, which is being replaced by the "new" plugin system introduced +circa 2024. The sources for the "new" plugin system are located in `../plugin2`. diff --git a/pkg/analysis_server/lib/src/plugin2/README.md b/pkg/analysis_server/lib/src/plugin2/README.md new file mode 100644 index 00000000000..947edd44906 --- /dev/null +++ b/pkg/analysis_server/lib/src/plugin2/README.md @@ -0,0 +1,8 @@ +This directory contains sources for the "new" plugin system introduced circa +2024, which is the replacement for the "prototype" plugin system introduced +circa 2017. The sources for the "prototype" plugin system are located in +`../plugin`. + +The "new" plugin system is partially based on the "prototype" plugin system. As +the "prototype" plugin system becomes deprecated and unsupported, any features +that the "new" plugin system relies on can be migrated to this directory. \ No newline at end of file diff --git a/pkg/analysis_server/lib/src/plugin2/generator.dart b/pkg/analysis_server/lib/src/plugin2/generator.dart new file mode 100644 index 00000000000..cab35484b55 --- /dev/null +++ b/pkg/analysis_server/lib/src/plugin2/generator.dart @@ -0,0 +1,79 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// This class can generate various files to make up the shared plugin package. +class PluginPackageGenerator { + /// The plugin configuration, a map of plugin names to each plugin's + /// configuration. + /// + /// This typically stems from plugin configuration in an analysis options + /// file. + final Map _pluginConfiguration; + + PluginPackageGenerator(this._pluginConfiguration); + + /// Generates the Dart entrpoint file which is to be spawned in a Dart + /// isolate by the analysis server. + String generateEntrypoint() { + var imports = [ + "'package:analysis_server_plugin/src/plugin_server.dart'", + "'package:analyzer/file_system/physical_file_system.dart'", + "'package:analyzer_plugin/starter.dart'", + for (var name in _pluginConfiguration.keys) + "'package:$name/main.dart' as $name", + ]; + + var buffer = StringBuffer("import 'dart:isolate';"); + for (var import in imports..sort()) { + buffer.writeln('import $import;'); + } + + buffer.write(''' +Future main(List args, SendPort sendPort) async { + var pluginServer = PluginServer( + resourceProvider: PhysicalResourceProvider.INSTANCE, + plugins: [ +'''); + // TODO(srawlins): Format with the formatter, for readability. + for (var name in _pluginConfiguration.keys) { + buffer.writeln(' $name.plugin,'); + } + buffer.write(''' + ], + ); + await startPlugin(); + ServerPluginStarter(wrangler).start(sendPort); +} +'''); + + return buffer.toString(); + } + + /// Generates a pubspec file which spells out where to retreive plugin package + /// sources. + String generatePubspec() { + var buffer = StringBuffer(); + buffer.write(''' +name: plugin_entrypoint +version: 0.0.1 +dependencies: +'''); + + for (var MapEntry(key: name, value: configuration) + in _pluginConfiguration.entries) { + switch (configuration) { + case String(): + buffer.writeln(' $name: $configuration'); + case Map(): + if (configuration case {'path': String pathValue}) { + buffer.writeln(' $name:\n path: $pathValue'); + } else if (configuration case {'git': String gitValue}) { + buffer.writeln(' $name:\n git: $gitValue'); + } + } + } + + return buffer.toString(); + } +} diff --git a/pkg/analysis_server/test/src/plugin/test_all.dart b/pkg/analysis_server/test/src/plugin/test_all.dart index 9240a5d3a6f..dffd46e6a21 100644 --- a/pkg/analysis_server/test/src/plugin/test_all.dart +++ b/pkg/analysis_server/test/src/plugin/test_all.dart @@ -23,5 +23,5 @@ void main() { result_collector_test.main(); result_converter_test.main(); result_merger_test.main(); - }); + }, name: 'plugin'); } diff --git a/pkg/analysis_server/test/src/plugin2/README.md b/pkg/analysis_server/test/src/plugin2/README.md new file mode 100644 index 00000000000..061480e931c --- /dev/null +++ b/pkg/analysis_server/test/src/plugin2/README.md @@ -0,0 +1,5 @@ +This directory contains tests for the "new" plugin system introduced circa 2024, +which is the replacement for the "prototype" plugin system introduced circa +2017. The tests for the "prototype" plugin are located in `../plugin`. +Eventually, all tests in `../plugin` which test some equivalent behavior in the +"new" plugin system should be migrated here. \ No newline at end of file diff --git a/pkg/analysis_server/test/src/plugin2/generator_test.dart b/pkg/analysis_server/test/src/plugin2/generator_test.dart new file mode 100644 index 00000000000..7dfd3d710d2 --- /dev/null +++ b/pkg/analysis_server/test/src/plugin2/generator_test.dart @@ -0,0 +1,92 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. 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:analysis_server/src/plugin2/generator.dart'; +import 'package:test/test.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +void main() { + defineReflectiveSuite(() { + defineReflectiveTests(GeneratorTest); + }); +} + +@reflectiveTest +class GeneratorTest { + void test_entrypointImportsPluginEntrypoints() { + var pluginPackageGenerator = PluginPackageGenerator({ + 'no_bools': '^1.0.0', + 'no_ints': '^1.2.0', + }); + expect( + pluginPackageGenerator.generateEntrypoint(), + contains(''' +import 'package:no_bools/main.dart' as no_bools; +import 'package:no_ints/main.dart' as no_ints; +'''), + ); + } + + void test_entrypointListsPluginInstances() { + var pluginPackageGenerator = PluginPackageGenerator({ + 'no_bools': '^1.0.0', + 'no_ints': '^1.2.0', + }); + expect( + pluginPackageGenerator.generateEntrypoint(), + contains(''' + plugins: [ + no_bools.plugin, + no_ints.plugin, + ], +'''), + ); + } + + void test_pubspecContainsGitDependencies() { + var pluginPackageGenerator = PluginPackageGenerator({ + 'no_bools': {'git': 'https://example.com/example.git'}, + }); + expect( + pluginPackageGenerator.generatePubspec(), + contains(''' +dependencies: + no_bools: + git: https://example.com/example.git +'''), + ); + } + + void test_pubspecContainsPathDependencies() { + var pluginPackageGenerator = PluginPackageGenerator({ + 'no_bools': {'path': '../no_bools_plugin'}, + 'no_ints': {'path': 'tools/no_ints_plugin'}, + }); + expect( + pluginPackageGenerator.generatePubspec(), + contains(''' +dependencies: + no_bools: + path: ../no_bools_plugin + no_ints: + path: tools/no_ints_plugin +'''), + ); + } + + void test_pubspecContainsVersionedDependencies() { + var pluginPackageGenerator = PluginPackageGenerator({ + 'no_bools': '^1.0.0', + 'no_ints': '^1.2.0', + }); + expect( + pluginPackageGenerator.generatePubspec(), + contains(''' +dependencies: + no_bools: ^1.0.0 + no_ints: ^1.2.0 +'''), + ); + } +} diff --git a/pkg/analysis_server/test/src/plugin2/test_all.dart b/pkg/analysis_server/test/src/plugin2/test_all.dart new file mode 100644 index 00000000000..5e4264d3acb --- /dev/null +++ b/pkg/analysis_server/test/src/plugin2/test_all.dart @@ -0,0 +1,13 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. 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:test_reflective_loader/test_reflective_loader.dart'; + +import 'generator_test.dart' as generator_test; + +void main() { + defineReflectiveSuite(() { + generator_test.main(); + }, name: 'plugin2'); +} diff --git a/pkg/analysis_server/test/src/test_all.dart b/pkg/analysis_server/test/src/test_all.dart index 1b3b4b15f86..429356218cb 100644 --- a/pkg/analysis_server/test/src/test_all.dart +++ b/pkg/analysis_server/test/src/test_all.dart @@ -12,6 +12,7 @@ import 'flutter/test_all.dart' as flutter; import 'g3/test_all.dart' as g3; import 'lsp/test_all.dart' as lsp; import 'plugin/test_all.dart' as plugin; +import 'plugin2/test_all.dart' as plugin2; import 'server/test_all.dart' as server; import 'services/test_all.dart' as services; import 'utilities/test_all.dart' as utilities; @@ -26,6 +27,7 @@ void main() { g3.main(); lsp.main(); plugin.main(); + plugin2.main(); server.main(); services.main(); utilities.main();