blob: 8bded4d70521e555053e80c180180fd8e5066f8a [file] [log] [blame] [edit]
// Copyright (c) 2019, 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.
import 'dart:async';
import 'dart:io';
import 'package:args/args.dart';
import 'package:collection/collection.dart';
import 'package:github/github.dart';
import 'package:linter/src/utils.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart';
import 'crawl.dart';
void main(List<String> args) async {
var parser = ArgParser()
..addOption(
'token',
abbr: 't',
help: 'Specifies a GitHub auth token.',
)
..addFlag(
'linter',
abbr: 'l',
help: 'Prints out latest linter rule to linter release information.',
)
..addFlag(
'sdk',
abbr: 's',
help: 'Prints out latest SDK release to linter release information.',
);
ArgResults options;
try {
options = parser.parse(args);
} on FormatException {
printToConsole(parser.usage);
return;
}
var printLinter = options['linter'] == true;
var printSdk = options['sdk'] == true;
if (!printLinter && !printSdk) {
printToConsole('Either --linter or --sdk must be specified!');
return;
}
var token = options['token'];
var auth = token is String ? Authentication.withToken(token) : null;
if (printLinter) {
var sinceInfo = await getSinceMap(auth);
for (var MapEntry(key: lintName, value: sinceInfo) in sinceInfo.entries) {
var sinceLinter = sinceInfo.sinceLinter;
if (sinceLinter != null) {
printToConsole('$lintName: $sinceLinter');
}
}
if (printSdk) {
printToConsole('\n================\n');
}
}
if (printSdk) {
var sinceSdk = await getDartSdkMap(auth);
for (var MapEntry(key: sdkVersion, value: linterVersion) in sinceSdk.entries
.sorted(
(a, b) => Version.parse(b.key).compareTo(Version.parse(a.key)))) {
printToConsole('$sdkVersion: $linterVersion');
}
}
}
final Version earliestLinterInDart2 = Version.parse('0.1.58');
Map<String, String>? _dartSdkMap;
Map<String, SinceInfo>? _sinceMap;
Future<Map<String, String>> getDartSdkMap([Authentication? auth]) async {
var dartSdkMap = _dartSdkMap;
if (dartSdkMap == null) {
var dartSdkCache = File('tool/since/dart_sdk.yaml').readAsStringSync();
var yamlMap = loadYamlNode(dartSdkCache) as YamlMap;
dartSdkMap = yamlMap.map((k, v) => MapEntry(k.toString(), v.toString()));
var sdks = await getSdkTags(auth, onlyStable: true);
for (var sdk in sdks) {
if (!dartSdkMap.containsKey(sdk)) {
var linterVersion = await linterForDartSdk(sdk);
if (linterVersion != null) {
dartSdkMap[sdk] = linterVersion;
printToConsole('fetched...');
printToConsole('$sdk : $linterVersion');
printToConsole('(consider caching in tool/since/dart_sdk.yaml)');
}
}
}
_dartSdkMap = dartSdkMap;
}
return dartSdkMap;
}
Future<Map<String, SinceInfo>> getSinceMap([Authentication? auth]) async =>
_sinceMap ??= await _getSinceInfo(auth);
Future<Map<String, SinceInfo>> _getSinceInfo(Authentication? auth) async {
var linterCache = File('tool/since/linter.yaml').readAsStringSync();
var linterVersionCache = loadYamlNode(linterCache) as YamlMap;
var sinceMap = <String, SinceInfo>{};
for (var lint in registeredLints.map((l) => l.name)) {
var linterVersion = linterVersionCache[lint] as String?;
if (linterVersion == null) {
linterVersion = await findSinceLinter(lint, auth);
if (linterVersion != null) {
printToConsole('fetched...');
printToConsole('$lint : $linterVersion');
printToConsole('(consider caching in tool/since/linter.yaml)');
}
}
sinceMap[lint] = SinceInfo(
sinceLinter: linterVersion,
sinceDartSdk: await _sinceSdkForLinter(linterVersion, auth),
);
}
return sinceMap;
}
Future<String?> _nextLinterVersion(
Version linterVersion, Authentication? auth) async {
var versions = await getLinterReleases(auth);
for (var version in versions) {
if (Version.parse(version) > linterVersion) {
return version;
}
}
return null;
}
Future<String?> _sinceSdkForLinter(
String? linterVersionString, Authentication? auth) async {
if (linterVersionString == null) {
return null;
}
try {
var linterVersion = Version.parse(linterVersionString);
if (linterVersion.compareTo(earliestLinterInDart2) < 0) {
return bottomDartSdk.toString();
}
var sdkVersions = <String>[];
var sdkCache = await getDartSdkMap(auth);
for (var sdkEntry in sdkCache.entries) {
if (Version.parse(sdkEntry.value) == linterVersion) {
sdkVersions.add(sdkEntry.key);
}
}
if (sdkVersions.isEmpty) {
var nextLinter = await _nextLinterVersion(linterVersion, auth);
return _sinceSdkForLinter(nextLinter, auth);
}
sdkVersions.sort();
return sdkVersions.first;
} on FormatException {
return null;
}
}
class SinceInfo {
final String? sinceLinter;
final String? sinceDartSdk;
SinceInfo({this.sinceLinter, this.sinceDartSdk});
@override
String toString() => 'linter: $sinceLinter | sdk: $sinceDartSdk';
}