blob: 7f6da678561980f13afc3522f02cb18ebdcb69c2 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The branch-diff command compares two git repos looking for changes that
// are missing in one compared to the other.
package main
import (
"flag"
"fmt"
"regexp"
"android.googlesource.com/platform/tools/gpu/client/git"
"android.googlesource.com/platform/tools/gpu/framework/app"
"android.googlesource.com/platform/tools/gpu/framework/file"
"android.googlesource.com/platform/tools/gpu/framework/log"
)
var (
src = flag.String("src", "", "the source directory")
dst = flag.String("dst", "", "the destination directory")
cnt = flag.Int("c", 100, "maximum number of CLs to consider")
)
func main() {
app.ShortHelp = "branch-diff: A tool to compare two git repos for changes that exist in src and not dst."
app.Run(run)
}
func run(ctx log.Context) error {
if *src == "" {
app.Usage(ctx, "Missing src directory")
return nil
}
if *dst == "" {
app.Usage(ctx, "Missing dst directory")
return nil
}
src, err := git.New(file.Abs(*src).System())
if err != nil {
return ctx.WrapError(err, "Invalid src directory")
}
dst, err := git.New(file.Abs(*dst).System())
if err != nil {
return ctx.WrapError(err, "Invalid dst directory")
}
srcCLs, err := src.Log(ctx, *cnt)
if err != nil {
return ctx.WrapError(err, "src log")
}
dstCLs, err := dst.Log(ctx, *cnt)
if err != nil {
return ctx.WrapError(err, "dst log")
}
got := map[string]git.ChangeList{}
for _, cl := range dstCLs {
if changeID := parseChangeID(cl.Description); changeID != "" {
got[changeID] = cl
}
}
for _, cl := range srcCLs {
if changeID := parseChangeID(cl.Description); changeID != "" {
if _, found := got[changeID]; !found {
parent, err := src.Parent(ctx, cl)
if err != nil {
return ctx.WrapError(err, "getting parent")
}
patch, err := src.GetPatch(ctx, parent.SHA, cl.SHA)
if err != nil {
return ctx.WrapError(err, "creating patch")
}
canApply, err := dst.CanApplyPatch(ctx, patch)
if err != nil {
return ctx.WrapError(err, "can apply")
}
applyable := '❌'
if canApply {
applyable = '✅'
}
fmt.Printf("%c %v %-10.10s %v\n", applyable, cl.SHA.String()[:8], cl.GetLdapOrAuthor(), cl.Subject)
}
}
}
return nil
}
var reChangeID = regexp.MustCompile("Change-Id: (I.*)")
func parseChangeID(description string) string {
matches := reChangeID.FindStringSubmatch(description)
if len(matches) < 2 {
return ""
}
return matches[1]
}