| // 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. |
| |
| // This script looks at the current commit and branch of the git repository in |
| // which it was run, and finds the contemporary commit in the master branch of |
| // another git repository, whose path is provided on the command line. The |
| // contemporary commit is the one that was public at the time of the last commit |
| // on the master branch before the current commit's branch was created. |
| |
| import 'dart:io'; |
| |
| const bool debugLogging = false; |
| |
| void log(String message) { |
| if (debugLogging) { |
| print(message); |
| } |
| } |
| |
| const String _commitTimestampFormat = '--format=%cI'; |
| DateTime _parseTimestamp(String line) => DateTime.parse(line.trim()); |
| int _countLines(String output) => |
| output.trim().split('/n').where((String line) => line.isNotEmpty).length; |
| |
| String findCommit({ |
| required String primaryRepoDirectory, |
| required String primaryBranch, |
| required String primaryTrunk, |
| required String secondaryRepoDirectory, |
| required String secondaryBranch, |
| }) { |
| final DateTime anchor; |
| if (primaryBranch == primaryTrunk) { |
| log('on $primaryTrunk, using last commit time'); |
| anchor = _parseTimestamp( |
| git(primaryRepoDirectory, <String>[ |
| 'log', |
| _commitTimestampFormat, |
| '--max-count=1', |
| primaryBranch, |
| '--', |
| ]), |
| ); |
| } else { |
| final String mergeBase = |
| git(primaryRepoDirectory, <String>[ |
| 'merge-base', |
| primaryBranch, |
| primaryTrunk, |
| ], allowFailure: true).trim(); |
| if (mergeBase.isEmpty) { |
| throw StateError( |
| 'Branch $primaryBranch does not seem to have a common history with trunk $primaryTrunk.', |
| ); |
| } |
| anchor = _parseTimestamp( |
| git(primaryRepoDirectory, <String>[ |
| 'log', |
| _commitTimestampFormat, |
| '--max-count=1', |
| mergeBase, |
| '--', |
| ]), |
| ); |
| if (debugLogging) { |
| final int missingTrunkCommits = _countLines( |
| git(primaryRepoDirectory, <String>['rev-list', primaryTrunk, '^$primaryBranch', '--']), |
| ); |
| final int extraCommits = _countLines( |
| git(primaryRepoDirectory, <String>['rev-list', primaryBranch, '^$primaryTrunk', '--']), |
| ); |
| if (missingTrunkCommits == 0 && extraCommits == 0) { |
| log('$primaryBranch is even with $primaryTrunk at $mergeBase'); |
| } else { |
| log( |
| '$primaryBranch branched from $primaryTrunk $missingTrunkCommits commits ago, trunk has advanced by $extraCommits commits since then.', |
| ); |
| } |
| } |
| } |
| return git(secondaryRepoDirectory, <String>[ |
| 'log', |
| '--format=%H', |
| '--until=${anchor.toIso8601String()}', |
| '--max-count=1', |
| secondaryBranch, |
| '--', |
| ]); |
| } |
| |
| String git(String workingDirectory, List<String> arguments, {bool allowFailure = false}) { |
| final ProcessResult result = Process.runSync( |
| 'git', |
| arguments, |
| workingDirectory: workingDirectory, |
| ); |
| if (!allowFailure && result.exitCode != 0 || '${result.stderr}'.isNotEmpty) { |
| throw ProcessException('git', arguments, '${result.stdout}${result.stderr}', result.exitCode); |
| } |
| return '${result.stdout}'; |
| } |
| |
| void main(List<String> arguments) { |
| if (arguments.isEmpty || |
| arguments.length != 4 || |
| arguments.contains('--help') || |
| arguments.contains('-h')) { |
| print( |
| 'Usage: dart find_commit.dart <path-to-primary-repo> <primary-trunk> <path-to-secondary-repo> <secondary-branch>\n' |
| 'This script will find the commit in the secondary repo that was contemporary\n' |
| 'when the commit in the primary repo was created. If that commit is on a\n' |
| "branch, then the date of the branch's last merge is used instead.", |
| ); |
| } else { |
| final String primaryRepo = arguments.first; |
| final String primaryTrunk = arguments[1]; |
| final String secondaryRepo = arguments[2]; |
| final String secondaryBranch = arguments.last; |
| print( |
| findCommit( |
| primaryRepoDirectory: primaryRepo, |
| primaryBranch: git(primaryRepo, <String>['rev-parse', '--abbrev-ref', 'HEAD']).trim(), |
| primaryTrunk: primaryTrunk, |
| secondaryRepoDirectory: secondaryRepo, |
| secondaryBranch: secondaryBranch, |
| ).trim(), |
| ); |
| } |
| } |