// 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. // @dart = 2.6 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 runGit( List args, { String processWorkingDir, }) async { return Process.run( 'git', args, workingDirectory: processWorkingDir, runInShell: true, ); } Future> 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( ['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 points; final String date; } Future parse(String jsonFileName) async { final List gitLog = await getGitLog(); final String gitRevision = gitLog[0]; final String gitCommitDate = gitLog[1]; final List rawPoints = await GoogleBenchmarkParser.parse( jsonFileName, ); final List points = []; for (final MetricPoint rawPoint in rawPoints) { points.add(FlutterEngineMetricPoint( rawPoint.tags[kNameKey], rawPoint.value, gitRevision, moreTags: rawPoint.tags, )); } return PointsAndDate(points, gitCommitDate); } Future connectFlutterDestination() async { const String kTokenPath = 'TOKEN_PATH'; const String kGcpProject = 'GCP_PROJECT'; final Map 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, 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.', defaultsTo: false, ); return parser; } Future main(List 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, ), ); }