git.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package git
  2. import (
  3. "bufio"
  4. "io"
  5. "os"
  6. "os/exec"
  7. "path/filepath"
  8. "strings"
  9. "github.com/gitleaks/go-gitdiff/gitdiff"
  10. "github.com/rs/zerolog/log"
  11. )
  12. // GitLog returns a channel of gitdiff.File objects from the git log -p command for the given source.
  13. func GitLog(source string, logOpts string) (<-chan *gitdiff.File, error) {
  14. sourceClean := filepath.Clean(source)
  15. var cmd *exec.Cmd
  16. if logOpts != "" {
  17. args := []string{"-C", sourceClean, "log", "-p", "-U0"}
  18. args = append(args, strings.Split(logOpts, " ")...)
  19. cmd = exec.Command("git", args...)
  20. } else {
  21. cmd = exec.Command("git", "-C", sourceClean, "log", "-p", "-U0", "--full-history", "--all")
  22. }
  23. log.Debug().Msgf("executing: %s", cmd.String())
  24. stdout, err := cmd.StdoutPipe()
  25. if err != nil {
  26. return nil, err
  27. }
  28. stderr, err := cmd.StderrPipe()
  29. if err != nil {
  30. return nil, err
  31. }
  32. if err := cmd.Start(); err != nil {
  33. return nil, err
  34. }
  35. go listenForStdErr(stderr)
  36. return gitdiff.Parse(stdout)
  37. }
  38. // GitDiff returns a channel of gitdiff.File objects from the git diff command for the given source.
  39. func GitDiff(source string, staged bool) (<-chan *gitdiff.File, error) {
  40. sourceClean := filepath.Clean(source)
  41. var cmd *exec.Cmd
  42. cmd = exec.Command("git", "-C", sourceClean, "diff", "-U0", ".")
  43. if staged {
  44. cmd = exec.Command("git", "-C", sourceClean, "diff", "-U0", "--staged", ".")
  45. }
  46. log.Debug().Msgf("executing: %s", cmd.String())
  47. stdout, err := cmd.StdoutPipe()
  48. if err != nil {
  49. return nil, err
  50. }
  51. stderr, err := cmd.StderrPipe()
  52. if err != nil {
  53. return nil, err
  54. }
  55. if err := cmd.Start(); err != nil {
  56. return nil, err
  57. }
  58. go listenForStdErr(stderr)
  59. return gitdiff.Parse(stdout)
  60. }
  61. // listenForStdErr listens for stderr output from git and prints it to stdout
  62. // then exits with exit code 1
  63. func listenForStdErr(stderr io.ReadCloser) {
  64. scanner := bufio.NewScanner(stderr)
  65. errEncountered := false
  66. for scanner.Scan() {
  67. log.Error().Msg(scanner.Text())
  68. errEncountered = true
  69. }
  70. if errEncountered {
  71. os.Exit(1)
  72. }
  73. }