Skip to content

Commit 2030554

Browse files
authored
support file uris outside the root package (#3530)
Fixes #3528 This will allow us to look up asset ids for file uris in any package - which is needed for custom build scripts shipped as `bin` scripts in packages.
1 parent f2fee27 commit 2030554

File tree

4 files changed

+107
-36
lines changed

4 files changed

+107
-36
lines changed

build_runner_core/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 7.2.10
2+
3+
- Fix build script invalidation check for custom build scripts from other
4+
packages.
5+
16
## 7.2.9
27

38
- Fix compatibility with `package:logging` version `1.2.0`.

build_runner_core/lib/src/changes/build_script_updates.dart

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dart:mirrors';
88
import 'package:build/build.dart';
99
import 'package:collection/collection.dart';
1010
import 'package:logging/logging.dart';
11+
import 'package:meta/meta.dart';
1112
import 'package:path/path.dart' as p;
1213

1314
import '../asset/reader.dart';
@@ -45,12 +46,11 @@ class _MirrorBuildScriptUpdates implements BuildScriptUpdates {
4546
static Future<BuildScriptUpdates> create(RunnerAssetReader reader,
4647
PackageGraph packageGraph, AssetGraph graph) async {
4748
var supportsIncrementalRebuilds = true;
48-
var rootPackage = packageGraph.root.name;
4949
Set<AssetId> allSources;
5050
var logger = Logger('BuildScriptUpdates');
5151
try {
5252
allSources = _urisForThisScript
53-
.map((id) => _idForUri(id, rootPackage))
53+
.map((id) => idForUri(id, packageGraph))
5454
.whereNotNull()
5555
.toSet();
5656
var missing = allSources.firstWhereOrNull((id) => !graph.contains(id));
@@ -84,39 +84,6 @@ class _MirrorBuildScriptUpdates implements BuildScriptUpdates {
8484
if (!_supportsIncrementalRebuilds) return true;
8585
return updatedIds.intersection(_allSources).isNotEmpty;
8686
}
87-
88-
/// Attempts to return an [AssetId] for [uri].
89-
///
90-
/// Returns `null` if the uri should be ignored, or throws an [ArgumentError]
91-
/// if the [uri] is not recognized.
92-
static AssetId? _idForUri(Uri uri, String rootPackage) {
93-
switch (uri.scheme) {
94-
case 'dart':
95-
// TODO: check for sdk updates!
96-
break;
97-
case 'package':
98-
var parts = uri.pathSegments;
99-
return AssetId(parts[0],
100-
p.url.joinAll(['lib', ...parts.getRange(1, parts.length)]));
101-
case 'file':
102-
var relativePath = p.relative(uri.toFilePath(), from: p.current);
103-
return AssetId(rootPackage, relativePath);
104-
case 'data':
105-
// Test runner uses a `data` scheme, don't invalidate for those.
106-
if (uri.path.contains('package:test')) break;
107-
continue unsupported;
108-
case 'http':
109-
continue unsupported;
110-
unsupported:
111-
default:
112-
throw ArgumentError('Unsupported uri scheme `${uri.scheme}` found for '
113-
'library in build script.\n'
114-
'This probably means you are running in an unsupported '
115-
'context, such as in an isolate or via `dart run`.\n'
116-
'Full uri was: $uri.');
117-
}
118-
return null;
119-
}
12087
}
12188

12289
/// Always returns false for [hasBeenUpdated], used when we want to skip
@@ -125,3 +92,47 @@ class _NoopBuildScriptUpdates implements BuildScriptUpdates {
12592
@override
12693
bool hasBeenUpdated(void _) => false;
12794
}
95+
96+
/// Attempts to return an [AssetId] for [uri].
97+
///
98+
/// Returns `null` if the uri should be ignored, or throws an [ArgumentError]
99+
/// if the [uri] is not recognized.
100+
@visibleForTesting
101+
AssetId? idForUri(Uri uri, PackageGraph packageGraph) {
102+
switch (uri.scheme) {
103+
case 'dart':
104+
// TODO: check for sdk updates!
105+
break;
106+
case 'package':
107+
var parts = uri.pathSegments;
108+
return AssetId(
109+
parts[0], p.url.joinAll(['lib', ...parts.getRange(1, parts.length)]));
110+
case 'file':
111+
final package = packageGraph.asPackageConfig
112+
.packageOf(Uri.file(p.canonicalize(uri.toFilePath())));
113+
if (package == null) {
114+
throw ArgumentError(
115+
'The uri $uri could not be resolved to a package in the current '
116+
'package graph. Do you have a dependency on the package '
117+
'containing this uri?');
118+
}
119+
// The `AssetId` constructor normalizes this path to a URI style.
120+
var relativePath =
121+
p.relative(uri.toFilePath(), from: package.root.toFilePath());
122+
return AssetId(package.name, relativePath);
123+
case 'data':
124+
// Test runner uses a `data` scheme, don't invalidate for those.
125+
if (uri.path.contains('package:test')) break;
126+
continue unsupported;
127+
case 'http':
128+
continue unsupported;
129+
unsupported:
130+
default:
131+
throw ArgumentError('Unsupported uri scheme `${uri.scheme}` found for '
132+
'library in build script.\n'
133+
'This probably means you are running in an unsupported '
134+
'context, such as in an isolate or via `dart run`.\n'
135+
'Full uri was: $uri.');
136+
}
137+
return null;
138+
}

build_runner_core/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: build_runner_core
2-
version: 7.2.9
2+
version: 7.2.10
33
description: Core tools to organize the structure of a build and run Builders.
44
repository: https://github.com/dart-lang/build/tree/master/build_runner_core
55

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (c) 2023, 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 'package:build/build.dart';
6+
import 'package:build_runner_core/src/changes/build_script_updates.dart';
7+
import 'package:build_runner_core/src/package_graph/package_graph.dart';
8+
import 'package:package_config/package_config_types.dart';
9+
import 'package:test/test.dart';
10+
11+
void main() {
12+
group('idForUri', () {
13+
late final PackageGraph packageGraph;
14+
setUpAll(() async {
15+
final rootPackage = PackageNode(
16+
'a', '/a/', DependencyType.path, LanguageVersion(3, 0),
17+
isRoot: true);
18+
final dependency =
19+
PackageNode('b', '/b/', DependencyType.path, LanguageVersion(3, 0));
20+
rootPackage.dependencies.add(dependency);
21+
packageGraph = PackageGraph.fromRoot(rootPackage);
22+
});
23+
24+
test('dart: uris return null', () {
25+
expect(idForUri(Uri.parse('dart:io'), packageGraph), isNull);
26+
});
27+
28+
test('package: uris can be converted', () {
29+
expect(idForUri(Uri.parse('package:a/a.dart'), packageGraph),
30+
AssetId('a', 'lib/a.dart'));
31+
});
32+
33+
test('file: uris can be looked up', () {
34+
expect(idForUri(Uri.file('/a/lib/a.dart'), packageGraph),
35+
AssetId('a', 'lib/a.dart'));
36+
expect(idForUri(Uri.file('/b/b.dart'), packageGraph),
37+
AssetId('b', 'b.dart'));
38+
});
39+
test('data: arent supported unless they are from the test runner', () {
40+
expect(
41+
() => idForUri(
42+
Uri.parse('data:text/plain;charset=UTF-8,foo'), packageGraph),
43+
throwsA(isA<ArgumentError>()));
44+
expect(
45+
idForUri(Uri.parse('data:text/plain;charset=UTF-8,package:test'),
46+
packageGraph),
47+
null);
48+
});
49+
50+
test('http: uris are not supported', () {
51+
expect(() => idForUri(Uri.parse('http://google.com'), packageGraph),
52+
throwsA(isA<ArgumentError>()));
53+
});
54+
});
55+
}

0 commit comments

Comments
 (0)