forked from akupila/gitprompt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.go
126 lines (109 loc) · 2.5 KB
/
parser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package gitprompt
import (
"bufio"
"bytes"
"errors"
"os"
"os/exec"
"strconv"
"strings"
)
// GitStatus is the parsed status for the current state in git.
type GitStatus struct {
Sha string
Branch string
Untracked int
Modified int
Staged int
Conflicts int
Ahead int
Behind int
Stashed int
Upstream string
Clean bool
Outdated bool
}
// Parse parses the status for the repository from git. Returns nil if the
// current directory is not part of a git repository.
func Parse() (*GitStatus, error) {
stat, err := runGitCommand("git", "status", "--branch", "--porcelain=2")
if err != nil {
if strings.HasPrefix(err.Error(), "fatal:") {
return nil, nil
}
return nil, err
}
status := &GitStatus{}
lines := strings.Split(stat, "\n")
for _, line := range lines {
switch line[0] {
case '#':
parseHeader(line, status)
case '?':
status.Untracked++
case 'u':
status.Conflicts++
case '1', '2':
if line[2] != '.' {
status.Staged++
}
if line[3] != '.' {
status.Modified++
}
}
}
status.Clean = status.Conflicts == 0 &&
status.Staged == 0 &&
status.Modified == 0
status.Outdated = !status.Clean ||
status.Ahead != 0 ||
status.Behind != 0 ||
status.Untracked != 0
if stashed, err := runGitCommand("git", "rev-list", "--walk-reflogs", "--count", "refs/stash"); err == nil {
if s, err := strconv.Atoi(stashed); err == nil {
status.Stashed = s
}
}
return status, nil
}
func parseHeader(h string, s *GitStatus) {
if strings.HasPrefix(h, "# branch.oid") {
hash := h[13:]
if hash != "(initial)" {
s.Sha = hash
}
return
}
if strings.HasPrefix(h, "# branch.head") {
branch := h[14:]
if branch != "(detached)" {
s.Branch = branch
}
return
}
if strings.HasPrefix(h, "# branch.upstream") {
s.Upstream = h[18:]
}
if strings.HasPrefix(h, "# branch.ab") {
parts := strings.Split(h, " ")
s.Ahead, _ = strconv.Atoi(strings.TrimPrefix(parts[2], "+"))
s.Behind, _ = strconv.Atoi(strings.TrimPrefix(parts[3], "-"))
return
}
}
func runGitCommand(cmd string, args ...string) (string, error) {
var stdout bytes.Buffer
var stderr bytes.Buffer
command := exec.Command(cmd, args...)
command.Stdout = bufio.NewWriter(&stdout)
command.Stderr = bufio.NewWriter(&stderr)
command.Env = os.Environ()
command.Env = append(command.Env, "LC_ALL=C")
if err := command.Run(); err != nil {
if stderr.Len() > 0 {
return "", errors.New(stderr.String())
}
return "", err
}
return strings.TrimSpace(stdout.String()), nil
}