Skip to content

Commit

Permalink
Add _macro_tool.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmorgan committed Sep 30, 2024
1 parent 20c1bf1 commit cbf0013
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 9 deletions.
45 changes: 36 additions & 9 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ jobs:
- name: mono_repo self validate
run: dart pub global run mono_repo generate --validate
job_002:
name: "analyze_and_format; linux; Dart 3.6.0-198.0.dev; PKGS: pkgs/_analyzer_macros, pkgs/_cfe_macros, pkgs/_macro_builder, pkgs/_macro_client, pkgs/_macro_host, pkgs/_macro_runner, pkgs/_macro_server, pkgs/_test_macros, pkgs/dart_model, pkgs/macro, pkgs/macro_service, tool/dart_model_generator; `dart analyze --fatal-infos .`"
name: "analyze_and_format; linux; Dart 3.6.0-198.0.dev; PKGS: pkgs/_analyzer_macros, pkgs/_cfe_macros, pkgs/_macro_builder, pkgs/_macro_client, pkgs/_macro_host, pkgs/_macro_runner, pkgs/_macro_server, pkgs/_macro_tool, pkgs/_test_macros, pkgs/dart_model, pkgs/macro, pkgs/macro_service, tool/dart_model_generator; `dart analyze --fatal-infos .`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0-198.0.dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator;commands:analyze"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0-198.0.dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_macro_tool-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator;commands:analyze"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0-198.0.dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator
os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0-198.0.dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_macro_tool-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator
os:ubuntu-latest;pub-cache-hosted;sdk:3.6.0-198.0.dev
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
Expand Down Expand Up @@ -121,6 +121,15 @@ jobs:
run: dart analyze --fatal-infos .
if: "always() && steps.pkgs__macro_server_pub_upgrade.conclusion == 'success'"
working-directory: pkgs/_macro_server
- id: pkgs__macro_tool_pub_upgrade
name: pkgs/_macro_tool; dart pub upgrade
run: dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: pkgs/_macro_tool
- name: "pkgs/_macro_tool; dart analyze --fatal-infos ."
run: dart analyze --fatal-infos .
if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'"
working-directory: pkgs/_macro_tool
- id: pkgs__test_macros_pub_upgrade
name: pkgs/_test_macros; dart pub upgrade
run: dart pub upgrade
Expand Down Expand Up @@ -167,16 +176,16 @@ jobs:
if: "always() && steps.tool_dart_model_generator_pub_upgrade.conclusion == 'success'"
working-directory: tool/dart_model_generator
job_003:
name: "analyze_and_format; linux; Dart dev; PKGS: pkgs/_analyzer_macros, pkgs/_macro_builder, pkgs/_macro_client, pkgs/_macro_host, pkgs/_macro_runner, pkgs/_macro_server, pkgs/_test_macros, pkgs/dart_model, pkgs/macro, pkgs/macro_service, tool/dart_model_generator; `dart analyze --fatal-infos .`"
name: "analyze_and_format; linux; Dart dev; PKGS: pkgs/_analyzer_macros, pkgs/_macro_builder, pkgs/_macro_client, pkgs/_macro_host, pkgs/_macro_runner, pkgs/_macro_server, pkgs/_macro_tool, pkgs/_test_macros, pkgs/dart_model, pkgs/macro, pkgs/macro_service, tool/dart_model_generator; `dart analyze --fatal-infos .`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator;commands:analyze"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_macro_tool-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator;commands:analyze"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_macro_tool-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator
os:ubuntu-latest;pub-cache-hosted;sdk:dev
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
Expand Down Expand Up @@ -241,6 +250,15 @@ jobs:
run: dart analyze --fatal-infos .
if: "always() && steps.pkgs__macro_server_pub_upgrade.conclusion == 'success'"
working-directory: pkgs/_macro_server
- id: pkgs__macro_tool_pub_upgrade
name: pkgs/_macro_tool; dart pub upgrade
run: dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: pkgs/_macro_tool
- name: "pkgs/_macro_tool; dart analyze --fatal-infos ."
run: dart analyze --fatal-infos .
if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'"
working-directory: pkgs/_macro_tool
- id: pkgs__test_macros_pub_upgrade
name: pkgs/_test_macros; dart pub upgrade
run: dart pub upgrade
Expand Down Expand Up @@ -287,16 +305,16 @@ jobs:
if: "always() && steps.tool_dart_model_generator_pub_upgrade.conclusion == 'success'"
working-directory: tool/dart_model_generator
job_004:
name: "analyze_and_format; linux; Dart dev; PKGS: pkgs/_analyzer_macros, pkgs/_cfe_macros, pkgs/_macro_builder, pkgs/_macro_client, pkgs/_macro_host, pkgs/_macro_runner, pkgs/_macro_server, pkgs/_test_macros, pkgs/dart_model, pkgs/macro, pkgs/macro_service, tool/dart_model_generator; `dart format --output=none --set-exit-if-changed .`"
name: "analyze_and_format; linux; Dart dev; PKGS: pkgs/_analyzer_macros, pkgs/_cfe_macros, pkgs/_macro_builder, pkgs/_macro_client, pkgs/_macro_host, pkgs/_macro_runner, pkgs/_macro_server, pkgs/_macro_tool, pkgs/_test_macros, pkgs/dart_model, pkgs/macro, pkgs/macro_service, tool/dart_model_generator; `dart format --output=none --set-exit-if-changed .`"
runs-on: ubuntu-latest
steps:
- name: Cache Pub hosted dependencies
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: "~/.pub-cache/hosted"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator;commands:format"
key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_macro_tool-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator;commands:format"
restore-keys: |
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator
os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros-pkgs/_cfe_macros-pkgs/_macro_builder-pkgs/_macro_client-pkgs/_macro_host-pkgs/_macro_runner-pkgs/_macro_server-pkgs/_macro_tool-pkgs/_test_macros-pkgs/dart_model-pkgs/macro-pkgs/macro_service-tool/dart_model_generator
os:ubuntu-latest;pub-cache-hosted;sdk:dev
os:ubuntu-latest;pub-cache-hosted
os:ubuntu-latest
Expand Down Expand Up @@ -370,6 +388,15 @@ jobs:
run: "dart format --output=none --set-exit-if-changed ."
if: "always() && steps.pkgs__macro_server_pub_upgrade.conclusion == 'success'"
working-directory: pkgs/_macro_server
- id: pkgs__macro_tool_pub_upgrade
name: pkgs/_macro_tool; dart pub upgrade
run: dart pub upgrade
if: "always() && steps.checkout.conclusion == 'success'"
working-directory: pkgs/_macro_tool
- name: "pkgs/_macro_tool; dart format --output=none --set-exit-if-changed ."
run: "dart format --output=none --set-exit-if-changed ."
if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'"
working-directory: pkgs/_macro_tool
- id: pkgs__test_macros_pub_upgrade
name: pkgs/_test_macros; dart pub upgrade
run: dart pub upgrade
Expand Down
1 change: 1 addition & 0 deletions goldens/foo/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
analyzer:
enable-experiment:
- enhanced-parts
- macros
2 changes: 2 additions & 0 deletions goldens/foo/lib/declare_x.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ import 'package:_test_macros/declare_x_macro.dart';

@DeclareX()
class Foo {}

void main() => print(Foo().x);
37 changes: 37 additions & 0 deletions pkgs/_macro_tool/bin/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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 'dart:io';

import 'package:_macro_tool/macro_tool.dart';
import 'package:args/args.dart';
import 'package:path/path.dart' as p;

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

Future<void> main(List<String> arguments) async {
final args = argParser.parse(arguments);
final workspace = args['workspace'] as String?;
final packageConfig = args['packageConfig'] as String?;
final script = args['script'] as String?;

if (workspace == null || packageConfig == null || script == null) {
print('''
Runs a Dart script with `dart_model` macros.
${argParser.usage}''');
exit(1);
}

final tool = MacroTool(
workspacePath: p.canonicalize(workspace),
packageConfigPath: p.canonicalize(packageConfig),
scriptPath: p.canonicalize(script),
skipCleanup: args['skip-cleanup'] as bool);
await tool.run();
}
152 changes: 152 additions & 0 deletions pkgs/_macro_tool/lib/macro_tool.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// 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 '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/src/summary2/macro_injected_impl.dart' as injected;
import 'package:macro_service/macro_service.dart';
import 'package:path/path.dart' as p;

class MacroTool {
String workspacePath;
String packageConfigPath;
String scriptPath;
bool skipCleanup;

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

Future<void> run() async {
print('Running ${p.basename(scriptPath)} with macros.');
print('~~~');
print('Package config: $packageConfigPath');
print('Workspace: $workspacePath');
print('Script: $scriptPath');

// TODO(davidmorgan): make it an option to run with the CFE instead.
if (!await _augmentUsingAnalyzer()) {
print('No augmentation was generated, nothing to do, exiting.');
exit(0);
}

_addImportAugment();

try {
print('~~~ running, output follows');
final result = Process.runSync(
Platform.resolvedExecutable,
[
'run',
'--enable-experiment=macros',
'--enable-experiment=enhanced-parts',
'--packages=$packageConfigPath',
scriptPath
],
workingDirectory: workspacePath,
);
stdout.write(result.stdout);
stderr.write(result.stderr);
exitCode = result.exitCode;
} finally {
if (skipCleanup) {
print('~~~ done running, skipping cleanup because --skip-cleanup');
} else {
print('~~~ done running, cleanup follows');
_removeImportAugment();
_removeAugmentations();
}
}

// The analyzer seems to prevent exit.
exit(0);
}

/// The path where macro-generated augmentations will be written.
String get _augmentationFilePath => '$scriptPath.macro_tool_output';

/// Runs macros in [scriptFile].
///
/// Writes any augmentation to [_augmentationFilePath].
///
/// Returns whether an augmentation file was written.
Future<bool> _augmentUsingAnalyzer() async {
final scriptUri = Directory.current.uri.resolve(scriptPath);
final contextCollection =
AnalysisContextCollection(includedPaths: [workspacePath]);
final analysisContext = contextCollection.contexts.first;
injected.macroImplementation = await AnalyzerMacroImplementation.start(
protocol: Protocol(
encoding: ProtocolEncoding.binary,
version: ProtocolVersion.macros1),
packageConfig: File(packageConfigPath).uri);

final resolvedLibrary = (await analysisContext.currentSession
.getResolvedLibrary(scriptUri.toFilePath())) as ResolvedLibraryResult;

final errors = (await analysisContext.currentSession
.getErrors(scriptUri.toFilePath())) as ErrorsResult;
if (errors.errors.isNotEmpty) {
print('Errors: ${errors.errors}');
}

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

print('Macro output (patched to use augment library): '
'$_augmentationFilePath');
File(_augmentationFilePath).writeAsStringSync(augmentationUnits
.first.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;
}

/// Deletes the augmentation file created by this tool.
void _removeAugmentations() {
final scriptUri = Directory.current.uri.resolve(scriptPath);
final out = scriptUri.toFilePath() + '.macro_tool_output';
print('Deleting: $out');
File(out).deleteSync();
}

/// The path where the script file will be backed up before modification.
String get _backupScriptPath => '$scriptPath.backup';

/// Adds `import augment` of the augmentation file.
///
/// When macros run in the analyzer or CFE this inclusion of the augmentation
/// output is automatic, but for `macro_tool` it has to be patched in.
void _addImportAugment() {
print('Patching to import augmentations: $scriptPath');
final file = File(scriptPath);
// Back up the unmodified file for [_removeImportAugment].
file.copySync(_backupScriptPath);

final partName = p.basename(_augmentationFilePath);
final line = "import augment '$partName'; // added by macro_tool";
final lines = file.readAsLinesSync();
final lastImport = lines.lastIndexWhere((l) => l.startsWith('import'));

final insertAt = lastImport == -1 ? 0 : lastImport + 1;
lines.insert(insertAt, line);
file.writeAsStringSync(lines.map((l) => l + '\n').join());
}

/// Reverts the script file.
void _removeImportAugment() {
print('Reverting: $scriptPath');
File(_backupScriptPath).renameSync(scriptPath);
}
}
10 changes: 10 additions & 0 deletions pkgs/_macro_tool/mono_pkg.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
sdk:
- pubspec
- dev

stages:
- analyze_and_format:
- analyze: --fatal-infos .
- format:
sdk:
- dev
14 changes: 14 additions & 0 deletions pkgs/_macro_tool/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: _macro_tool
publish-to: none
description: >-
CLI for running macros and for building code with macros applied.
resolution: workspace
environment:
sdk: ^3.6.0-198.0.dev

dependencies:
_analyzer_macros: any

dev_dependencies:
dart_flutter_team_lints: ^3.0.0
test: ^1.25.7
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ workspace:
- pkgs/_macro_host
- pkgs/_macro_runner
- pkgs/_macro_server
- pkgs/_macro_tool
- pkgs/_test_macros
- pkgs/dart_model
- pkgs/macro
Expand Down

0 comments on commit cbf0013

Please sign in to comment.