blob: 705ee49cfa2f932476fe7d993d02209f6269782f [file] [log] [blame] [edit]
// Copyright 2013 The Flutter Authors. 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:convert';
import 'dart:io';
import 'package:args/args.dart';
import 'package:metrics_center/metrics_center.dart';
import 'package:path/path.dart' as p;
Future<ProcessResult> runGit(
List<String> args, {
String? processWorkingDir,
}) async {
return Process.run(
'git',
args,
workingDirectory: processWorkingDir,
runInShell: true,
);
}
Future<List<String>> getGitLog() async {
final String gitRoot = p.absolute('../..');
// Somehow gitDir.currentBranch() doesn't work in Cirrus with "fatal: 'HEAD' -
// not a valid ref". Therefore, we use "git log" to get the revision manually.
final ProcessResult logResult = await runGit(
<String>['log', '--pretty=format:%H %ct', '-n', '1'],
processWorkingDir: gitRoot,
);
if (logResult.exitCode != 0) {
throw 'Unexpected exit code ${logResult.exitCode}';
}
return logResult.stdout.toString().trim().split(' ');
}
class PointsAndDate {
PointsAndDate(this.points, this.date);
final List<FlutterEngineMetricPoint> points;
final String date;
}
Future<PointsAndDate> parse(String jsonFileName) async {
final List<String> gitLog = await getGitLog();
final String gitRevision = gitLog[0];
final String gitCommitDate = gitLog[1];
final List<MetricPoint> rawPoints = await GoogleBenchmarkParser.parse(
jsonFileName,
);
final List<FlutterEngineMetricPoint> points = <FlutterEngineMetricPoint>[];
for (final MetricPoint rawPoint in rawPoints) {
points.add(FlutterEngineMetricPoint(
rawPoint.tags[kNameKey]!,
rawPoint.value!,
gitRevision,
moreTags: rawPoint.tags,
));
}
return PointsAndDate(points, gitCommitDate);
}
Future<FlutterDestination> connectFlutterDestination() async {
const String kTokenPath = 'TOKEN_PATH';
const String kGcpProject = 'GCP_PROJECT';
final Map<String, String> env = Platform.environment;
final bool isTesting = env['IS_TESTING'] == 'true';
if (env.containsKey(kTokenPath) && env.containsKey(kGcpProject)) {
return FlutterDestination.makeFromAccessToken(
File(env[kTokenPath]!).readAsStringSync(),
env[kGcpProject]!,
isTesting: isTesting,
);
}
return FlutterDestination.makeFromCredentialsJson(
jsonDecode(Platform.environment['BENCHMARK_GCP_CREDENTIALS']!)
as Map<String, dynamic>,
isTesting: isTesting,
);
}
ArgParser _serupOptions() {
final ArgParser parser = ArgParser();
parser.addOption(
'json',
mandatory: true,
help: 'Path to the benchmarks json file.',
);
parser.addFlag(
'no-upload',
help: 'Upload the parsed benchmarks.',
);
return parser;
}
Future<void> main(List<String> args) async {
final ArgParser parser = _serupOptions();
final ArgResults options = parser.parse(args);
final String json = options['json'] as String;
final PointsAndDate pointsAndDate = await parse(json);
final bool noUpload = options['no-upload'] as bool;
if (noUpload) {
return;
}
// The data will be sent to the Datastore of the GCP project specified through
// environment variable BENCHMARK_GCP_CREDENTIALS, or TOKEN_PATH/GCP_PROJECT.
// The engine Cirrus job has currently configured the GCP project to
// flutter-cirrus for test. We'll eventually migrate to flutter-infra project
// once the test is done.
final FlutterDestination destination = await connectFlutterDestination();
await destination.update(
pointsAndDate.points,
DateTime.fromMillisecondsSinceEpoch(
int.parse(pointsAndDate.date) * 1000,
isUtc: true,
),
'flutter_engine_benchmark',
);
}