Skip to content

Commit 86434c4

Browse files
authored
Download SDK index.jsons at docker build. (#8699)
1 parent 5f30f80 commit 86434c4

File tree

8 files changed

+69
-86
lines changed

8 files changed

+69
-86
lines changed

Dockerfile.app

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ WORKDIR /project/app
3333
RUN dart /project/tool/pub_get_offline.dart /project/app
3434

3535
RUN /project/tool/setup-webp.sh /usr/local/bin
36+
RUN /project/tool/download-sdk-index-jsons.sh
3637

3738
# Clear out any arguments the base images might have set
3839
CMD []

app/lib/search/backend.dart

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'package:logging/logging.dart';
1717
import 'package:meta/meta.dart';
1818
// ignore: implementation_imports
1919
import 'package:pana/src/dartdoc/pub_dartdoc_data.dart';
20+
import 'package:path/path.dart' as p;
2021
import 'package:pool/pool.dart';
2122
import 'package:pub_dev/shared/monitoring.dart';
2223
import 'package:retry/retry.dart';
@@ -427,17 +428,40 @@ class SearchBackend {
427428
}
428429
}
429430

430-
/// Downloads the remote SDK content relative to the base URI.
431-
Future<String> fetchSdkIndexContentAsString({
432-
required Uri baseUri,
433-
required String relativePath,
431+
/// Downloads the remote SDK content from [uri] and creates a cached file in the
432+
/// `.dart_tool/pub-search-data/` directory.
433+
///
434+
/// When a local file in `app/.dart_tool/pub-search-data/<reduced-uri>` exists,
435+
/// its content will be loaded instead. URL reduction replaces slashes and other
436+
/// non-characters with a single dash `-`, like:
437+
/// - `https-api.dart.dev-stable-latest-index.json`
438+
Future<String> loadOrFetchSdkIndexJsonAsString(
439+
Uri uri, {
440+
@visibleForTesting Duration? ttl,
434441
}) async {
435-
final uri = baseUri.resolve(relativePath);
442+
final fileName = uri.toString().replaceAll(RegExp(r'[^a-z0-9\.]+'), '-');
443+
final file = File(p.join('.dart_tool', 'pub-search-data', fileName));
444+
if (await file.exists()) {
445+
var canUseCached = true;
446+
if (ttl != null) {
447+
final age = clock.now().difference(await file.lastModified());
448+
if (age > ttl) {
449+
canUseCached = false;
450+
}
451+
}
452+
if (canUseCached) {
453+
return await file.readAsString();
454+
}
455+
}
456+
436457
final rs = await _http.get(uri);
437458
if (rs.statusCode != 200) {
438459
throw Exception('Unexpected status code for $uri: ${rs.statusCode}');
439460
}
440-
return rs.body;
461+
final content = rs.body;
462+
await file.parent.create(recursive: true);
463+
await file.writeAsString(content);
464+
return content;
441465
}
442466

443467
Future<List<PackageDocument>?> fetchSnapshotDocuments() async {

app/lib/search/dart_sdk_mem_index.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ SdkMemIndex? get dartSdkMemIndex =>
3838
Future<SdkMemIndex?> createDartSdkMemIndex() async {
3939
try {
4040
final index = await SdkMemIndex.dart();
41-
final content = await searchBackend.fetchSdkIndexContentAsString(
42-
baseUri: index.baseUri,
43-
relativePath: 'index.json',
44-
);
41+
final content =
42+
await searchBackend.loadOrFetchSdkIndexJsonAsString(index.indexJsonUri);
4543
await index.addDartdocIndex(DartdocIndex.parseJsonText(content));
4644
index.updateWeights(
4745
libraryWeights: dartSdkLibraryWeights,

app/lib/search/flutter_sdk_mem_index.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,8 @@ SdkMemIndex? get flutterSdkMemIndex =>
5555
Future<SdkMemIndex?> createFlutterSdkMemIndex() async {
5656
try {
5757
final index = SdkMemIndex.flutter();
58-
final content = await searchBackend.fetchSdkIndexContentAsString(
59-
baseUri: index.baseUri,
60-
relativePath: 'index.json',
61-
);
58+
final content =
59+
await searchBackend.loadOrFetchSdkIndexJsonAsString(index.indexJsonUri);
6260
await index.addDartdocIndex(DartdocIndex.parseJsonText(content),
6361
allowedLibraries: _allowedLibraries);
6462
index.updateWeights(

app/lib/search/sdk_mem_index.dart

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import 'dart:math';
66

7-
import 'package:_pub_shared/utils/http.dart';
87
import 'package:meta/meta.dart';
98
// ignore: implementation_imports
109
import 'package:pana/src/dartdoc/dartdoc_index.dart';
@@ -36,39 +35,13 @@ class SdkMemIndex {
3635
_baseUri = baseUri;
3736

3837
static Future<SdkMemIndex> dart() async {
39-
final versions = <String>{
40-
toolStableDartSdkVersion,
41-
runtimeSdkVersion,
42-
};
43-
final client = httpRetryClient();
44-
try {
45-
for (final version in versions) {
46-
final uri = _dartSdkBaseUri(version);
47-
final rs = await client.head(uri);
48-
if (rs.statusCode < 400) {
49-
return SdkMemIndex(sdk: 'dart', version: version, baseUri: uri);
50-
}
51-
}
52-
} finally {
53-
client.close();
54-
}
5538
return SdkMemIndex(
5639
sdk: 'dart',
5740
version: runtimeSdkVersion,
58-
baseUri: _dartSdkBaseUri(runtimeSdkVersion),
41+
baseUri: Uri.parse('https://api.dart.dev/stable/latest/'),
5942
);
6043
}
6144

62-
static Uri _dartSdkBaseUri(String version) {
63-
var branch = 'stable';
64-
if (version.contains('beta')) {
65-
branch = 'beta';
66-
} else if (version.contains('dev')) {
67-
branch = 'dev';
68-
}
69-
return Uri.parse('https://api.dart.dev/$branch/$version/');
70-
}
71-
7245
factory SdkMemIndex.flutter() {
7346
return SdkMemIndex(
7447
sdk: 'flutter',
@@ -77,7 +50,7 @@ class SdkMemIndex {
7750
);
7851
}
7952

80-
Uri get baseUri => _baseUri;
53+
late final indexJsonUri = _baseUri.resolve('index.json');
8154

8255
Future<void> addDartdocIndex(
8356
DartdocIndex index, {

app/test/search/backend_test.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ void main() {
1414
group('search backend', () {
1515
testWithProfile('fetch SDK library description', fn: () async {
1616
final index = await SdkMemIndex.dart();
17-
final content = await searchBackend.fetchSdkIndexContentAsString(
18-
baseUri: index.baseUri,
19-
relativePath: 'index.json',
20-
);
17+
final content = await searchBackend
18+
.loadOrFetchSdkIndexJsonAsString(index.indexJsonUri);
2119
await index.addDartdocIndex(DartdocIndex.parseJsonText(content));
2220
expect(
2321
index.getLibraryDescription('dart:async'),

app/test/search/dartdoc_index_parsing_test.dart

Lines changed: 15 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,21 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:convert';
6-
import 'dart:io';
76

8-
import 'package:clock/clock.dart';
9-
import 'package:http/http.dart' as http;
10-
import 'package:path/path.dart' as p;
7+
import 'package:pub_dev/search/backend.dart';
118
import 'package:pub_dev/search/sdk_mem_index.dart';
12-
import 'package:pub_dev/shared/versions.dart';
13-
import 'package:retry/retry.dart';
149
import 'package:test/test.dart';
1510

11+
import '../shared/test_services.dart';
12+
1613
void main() {
1714
group('dartdoc index.json parsing', () {
18-
/// Downloads [url and creates a cached file in the .dart_tool/pub-search-data directory.
19-
///
20-
/// Reuses the same file up to a week.
21-
Future<File> getCachedFile(String name, String url) async {
22-
final file = File(p.join('.dart_tool', 'pub-search-data', name));
23-
if (await file.exists()) {
24-
final lastModified = await file.lastModified();
25-
final age = clock.now().difference(lastModified);
26-
if (age.inDays < 7) {
27-
return file;
28-
}
29-
}
30-
await file.parent.create(recursive: true);
31-
return retry(() async {
32-
final rs = await http.get(Uri.parse(url));
33-
if (rs.statusCode != 200) {
34-
throw Exception('Unexpected status code for $url: ${rs.statusCode}');
35-
}
36-
await file.writeAsBytes(rs.bodyBytes);
37-
return file;
38-
});
39-
}
40-
41-
test('parse Dart SDK index.json', () async {
42-
final file = await getCachedFile('dart-sdk-$runtimeSdkVersion.json',
43-
'https://api.dart.dev/stable/$runtimeSdkVersion/index.json');
44-
final textContent = await file.readAsString();
45-
final index = DartdocIndex.parseJsonText(await file.readAsString());
15+
testWithProfile('parse Dart SDK index.json', fn: () async {
16+
final textContent = await searchBackend.loadOrFetchSdkIndexJsonAsString(
17+
Uri.parse('https://api.dart.dev/stable/latest/index.json'),
18+
ttl: Duration(days: 1),
19+
);
20+
final index = DartdocIndex.parseJsonText(textContent);
4621
expect(index.entries, hasLength(greaterThan(10000)));
4722

4823
final libraries =
@@ -59,11 +34,12 @@ void main() {
5934
expect(json.decode(index.toJsonText()), json.decode(textContent));
6035
});
6136

62-
test('parse Flutter SDK index.json', () async {
63-
final file = await getCachedFile(
64-
'flutter-sdk.json', 'https://api.flutter.dev/flutter/index.json');
65-
final textContent = await file.readAsString();
66-
final index = DartdocIndex.parseJsonText(await file.readAsString());
37+
testWithProfile('parse Flutter SDK index.json', fn: () async {
38+
final textContent = await searchBackend.loadOrFetchSdkIndexJsonAsString(
39+
Uri.parse('https://api.flutter.dev/flutter/index.json'),
40+
ttl: Duration(days: 1),
41+
);
42+
final index = DartdocIndex.parseJsonText(textContent);
6743
expect(index.entries, hasLength(greaterThan(10000)));
6844

6945
final libraries =

tool/download-sdk-index-jsons.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
6+
7+
cd "$SCRIPT_DIR/../app/"
8+
mkdir -p .dart_tool/pub-search-data
9+
cd .dart_tool/pub-search-data
10+
11+
echo "Downloading Dart SDK index.json"
12+
curl -o https-api.dart.dev-stable-latest-index.json https://api.dart.dev/stable/latest/index.json
13+
14+
echo "Downloading Flutter SDK index.json"
15+
curl -o https-api.flutter.dev-flutter-index.json https://api.flutter.dev/flutter/index.json

0 commit comments

Comments
 (0)