blob: 9f18c99269e1b823d9b7eec01158fd5cdf7c3bc4 [file] [log] [blame]
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// This is a manual test that can be run to test the .tar.gz decoding.
/// It will save progress in [statusFileName] such that it doesn't have to be
/// finished in a single run.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:pool/pool.dart';
import 'package:pub/src/http.dart';
import 'package:pub/src/io.dart';
const statusFilename = 'extract_all_pub_status.json';
Future<List<String>> allPackageNames() async {
var nextUrl = 'https://pub.dev/api/packages?compact=1';
final result = json.decode(await httpClient.read(nextUrl));
return List<String>.from(result['packages']);
}
Future<List<String>> versionArchiveUrls(String packageName) async {
final url = 'https://pub.dev/api/packages/$packageName';
final result = json.decode(await httpClient.read(url));
return List<String>.from(result['versions'].map((v) => v['archive_url']));
}
Future<void> main() async {
var alreadyDonePackages = <String>{};
var failures = <Map<String, dynamic>>[];
if (fileExists(statusFilename)) {
final json = jsonDecode(readTextFile(statusFilename));
for (final packageName in json['packages'] ?? []) {
alreadyDonePackages.add(packageName);
}
for (final failure in json['failures'] ?? []) {
failures.add(failure);
}
}
print('Already processed ${alreadyDonePackages.length} packages');
print('Already found ${alreadyDonePackages.length}');
void writeStatus() {
writeTextFile(
statusFilename,
JsonEncoder.withIndent(' ').convert({
'packages': [...alreadyDonePackages],
'failures': [...failures],
}),
);
print('Wrote status to $statusFilename');
}
ProcessSignal.sigint.watch().listen((_) {
writeStatus();
exit(1);
});
final pool = Pool(10); // Process 10 packages at a time.
try {
for (final packageName in await allPackageNames()) {
if (alreadyDonePackages.contains(packageName)) {
print('Skipping $packageName - already done');
continue;
}
print('Processing all versions of $packageName '
'[+${alreadyDonePackages.length}, - ${failures.length}]');
final resource = await pool.request();
scheduleMicrotask(() async {
try {
final versions = await versionArchiveUrls(packageName);
var allVersionsGood = true;
await Future.wait(versions.map((archiveUrl) async {
await withTempDir((tempDir) async {
print('downloading $archiveUrl');
http.StreamedResponse response;
try {
response = await httpClient
.send(http.Request('GET', Uri.parse(archiveUrl)));
await extractTarGz(response.stream, tempDir);
print('Extracted $archiveUrl');
} catch (e, _) {
print('Failed to get and extract $archiveUrl $e');
failures.add({'archive': archiveUrl, 'error': e.toString()});
allVersionsGood = false;
return;
}
});
}));
if (allVersionsGood) alreadyDonePackages.add(packageName);
} finally {
resource.release();
}
});
}
} finally {
writeStatus();
exit(failures.isEmpty ? 0 : 1);
}
}