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();