Skip to content

Commit 0cc596b

Browse files
authored
Support serving from folders called packages. (#4142)
1 parent aa89301 commit 0cc596b

File tree

13 files changed

+140
-37
lines changed

13 files changed

+140
-37
lines changed

build/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.0.3-wip
2+
3+
- Use `build_runner_core` 9.3.1.
4+
15
## 3.0.2
26

37
- Use `build_runner_core` 9.3.0.

build/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: build
2-
version: 3.0.2
2+
version: 3.0.3-wip
33
description: A package for authoring build_runner compatible code generators.
44
repository: https://github.com/dart-lang/build/tree/master/build
55
resolution: workspace
@@ -10,7 +10,7 @@ environment:
1010
dependencies:
1111
analyzer: '>=7.4.0 <9.0.0'
1212
async: ^2.5.0
13-
build_runner_core: '9.3.0'
13+
build_runner_core: '9.3.1-wip'
1414
built_collection: ^5.1.1
1515
built_value: ^8.9.5
1616
convert: ^3.0.0

build_resolvers/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 3.0.3-wip
2+
3+
- Use `build` 3.0.3.
4+
- Use `build_runner` 2.7.1.
5+
16
## 3.0.2
27

38
- Use `build` 3.0.2.

build_resolvers/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: build_resolvers
2-
version: 3.0.2
2+
version: 3.0.3-wip
33
description: Resolve Dart code in a Builder
44
repository: https://github.com/dart-lang/build/tree/master/build_resolvers
55
resolution: workspace
@@ -10,8 +10,8 @@ environment:
1010
dependencies:
1111
analyzer: '>=7.4.0 <9.0.0'
1212
async: ^2.5.0
13-
build: '3.0.2'
14-
build_runner_core: '9.3.0'
13+
build: '3.0.3-wip'
14+
build_runner_core: '9.3.1-wip'
1515
collection: ^1.17.0
1616
package_config: ^2.0.0
1717
path: ^1.8.0

build_runner/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 2.7.1-wip
2+
3+
- Bug fix: with `build_runner serve`, special handling of paths containing
4+
`/packages/` was hiding actual folders called `packages`. Serve the actual
5+
folders first, before trying the package lookup.
6+
17
## 2.7.0
28

39
- Performance: builders can choose to run only when "triggered". A builder runs

build_runner/lib/src/server/path_to_asset_id.dart

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,27 @@
55
import 'package:build/build.dart';
66
import 'package:path/path.dart' as p;
77

8-
AssetId pathToAssetId(
8+
/// Converts [pathSegments] to `AssetId`s.
9+
///
10+
/// A path segment of `packages` is special, it is followed by a path segment
11+
/// giving the package name then path segments giving the path under `lib`.
12+
/// In this case, two `AssetId`s are returned: one ignoring the package mapping
13+
/// then one with the package mapping.
14+
List<AssetId> pathToAssetIds(
915
String rootPackage,
1016
String rootDir,
1117
List<String> pathSegments,
1218
) {
13-
var packagesIndex = pathSegments.indexOf('packages');
14-
return packagesIndex >= 0
15-
? AssetId(
16-
pathSegments[packagesIndex + 1],
17-
p.join('lib', p.joinAll(pathSegments.sublist(packagesIndex + 2))),
18-
)
19-
: AssetId(rootPackage, p.joinAll([rootDir, ...pathSegments]));
19+
final result = <AssetId>[
20+
AssetId(rootPackage, p.joinAll([rootDir, ...pathSegments])),
21+
];
22+
final packagesIndex = pathSegments.indexOf('packages');
23+
if (packagesIndex >= 0 && pathSegments.length - packagesIndex > 2) {
24+
final package = pathSegments[packagesIndex + 1];
25+
final path = p.joinAll(pathSegments.sublist(packagesIndex + 2));
26+
result.add(AssetId(package, p.join('lib', path)));
27+
}
28+
return result;
2029
}
2130

2231
/// Returns null for paths that neither a lib nor starts from a rootDir

build_runner/lib/src/server/server.dart

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,24 @@ class ServeHandler implements BuildState {
126126
var rootPackage = _state.packageGraph.root.name;
127127
var results = <String, String>{};
128128
for (final path in assertPathList) {
129-
try {
130-
var assetId = pathToAssetId(rootPackage, rootDir, p.url.split(path));
131-
var digest = await reader.digest(assetId);
132-
results[path] = digest.toString();
133-
} on AssetNotFoundException {
129+
final assetIds = pathToAssetIds(rootPackage, rootDir, p.url.split(path));
130+
AssetId? assetId;
131+
for (final id in assetIds) {
132+
try {
133+
if (await reader.canRead(id)) {
134+
assetId = id;
135+
break;
136+
}
137+
} on AssetNotFoundException {
138+
// Try the next one.
139+
}
140+
}
141+
142+
if (assetId == null) {
134143
results.remove(path);
144+
} else {
145+
final digest = await reader.digest(assetId);
146+
results[path] = digest.toString();
135147
}
136148
}
137149
return shelf.Response.ok(
@@ -281,22 +293,33 @@ class AssetHandler {
281293
(request.url.path.endsWith('/') || request.url.path.isEmpty)
282294
? _handle(
283295
request,
284-
pathToAssetId(_rootPackage, rootDir, [
285-
...request.url.pathSegments,
296+
pathToAssetIds(_rootPackage, rootDir, [
297+
...request.url.pathSegments.where((p) => p.isNotEmpty),
286298
'index.html',
287299
]),
288300
fallbackToDirectoryList: true,
289301
)
290302
: _handle(
291303
request,
292-
pathToAssetId(_rootPackage, rootDir, request.url.pathSegments),
304+
pathToAssetIds(_rootPackage, rootDir, request.url.pathSegments),
293305
);
294306

295307
Future<shelf.Response> _handle(
296308
shelf.Request request,
297-
AssetId assetId, {
309+
List<AssetId> assetIds, {
298310
bool fallbackToDirectoryList = false,
299311
}) async {
312+
// Use the first of [assetIds] that exists.
313+
AssetId? assetId;
314+
for (final id in assetIds) {
315+
if (await _reader.canRead(id)) {
316+
assetId = id;
317+
break;
318+
}
319+
}
320+
// Or if none exists, report an error about the first one.
321+
assetId ??= assetIds.first;
322+
300323
try {
301324
try {
302325
if (!await _reader.canRead(assetId)) {
@@ -375,10 +398,6 @@ class AssetHandler {
375398
..writeAll(result, '\n')
376399
..writeln();
377400
}
378-
message.write(
379-
' See https://github.com/dart-lang/build/blob/master/docs/faq.md'
380-
'#why-cant-i-see-a-file-i-know-exists',
381-
);
382401
return '$message';
383402
}
384403
}

build_runner/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: build_runner
2-
version: 2.7.0
2+
version: 2.7.1-wip
33
description: A build system for Dart code generation and modular compilation.
44
repository: https://github.com/dart-lang/build/tree/master/build_runner
55
resolution: workspace
@@ -15,10 +15,10 @@ platforms:
1515
dependencies:
1616
args: ^2.0.0
1717
async: ^2.5.0
18-
build: '3.0.2'
18+
build: '3.0.3-wip'
1919
build_config: ">=1.2.0 <1.3.0"
2020
build_daemon: ^4.0.0
21-
build_runner_core: '9.3.0'
21+
build_runner_core: '9.3.1-wip'
2222
code_builder: ^4.2.0
2323
crypto: ^3.0.0
2424
dart_style: '>=2.3.7 <4.0.0'

build_runner/test/server/serve_handler_test.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,57 @@ void main() {
162162
expect(await response.readAsString(), 'content');
163163
});
164164

165+
test('serves package files for /packages/<package name>', () async {
166+
addSource('a|lib/a.html', 'content');
167+
var response = await serveHandler.handlerFor('web')(
168+
Request('GET', Uri.parse('http://server.com/packages/a/a.html')),
169+
);
170+
expect(await response.readAsString(), 'content');
171+
});
172+
173+
test('serves packages for /anywhere/packages/<package name>', () async {
174+
addSource('a|lib/a.html', 'content');
175+
var response = await serveHandler.handlerFor('web')(
176+
Request('GET', Uri.parse('http://server.com/anywhere/packages/a/a.html')),
177+
);
178+
expect(await response.readAsString(), 'content');
179+
});
180+
181+
test('servers actual files before from packages for /packages/...', () async {
182+
// Match in `web` takes precedence over match in packages.
183+
addSource('a|lib/a.html', 'package_content');
184+
addSource('a|web/packages/a/a.html', 'web_content');
185+
var responseA = await serveHandler.handlerFor('web')(
186+
Request('GET', Uri.parse('http://server.com/packages/a/a.html')),
187+
);
188+
expect(await responseA.readAsString(), 'web_content');
189+
190+
// Fall back to match in packages.
191+
addSource('b|lib/b.html', 'package_content');
192+
var responseB = await serveHandler.handlerFor('web')(
193+
Request('GET', Uri.parse('http://server.com/packages/b/b.html')),
194+
);
195+
expect(await responseB.readAsString(), 'package_content');
196+
});
197+
198+
test(
199+
'serves index.html for actual folder called packages from /packages/`',
200+
() async {
201+
addSource('a|web/packages/index.html', 'content');
202+
var response = await serveHandler.handlerFor('web')(
203+
Request('GET', Uri.parse('http://server.com/packages/')),
204+
);
205+
expect(await response.readAsString(), 'content');
206+
},
207+
);
208+
209+
test('serves nothing from /packages/` if missing', () async {
210+
var response = await serveHandler.handlerFor('web')(
211+
Request('GET', Uri.parse('http://server.com/packages/')),
212+
);
213+
expect(response.statusCode, HttpStatus.notFound);
214+
});
215+
165216
test('caching with etags works', () async {
166217
addSource('a|web/index.html', 'content');
167218
var handler = serveHandler.handlerFor('web');

build_runner_core/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 9.3.1-wip
2+
3+
- Use `build_runner` 2.7.1.
4+
15
## 9.3.0
26

37
- Add support for build.yaml `triggers`. See `build_runner` 2.7.0 for usage.

0 commit comments

Comments
 (0)