From a4a47ead63ceeabab3d90da5fb274a1ba4acae44 Mon Sep 17 00:00:00 2001 From: David Morgan Date: Wed, 6 Nov 2024 09:43:32 +0100 Subject: [PATCH] Improvements to macro_tool for benchmarking. Split functionality into explicit "commands", add patching for analyzer for benchmarking as an alternative to patching for CFE for running, add benchmarking. --- .github/workflows/dart.yml | 216 +++++++++--- pkgs/_macro_tool/README.md | 71 +++- pkgs/_macro_tool/bin/main.dart | 41 +-- .../lib/analyzer_macro_runner.dart | 89 +++++ pkgs/_macro_tool/lib/analyzer_macro_tool.dart | 88 ----- pkgs/_macro_tool/lib/cfe_macro_runner.dart | 109 ++++++ pkgs/_macro_tool/lib/cfe_macro_tool.dart | 87 ----- pkgs/_macro_tool/lib/macro_runner.dart | 60 ++++ pkgs/_macro_tool/lib/macro_tool.dart | 309 +++++++++++------- pkgs/_macro_tool/lib/main.dart | 102 ++++++ pkgs/_macro_tool/lib/source_file.dart | 100 ++++++ pkgs/_macro_tool/mono_pkg.yaml | 6 + pkgs/_macro_tool/test/macro_runner_test.dart | 46 +++ pkgs/_macro_tool/test/macro_tool_test.dart | 45 +++ .../package_under_test/analysis_options.yaml | 3 + .../lib/apply_declare_x.dart | 19 ++ .../lib/apply_query_class.dart | 11 + .../test/package_under_test/pubspec.yaml | 9 + pubspec.yaml | 1 + .../lib/json_encodable/input_generator.dart | 19 +- tool/benchmark_generator/lib/random.dart | 9 - tool/ci.sh | 6 +- tool/run_e2e_tests.sh | 5 +- 23 files changed, 1036 insertions(+), 415 deletions(-) create mode 100644 pkgs/_macro_tool/lib/analyzer_macro_runner.dart delete mode 100644 pkgs/_macro_tool/lib/analyzer_macro_tool.dart create mode 100644 pkgs/_macro_tool/lib/cfe_macro_runner.dart delete mode 100644 pkgs/_macro_tool/lib/cfe_macro_tool.dart create mode 100644 pkgs/_macro_tool/lib/macro_runner.dart create mode 100644 pkgs/_macro_tool/lib/main.dart create mode 100644 pkgs/_macro_tool/lib/source_file.dart create mode 100644 pkgs/_macro_tool/test/macro_runner_test.dart create mode 100644 pkgs/_macro_tool/test/macro_tool_test.dart create mode 100644 pkgs/_macro_tool/test/package_under_test/analysis_options.yaml create mode 100644 pkgs/_macro_tool/test/package_under_test/lib/apply_declare_x.dart create mode 100644 pkgs/_macro_tool/test/package_under_test/lib/apply_query_class.dart create mode 100644 pkgs/_macro_tool/test/package_under_test/pubspec.yaml delete mode 100644 tool/benchmark_generator/lib/random.dart diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index aaaf4eb4..fdd3143a 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -530,7 +530,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_analyzer_cfe_macros;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_analyzer_cfe_macros;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_analyzer_cfe_macros os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -565,7 +565,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_analyzer_macros;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_analyzer_macros;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_analyzer_macros os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -600,7 +600,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_cfe_macros;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_cfe_macros;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_cfe_macros os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -635,7 +635,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_builder;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_builder;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_builder os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -670,7 +670,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_client;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_client;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_client os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -705,7 +705,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_host;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_host;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_host os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -740,7 +740,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_runner;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_runner;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_runner os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -775,7 +775,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_server;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_server;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_server os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -810,7 +810,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/macro_service;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/macro_service;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/macro_service os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -845,7 +845,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:tool/dart_model_generator;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:tool/dart_model_generator;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:tool/dart_model_generator os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev @@ -873,6 +873,41 @@ jobs: - job_003 - job_004 job_016: + name: "unit_test; linux; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_tool; `dart test --test-randomize-ordering-seed=random --concurrency=1`" + runs-on: ubuntu-latest + steps: + - name: Cache Pub hosted dependencies + uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a + with: + path: "~/.pub-cache/hosted" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_tool;commands:test_1" + restore-keys: | + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev;packages:pkgs/_macro_tool + os:ubuntu-latest;pub-cache-hosted;sdk:3.7.0-39.0.dev + os:ubuntu-latest;pub-cache-hosted + os:ubuntu-latest + - name: Setup Dart SDK + uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + with: + sdk: "3.7.0-39.0.dev" + - id: checkout + name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - 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 test --test-randomize-ordering-seed=random --concurrency=1" + run: "dart test --test-randomize-ordering-seed=random --concurrency=1" + if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/_macro_tool + needs: + - job_001 + - job_002 + - job_003 + - job_004 + job_017: name: "unit_test; linux; Dart 3.7.0-39.0.dev; PKG: pkgs/dart_model; `dart -Ddebug_json_buffer=true test --test-randomize-ordering-seed=random -c source`" runs-on: ubuntu-latest steps: @@ -907,7 +942,7 @@ jobs: - job_002 - job_003 - job_004 - job_017: + job_018: name: "unit_test; linux; Dart dev; PKG: goldens/foo; `../../tool/run_e2e_tests.sh`" runs-on: ubuntu-latest steps: @@ -942,7 +977,7 @@ jobs: - job_002 - job_003 - job_004 - job_018: + job_019: name: "unit_test; linux; Dart dev; PKG: pkgs/_analyzer_macros; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -950,7 +985,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_analyzer_macros os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -977,7 +1012,7 @@ jobs: - job_002 - job_003 - job_004 - job_019: + job_020: name: "unit_test; linux; Dart dev; PKG: pkgs/_macro_builder; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -985,7 +1020,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_builder;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_builder;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_builder os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1012,7 +1047,7 @@ jobs: - job_002 - job_003 - job_004 - job_020: + job_021: name: "unit_test; linux; Dart dev; PKG: pkgs/_macro_client; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -1020,7 +1055,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_client;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_client;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_client os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1047,7 +1082,7 @@ jobs: - job_002 - job_003 - job_004 - job_021: + job_022: name: "unit_test; linux; Dart dev; PKG: pkgs/_macro_host; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -1055,7 +1090,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_host;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_host;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_host os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1082,7 +1117,7 @@ jobs: - job_002 - job_003 - job_004 - job_022: + job_023: name: "unit_test; linux; Dart dev; PKG: pkgs/_macro_runner; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -1090,7 +1125,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_runner;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_runner;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_runner os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1117,7 +1152,7 @@ jobs: - job_002 - job_003 - job_004 - job_023: + job_024: name: "unit_test; linux; Dart dev; PKG: pkgs/_macro_server; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -1125,7 +1160,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_server;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_server;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_server os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1152,7 +1187,7 @@ jobs: - job_002 - job_003 - job_004 - job_024: + job_025: name: "unit_test; linux; Dart dev; PKG: pkgs/macro_service; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -1160,7 +1195,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/macro_service;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/macro_service;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/macro_service os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1187,7 +1222,7 @@ jobs: - job_002 - job_003 - job_004 - job_025: + job_026: name: "unit_test; linux; Dart dev; PKG: tool/dart_model_generator; `dart test --test-randomize-ordering-seed=random`" runs-on: ubuntu-latest steps: @@ -1195,7 +1230,7 @@ jobs: uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a with: path: "~/.pub-cache/hosted" - key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:tool/dart_model_generator;commands:test" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:tool/dart_model_generator;commands:test_0" restore-keys: | os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:tool/dart_model_generator os:ubuntu-latest;pub-cache-hosted;sdk:dev @@ -1222,7 +1257,42 @@ jobs: - job_002 - job_003 - job_004 - job_026: + job_027: + name: "unit_test; linux; Dart dev; PKG: pkgs/_macro_tool; `dart test --test-randomize-ordering-seed=random --concurrency=1`" + runs-on: ubuntu-latest + steps: + - name: Cache Pub hosted dependencies + uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a + with: + path: "~/.pub-cache/hosted" + key: "os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_tool;commands:test_1" + restore-keys: | + os:ubuntu-latest;pub-cache-hosted;sdk:dev;packages:pkgs/_macro_tool + os:ubuntu-latest;pub-cache-hosted;sdk:dev + os:ubuntu-latest;pub-cache-hosted + os:ubuntu-latest + - name: Setup Dart SDK + uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + with: + sdk: dev + - id: checkout + name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - 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 test --test-randomize-ordering-seed=random --concurrency=1" + run: "dart test --test-randomize-ordering-seed=random --concurrency=1" + if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/_macro_tool + needs: + - job_001 + - job_002 + - job_003 + - job_004 + job_028: name: "unit_test; linux; Dart dev; PKG: pkgs/dart_model; `dart -Ddebug_json_buffer=true test --test-randomize-ordering-seed=random -c source`" runs-on: ubuntu-latest steps: @@ -1257,7 +1327,7 @@ jobs: - job_002 - job_003 - job_004 - job_027: + job_029: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_analyzer_cfe_macros; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1282,7 +1352,7 @@ jobs: - job_002 - job_003 - job_004 - job_028: + job_030: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_analyzer_macros; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1307,7 +1377,7 @@ jobs: - job_002 - job_003 - job_004 - job_029: + job_031: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_cfe_macros; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1332,7 +1402,7 @@ jobs: - job_002 - job_003 - job_004 - job_030: + job_032: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_builder; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1357,7 +1427,7 @@ jobs: - job_002 - job_003 - job_004 - job_031: + job_033: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_client; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1382,7 +1452,7 @@ jobs: - job_002 - job_003 - job_004 - job_032: + job_034: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_host; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1407,7 +1477,7 @@ jobs: - job_002 - job_003 - job_004 - job_033: + job_035: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_runner; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1432,7 +1502,7 @@ jobs: - job_002 - job_003 - job_004 - job_034: + job_036: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_server; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1457,7 +1527,7 @@ jobs: - job_002 - job_003 - job_004 - job_035: + job_037: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/macro_service; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1482,7 +1552,7 @@ jobs: - job_002 - job_003 - job_004 - job_036: + job_038: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: tool/dart_model_generator; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1507,7 +1577,32 @@ jobs: - job_002 - job_003 - job_004 - job_037: + job_039: + name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/_macro_tool; `dart test --test-randomize-ordering-seed=random --concurrency=1`" + runs-on: windows-latest + steps: + - name: Setup Dart SDK + uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + with: + sdk: "3.7.0-39.0.dev" + - id: checkout + name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - 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 test --test-randomize-ordering-seed=random --concurrency=1" + run: "dart test --test-randomize-ordering-seed=random --concurrency=1" + if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/_macro_tool + needs: + - job_001 + - job_002 + - job_003 + - job_004 + job_040: name: "unit_test; windows; Dart 3.7.0-39.0.dev; PKG: pkgs/dart_model; `dart -Ddebug_json_buffer=true test --test-randomize-ordering-seed=random -c source`" runs-on: windows-latest steps: @@ -1532,7 +1627,7 @@ jobs: - job_002 - job_003 - job_004 - job_038: + job_041: name: "unit_test; windows; Dart dev; PKG: pkgs/_analyzer_macros; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1557,7 +1652,7 @@ jobs: - job_002 - job_003 - job_004 - job_039: + job_042: name: "unit_test; windows; Dart dev; PKG: pkgs/_macro_builder; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1582,7 +1677,7 @@ jobs: - job_002 - job_003 - job_004 - job_040: + job_043: name: "unit_test; windows; Dart dev; PKG: pkgs/_macro_client; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1607,7 +1702,7 @@ jobs: - job_002 - job_003 - job_004 - job_041: + job_044: name: "unit_test; windows; Dart dev; PKG: pkgs/_macro_host; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1632,7 +1727,7 @@ jobs: - job_002 - job_003 - job_004 - job_042: + job_045: name: "unit_test; windows; Dart dev; PKG: pkgs/_macro_runner; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1657,7 +1752,7 @@ jobs: - job_002 - job_003 - job_004 - job_043: + job_046: name: "unit_test; windows; Dart dev; PKG: pkgs/_macro_server; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1682,7 +1777,7 @@ jobs: - job_002 - job_003 - job_004 - job_044: + job_047: name: "unit_test; windows; Dart dev; PKG: pkgs/macro_service; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1707,7 +1802,7 @@ jobs: - job_002 - job_003 - job_004 - job_045: + job_048: name: "unit_test; windows; Dart dev; PKG: tool/dart_model_generator; `dart test --test-randomize-ordering-seed=random`" runs-on: windows-latest steps: @@ -1732,7 +1827,32 @@ jobs: - job_002 - job_003 - job_004 - job_046: + job_049: + name: "unit_test; windows; Dart dev; PKG: pkgs/_macro_tool; `dart test --test-randomize-ordering-seed=random --concurrency=1`" + runs-on: windows-latest + steps: + - name: Setup Dart SDK + uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 + with: + sdk: dev + - id: checkout + name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - 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 test --test-randomize-ordering-seed=random --concurrency=1" + run: "dart test --test-randomize-ordering-seed=random --concurrency=1" + if: "always() && steps.pkgs__macro_tool_pub_upgrade.conclusion == 'success'" + working-directory: pkgs/_macro_tool + needs: + - job_001 + - job_002 + - job_003 + - job_004 + job_050: name: "unit_test; windows; Dart dev; PKG: pkgs/dart_model; `dart -Ddebug_json_buffer=true test --test-randomize-ordering-seed=random -c source`" runs-on: windows-latest steps: diff --git a/pkgs/_macro_tool/README.md b/pkgs/_macro_tool/README.md index d2580045..c80f06f5 100644 --- a/pkgs/_macro_tool/README.md +++ b/pkgs/_macro_tool/README.md @@ -1,15 +1,74 @@ -A tool for running macro examples end to end. +# macro_tool -## Example usage +A tool for running and benchmarking with macros. -The following will run the json_codable example, assuming you start at the root -of this repo: +Specify a list of commands in addition to options: + + apply: runs macros, outputs to disk + patch_for_analyzer: fixes macro output for the analyzer + patch_for_cfe: fixes macro output for the CFE + run: runs the specified script + revert: reverts patches to files + benchmark_apply: benchmarks applying macros + benchmark_analyze: benchmarks analyzing macros + bust_caches: modifies files like the benchmarks do + watch: loops watching for changes to the specified script and applying + +## Examples + +All examples are run from the root of this repo. + +Benchmarks required that you first create sources to benchmark with: + +```bash +dart tool/benchmark_generator/bin/main.dart large macro 16 +``` + +Benchmark running macros: + +```bash +dart pkgs/_macro_tool/bin/main.dart \ + --workspace=goldens/foo/lib/generated/large \ + --packageConfig=.dart_tool/package_config.json \ + benchmark_apply +``` + +Benchmark analysis on macro output without running macros: + +```bash +dart pkgs/_macro_tool/bin/main.dart \ + --workspace=goldens/foo/lib/generated/large \ + --packageConfig=.dart_tool/package_config.json \ + apply patch_for_analyzer benchmark_analyze revert +``` + +Run a script with macros: ```bash dart pkgs/_macro_tool/bin/main.dart \ --workspace=goldens/foo \ --packageConfig=.dart_tool/package_config.json \ - --script=goldens/foo/lib/json_codable_test.dart + --script=goldens/foo/lib/json_codable_test.dart \ + apply patch_for_cfe run revert ``` -You can also enable watch mode using `--watch`. +Watch for changes to a script, applying macros when it changes, writing the +output to disk and reporting how long it took: + +```bash +dart pkgs/_macro_tool/bin/main.dart \ + --workspace=goldens/foo \ + --packageConfig=.dart_tool/package_config.json \ + --script=goldens/foo/lib/json_codable_test.dart \ + watch +``` + +Clean up output after using `watch`: + +```bash +dart pkgs/_macro_tool/bin/main.dart \ + --workspace=goldens/foo \ + --packageConfig=.dart_tool/package_config.json \ + --script=goldens/foo/lib/json_codable_test.dart \ + revert +``` diff --git a/pkgs/_macro_tool/bin/main.dart b/pkgs/_macro_tool/bin/main.dart index a8bb4b26..a6c3b54d 100644 --- a/pkgs/_macro_tool/bin/main.dart +++ b/pkgs/_macro_tool/bin/main.dart @@ -4,45 +4,8 @@ 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('host', - defaultsTo: 'analyzer', help: 'The macro host: "analyzer" or "cfe".') - ..addOption('workspace', help: 'Path to workspace.') - ..addOption('packageConfig', help: 'Path to package config.') - ..addOption('script', help: 'Path to script.') - ..addFlag('skip-cleanup', - help: 'Whether to skip delete of augmentations and revert of script.') - ..addFlag('watch', help: 'Whether to watch for changes.'); +import 'package:_macro_tool/main.dart' as macro_tool; Future main(List arguments) async { - final args = argParser.parse(arguments); - - final host = HostOption.forString(args['host'] as String?); - final workspace = args['workspace'] as String?; - final packageConfig = args['packageConfig'] as String?; - final script = args['script'] as String?; - - if (host == null || - workspace == null || - packageConfig == null || - script == null) { - print(''' -Runs a Dart script with `dart_model` macros. - -${argParser.usage}'''); - exit(1); - } - - final tool = MacroTool( - host: host, - workspacePath: p.canonicalize(workspace), - packageConfigPath: p.canonicalize(packageConfig), - scriptPath: p.canonicalize(script), - skipCleanup: args['skip-cleanup'] as bool, - watch: args['watch'] as bool); - await tool.run(); + exit(await macro_tool.main(arguments)); } diff --git a/pkgs/_macro_tool/lib/analyzer_macro_runner.dart b/pkgs/_macro_tool/lib/analyzer_macro_runner.dart new file mode 100644 index 00000000..0da76ade --- /dev/null +++ b/pkgs/_macro_tool/lib/analyzer_macro_runner.dart @@ -0,0 +1,89 @@ +// 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.dart'; +import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; +import 'package:analyzer/dart/analysis/results.dart' hide FileResult; +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'; + +import 'macro_runner.dart'; +import 'source_file.dart'; + +class AnalyzerMacroRunner implements MacroRunner { + final String workspacePath; + final String packageConfigPath; + + @override + final List sourceFiles; + + late final AnalysisContext analysisContext; + AnalyzerMacroImplementation? analyzerMacroImplementation; + + AnalyzerMacroRunner( + {required this.workspacePath, required this.packageConfigPath}) + : sourceFiles = Directory(workspacePath) + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart')) + .map((f) => SourceFile(f.path)) + .toList() { + final contextCollection = + AnalysisContextCollection(includedPaths: [workspacePath]); + analysisContext = contextCollection.contexts.first; + } + + void notifyChange(SourceFile sourceFile) { + analysisContext.changeFile(sourceFile.path); + } + + @override + Future run({bool injectImplementation = true}) async { + if (injectImplementation) { + analyzerMacroImplementation ??= await AnalyzerMacroImplementation.start( + protocol: Protocol( + encoding: ProtocolEncoding.binary, + version: ProtocolVersion.macros1), + packageConfig: Uri.file(packageConfigPath)); + injected_analyzer.macroImplementation = analyzerMacroImplementation; + } else { + injected_analyzer.macroImplementation = null; + } + + final fileResults = []; + final stopwatch = Stopwatch()..start(); + Duration? firstDuration; + for (final sourceFile in sourceFiles) { + await analysisContext.applyPendingFileChanges(); + ResolvedLibraryResult resolvedLibrary = + (await analysisContext.currentSession.getResolvedLibrary(sourceFile)) + as ResolvedLibraryResult; + + final errors = ((await analysisContext.currentSession + .getErrors(sourceFile)) as ErrorsResult) + .errors + .where((e) => e.severity == Severity.error) + .map((e) => e.toString()) + .toList(); + + final augmentationUnits = + resolvedLibrary.units.where((u) => u.isMacroPart).toList(); + final output = augmentationUnits.singleOrNull?.content; + + fileResults.add( + FileResult(sourceFile: sourceFile, output: output, errors: errors)); + if (firstDuration == null) firstDuration = stopwatch.elapsed; + } + + return WorkspaceResult( + fileResults: fileResults, + firstResultAfter: firstDuration!, + lastResultAfter: stopwatch.elapsed); + } +} diff --git a/pkgs/_macro_tool/lib/analyzer_macro_tool.dart b/pkgs/_macro_tool/lib/analyzer_macro_tool.dart deleted file mode 100644 index c5695fd4..00000000 --- a/pkgs/_macro_tool/lib/analyzer_macro_tool.dart +++ /dev/null @@ -1,88 +0,0 @@ -// 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/diagnostic/diagnostic.dart'; -import 'package:analyzer/src/summary2/macro_injected_impl.dart' - as injected_analyzer; -import 'package:macro_service/macro_service.dart'; - -import 'macro_tool.dart'; - -class AnalyzerMacroTool extends MacroTool { - AnalyzerMacroTool( - {required super.workspacePath, - required super.packageConfigPath, - required super.scriptPath, - required super.skipCleanup, - required super.watch}) - : super.internal(); - - /// Runs macros in [scriptFile] on the analyzer. - /// - /// Writes any augmentation to [_augmentationFilePath]. - /// - /// Returns whether an augmentation file was written. - @override - Future augment() async { - final contextCollection = - AnalysisContextCollection(includedPaths: [workspacePath]); - final analysisContext = contextCollection.contexts.first; - injected_analyzer.macroImplementation = - await AnalyzerMacroImplementation.start( - protocol: Protocol( - encoding: ProtocolEncoding.binary, - version: ProtocolVersion.macros1), - packageConfig: Uri.file(packageConfigPath)); - - 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; - 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; - } - - 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')); - - 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 - String toString() => 'analyzer'; -} diff --git a/pkgs/_macro_tool/lib/cfe_macro_runner.dart b/pkgs/_macro_tool/lib/cfe_macro_runner.dart new file mode 100644 index 00000000..79e99aee --- /dev/null +++ b/pkgs/_macro_tool/lib/cfe_macro_runner.dart @@ -0,0 +1,109 @@ +// 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:_cfe_macros/macro_implementation.dart'; +import 'package:front_end/src/macros/macro_injected_impl.dart' as injected_cfe; +import 'package:frontend_server/compute_kernel.dart'; +import 'package:macro_service/macro_service.dart'; +import 'package:path/path.dart' as p; + +import 'macro_runner.dart'; +import 'source_file.dart'; + +class CfeMacroRunner implements MacroRunner { + final String workspacePath; + final String packageConfigPath; + + @override + final List sourceFiles; + + CfeMacroImplementation? cfeMacroImplementation; + + CfeMacroRunner({required this.workspacePath, required this.packageConfigPath}) + : sourceFiles = Directory(workspacePath) + .listSync(recursive: true) + .whereType() + .where((f) => f.path.endsWith('.dart')) + .map((f) => SourceFile(f.path)) + .toList() {} + + void notifyChange(SourceFile sourceFile) { + throw UnimplementedError( + 'CfeMacroRunner does not support incremental compilation.'); + } + + File get _productPlatformDill { + // 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. + final result = File(p.canonicalize('${Platform.resolvedExecutable}/../../' + 'lib/_internal/vm_platform_strong_product.dill')); + if (!result.existsSync()) { + throw StateError('Failed to find platform dill: $result'); + } + return result; + } + + @override + Future run({bool injectImplementation = true}) async { + if (injectImplementation) { + cfeMacroImplementation ??= await CfeMacroImplementation.start( + protocol: Protocol( + encoding: ProtocolEncoding.json, + version: ProtocolVersion.macros1), + packageConfig: Uri.file(packageConfigPath)); + injected_cfe.macroImplementation = cfeMacroImplementation; + } else { + injected_cfe.macroImplementation = null; + } + + final fileResults = []; + final stopwatch = Stopwatch()..start(); + + // Don't directly use the compiler output: for consistency with the analyzer + // codepath, run from the resulting source. + // TODO(davidmorgan): maybe offer both as options? Not clear yet. + final outputFile = File('/dev/null'); + + final packagesUri = Uri.file(packageConfigPath); + + final computeKernelResult = await computeKernel([ + '--enable-experiment=macros', + '--no-summary', + '--no-summary-only', + '--target=vm', + '--dart-sdk-summary=${_productPlatformDill.uri}', + '--output=${outputFile.path}', + for (final sourceFile in sourceFiles) '--source=${Uri.file(sourceFile)}', + '--packages-file=$packagesUri', + // TODO(davidmorgan): this is so we can pull the generated + // augmentation source out of incremental compiler state; find a less + // hacky way. + '--use-incremental-compiler', + // For augmentations. + '--enable-experiment=macros', + ]); + + final sources = computeKernelResult + .previousState!.incrementalCompiler!.context.uriToSource; + + for (final sourceFile in sourceFiles) { + final macroSource = + sources[Uri.file(sourceFile.path).replace(scheme: 'dart-macro+file')]; + if (macroSource != null) { + fileResults.add(FileResult( + sourceFile: sourceFile, + output: macroSource.text, + errors: computeKernelResult.succeeded ? [] : ['compile failed'])); + } + } + + return WorkspaceResult( + fileResults: fileResults, + firstResultAfter: stopwatch.elapsed, + lastResultAfter: stopwatch.elapsed); + } +} diff --git a/pkgs/_macro_tool/lib/cfe_macro_tool.dart b/pkgs/_macro_tool/lib/cfe_macro_tool.dart deleted file mode 100644 index bb69cb61..00000000 --- a/pkgs/_macro_tool/lib/cfe_macro_tool.dart +++ /dev/null @@ -1,87 +0,0 @@ -// 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 'dart:isolate'; - -import 'package:_cfe_macros/macro_implementation.dart'; -import 'package:front_end/src/macros/macro_injected_impl.dart' as injected_cfe; -import 'package:frontend_server/compute_kernel.dart'; -import 'package:macro_service/macro_service.dart'; - -import 'macro_tool.dart'; - -class CfeMacroTool extends MacroTool { - CfeMacroTool( - {required super.workspacePath, - required super.packageConfigPath, - required super.scriptPath, - required super.skipCleanup, - required super.watch}) - : super.internal(); - - /// Runs macros in [scriptFile] using the CFE. - /// - /// Writes any augmentation to [augmentationFilePath]. - /// - /// Returns whether an augmentation file was written. - @override - Future 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. - final productPlatformDill = File('${Platform.resolvedExecutable}/../../' - 'lib/_internal/vm_platform_strong_product.dill'); - if (!File.fromUri(productPlatformDill.uri).existsSync()) { - throw StateError('Failed to find platform dill: $productPlatformDill'); - } - injected_cfe.macroImplementation = await CfeMacroImplementation.start( - protocol: Protocol( - encoding: ProtocolEncoding.json, version: ProtocolVersion.macros1), - packageConfig: Isolate.packageConfigSync!); - - final packagesUri = Isolate.packageConfigSync; - - // Don't directly use the compiler output: for consistency with the analyzer - // codepath, run from the resulting source. - // TODO(davidmorgan): maybe offer both as options? Not clear yet. - final outputFile = File('/dev/null'); - - final computeKernelResult = await computeKernel([ - '--enable-experiment=macros', - '--no-summary', - '--no-summary-only', - '--target=vm', - '--dart-sdk-summary=${productPlatformDill.uri}', - '--output=${outputFile.path}', - '--source=$scriptPath', - '--packages-file=$packagesUri', - // TODO(davidmorgan): this is so we can pull the generated - // augmentation source out of incremental compiler state; find a less - // hacky way. - '--use-incremental-compiler', - // For augmentations. - '--enable-experiment=macros', - ]); - - final sources = computeKernelResult - .previousState!.incrementalCompiler!.context.uriToSource; - final applicationMacroOutput = sources.entries - .where((e) => e.key.scheme == 'dart-macro+file') - .singleOrNull; - if (applicationMacroOutput == null) return false; - - print('Macro output: ' - '$augmentationFilePath'); - File(augmentationFilePath) - .writeAsStringSync(applicationMacroOutput.value.text); - - return true; - } - - @override - String toString() => 'CFE'; -} diff --git a/pkgs/_macro_tool/lib/macro_runner.dart b/pkgs/_macro_tool/lib/macro_runner.dart new file mode 100644 index 00000000..66d68579 --- /dev/null +++ b/pkgs/_macro_tool/lib/macro_runner.dart @@ -0,0 +1,60 @@ +// 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 'source_file.dart'; + +/// Runs macros. +abstract interface class MacroRunner { + /// Source files in the workspace. + List get sourceFiles; + + /// Runs macros in all files in the workspace, [sourceFiles]. + /// + /// Returns augmentations and errors for each file. + /// + /// [injectImplementation] controls whether the `dart_model` macro + /// implementation is injected. + Future run({bool injectImplementation = true}); + + /// Notifies the host that a file changed. + /// + /// Call this on changed files then call [run] again for an incremental run. + void notifyChange(SourceFile sourceFile); +} + +/// [MacroRunner] result for the whole workspace. +class WorkspaceResult { + /// Results per file. + List fileResults; + + /// Time taken to produce the first file result. + Duration firstResultAfter; + + /// Time taken to produce all results. + Duration lastResultAfter; + + WorkspaceResult( + {required this.fileResults, + required this.firstResultAfter, + required this.lastResultAfter}); + + /// Errors from all [FileResult]s. + List get allErrors => + [for (final result in fileResults) ...result.errors]; +} + +/// [MacroRunner] result for one file. +class FileResult { + /// The file. + final SourceFile sourceFile; + + /// Macro augmentation output, or `null` if there was no output. + final String? output; + + /// Errors for this file. + final List errors; + + FileResult( + {required this.sourceFile, required this.output, required this.errors}); +} diff --git a/pkgs/_macro_tool/lib/macro_tool.dart b/pkgs/_macro_tool/lib/macro_tool.dart index 5ac75056..60a7c947 100644 --- a/pkgs/_macro_tool/lib/macro_tool.dart +++ b/pkgs/_macro_tool/lib/macro_tool.dart @@ -4,147 +4,208 @@ import 'dart:io'; -import 'package:path/path.dart' as p; - -import 'analyzer_macro_tool.dart'; -import 'cfe_macro_tool.dart'; - -/// Runs a Dart script with `dart_model` macros. -abstract class MacroTool { - String workspacePath; - String packageConfigPath; - String scriptPath; - bool skipCleanup; - bool watch; - - MacroTool.internal( - {required this.workspacePath, - required this.packageConfigPath, - required this.scriptPath, - 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 watch}) => - host == HostOption.analyzer - ? AnalyzerMacroTool( - workspacePath: workspacePath, - packageConfigPath: packageConfigPath, - scriptPath: scriptPath, - skipCleanup: skipCleanup, - watch: watch) - : CfeMacroTool( - workspacePath: workspacePath, - packageConfigPath: packageConfigPath, - scriptPath: scriptPath, - skipCleanup: skipCleanup, - watch: watch); - - Future run() async { - print('Running ${p.basename(scriptPath)} with macros on $this.'); - 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 augment()) { - print('No augmentation was generated, nothing to do, exiting.'); - exit(1); +import 'macro_runner.dart'; +import 'source_file.dart'; + +/// Runs macros. +/// +/// Various functionality related to running macros. +class MacroTool { + final MacroRunner macroRunner; + final String packageConfigPath; + final String workspacePath; + final int benchmarkIterations; + final String? scriptPath; + + /// The most recent result from running macros. + WorkspaceResult? _applyResult; + + MacroTool({ + required this.macroRunner, + required this.packageConfigPath, + required this.workspacePath, + required this.benchmarkIterations, + this.scriptPath, + }); + + /// Runs macros. + /// + /// Throws `StateError` if there are any errors. + /// + /// Otherwise, writes macro augmentations next to each source file with the + /// extension `.macro_tool_output`. + Future apply() async { + _applyResult = await macroRunner.run(); + + if (_applyResult!.allErrors.isNotEmpty) { + throw StateError('Errors: ${_applyResult!.allErrors}'); } - _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( - '~~~ exit code $exitCode, skipping cleanup because --skip-cleanup'); - } else { - print('~~~ exit code $exitCode, cleanup follows'); - _removeImportAugment(); - _removeAugmentations(); + for (final result in _applyResult!.fileResults) { + if (result.output != null) { + result.sourceFile.writeOutput(result.output!); } } - - // The analyzer seems to prevent exit. - exit(exitCode); } - /// The path where macro-generated augmentations will be written. - String get augmentationFilePath => '$scriptPath.macro_tool_output'; - - /// Runs macros in [scriptFile] on the analyzer. + /// Patches source so the analyzer can analyze it without running macros. /// - /// Writes any augmentation to [augmentationFilePath]. + /// Adds a `part` statement where needed to include augmentation output by + /// `apply`. + void patchForAnalyzer() { + if (_applyResult == null) { + throw UnsupportedError( + '"patch_for_analyzer" command requires "apply" first.'); + } + + for (final result in _applyResult!.fileResults) { + if (result.output != null) { + result.sourceFile.patchForAnalyzer(); + } + } + } + + /// Patches source and augmentations so the CFE can run then without + /// running macros. /// - /// Returns whether an augmentation file was written. - Future augment(); + /// This means changing augmentations from using parts to library + /// augmentations and adding `import augment` as needed. + void patchForCfe() { + if (_applyResult == null) { + throw UnsupportedError('"patch_for_cfe" command requires "apply" first.'); + } - /// Deletes the augmentation file created by this tool. - void _removeAugmentations() { - print('Deleting: $augmentationFilePath'); - File(augmentationFilePath).deleteSync(); + for (final result in _applyResult!.fileResults) { + if (result.output != null) { + result.sourceFile.patchForCfe(); + } + } } - /// Adds `import augment` of the augmentation file. + /// Runs the script. /// - /// 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'); - - // Add the `import augment` statement at the start of the file. - final partName = p.basename(augmentationFilePath); - final line = "import augment '$partName'; $_addedMarker\n"; - - final file = File(scriptPath); - file.writeAsStringSync( - line + _removeToolAddedLinesFromSource(file.readAsStringSync())); + /// The process exit code becomes the tool exit code. + Future run() async { + if (scriptPath == null) { + throw UnsupportedError('"run" command requires "--script".'); + } + + 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); + return result.exitCode; } - /// Reverts the script file. - void _removeImportAugment() { - print('Reverting: $scriptPath'); - final file = File(scriptPath); - file.writeAsStringSync( - _removeToolAddedLinesFromSource(file.readAsStringSync())); + /// Reverts changes to source from any of [patchForAnalyzer], [patchForCfe] + /// and/or [bustCaches]. + void revert() { + for (final sourceFile in macroRunner.sourceFiles) { + sourceFile.revert(); + } } - /// Returns [source] with lines added by [_addImportAugment] removed. - String _removeToolAddedLinesFromSource(String source) => - source.split('\n').where((l) => !l.endsWith(_addedMarker)).join('\n'); -} + /// Benchmarks [apply]. + /// + /// Each [apply] returns two timings: the time to first result and the time + /// to last result. For the analyzer, this corresponds to analysis complete + /// for one file in the workspace and analysis complete for all files in the + /// workspace. + /// + /// Output is three sets of values separated by double commas: + /// + /// 1. Initial apply, first file time then last files time + /// 2. All non-initial applies first file times + /// 3. All non-initial applies last file times + Future benchmarkApply({bool injectImplementation = true}) async { + // Busts caches, applies, throws if error, returns result. + Future measure() async { + bustCaches(); + _applyResult = + await macroRunner.run(injectImplementation: injectImplementation); + if (_applyResult!.allErrors.isNotEmpty) { + throw StateError('Errors: ${_applyResult!.allErrors}'); + } + return _applyResult!; + } + + final initialResult = await measure(); + stdout.write('${initialResult.firstResultAfter.inMilliseconds},'); + stdout.write('${initialResult.lastResultAfter.inMilliseconds},'); + stdout.write(','); + + final subsequentResults = []; + for (var i = 0; i != benchmarkIterations; ++i) { + subsequentResults.add(await measure()); + stdout.write('${subsequentResults[i].firstResultAfter.inMilliseconds},'); + } + + for (var i = 0; i != benchmarkIterations; ++i) { + stdout.write(',${subsequentResults[i].lastResultAfter.inMilliseconds}'); + } + print(''); + } + + /// As [benchmarkApply] but without injecting the `data_model` macro + /// implementation. + Future benchmarkAnalyze() async { + await benchmarkApply(injectImplementation: false); + } -final String _addedMarker = '// added by macro_tool'; + /// Modifies source to avoid cached results, for benchmarking. + /// + /// Modifies files with `CACHEBUSTER`. Throws if not found in any source. + void bustCaches() { + var cacheBusterFound = false; + for (final sourceFile in macroRunner.sourceFiles) { + if (sourceFile.bustCaches()) { + cacheBusterFound = true; + // Notify the macro runner of the change so that it will be picked up + // by the next incremental run. + macroRunner.notifyChange(sourceFile); + } + } + if (!cacheBusterFound) { + throw StateError( + 'Did not find CACHEBUSTER in any source, no changes were made.'); + } + } -enum HostOption { - analyzer, - cfe; + /// Loops watching for changes to [scriptPath] and applying after every change. + Future watch() async { + if (scriptPath == null) { + throw UnsupportedError('"watch" command requires "--script".'); + } + // `asBroadcastStream` so repeated use of `first` below waits for the next + // change. + var events = File(scriptPath!).watch().asBroadcastStream(); + print('Watching for changes to: $scriptPath'); + while (true) { + _applyResult = await macroRunner.run(); + for (final result in _applyResult!.fileResults) { + if (result.output != null) { + result.sourceFile.writeOutput(result.output!); + } + } + if (_applyResult!.allErrors.isNotEmpty) { + print('Errors: ${_applyResult!.allErrors}'); + } - static HostOption? forString(String? option) => switch (option) { - 'analyzer' => HostOption.analyzer, - 'cfe' => HostOption.cfe, - _ => null, - }; + stdout.write( + 'Macros ran in in ${_applyResult!.firstResultAfter.inMilliseconds}ms,' + ' watching...'); + await events.first; + print('changed, rerunning.'); + macroRunner.notifyChange(SourceFile(scriptPath!)); + } + } } diff --git a/pkgs/_macro_tool/lib/main.dart b/pkgs/_macro_tool/lib/main.dart new file mode 100644 index 00000000..6fb8bfef --- /dev/null +++ b/pkgs/_macro_tool/lib/main.dart @@ -0,0 +1,102 @@ +// 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:args/args.dart'; +import 'package:path/path.dart' as p; + +import 'analyzer_macro_runner.dart'; +import 'cfe_macro_runner.dart'; +import 'macro_tool.dart'; + +final argParser = ArgParser() + ..addOption('host', + defaultsTo: 'analyzer', help: 'The macro host: "analyzer" or "cfe".') + ..addOption('workspace', help: 'Path to workspace.') + ..addOption('packageConfig', help: 'Path to package config.') + ..addOption('script', help: 'Path to script.') + ..addOption('benchmark-iterations', + defaultsTo: '5', help: 'Benchmark iterations.'); + +Future main(List arguments) async { + final args = argParser.parse(arguments); + final commands = args.rest; + + final host = HostOption.forString(args['host'] as String?); + final workspace = args['workspace'] as String?; + final packageConfig = args['packageConfig'] as String?; + final script = args['script'] as String?; + + if (host == null || + workspace == null || + packageConfig == null || + commands.isEmpty) { + print(''' +Runs a Dart script with `dart_model` macros. + +Usage: after the options, pass a list of commands. See `README.md` for +commands and examples. + +${argParser.usage}'''); + return 1; + } + + final canonicalizedPackageConfig = p.canonicalize(packageConfig); + final canonicalizedWorkspace = p.canonicalize(workspace); + + final tool = MacroTool( + macroRunner: host == HostOption.analyzer + ? AnalyzerMacroRunner( + packageConfigPath: canonicalizedPackageConfig, + workspacePath: canonicalizedWorkspace, + ) + : CfeMacroRunner( + packageConfigPath: canonicalizedPackageConfig, + workspacePath: canonicalizedWorkspace, + ), + packageConfigPath: canonicalizedPackageConfig, + workspacePath: canonicalizedWorkspace, + benchmarkIterations: int.parse(args['benchmark-iterations']), + scriptPath: script == null ? null : p.canonicalize(script), + ); + + var exitCode = 0; + for (final command in commands) { + switch (command) { + case 'apply': + await tool.apply(); + case 'patch_for_analyzer': + tool.patchForAnalyzer(); + case 'patch_for_cfe': + tool.patchForCfe(); + case 'run': + exitCode = await tool.run(); + case 'revert': + tool.revert(); + case 'benchmark_apply': + await tool.benchmarkApply(); + case 'benchmark_analyze': + await tool.benchmarkAnalyze(); + case 'bust_caches': + tool.bustCaches(); + case 'watch': + await tool.watch(); + default: + print('Unknown command: $command'); + return 1; + } + } + + return exitCode; +} + +enum HostOption { + analyzer, + cfe; + + static HostOption? forString(String? option) => switch (option) { + 'analyzer' => HostOption.analyzer, + 'cfe' => HostOption.cfe, + _ => throw ArgumentError('Not a valid host: $option'), + }; +} diff --git a/pkgs/_macro_tool/lib/source_file.dart b/pkgs/_macro_tool/lib/source_file.dart new file mode 100644 index 00000000..f2f37d4c --- /dev/null +++ b/pkgs/_macro_tool/lib/source_file.dart @@ -0,0 +1,100 @@ +// 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 'dart:math'; + +import 'package:path/path.dart' as p; + +final _random = Random.secure(); + +extension type SourceFile(String path) implements String { + static const _addedMarker = '// added by macro_tool'; + static final _cacheBusterString = 'CACHEBUSTER'; + static final _cacheBusterRegexp = RegExp('$_cacheBusterString[a-z0-9]*'); + + /// The source file path plus `.macro_tool_output`. + String get toolOutputPath => '$path.macro_tool_output'; + + /// Writes [output] to [toolOutputPath]. + void writeOutput(String output) { + File(toolOutputPath).writeAsStringSync(output); + } + + void patchForAnalyzer() { + final partName = p.basename(toolOutputPath); + final line = "part '$partName'; $_addedMarker\n"; + + final file = File(path); + file.writeAsStringSync(_insertAfterLastImport( + line, _removeToolAddedLinesFromSource(file.readAsStringSync()))); + } + + String _insertAfterLastImport(String line, String source) { + final importRegexp = RegExp(r'^import .*;$', multiLine: true); + final index = source.lastIndexOf(importRegexp); + if (index == -1) return line + source; + final nextLineIndex = index + source.substring(index).indexOf('\n') + 1; + return source.substring(0, nextLineIndex) + + line + + source.substring(nextLineIndex); + } + + void patchForCfe() { + final partName = p.basename(toolOutputPath); + final line = "import augment '$partName'; $_addedMarker\n"; + + final file = File(path); + file.writeAsStringSync( + line + _removeToolAddedLinesFromSource(file.readAsStringSync())); + + final toolOutputFile = File(toolOutputPath); + toolOutputFile.writeAsStringSync(toolOutputFile + .readAsStringSync() + .replaceAll('part of ', 'augment library ')); + } + + void revert() { + final file = File(path); + file.writeAsStringSync(_resetCacheBusters( + _removeToolAddedLinesFromSource(file.readAsStringSync()))); + final toolOutputFile = File(toolOutputPath); + if (toolOutputFile.existsSync()) toolOutputFile.deleteSync(); + } + + /// Returns [source] with lines added by [_addImportAugment] removed. + String _removeToolAddedLinesFromSource(String source) => + source.split('\n').where((l) => !l.endsWith(_addedMarker)).join('\n'); + + /// Updates the file to trigger macro rerun. + /// + /// The file must contain the string `CACHEBUSTER` in a place that triggers + /// recomputation, for example in a field name. + /// + /// If there is an augmentation output file, updates that too. + /// + /// Returns whether any change was made to a file. + bool bustCaches() { + final token = _random.nextInt(1 << 32).toRadixString(16) + + _random.nextInt(1 << 32).toRadixString(16); + var cacheBusterFound = false; + for (final path in [ + path, + toolOutputPath, + ]) { + final file = File(path); + if (!file.existsSync()) continue; + final source = file.readAsStringSync(); + if (source.contains(_cacheBusterRegexp)) { + cacheBusterFound = true; + file.writeAsStringSync( + source.replaceAll(_cacheBusterRegexp, '$_cacheBusterString$token')); + } + } + return cacheBusterFound; + } + + String _resetCacheBusters(String source) => + source.replaceAll(_cacheBusterRegexp, _cacheBusterString); +} diff --git a/pkgs/_macro_tool/mono_pkg.yaml b/pkgs/_macro_tool/mono_pkg.yaml index 15378042..37acd8e1 100644 --- a/pkgs/_macro_tool/mono_pkg.yaml +++ b/pkgs/_macro_tool/mono_pkg.yaml @@ -8,3 +8,9 @@ stages: - format: sdk: - dev +- unit_test: + # Some tests write to test/package_under_test, so limit concurrency. + - test: --test-randomize-ordering-seed=random --concurrency=1 + os: + - linux + - windows diff --git a/pkgs/_macro_tool/test/macro_runner_test.dart b/pkgs/_macro_tool/test/macro_runner_test.dart new file mode 100644 index 00000000..350dbccb --- /dev/null +++ b/pkgs/_macro_tool/test/macro_runner_test.dart @@ -0,0 +1,46 @@ +// 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 'dart:isolate'; + +import 'package:_macro_tool/analyzer_macro_runner.dart'; +import 'package:_macro_tool/cfe_macro_runner.dart'; +import 'package:test/test.dart'; + +void main() { + final packageConfigPath = Isolate.packageConfigSync!.toFilePath(); + final workspacePath = + Directory.fromUri(Uri.parse('./test/package_under_test')).absolute.path; + + group('AnalyzerMacroRunner', () { + test('runs macros', () async { + final macroRunner = AnalyzerMacroRunner( + packageConfigPath: packageConfigPath, + workspacePath: workspacePath, + ); + final result = await macroRunner.run(); + + // Two files that produce macro output, no errors. + expect(result.fileResults.length, 2); + expect(result.allErrors, isEmpty); + expect(result.fileResults.map((r) => r.output), everyElement(isNotNull)); + }); + }); + + group('CfeMacroRunner', () { + test('runs macros', () async { + final macroRunner = CfeMacroRunner( + packageConfigPath: packageConfigPath, + workspacePath: workspacePath, + ); + final result = await macroRunner.run(); + + // Two files that produce macro output, no errors. + expect(result.fileResults.length, 2); + expect(result.allErrors, isEmpty); + expect(result.fileResults.map((r) => r.output), everyElement(isNotNull)); + }); + }); +} diff --git a/pkgs/_macro_tool/test/macro_tool_test.dart b/pkgs/_macro_tool/test/macro_tool_test.dart new file mode 100644 index 00000000..5d42822b --- /dev/null +++ b/pkgs/_macro_tool/test/macro_tool_test.dart @@ -0,0 +1,45 @@ +// 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:_macro_tool/main.dart' as macro_tool; +import 'package:test/test.dart'; + +void main() { + tearDown(() async { + await macro_tool.main([ + '--workspace=test/package_under_test', + '--packageConfig=../../.dart_tool/package_config.json', + 'revert', + ]); + }); + + test('apply macros with analyzer then run', () async { + expect( + await macro_tool.main([ + '--workspace=test/package_under_test', + '--packageConfig=../../.dart_tool/package_config.json', + '--script=test/package_under_test/lib/apply_declare_x.dart', + 'apply', + 'patch_for_cfe', + 'run', + ]), + // The script exit code is the macro-generated value: 3. + 3); + }); + + test('apply macros with CFE then run', () async { + expect( + await macro_tool.main([ + '--workspace=test/package_under_test', + '--packageConfig=../../.dart_tool/package_config.json', + '--script=test/package_under_test/lib/apply_declare_x.dart', + '--host=cfe', + 'apply', + 'patch_for_cfe', + 'run', + ]), + // The script exit code is the macro-generated value: 3. + 3); + }); +} diff --git a/pkgs/_macro_tool/test/package_under_test/analysis_options.yaml b/pkgs/_macro_tool/test/package_under_test/analysis_options.yaml new file mode 100644 index 00000000..c38912d5 --- /dev/null +++ b/pkgs/_macro_tool/test/package_under_test/analysis_options.yaml @@ -0,0 +1,3 @@ +analyzer: + enable-experiment: + - macros diff --git a/pkgs/_macro_tool/test/package_under_test/lib/apply_declare_x.dart b/pkgs/_macro_tool/test/package_under_test/lib/apply_declare_x.dart new file mode 100644 index 00000000..2f6b506d --- /dev/null +++ b/pkgs/_macro_tool/test/package_under_test/lib/apply_declare_x.dart @@ -0,0 +1,19 @@ +import augment 'apply_declare_x.dart.macro_tool_output'; // added by macro_tool +// 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:_test_macros/declare_x_macro.dart'; + +@DeclareX() +class ClassWithMacroApplied { + int CACHEBUSTER = 1; +} + +void main() { + final code = ((ClassWithMacroApplied() as dynamic).x); + print(code); + exit(code); +} diff --git a/pkgs/_macro_tool/test/package_under_test/lib/apply_query_class.dart b/pkgs/_macro_tool/test/package_under_test/lib/apply_query_class.dart new file mode 100644 index 00000000..b7575c3c --- /dev/null +++ b/pkgs/_macro_tool/test/package_under_test/lib/apply_query_class.dart @@ -0,0 +1,11 @@ +import augment 'apply_query_class.dart.macro_tool_output'; // added by macro_tool +// 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_macros/query_class.dart'; + +@QueryClass() +abstract class ClassWithMacroApplied { + abstract final int x; +} diff --git a/pkgs/_macro_tool/test/package_under_test/pubspec.yaml b/pkgs/_macro_tool/test/package_under_test/pubspec.yaml new file mode 100644 index 00000000..420931f6 --- /dev/null +++ b/pkgs/_macro_tool/test/package_under_test/pubspec.yaml @@ -0,0 +1,9 @@ +name: package_under_test_macro_tool +publish-to: none +resolution: workspace + +environment: + sdk: ^3.7.0-39.0.dev + +dependencies: + _test_macros: any diff --git a/pubspec.yaml b/pubspec.yaml index 3c771d41..ad3f5a70 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ workspace: - pkgs/_macro_runner - pkgs/_macro_server - pkgs/_macro_tool + - pkgs/_macro_tool/test/package_under_test - pkgs/_test_macros - pkgs/dart_model - pkgs/macro diff --git a/tool/benchmark_generator/lib/json_encodable/input_generator.dart b/tool/benchmark_generator/lib/json_encodable/input_generator.dart index b03f5417..41c8cf0a 100644 --- a/tool/benchmark_generator/lib/json_encodable/input_generator.dart +++ b/tool/benchmark_generator/lib/json_encodable/input_generator.dart @@ -2,7 +2,6 @@ // 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:benchmark_generator/random.dart'; import 'package:benchmark_generator/workspace.dart'; enum Strategy { @@ -53,20 +52,21 @@ class JsonEncodableInputGenerator { buffer.writeln('next_in_cycle.A0? referenceOther;'); } - if (topLevelCacheBuster) { - buffer.writeln('int? cacheBuster$largeRandom;'); - } - for (var j = 0; j != classesPerLibrary; ++j) { - buffer.write(_generateClass(j, fieldCacheBuster: fieldCacheBuster)); + buffer.write(_generateClass(index, j)); } return buffer.toString(); } - String _generateClass(int index, {required bool fieldCacheBuster}) { + String _generateClass(int libraryIndex, int index) { final className = 'A$index'; - String fieldName(int index) => 'a$index'; + String fieldName(int fieldIndex) { + if (libraryIndex == 0 && index == 0 && fieldIndex == 0) { + return 'aCACHEBUSTER'; + } + return 'a$fieldIndex'; + } final result = StringBuffer(strategy == Strategy.macro ? '@JsonCodable()' : ''); @@ -77,9 +77,6 @@ class JsonEncodableInputGenerator { external $className.fromJson(Map json); external Map toJson();'''); - if (fieldCacheBuster) { - result.writeln('int? b$largeRandom;'); - } for (var i = 0; i != fieldsPerClass; ++i) { result.writeln('int? ${fieldName(i)};'); } diff --git a/tool/benchmark_generator/lib/random.dart b/tool/benchmark_generator/lib/random.dart deleted file mode 100644 index 1a0be399..00000000 --- a/tool/benchmark_generator/lib/random.dart +++ /dev/null @@ -1,9 +0,0 @@ -// 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:math'; - -final _random = Random.secure(); -int get largeRandom => - _random.nextInt(0xFFFFFFFF) + (_random.nextInt(0x7FFFFFFF) << 32); diff --git a/tool/ci.sh b/tool/ci.sh index c7a69465..bb9258ab 100755 --- a/tool/ci.sh +++ b/tool/ci.sh @@ -79,10 +79,14 @@ for PKG in ${PKGS}; do echo 'dart format --output=none --set-exit-if-changed .' dart format --output=none --set-exit-if-changed . || EXIT_CODE=$? ;; - test) + test_0) echo 'dart test --test-randomize-ordering-seed=random' dart test --test-randomize-ordering-seed=random || EXIT_CODE=$? ;; + test_1) + echo 'dart test --test-randomize-ordering-seed=random --concurrency=1' + dart test --test-randomize-ordering-seed=random --concurrency=1 || EXIT_CODE=$? + ;; *) echo -e "\033[31mUnknown TASK '${TASK}' - TERMINATING JOB\033[0m" exit 64 diff --git a/tool/run_e2e_tests.sh b/tool/run_e2e_tests.sh index 4c45c82f..5dde8e25 100755 --- a/tool/run_e2e_tests.sh +++ b/tool/run_e2e_tests.sh @@ -7,12 +7,13 @@ cd $(dirname ${BASH_SOURCE[0]}) echo "Testing goldens/foo/*_test.dart..." -for test_file in $(ls ../goldens/foo/lib/ | grep _test.dart); do +for test_file in $(ls ../goldens/foo/lib/ | egrep '_test.dart$'); do echo "Testing $test_file..." if dart ../pkgs/_macro_tool/bin/main.dart \ --workspace=../goldens/foo \ --packageConfig=../.dart_tool/package_config.json \ - --script=../goldens/foo/lib/${test_file}; then + --script=../goldens/foo/lib/${test_file} \ + apply patch_for_cfe run revert; then echo "PASS" else echo "FAIL"