Index: tools/gardening/lib/src/buildbot_loading.dart |
diff --git a/tools/gardening/lib/src/buildbot_loading.dart b/tools/gardening/lib/src/buildbot_loading.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..35cf6d7c09ff799470ad077bc86ea2358469b355 |
--- /dev/null |
+++ b/tools/gardening/lib/src/buildbot_loading.dart |
@@ -0,0 +1,140 @@ |
+// Copyright (c) 2017, 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 'util.dart'; |
+ |
+import 'buildbot_structures.dart'; |
+import 'cache.dart'; |
+import 'logdog.dart'; |
+ |
+const String BUILDBOT_BUILDNUMBER = ' BUILDBOT_BUILDNUMBER: '; |
+ |
+/// Read the build result for [buildUri]. |
+/// |
+/// The data is loaded from the cache, if available, otherwise [read] is called |
+/// to fetch the data and stored in the cache afterwards. |
+Future<BuildResult> _readBuildResult( |
+ BuildUri buildUri, Future<String> read()) async { |
+ if (buildUri.buildNumber < 0) { |
+ String text = await read(); |
+ BuildResult result = parseTestStepResult(buildUri, text); |
+ if (result.buildNumber != null) { |
+ cache.write(result.buildUri.logdogPath, text); |
+ } |
+ return result; |
+ } else { |
+ return parseTestStepResult( |
+ buildUri, await cache.read(buildUri.logdogPath, read)); |
+ } |
+} |
+ |
+/// Fetches test data for [buildUri] through the buildbot stdio. |
+Future<BuildResult> readBuildResult( |
+ HttpClient client, BuildUri buildUri) async { |
+ Future<String> read() async { |
+ Uri uri = buildUri.toUri(); |
+ log('Reading buildbot results: $uri'); |
+ return await readUriAsText(client, uri); |
+ } |
+ |
+ return _readBuildResult(buildUri, read); |
+} |
+ |
+/// Fetches test data for [buildUri] through logdog. |
+/// |
+/// The build number of [buildUri] most be non-negative. |
+Future<BuildResult> readLogDogResult(BuildUri buildUri) { |
+ Future<String> read() async { |
+ log('Reading logdog results: $buildUri'); |
+ return cat(buildUri.logdogPath); |
+ } |
+ |
+ return _readBuildResult(buildUri, read); |
+} |
+ |
+/// Parses a test status line of the from |
+/// `Done <config-name> <arch-name> <test-name>: <status>`. |
+/// |
+/// If [line] is not of the correct form, `null` is returned. |
+TestStatus parseTestStatus(String line) { |
+ try { |
+ List<String> parts = split(line, ['Done ', ' ', ' ', ': ']); |
+ String testName = parts[3]; |
+ String configName = parts[1]; |
+ String archName = parts[2]; |
+ String status = parts[4]; |
+ return new TestStatus( |
+ new TestConfiguration(configName, archName, testName), status); |
+ } catch (_) { |
+ return null; |
+ } |
+} |
+ |
+/// Parses the [buildUri] test log and creates a [BuildResult] for it. |
+BuildResult parseTestStepResult(BuildUri buildUri, String text) { |
+ log('Parsing results: $buildUri (${text.length} bytes)'); |
+ int buildNumber; |
+ List<String> currentFailure; |
+ bool parsingTimingBlock = false; |
+ |
+ List<TestStatus> results = <TestStatus>[]; |
+ List<TestFailure> failures = <TestFailure>[]; |
+ List<Timing> timings = <Timing>[]; |
+ for (String line in text.split('\n')) { |
+ if (line.startsWith(BUILDBOT_BUILDNUMBER)) { |
+ buildNumber = |
+ int.parse(line.substring(BUILDBOT_BUILDNUMBER.length).trim()); |
+ } |
+ if (currentFailure != null) { |
+ if (line.startsWith('Done ')) { |
+ TestStatus status = parseTestStatus(line); |
+ if (status != null) { |
+ results.add(status); |
+ failures.add(new TestFailure(buildUri, currentFailure)); |
+ currentFailure = null; |
+ } |
+ } else { |
+ currentFailure.add(line); |
+ } |
+ } else if (line.startsWith('FAILED:')) { |
+ currentFailure = <String>[]; |
+ currentFailure.add(line); |
+ } |
+ if (line.startsWith('--- Total time:')) { |
+ parsingTimingBlock = true; |
+ } else if (parsingTimingBlock) { |
+ if (line.startsWith('0:')) { |
+ timings.addAll(parseTimings(buildUri, line)); |
+ } else { |
+ parsingTimingBlock = false; |
+ } |
+ } |
+ } |
+ return new BuildResult(buildUri, buildNumber, results, failures, timings); |
+} |
+ |
+/// Create the [Timing]s for the [line] as found in the top-20 timings of a |
+/// build step stdio log. |
+List<Timing> parseTimings(BuildUri uri, String line) { |
+ List<String> parts = split(line, [' - ', ' - ', ' ']); |
+ String time = parts[0]; |
+ String stepName = parts[1]; |
+ String configName = parts[2]; |
+ String testNames = parts[3]; |
+ List<Timing> timings = <Timing>[]; |
+ for (String name in testNames.split(',')) { |
+ name = name.trim(); |
+ int slashPos = name.indexOf('/'); |
+ String archName = name.substring(0, slashPos); |
+ String testName = name.substring(slashPos + 1); |
+ timings.add(new Timing( |
+ uri, |
+ time, |
+ new TestStep( |
+ stepName, new TestConfiguration(configName, archName, testName)))); |
+ } |
+ return timings; |
+} |