Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --watch to _macro_tool for analyzer. #99

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions pkgs/_macro_tool/bin/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ final argParser = ArgParser()
..addOption('workspace', help: 'Path to workspace.')
..addOption('packageConfig', help: 'Path to package config.')
..addOption('script', help: 'Path to script.')
..addFlag('skip-cleanup');
..addFlag('skip-cleanup',
help: 'Whether to skip delete of augmentations and revert of script.')
..addFlag('watch', help: 'Whether to watch for changes.');

Future<void> main(List<String> arguments) async {
final args = argParser.parse(arguments);
Expand All @@ -40,6 +42,7 @@ ${argParser.usage}''');
workspacePath: p.canonicalize(workspace),
packageConfigPath: p.canonicalize(packageConfig),
scriptPath: p.canonicalize(script),
skipCleanup: args['skip-cleanup'] as bool);
skipCleanup: args['skip-cleanup'] as bool,
watch: args['watch'] as bool);
await tool.run();
}
61 changes: 40 additions & 21 deletions pkgs/_macro_tool/lib/analyzer_macro_tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:io';
import 'package:_analyzer_macros/macro_implementation.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/src/summary2/macro_injected_impl.dart'
as injected_analyzer;
import 'package:macro_service/macro_service.dart';
Expand All @@ -18,7 +19,8 @@ class AnalyzerMacroTool extends MacroTool {
{required super.workspacePath,
required super.packageConfigPath,
required super.scriptPath,
required super.skipCleanup})
required super.skipCleanup,
required super.watch})
: super.internal();

/// Runs macros in [scriptFile] on the analyzer.
Expand All @@ -38,30 +40,47 @@ class AnalyzerMacroTool extends MacroTool {
version: ProtocolVersion.macros1),
packageConfig: Uri.file(packageConfigPath));

final resolvedLibrary = (await analysisContext.currentSession
.getResolvedLibrary(scriptPath)) as ResolvedLibraryResult;
ResolvedLibraryResult resolvedLibrary;
// `asBroadcastStream` so repeated use of `first` below waits for the next
// change.
var events = File(scriptPath).watch().asBroadcastStream();
var stopwatch = Stopwatch()..start();
while (true) {
resolvedLibrary = (await analysisContext.currentSession
.getResolvedLibrary(scriptPath)) as ResolvedLibraryResult;
print('Resolved in ${stopwatch.elapsedMilliseconds}ms.');

final errors = (await analysisContext.currentSession.getErrors(scriptPath))
as ErrorsResult;
if (errors.errors.isNotEmpty) {
print('Errors: ${errors.errors}');
}
final errors = (await analysisContext.currentSession
.getErrors(scriptPath)) as ErrorsResult;
final actualErrors =
errors.errors.where((e) => e.severity == Severity.error).toList();
if (actualErrors.isNotEmpty) {
print('Errors: $actualErrors');
}

final augmentationUnits =
resolvedLibrary.units.where((u) => u.isMacroPart).toList();
if (augmentationUnits.isEmpty) {
return false;
}
final augmentationUnits =
resolvedLibrary.units.where((u) => u.isMacroPart).toList();
if (augmentationUnits.isEmpty) {
return false;
}

print('Macro output (patched to use augment library): '
'$augmentationFilePath');
File(augmentationFilePath).writeAsStringSync(augmentationUnits
.single.content
// The analyzer produces augmentations in parts, but the CFE still
// wants them in augmentation libraries. Adjust the output accordingly.
.replaceAll('part of', 'augment library'));
print('Macro output (patched to use augment library): '
'$augmentationFilePath');
File(augmentationFilePath).writeAsStringSync(augmentationUnits
.single.content
// The analyzer produces augmentations in parts, but the CFE still
// wants them in augmentation libraries. Adjust the output accordingly.
.replaceAll('part of', 'augment library'));

return true;
if (!watch) return true;

print('Running with --watch, waiting for next change to script.');
await events.first;
print('Script changed, rerunning macro.');
stopwatch.reset();
analysisContext.changeFile(scriptPath);
await analysisContext.applyPendingFileChanges();
}
}

@override
Expand Down
5 changes: 4 additions & 1 deletion pkgs/_macro_tool/lib/cfe_macro_tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class CfeMacroTool extends MacroTool {
{required super.workspacePath,
required super.packageConfigPath,
required super.scriptPath,
required super.skipCleanup})
required super.skipCleanup,
required super.watch})
: super.internal();

/// Runs macros in [scriptFile] using the CFE.
Expand All @@ -27,6 +28,8 @@ class CfeMacroTool extends MacroTool {
/// Returns whether an augmentation file was written.
@override
Future<bool> augment() async {
if (watch) throw UnimplementedError('--watch not implemented for CFE.');

// TODO(davidmorgan): this dill comes from the Dart SDK running the test,
// but `package:frontend_server` and `package:front_end` are used as a
// library, so we will see version skew breakage. Find a better way.
Expand Down
13 changes: 9 additions & 4 deletions pkgs/_macro_tool/lib/macro_tool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,35 @@ abstract class MacroTool {
String packageConfigPath;
String scriptPath;
bool skipCleanup;
bool watch;

MacroTool.internal(
{required this.workspacePath,
required this.packageConfigPath,
required this.scriptPath,
required this.skipCleanup});
required this.skipCleanup,
required this.watch});

factory MacroTool(
{required HostOption host,
required String workspacePath,
required String packageConfigPath,
required String scriptPath,
required bool skipCleanup}) =>
required bool skipCleanup,
required bool watch}) =>
host == HostOption.analyzer
? AnalyzerMacroTool(
workspacePath: workspacePath,
packageConfigPath: packageConfigPath,
scriptPath: scriptPath,
skipCleanup: skipCleanup)
skipCleanup: skipCleanup,
watch: watch)
: CfeMacroTool(
workspacePath: workspacePath,
packageConfigPath: packageConfigPath,
scriptPath: scriptPath,
skipCleanup: skipCleanup);
skipCleanup: skipCleanup,
watch: watch);

Future<void> run() async {
print('Running ${p.basename(scriptPath)} with macros on $this.');
Expand Down