forked from rkt/rkt
/
vcs.go
118 lines (99 loc) · 2.53 KB
/
vcs.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
package proj2aci
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
func repoDirExists(projPath, repoDir string) bool {
path := filepath.Join(projPath, repoDir)
info, err := os.Stat(path)
if err != nil {
return false
}
return info.IsDir()
}
// getId gets first line of commands output which should hold some VCS
// specific id of current code checkout.
func getId(dir, cmd string, params []string) (string, error) {
args := []string{cmd}
args = append(args, params...)
buffer := new(bytes.Buffer)
cmdPath, err := exec.LookPath(cmd)
if err != nil {
return "", nil
}
process := &exec.Cmd{
Path: cmdPath,
Args: args,
Env: []string{
"PATH=" + os.Getenv("PATH"),
},
Dir: dir,
Stdout: buffer,
}
if err := process.Run(); err != nil {
return "", err
}
output := string(buffer.Bytes())
if newline := strings.Index(output, "\n"); newline < 0 {
return output, nil
} else {
return output[:newline], nil
}
}
func getLabelAndId(label, path, cmd string, params []string) (string, string, error) {
if info, err := getId(path, cmd, params); err != nil {
return "", "", err
} else {
return label, info, nil
}
}
type VCSInfo interface {
IsValid(path string) bool
GetLabelAndId(path string) (string, string, error)
}
type GitInfo struct{}
func (info GitInfo) IsValid(path string) bool {
return repoDirExists(path, ".git")
}
func (info GitInfo) GetLabelAndId(path string) (string, string, error) {
return getLabelAndId("git", path, "git", []string{"rev-parse", "HEAD"})
}
type HgInfo struct{}
func (info HgInfo) IsValid(path string) bool {
return repoDirExists(path, ".hg")
}
func (info HgInfo) GetLabelAndId(path string) (string, string, error) {
return getLabelAndId("hg", path, "hg", []string{"id", "-i"})
}
type SvnInfo struct{}
func (info SvnInfo) IsValid(path string) bool {
return repoDirExists(path, ".svn")
}
func (info SvnInfo) GetLabelAndId(path string) (string, string, error) {
return getLabelAndId("svn", path, "svnversion", []string{})
}
type BzrInfo struct{}
func (info BzrInfo) IsValid(path string) bool {
return repoDirExists(path, ".bzr")
}
func (info BzrInfo) GetLabelAndId(path string) (string, string, error) {
return getLabelAndId("bzr", path, "bzr", []string{"revno"})
}
func GetVCSInfo(projPath string) (string, string, error) {
vcses := []VCSInfo{
GitInfo{},
HgInfo{},
SvnInfo{},
BzrInfo{},
}
for _, vcs := range vcses {
if vcs.IsValid(projPath) {
return vcs.GetLabelAndId(projPath)
}
}
return "", "", fmt.Errorf("Unknown code repository in %q", projPath)
}