blob: c659dd94e43e9b0a982e9b61f7a701551602dc7b [file] [log] [blame] [edit]
import 'dart:convert';
import 'dart:io';
import 'package:discoveryapis_generator/discoveryapis_generator.dart';
import 'package:io/ansi.dart' as ansi;
import 'package:path/path.dart' as p;
import 'package:pool/pool.dart';
import 'fetch_core.dart';
import 'utils.dart';
const _submodulePath = 'discovery-artifact-manager';
const _discoveriesPath = 'discoveries';
class FetchGitHub extends FetchCore {
const FetchGitHub();
@override
Future<List<RestDescription>> fetchDiscoveryDocuments({
Map<String, String>? existingRevisions,
}) async {
final executablePath = p.dirname(Platform.script.toFilePath());
final repoRoot = p.dirname(p.dirname(executablePath));
final submodulePath = p.join(repoRoot, _submodulePath);
final discoveriesPath = p.join(submodulePath, _discoveriesPath);
final discoveriesIndex = p.join(discoveriesPath, 'index.json');
final directoryList = DirectoryList.fromJson(
await _jsonFromFile(discoveriesIndex),
);
final list = directoryList.items!;
Future<RestDescription?> download(DirectoryListItems item) async {
final itemPath = p.join(
discoveriesPath,
'${item.name}.${item.version}.json',
);
try {
final description = RestDescription.fromJson(
await _jsonFromFile(itemPath),
);
description.sort();
return description;
} on PathNotFoundException catch (e, stack) {
ansi.red.wrap('$e\n$stack');
return null;
}
}
final pool = Pool(10);
try {
var count = 0;
return await pool
.forEach(list, (DirectoryListItems item) async {
print(
ansi.darkGray.wrap(
'Requesting ${++count} of ${list.length} - ${item.id}',
),
);
RestDescription? description;
for (var i = 1; i <= 10; i++) {
description = await download(item);
if (i > 1) {
print(' ${item.id} try #$i');
}
final existingRevision = existingRevisions![description?.id!];
if (existingRevision != null &&
existingRevision != description!.revision) {
final compare = existingRevision.compareTo(
description.revision!,
);
if (compare.isNegative) {
print(
' New! ${description.id} '
'from $existingRevision to ${description.revision}',
);
} else {
final tryAgainLag = i > 5 ? 5 : i;
print(
' Old revision for ${description.id} '
'from $existingRevision to ${description.revision}.\n'
' Trying again in $tryAgainLag second(s) – '
'${item.discoveryRestUrl}',
);
await Future<void>.delayed(Duration(seconds: tryAgainLag));
continue;
}
}
return description;
}
return description;
})
.where((rd) => rd != null)
.cast<RestDescription>()
.toList();
} finally {
await pool.close();
}
}
}
Future<Map<String, dynamic>> _jsonFromFile(String filePath) async =>
(await _decoder.bind(File(filePath).openRead()).single)
as Map<String, dynamic>;
final _decoder = const Utf8Decoder().fuse(const JsonDecoder());