blob: 60638819b6a7be68e7bcbb0cedb69a15a246af4a [file] [log] [blame]
/*
Copyright 2013 Google Inc. All Rights Reserved.
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.
*/
// Package git provides helper methods for invoking Git commands.
package git
import (
"bufio"
"errors"
"io"
"os"
"os/exec"
"strconv"
"strings"
)
// Errors returned by this package.
var (
NotOneLine = errors.New("git command output was not one line")
)
// Run invokes git with the specified arguments.
func Run(args ...string) error {
cmd := exec.Command("git", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// Lines invokes git with the specified arguments and returns a slice of
// the output lines.
func Lines(args ...string) (res []string, err error) {
cmd := exec.Command("git", args...)
reader, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
defer reader.Close()
cmd.Stderr = os.Stderr
if err = cmd.Start(); err != nil {
return nil, err
}
defer func() {
errwait := cmd.Wait()
if err == nil {
err = errwait
}
}()
r := bufio.NewReader(reader)
for {
line, err := r.ReadString('\n')
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
res = append(res, line[:len(line)-1])
}
return res, nil
}
// Lines invokes git with the specified arguments and returns a string
// containing its single line of output. Returns NotOneLine if the
// git does not output a single line.
func Line(args ...string) (string, error) {
lines, err := Lines(args...)
if err != nil {
return "", err
}
if len(lines) != 1 {
return "", NotOneLine
}
return lines[0], err
}
// Blame returns the set of line numbers from file that were added or modified
// in Git revision rev. Rev must be a full 20 char hex revision id. Lines are
// numbered from 1.
func Blame(rev, file string) (map[int]bool, error) {
lines, err := Lines("blame", "--porcelain", rev+"^..", "--", file)
if err != nil {
return nil, err
}
res := make(map[int]bool)
for _, s := range lines {
if !strings.HasPrefix(s, rev+" ") {
continue
}
i, err := strconv.Atoi(strings.Split(s, " ")[2])
if err != nil {
return nil, err
}
res[i] = true
}
return res, nil
}