Remove try from future.

Bug:
Change-Id: I4e003bfa1cccbb8445450d2e897037b8dd7dc941
Reviewed-on: https://dart-review.googlesource.com/10940
Reviewed-by: William Hesse <whesse@google.com>
This commit is contained in:
Morten Krogh-Jespersen 2017-10-05 11:49:52 +00:00 committed by Morten Krogh-jespersen
parent bc64539b68
commit 4962444511
5 changed files with 100 additions and 135 deletions

View file

@ -5,7 +5,7 @@
import 'dart:async';
import 'dart:io';
import 'logger.dart';
import 'try.dart';
import 'util.dart';
typedef Future<String> FetchDataFunction();
typedef Future<String> WithCacheFunction(FetchDataFunction fetchData,
@ -26,21 +26,15 @@ CreateCacheFunction initCache(Uri baseUri, [Logger logger]) {
if (overrideKey != null) {
key = overrideKey;
}
if (key == null || key.isEmpty) {
logger.warning("Key is null or empty - cannot cache result");
} else {
// format key
key = key.replaceAll("/", "_").replaceAll(".", "_");
Try<CacheResult> readResult = await cache.read(key, duration);
if (!readResult.isError && readResult.value.hasResult) {
var cacheResult = await cache.read(key, duration);
if (cacheResult.hasResult) {
logger.debug("Found key $key in cache");
return readResult.value.result;
}
if (readResult.isError) {
logger.error("Error when reading from cache", readResult.error,
readResult.stackTrace);
return cacheResult.result;
}
}
@ -93,32 +87,35 @@ class Cache {
}
/// Try reading [path] from cache
Future<Try<CacheResult>> read(String path, [Duration duration]) async {
Future<CacheResult> read(String path, [Duration duration]) async {
if (memoryCache.containsKey(path)) {
logger.debug('Found $path in memory cache');
return new Try.from(new CacheResult(memoryCache[path]));
return new CacheResult(memoryCache[path]);
}
File file = new File.fromUri(base.resolve(path));
if (!(await file.exists())) {
if (!await file.exists()) {
logger.debug('Could not find file $path in file cache');
return new Try.from(new CacheResult.noResult());
return new CacheResult.noResult();
}
if (duration != null &&
new DateTime.now().difference(await file.lastModified()) > duration) {
logger.debug('File $path was found but the information is too stale,'
'for the duration: $duration');
return new Try.from(new CacheResult.noResult());
return new CacheResult.noResult();
}
return tryStartAsync(() async {
logger.debug('Found $path in file cache');
var text = await file.readAsString();
logger.debug('Found $path in file cache');
try {
String text = await file.readAsString();
memoryCache[path] = text;
return new CacheResult(text);
});
} catch (error, st) {
logger.error("Could not read $path:", error, st);
return new CacheResult.noResult();
}
}
/// Store [text] as the cache data for [path].

View file

@ -16,7 +16,6 @@ import 'cache_new.dart';
import 'logger.dart';
import 'luci_api.dart' hide Timing;
import 'luci.dart';
import 'try.dart';
import 'util.dart';
Future mainInternal(Bot bot, List<String> args,
@ -51,22 +50,16 @@ Future<Map<BuildUri, List<BuildResult>>> loadBuildResults(
Logger logger = createLogger(verbose: verbose);
CreateCacheFunction createCache =
createCacheFunction(logger, disableCache: noCache);
Try<List<BuildDetail>> tryBuildDetails = await fetchBuildsForCommmit(
buildDetails = await fetchBuildsForCommmit(
luci, logger, DART_CLIENT, commit, createCache, 25);
tryBuildDetails.fold(exceptionPrint('Failed to fetch commits.'),
(List<BuildDetail> result) {
if (result.isEmpty) {
print('No builds found for $commit');
} else {
buildDetails = result;
if (verbose) {
log('Found builds for commit $commit:');
buildDetails.forEach((b) => log(' ${b.botName}: ${b.buildNumber}'));
} else {
print('Found ${buildDetails.length} builds for commit $commit.');
}
}
});
if (buildDetails.isEmpty) {
print('No builds found for $commit');
} else if (verbose) {
log('Found builds for commit $commit:');
buildDetails.forEach((b) => log(' ${b.botName}: ${b.buildNumber}'));
} else {
print('Found ${buildDetails.length} builds for commit $commit.');
}
}
BuildUri updateWithCommit(BuildUri buildUri) {

View file

@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'try.dart';
import 'logger.dart';
import 'cache_new.dart';
import 'luci_api.dart';
@ -19,49 +18,46 @@ const String DART_CLIENT = 'client.dart';
/// Fetches all builds for a given [commit]-hash, by searching the latest
/// [amount] builds.
Future<Try<List<BuildDetail>>> fetchBuildsForCommmit(
LuciApi luciApi,
Logger logger,
String client,
String commit,
CreateCacheFunction createCache,
[int amount = 1]) async {
Future<List<BuildDetail>> fetchBuildsForCommmit(LuciApi luciApi, Logger logger,
String client, String commit, CreateCacheFunction createCache,
[int amount = 1]) {
logger.info(
"Sorry - this is going to take some time, since we have to look into all "
"$amount latest builds for all bots for client ${client}.\n"
"Subsequent queries run faster if caching is not turned off...");
logger.debug("Finding primary bots for client $client");
var buildBots = await getPrimaryBuilders(
var futureBuildBots = getPrimaryBuilders(
luciApi, client, createCache(duration: new Duration(minutes: 30)));
var cache = createCache(duration: new Duration(minutes: 30));
return (await buildBots.bindAsync((buildBots) async {
return futureBuildBots.then((buildBots) {
var buildBotBuilds = new List<List<BuildDetail>>();
for (var buildBot in buildBots) {
(await luciApi.getBuildBotDetails(client, buildBot, cache, amount)).fold(
(ex, st) {
logger.error("Problem getting results", ex, st);
}, buildBotBuilds.add);
}
logger.debug("All latest $amount builds found for client $client. "
"Processing results...");
return buildBotBuilds.expand((id) => id).toList();
})).bind((buildDetails) {
return buildDetails.where((BuildDetail buildDetail) {
return buildDetail.allChanges
.any((change) => change.revision.startsWith(commit));
}).toList();
var futureDetails = buildBots.map((buildBot) {
return luciApi
.getBuildBotDetails(client, buildBot, cache, amount)
.then(buildBotBuilds.add)
.catchError(
errorLogger(logger, "Could not get details for $buildBot", []));
});
return Future.wait(futureDetails).then((details) {
return buildBotBuilds.expand((id) => id);
}).then((details) {
return details.where((buildDetail) {
return buildDetail.allChanges
.any((change) => change.revision.startsWith(commit));
}).toList();
});
});
}
/// [getBuilderGroups] fetches all builder groups not in -dev, -stable and
/// -integration from CBE.
Future<Try<List<String>>> getBuilderGroups(
LuciApi luciApi, String client, WithCacheFunction withCache) async {
var result = await luciApi.getJsonFromChromeBuildExtract(client, withCache);
return result.bind((json) {
Future<List<String>> getBuilderGroups(
LuciApi luciApi, String client, WithCacheFunction withCache) {
var result = luciApi.getJsonFromChromeBuildExtract(client, withCache);
return result.then((json) {
var builders = json["builders"];
return builders.keys.fold<Map<String, Object>>({},
(Map<String, Object> map, builderKey) {
@ -75,19 +71,19 @@ Future<Try<List<String>>> getBuilderGroups(
}
/// [getAllBuilders] fetches all builders from CBE.
Future<Try<List<String>>> getAllBuilders(
LuciApi luciApi, String client, WithCacheFunction withCache) async {
var result = await luciApi.getJsonFromChromeBuildExtract(client, withCache);
return result.bind((json) {
Future<List<String>> getAllBuilders(
LuciApi luciApi, String client, WithCacheFunction withCache) {
var result = luciApi.getJsonFromChromeBuildExtract(client, withCache);
return result.then((json) {
return json["builders"].keys;
});
}
/// [getPrimaryBuilders] fetches all primary builders from CBE.
Future<Try<List<String>>> getPrimaryBuilders(
LuciApi luciApi, String client, WithCacheFunction withCache) async {
var result = await getAllBuilders(luciApi, client, withCache);
return result.bind((builders) {
Future<List<String>> getPrimaryBuilders(
LuciApi luciApi, String client, WithCacheFunction withCache) {
var result = getAllBuilders(luciApi, client, withCache);
return result.then((builders) {
return builders
.where((builderKey) =>
!UNINTERESTING_BUILDER_SUFFIXES.any((x) => builderKey.contains(x)))
@ -96,13 +92,13 @@ Future<Try<List<String>>> getPrimaryBuilders(
}
/// [getPrimaryBuilders] gets all builders in builder group [builderGroup].
Future<Try<List<String>>> getBuildersInBuilderGroup(LuciApi luciApi,
String client, WithCacheFunction withCache, String builderGroup) async {
var result = await luciApi.getJsonFromChromeBuildExtract(client, withCache);
return result.bind((json) {
Future<List<String>> getBuildersInBuilderGroup(LuciApi luciApi, String client,
WithCacheFunction withCache, String builderGroup) {
var result = luciApi.getJsonFromChromeBuildExtract(client, withCache);
return result.then((json) {
var builders = json["builders"];
return builders.keys.where((builder) {
return sanitizeCategory(builders[builder]["category"]) == builderGroup;
});
}).toList();
});
}

View file

@ -7,7 +7,6 @@ import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:archive/archive.dart';
import 'try.dart';
import 'cache_new.dart';
const String LUCI_HOST = "luci-milo.appspot.com";
@ -28,30 +27,32 @@ class LuciApi {
/// [getJsonFromChromeBuildExtract] gets json from Cbe, with information
/// about all bots and current builds.
Future<Try<dynamic>> getJsonFromChromeBuildExtract(
Future<dynamic> getJsonFromChromeBuildExtract(
String client, WithCacheFunction withCache) async {
var result = await tryStartAsync(() => withCache(
() => _makeGetRequest(new Uri(
scheme: 'https', host: CBE_HOST, path: "/get_master/${client}")),
"cbe"));
return result.bind((str) => JSON.decode(str));
return withCache(
() => _makeGetRequest(new Uri(
scheme: 'https',
host: CBE_HOST,
path: "/get_master/${client}")),
"cbe")
.then(JSON.decode);
}
/// [getMaster] fetches master information for all bots.
Future<Try<Object>> getMaster(
String client, WithCacheFunction withCache) async {
Future<dynamic> getMaster(String client, WithCacheFunction withCache) async {
var uri = new Uri(
scheme: "https",
host: LUCI_HOST,
path: "prpc/milo.Buildbot/GetCompressedMasterJSON");
var body = {"name": client};
var result = await tryStartAsync(() => withCache(
() => _makePostRequest(uri, JSON.encode(body), {
HttpHeaders.CONTENT_TYPE: "application/json",
HttpHeaders.ACCEPT: "application/json"
}),
'${uri.path}'));
return result.bind((str) => JSON.decode(str)).bind((json) {
return withCache(
() => _makePostRequest(uri, JSON.encode(body), {
HttpHeaders.CONTENT_TYPE: "application/json",
HttpHeaders.ACCEPT: "application/json"
}),
'${uri.path}')
.then(JSON.decode)
.then((json) {
var data = JSON.decode(UTF8
.decode(new GZipDecoder().decodeBytes(BASE64.decode(json["data"]))));
return data;
@ -60,7 +61,7 @@ class LuciApi {
/// Calling the Milo Api to get latest builds for this bot,
/// where the field [amount] is the number of recent builds to fetch.
Future<Try<List<BuildDetail>>> getBuildBotDetails(
Future<List<BuildDetail>> getBuildBotDetails(
String client, String botName, WithCacheFunction withCache,
[int amount = 20]) async {
var uri = new Uri(
@ -73,13 +74,14 @@ class LuciApi {
"limit": amount,
"includeCurrent": true
};
var result = await tryStartAsync(() => withCache(
() => _makePostRequest(uri, JSON.encode(body), {
HttpHeaders.CONTENT_TYPE: "application/json",
HttpHeaders.ACCEPT: "application/json"
}),
'${uri.path}_${botName}_$amount'));
return result.bind((str) => JSON.decode(str)).bind((json) {
return withCache(
() => _makePostRequest(uri, JSON.encode(body), {
HttpHeaders.CONTENT_TYPE: "application/json",
HttpHeaders.ACCEPT: "application/json"
}),
'${uri.path}_${botName}_$amount')
.then(JSON.decode)
.then((json) {
return json["builds"].map((b) {
var build = JSON.decode(UTF8.decode(BASE64.decode(b["data"])));
return getBuildDetailFromJson(client, botName, build);
@ -89,20 +91,21 @@ class LuciApi {
/// Calling the Milo Api to get information about a specific build
/// where the field [buildNumber] is the build number to fetch.
Future<Try<BuildDetail>> getBuildBotBuildDetails(String client,
String botName, int buildNumber, WithCacheFunction withCache) async {
Future<BuildDetail> getBuildBotBuildDetails(String client, String botName,
int buildNumber, WithCacheFunction withCache) async {
var uri = new Uri(
scheme: "https",
host: LUCI_HOST,
path: "prpc/milo.Buildbot/GetBuildbotBuildJSON");
var body = {"master": client, "builder": botName, "buildNum": buildNumber};
var result = await tryStartAsync(() => withCache(
() => _makePostRequest(uri, JSON.encode(body), {
HttpHeaders.CONTENT_TYPE: "application/json",
HttpHeaders.ACCEPT: "application/json"
}),
'${uri.path}_${botName}_$buildNumber'));
return result.bind((str) => JSON.decode(str)).bind((json) {
return withCache(
() => _makePostRequest(uri, JSON.encode(body), {
HttpHeaders.CONTENT_TYPE: "application/json",
HttpHeaders.ACCEPT: "application/json"
}),
'${uri.path}_${botName}_$buildNumber')
.then(JSON.decode)
.then((json) {
var build = JSON.decode(UTF8.decode(BASE64.decode(json["data"])));
return getBuildDetailFromJson(client, botName, build);
});

View file

@ -30,17 +30,6 @@ class Try<T> {
}
}
Future<Try<S>> bindAsync<S>(Future<S> f(T x)) async {
if (_err != null) {
return new Try.fail(_err, _stackTrace);
}
try {
return new Try.from(await f(_val));
} catch (ex, stackTrace) {
return new Try.fail(ex, stackTrace);
}
}
void fold(void caseErr(dynamic ex, StackTrace st), void caseVal(T x)) {
if (_err != null) {
caseErr(_err, _stackTrace);
@ -49,18 +38,9 @@ class Try<T> {
}
}
Future foldAsync(
Future caseErr(dynamic ex, StackTrace st), Future caseVal(T x)) async {
if (_err != null) {
await caseErr(_err, _stackTrace);
} else {
await caseVal(_val);
}
}
bool get isError => _err != null;
Exception get error => _err;
Error get error => _err;
StackTrace get stackTrace => _stackTrace;
T get value => _val;
@ -71,7 +51,3 @@ class Try<T> {
Try<T> tryStart<T>(T action()) {
return new Try<int>.from(0).bind<T>((dummy) => action());
}
Future<Try<T>> tryStartAsync<T>(Future<T> action()) {
return new Try<int>.from(0).bindAsync<T>((dummy) => action());
}