Skip to content

Commit ccb3943

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Check for workspaces consistency after analysis contexts creation.
Bug: https://github.com/dart-lang/linter/issues/2694 Change-Id: I13cae115e48ae794e0751b6099f864ca9d202cdc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/203821 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent c83eeac commit ccb3943

File tree

7 files changed

+88
-2
lines changed

7 files changed

+88
-2
lines changed

pkg/analysis_server/lib/src/context_manager.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ class ContextManagerImpl implements ContextManager {
175175
final Map<Folder, AnalysisDriver> driverMap =
176176
HashMap<Folder, AnalysisDriver>();
177177

178+
/// The timer that is started after creating analysis contexts, to check
179+
/// for in-between changes to configuration files.
180+
Timer? _collectionConsistencyCheckTimer;
181+
178182
/// Stream subscription we are using to watch each analysis root directory for
179183
/// changes.
180184
final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions =
@@ -461,6 +465,7 @@ class ContextManagerImpl implements ContextManager {
461465
}
462466

463467
callbacks.afterContextsCreated();
468+
_scheduleCollectionConsistencyCheck(collection);
464469
}
465470

466471
/// Clean up and destroy the context associated with the given folder.
@@ -482,6 +487,7 @@ class ContextManagerImpl implements ContextManager {
482487
void _destroyAnalysisContexts() {
483488
var collection = _collection;
484489
if (collection != null) {
490+
_collectionConsistencyCheckTimer?.cancel();
485491
for (var analysisContext in collection.contexts) {
486492
_destroyAnalysisContext(analysisContext);
487493
}
@@ -632,6 +638,28 @@ class ContextManagerImpl implements ContextManager {
632638
existingExcludedSet.containsAll(excludedPaths);
633639
}
634640

641+
/// We create analysis contexts, and then start watching the file system
642+
/// for modifications to Dart files, and to configuration files, e.g.
643+
/// `pubspec.yaml` file Pub workspaces.
644+
///
645+
/// So, it is possible that one of these files will be changed between the
646+
/// moment when we read it, and the moment when we started watching for
647+
/// changes. Using `package:watcher` before creating analysis contexts
648+
/// was still not reliable enough.
649+
///
650+
/// To work around this we check after a short timeout, and hope that
651+
/// any subsequent changes will be noticed by `package:watcher`.
652+
void _scheduleCollectionConsistencyCheck(
653+
AnalysisContextCollectionImpl collection,
654+
) {
655+
_collectionConsistencyCheckTimer = Timer(Duration(seconds: 1), () {
656+
_collectionConsistencyCheckTimer = null;
657+
if (!collection.areWorkspacesConsistent) {
658+
_createAnalysisContexts();
659+
}
660+
});
661+
}
662+
635663
/// Starts watching for the `bazel-bin` and `blaze-bin` symlinks.
636664
///
637665
/// This is important since these symlinks might not be present when the

pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ class AnalysisContextCollectionImpl implements AnalysisContextCollection {
7979
}
8080
}
8181

82+
/// Return `true` if the read state of configuration files is consistent
83+
/// with their current state on the file system. We use this as a work
84+
/// around an issue with watching for file system changes.
85+
bool get areWorkspacesConsistent {
86+
for (var analysisContext in contexts) {
87+
var contextRoot = analysisContext.contextRoot;
88+
var workspace = contextRoot.workspace;
89+
if (!workspace.isConsistentWithFileSystem) {
90+
return false;
91+
}
92+
}
93+
return true;
94+
}
95+
8296
@override
8397
DriverBasedAnalysisContext contextFor(String path) {
8498
_throwIfNotAbsoluteNormalizedPath(path);

pkg/analyzer/lib/src/workspace/package_build.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
145145
/// package:build does it.
146146
static const String _pubspecName = 'pubspec.yaml';
147147

148+
/// The associated pubspec file.
149+
final File _pubspecFile;
150+
148151
/// The content of the `pubspec.yaml` file.
149152
/// We read it once, so that all usages return consistent results.
150153
final String? _pubspecContent;
@@ -185,10 +188,16 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
185188
this.generatedRootPath,
186189
this.generatedThisPath,
187190
File pubspecFile,
188-
) : _pubspecContent = _fileContentOrNull(pubspecFile) {
191+
) : _pubspecFile = pubspecFile,
192+
_pubspecContent = _fileContentOrNull(pubspecFile) {
189193
_theOnlyPackage = PackageBuildWorkspacePackage(root, this);
190194
}
191195

196+
@override
197+
bool get isConsistentWithFileSystem {
198+
return _fileContentOrNull(_pubspecFile) == _pubspecContent;
199+
}
200+
192201
@override
193202
UriResolver get packageUriResolver => PackageBuildPackageUriResolver(
194203
this, PackageMapUriResolver(provider, packageMap));

pkg/analyzer/lib/src/workspace/pub.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class PubWorkspace extends SimpleWorkspace {
2121
/// Each Pub workspace is itself one package.
2222
late final PubWorkspacePackage _theOnlyPackage;
2323

24+
/// The associated pubspec file.
25+
final File _pubspecFile;
26+
2427
/// The content of the `pubspec.yaml` file.
2528
/// We read it once, so that all usages return consistent results.
2629
final String? _pubspecContent;
@@ -30,11 +33,17 @@ class PubWorkspace extends SimpleWorkspace {
3033
Map<String, List<Folder>> packageMap,
3134
String root,
3235
File pubspecFile,
33-
) : _pubspecContent = _fileContentOrNull(pubspecFile),
36+
) : _pubspecFile = pubspecFile,
37+
_pubspecContent = _fileContentOrNull(pubspecFile),
3438
super(provider, packageMap, root) {
3539
_theOnlyPackage = PubWorkspacePackage(root, this);
3640
}
3741

42+
@override
43+
bool get isConsistentWithFileSystem {
44+
return _fileContentOrNull(_pubspecFile) == _pubspecContent;
45+
}
46+
3847
@internal
3948
@override
4049
void contributeToResolutionSalt(ApiSignature buffer) {

pkg/analyzer/lib/src/workspace/workspace.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ abstract class Workspace {
1717
/// Return true iff this [Workspace] is a [BazelWorkspace].
1818
bool get isBazel => false;
1919

20+
/// Return `true` if the read state of configuration files is consistent
21+
/// with their current state on the file system.
22+
@internal
23+
bool get isConsistentWithFileSystem => true;
24+
2025
/// The [UriResolver] that can resolve `package` URIs.
2126
UriResolver get packageUriResolver;
2227

pkg/analyzer/test/src/workspace/package_build_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,17 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
640640
workspace.findFile(convertPath('/workspace/web/file.dart')), webFile);
641641
}
642642

643+
void test_isConsistentWithFileSystem() {
644+
newFolder('/workspace/.dart_tool/build/generated/project/bin');
645+
newPubspecYamlFile('/workspace', 'name: project');
646+
PackageBuildWorkspace workspace =
647+
_createWorkspace('/workspace', ['project']);
648+
expect(workspace.isConsistentWithFileSystem, isTrue);
649+
650+
newPubspecYamlFile('/workspace', 'name: my2');
651+
expect(workspace.isConsistentWithFileSystem, isFalse);
652+
}
653+
643654
PackageBuildWorkspace _createWorkspace(
644655
String root, List<String> packageNames) {
645656
return PackageBuildWorkspace.find(

pkg/analyzer/test/src/workspace/pub_test.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,14 @@ class PubWorkspaceTest with ResourceProviderMixin {
111111
resourceProvider, {}, convertPath('/workspace/lib/lib1.dart'));
112112
expect(workspace, isNull);
113113
}
114+
115+
void test_isConsistentWithFileSystem() {
116+
newPubspecYamlFile('/workspace', 'name: my');
117+
var workspace =
118+
PubWorkspace.find(resourceProvider, {}, convertPath('/workspace'))!;
119+
expect(workspace.isConsistentWithFileSystem, isTrue);
120+
121+
newPubspecYamlFile('/workspace', 'name: my2');
122+
expect(workspace.isConsistentWithFileSystem, isFalse);
123+
}
114124
}

0 commit comments

Comments
 (0)