| /* | |
| 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 | |
| } |