From 889e606cebd8053fe7e0c8de98d6a45f01004b59 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 24 Feb 2020 14:49:12 -0800 Subject: [PATCH] Script to find Flutter earliest Flutter revision that contains an engine revision (#50948) --- dev/tools/find_engine_commit.dart | 130 ++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 dev/tools/find_engine_commit.dart diff --git a/dev/tools/find_engine_commit.dart b/dev/tools/find_engine_commit.dart new file mode 100644 index 0000000000..8b87553910 --- /dev/null +++ b/dev/tools/find_engine_commit.dart @@ -0,0 +1,130 @@ +// Copyright 2014 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:io'; + +void _validate(List args) { + bool errors = false; + if (!File('bin/internal/engine.version').existsSync()) { + errors = true; + print('This program must be run from the root of your flutter repository.'); + } + if (!File('../engine/src/flutter/DEPS').existsSync()) { + errors = true; + print('This program assumes the engine directory is a sibling to the flutter repository directory.'); + } + if (args.length != 1) { + errors = true; + print('This program takes the engine revision as a single argument.'); + } + if (errors) { + exit(-1); + } +} + +const String engineRepo = '../engine/src/flutter'; + +Future main(List args) async { + _validate(args); + await _fetchUpstream(); + await _fetchUpstream(engineRepo); + String flutterRevision; + await for (final FlutterEngineRevision revision in _logEngineVersions()) { + if (!await containsRevision(args[0], revision.engineRevision)) { + if (flutterRevision == null) { + print('Revision not found.'); + exit(-1); + } + print('earliest revision: $flutterRevision'); + print('Tags that contain this engine revision:'); + print(await _tagsForRevision(flutterRevision)); + exit(0); + } + flutterRevision = revision.flutterRevision; + } +} + +Future _fetchUpstream([String workingDirectory = '.']) async { + print('Fetching remotes for "$workingDirectory" - you may be prompted for SSH credentials by git.'); + final ProcessResult fetchResult = await Process.run( + 'git', + [ + 'fetch', + '--all', + ], + workingDirectory: workingDirectory, + ); + if (fetchResult.exitCode != 0) { + throw Exception('Failed to fetch upstream in repository $workingDirectory'); + } +} + +Future _tagsForRevision(String flutterRevision) async { + final ProcessResult tagResult = await Process.run( + 'git', + [ + 'tag', + '--contains', + flutterRevision, + ], + ); + return tagResult.stdout as String; +} + +Future containsRevision(String ancestorRevision, String revision) async { + final ProcessResult result = await Process.run( + 'git', + [ + 'merge-base', + '--is-ancestor', + ancestorRevision, + revision, + ], + workingDirectory: engineRepo, + ); + return result.exitCode == 0; +} + +Stream _logEngineVersions() async* { + final ProcessResult result = await Process.run( + 'git', + [ + 'log', + '--oneline', + '-p', + '--', + 'bin/internal/engine.version', + ], + ); + if (result.exitCode != 0) { + print(result.stderr); + throw Exception('Failed to log bin/internal/engine.version'); + } + + final List lines = (result.stdout as String).split('\n'); + int index = 0; + while (index < lines.length - 1) { + final String flutterRevision = lines[index].split(' ').first; + index += 1; + while (!lines[index].startsWith('+') || lines[index].startsWith('+++')) { + index += 1; + } + if (index >= lines.length) { + break; + } + final String engineRevision = lines[index].substring(1); + yield FlutterEngineRevision(flutterRevision, engineRevision); + index += lines[index + 1].startsWith(r'\ ') ? 2 : 1; + } +} + +class FlutterEngineRevision { + const FlutterEngineRevision(this.flutterRevision, this.engineRevision); + + final String flutterRevision; + final String engineRevision; + + @override + String toString() => '$flutterRevision: $engineRevision'; +}