2021-05-20 23:09:04 +00:00
// 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 ) ;
}
class Commit {
Commit ( this . hash , this . timestamp ) ;
final String hash ;
final DateTime timestamp ;
static String formatArgument = ' --format=%H %cI ' ;
static Commit parse ( String line ) {
final int space = line . indexOf ( ' ' ) ;
return Commit ( line . substring ( 0 , space ) , DateTime . parse ( line . substring ( space + 1 , line . length ) . trimRight ( ) ) ) ;
}
static List < Commit > parseList ( String lines ) {
return lines . split ( ' \n ' ) . where ( ( String line ) = > line . isNotEmpty ) . map ( parse ) . toList ( ) . reversed . toList ( ) ;
}
}
String findCommit ( {
required String primaryRepoDirectory ,
required String primaryBranch ,
required String primaryTrunk ,
required String secondaryRepoDirectory ,
required String secondaryBranch ,
} ) {
final Commit anchor ;
if ( primaryBranch = = primaryTrunk ) {
log ( ' on $ primaryTrunk , using last commit as anchor ' ) ;
2021-07-03 02:16:04 +00:00
anchor = Commit . parse ( git ( primaryRepoDirectory , < String > [ ' log ' , Commit . formatArgument , ' --max-count=1 ' , primaryBranch , ' -- ' ] ) ) ;
2021-05-20 23:09:04 +00:00
} else {
2021-07-03 02:16:04 +00:00
final List < Commit > branchCommits = Commit . parseList ( git ( primaryRepoDirectory , < String > [ ' log ' , Commit . formatArgument , primaryBranch , ' -- ' ] ) ) ;
final List < Commit > trunkCommits = Commit . parseList ( git ( primaryRepoDirectory , < String > [ ' log ' , Commit . formatArgument , primaryTrunk , ' -- ' ] ) ) ;
2021-05-20 23:09:04 +00:00
if ( branchCommits . isEmpty | | trunkCommits . isEmpty | | branchCommits . first . hash ! = trunkCommits . first . hash )
throw StateError ( ' Branch $ primaryBranch does not seem to have a common history with trunk $ primaryTrunk . ' ) ;
if ( branchCommits . last . hash = = trunkCommits . last . hash ) {
log ( ' $ primaryBranch is even with $ primaryTrunk , using last commit as anchor ' ) ;
anchor = trunkCommits . last ;
} else {
int index = 0 ;
while ( branchCommits . length > index & & trunkCommits . length > index & & branchCommits [ index ] . hash = = trunkCommits [ index ] . hash )
index + = 1 ;
log ( ' $ primaryBranch branched from $ primaryTrunk ${ branchCommits . length - index } commits ago, trunk has advanced by ${ trunkCommits . length - index } commits since then. ' ) ;
anchor = trunkCommits [ index - 1 ] ;
}
}
return git ( secondaryRepoDirectory , < String > [
' log ' ,
' --format=%H ' ,
' --until= ${ anchor . timestamp . toIso8601String ( ) } ' ,
' --max-count=1 ' ,
secondaryBranch ,
2021-07-03 02:16:04 +00:00
' -- ' ,
2021-05-20 23:09:04 +00:00
] ) ;
}
String git ( String workingDirectory , List < String > arguments ) {
final ProcessResult result = Process . runSync ( ' git ' , arguments , workingDirectory: workingDirectory ) ;
if ( 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 > 2 | | arguments . contains ( ' --help ' ) | | arguments . contains ( ' -h ' ) ) {
print (
' Usage: dart find_commit.dart [<path-to-primary-repo>] <path-to-secondary-repo> \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 creation is used instead. \n "
' If <path-to-primary-repo> is omitted, the current directory is used for the \n '
' primary repo. '
) ;
} else {
final String primaryRepo = arguments . length = = 1 ? ' . ' : arguments . first ;
final String secondaryRepo = arguments . last ;
print ( findCommit (
primaryRepoDirectory: primaryRepo ,
primaryBranch: git ( primaryRepo , < String > [ ' rev-parse ' , ' --abbrev-ref ' , ' HEAD ' ] ) . trim ( ) ,
primaryTrunk: ' master ' ,
secondaryRepoDirectory: secondaryRepo ,
secondaryBranch: ' master ' ,
) . trim ( ) ) ;
}
}