Skip to content

Commit bbbe12c

Browse files
authored
Move SDK summary generation to a separate library (#3431)
* Move SDK summary generation to a separate library The details of finding or generating the SDK summary are different internally, so this code gets patched. The patch file ends up needing frequent maintenance to keep up with unrelated other changes in this file. Separate the SDK summary related code into it's own library which will have a patch so that it is more isolated from other changes. Move `isFlutter` to `sdk_summary.dart` since it is used there, and it is related to the SDK. Update the test which imports from `src`. Move `packagePath` to `build_asset_uri_generator` so it can be used in both `resolver.dart` and `sdk_summary.dart`. * dartfmt
1 parent 28aea0f commit bbbe12c

File tree

4 files changed

+122
-109
lines changed

4 files changed

+122
-109
lines changed

build_resolvers/lib/src/build_asset_uri_resolver.dart

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:collection';
7+
import 'dart:isolate';
78

89
import 'package:analyzer/dart/analysis/utilities.dart';
910
import 'package:analyzer/dart/ast/ast.dart';
@@ -218,6 +219,11 @@ class BuildAssetUriResolver extends UriResolver {
218219
String assetPath(AssetId assetId) =>
219220
p.posix.join('/${assetId.package}', assetId.path);
220221

222+
Future<String> packagePath(String package) async {
223+
var libRoot = await Isolate.resolvePackageUri(Uri.parse('package:$package/'));
224+
return p.dirname(p.fromUri(libRoot));
225+
}
226+
221227
/// Returns all the directives from a Dart library that can be resolved to an
222228
/// [AssetId].
223229
Set<AssetId> _parseDirectives(String content, AssetId from) => HashSet.of(

build_resolvers/lib/src/resolver.dart

+4-109
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,21 @@ import 'package:analyzer/dart/analysis/features.dart';
1212
import 'package:analyzer/dart/analysis/results.dart';
1313
import 'package:analyzer/dart/ast/ast.dart';
1414
import 'package:analyzer/dart/element/element.dart';
15-
import 'package:analyzer/dart/sdk/build_sdk_summary.dart';
1615
import 'package:analyzer/error/error.dart';
17-
import 'package:analyzer/file_system/physical_file_system.dart';
1816
// ignore: implementation_imports
1917
import 'package:analyzer/src/clients/build_resolvers/build_resolvers.dart';
2018
import 'package:async/async.dart';
2119
import 'package:build/build.dart';
2220
import 'package:build/experiments.dart';
2321
import 'package:collection/collection.dart' show IterableExtension;
24-
import 'package:logging/logging.dart';
2522
import 'package:package_config/package_config.dart';
2623
import 'package:path/path.dart' as p;
2724
import 'package:pool/pool.dart';
2825
import 'package:yaml/yaml.dart';
2926

3027
import 'analysis_driver.dart';
3128
import 'build_asset_uri_resolver.dart';
32-
import 'human_readable_duration.dart';
33-
34-
final _logger = Logger('build_resolvers');
35-
36-
Future<String> _packagePath(String package) async {
37-
var libRoot = await Isolate.resolvePackageUri(Uri.parse('package:$package/'));
38-
return p.dirname(p.fromUri(libRoot));
39-
}
29+
import 'sdk_summary.dart';
4030

4131
/// Implements [Resolver.libraries] and [Resolver.findLibraryByName] by crawling
4232
/// down from entrypoints.
@@ -365,7 +355,7 @@ class AnalyzerResolvers implements Resolvers {
365355

366356
/// A function that returns the path to the SDK summary when invoked.
367357
///
368-
/// Defaults to [_defaultSdkSummaryGenerator].
358+
/// Defaults to [defaultSdkSummaryGenerator].
369359
final Future<String> Function() _sdkSummaryGenerator;
370360

371361
// Lazy, all access must be preceded by a call to `_ensureInitialized`.
@@ -400,7 +390,7 @@ class AnalyzerResolvers implements Resolvers {
400390
..contextFeatures =
401391
_featureSet(enableExperiments: enabledExperiments)),
402392
_sdkSummaryGenerator =
403-
sdkSummaryGenerator ?? _defaultSdkSummaryGenerator;
393+
sdkSummaryGenerator ?? defaultSdkSummaryGenerator;
404394

405395
/// Create a Resolvers backed by an `AnalysisContext` using options
406396
/// [_analysisOptions].
@@ -430,89 +420,6 @@ class AnalyzerResolvers implements Resolvers {
430420
}
431421
}
432422

433-
/// Lazily creates a summary of the users SDK and caches it under
434-
/// `.dart_tool/build_resolvers`.
435-
///
436-
/// This is only intended for use in typical dart packages, which must
437-
/// have an already existing `.dart_tool` directory (this is how we
438-
/// validate we are running under a typical dart package and not a custom
439-
/// environment).
440-
Future<String> _defaultSdkSummaryGenerator() async {
441-
var dartToolPath = '.dart_tool';
442-
if (!await Directory(dartToolPath).exists()) {
443-
throw StateError(
444-
'The default analyzer resolver can only be used when the current '
445-
'working directory is a standard pub package.');
446-
}
447-
448-
var cacheDir = p.join(dartToolPath, 'build_resolvers');
449-
var summaryPath = p.join(cacheDir, 'sdk.sum');
450-
var depsFile = File('$summaryPath.deps');
451-
var summaryFile = File(summaryPath);
452-
453-
var currentDeps = {
454-
'sdk': Platform.version,
455-
for (var package in _packageDepsToCheck)
456-
package: await _packagePath(package),
457-
};
458-
459-
// Invalidate existing summary/version/analyzer files if present.
460-
if (await depsFile.exists()) {
461-
if (!await _checkDeps(depsFile, currentDeps)) {
462-
await depsFile.delete();
463-
if (await summaryFile.exists()) await summaryFile.delete();
464-
}
465-
} else if (await summaryFile.exists()) {
466-
// Fallback for cases where we could not do a proper version check.
467-
await summaryFile.delete();
468-
}
469-
470-
// Generate the summary and version files if necessary.
471-
if (!await summaryFile.exists()) {
472-
var watch = Stopwatch()..start();
473-
_logger.info('Generating SDK summary...');
474-
await summaryFile.create(recursive: true);
475-
final embedderYamlPath =
476-
isFlutter ? p.join(_dartUiPath, '_embedder.yaml') : null;
477-
await summaryFile.writeAsBytes(
478-
await buildSdkSummary(
479-
sdkPath: _runningDartSdkPath,
480-
resourceProvider: PhysicalResourceProvider.INSTANCE,
481-
embedderYamlPath: embedderYamlPath,
482-
),
483-
);
484-
485-
await _createDepsFile(depsFile, currentDeps);
486-
watch.stop();
487-
_logger.info('Generating SDK summary completed, took '
488-
'${humanReadable(watch.elapsed)}\n');
489-
}
490-
491-
return p.absolute(summaryPath);
492-
}
493-
494-
final _packageDepsToCheck = ['analyzer', 'build_resolvers'];
495-
496-
Future<bool> _checkDeps(
497-
File versionsFile, Map<String, Object?> currentDeps) async {
498-
var previous =
499-
jsonDecode(await versionsFile.readAsString()) as Map<String, Object?>;
500-
501-
if (previous.keys.length != currentDeps.keys.length) return false;
502-
503-
for (var entry in previous.entries) {
504-
if (entry.value != currentDeps[entry.key]) return false;
505-
}
506-
507-
return true;
508-
}
509-
510-
Future<void> _createDepsFile(
511-
File depsFile, Map<String, Object?> currentDeps) async {
512-
await depsFile.create(recursive: true);
513-
await depsFile.writeAsString(jsonEncode(currentDeps));
514-
}
515-
516423
/// Checks that the current analyzer version supports the current language
517424
/// version.
518425
void _warnOnLanguageVersionMismatch() async {
@@ -528,7 +435,7 @@ void _warnOnLanguageVersionMismatch() async {
528435
var json = jsonDecode(content.toString());
529436
var latestAnalyzer = json['latest']['version'];
530437
var analyzerPubspecPath =
531-
p.join(await _packagePath('analyzer'), 'pubspec.yaml');
438+
p.join(await packagePath('analyzer'), 'pubspec.yaml');
532439
var currentAnalyzer =
533440
loadYaml(await File(analyzerPubspecPath).readAsString())['version'];
534441

@@ -580,11 +487,6 @@ https://pub.dev/packages/analyzer.
580487
}
581488
}
582489

583-
/// Path where the dart:ui package will be found, if executing via the dart
584-
/// binary provided by the Flutter SDK.
585-
final _dartUiPath =
586-
p.normalize(p.join(_runningDartSdkPath, '..', 'pkg', 'sky_engine', 'lib'));
587-
588490
/// The current feature set based on the current sdk version and enabled
589491
/// experiments.
590492
FeatureSet _featureSet({List<String> enableExperiments = const []}) {
@@ -609,10 +511,3 @@ current version by running `pub deps`.
609511
return FeatureSet.fromEnableFlags2(
610512
sdkLanguageVersion: sdkLanguageVersion, flags: enableExperiments);
611513
}
612-
613-
/// Path to the running dart's SDK root.
614-
final _runningDartSdkPath = p.dirname(p.dirname(Platform.resolvedExecutable));
615-
616-
/// `true` if the currently running dart was provided by the Flutter SDK.
617-
final isFlutter =
618-
Platform.version.contains('flutter') || Directory(_dartUiPath).existsSync();
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
import 'dart:io';
7+
8+
import 'package:analyzer/dart/sdk/build_sdk_summary.dart';
9+
import 'package:analyzer/file_system/physical_file_system.dart';
10+
import 'package:logging/logging.dart';
11+
import 'package:path/path.dart' as p;
12+
13+
import 'build_asset_uri_resolver.dart' show packagePath;
14+
import 'human_readable_duration.dart';
15+
16+
final _logger = Logger('build_resolvers');
17+
18+
/// `true` if the currently running dart was provided by the Flutter SDK.
19+
final isFlutter =
20+
Platform.version.contains('flutter') || Directory(_dartUiPath).existsSync();
21+
22+
/// Path to the running dart's SDK root.
23+
final _runningDartSdkPath = p.dirname(p.dirname(Platform.resolvedExecutable));
24+
25+
/// Path where the dart:ui package will be found, if executing via the dart
26+
/// binary provided by the Flutter SDK.
27+
final _dartUiPath =
28+
p.normalize(p.join(_runningDartSdkPath, '..', 'pkg', 'sky_engine', 'lib'));
29+
30+
/// Lazily creates a summary of the users SDK and caches it under
31+
/// `.dart_tool/build_resolvers`.
32+
///
33+
/// This is only intended for use in typical dart packages, which must
34+
/// have an already existing `.dart_tool` directory (this is how we
35+
/// validate we are running under a typical dart package and not a custom
36+
/// environment).
37+
Future<String> defaultSdkSummaryGenerator() async {
38+
var dartToolPath = '.dart_tool';
39+
if (!await Directory(dartToolPath).exists()) {
40+
throw StateError(
41+
'The default analyzer resolver can only be used when the current '
42+
'working directory is a standard pub package.');
43+
}
44+
45+
var cacheDir = p.join(dartToolPath, 'build_resolvers');
46+
var summaryPath = p.join(cacheDir, 'sdk.sum');
47+
var depsFile = File('$summaryPath.deps');
48+
var summaryFile = File(summaryPath);
49+
50+
var currentDeps = {
51+
'sdk': Platform.version,
52+
for (var package in _packageDepsToCheck)
53+
package: await packagePath(package),
54+
};
55+
56+
// Invalidate existing summary/version/analyzer files if present.
57+
if (await depsFile.exists()) {
58+
if (!await _checkDeps(depsFile, currentDeps)) {
59+
await depsFile.delete();
60+
if (await summaryFile.exists()) await summaryFile.delete();
61+
}
62+
} else if (await summaryFile.exists()) {
63+
// Fallback for cases where we could not do a proper version check.
64+
await summaryFile.delete();
65+
}
66+
67+
// Generate the summary and version files if necessary.
68+
if (!await summaryFile.exists()) {
69+
var watch = Stopwatch()..start();
70+
_logger.info('Generating SDK summary...');
71+
await summaryFile.create(recursive: true);
72+
final embedderYamlPath =
73+
isFlutter ? p.join(_dartUiPath, '_embedder.yaml') : null;
74+
await summaryFile.writeAsBytes(
75+
await buildSdkSummary(
76+
sdkPath: _runningDartSdkPath,
77+
resourceProvider: PhysicalResourceProvider.INSTANCE,
78+
embedderYamlPath: embedderYamlPath,
79+
),
80+
);
81+
82+
await _createDepsFile(depsFile, currentDeps);
83+
watch.stop();
84+
_logger.info('Generating SDK summary completed, took '
85+
'${humanReadable(watch.elapsed)}\n');
86+
}
87+
88+
return p.absolute(summaryPath);
89+
}
90+
91+
final _packageDepsToCheck = ['analyzer', 'build_resolvers'];
92+
93+
Future<bool> _checkDeps(
94+
File versionsFile, Map<String, Object?> currentDeps) async {
95+
var previous =
96+
jsonDecode(await versionsFile.readAsString()) as Map<String, Object?>;
97+
98+
if (previous.keys.length != currentDeps.keys.length) return false;
99+
100+
for (var entry in previous.entries) {
101+
if (entry.value != currentDeps[entry.key]) return false;
102+
}
103+
104+
return true;
105+
}
106+
107+
Future<void> _createDepsFile(
108+
File depsFile, Map<String, Object?> currentDeps) async {
109+
await depsFile.create(recursive: true);
110+
await depsFile.writeAsString(jsonEncode(currentDeps));
111+
}

build_resolvers/test/resolver_test.dart

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:build/build.dart';
1313
import 'package:build/experiments.dart';
1414
import 'package:build_resolvers/src/analysis_driver.dart';
1515
import 'package:build_resolvers/src/resolver.dart';
16+
import 'package:build_resolvers/src/sdk_summary.dart';
1617
import 'package:build_test/build_test.dart';
1718
import 'package:logging/logging.dart';
1819
import 'package:package_config/package_config.dart';

0 commit comments

Comments
 (0)