-
Notifications
You must be signed in to change notification settings - Fork 151
/
main.go
222 lines (198 loc) · 4.82 KB
/
main.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package main
import (
"bufio"
"bytes"
"crypto/sha256"
"encoding/hex"
"go/format"
"hash"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"text/template"
)
var (
// walkRootPaths contains the path roots we need
// to walk through. This is relative to the current
// directory.
walkRootPaths = []string{
"../../flux-core",
"../../flux",
"../../include",
"../../scanner.c",
"../../Cargo.toml",
"../../Cargo.lock",
}
// walkFluxPath is the path for the flux stdlib.
walkFluxPath = "../../../stdlib"
)
// lsFiles returns a list of files that exist on the filesystem that git does not ignore
func lsFiles(path string) ([]string, error) {
// List files in git's cache, i.e. all files that git knows about
cached, err := gitListFiles(path, "--cached")
if err != nil {
return nil, err
}
// List files that exist on the filesystem but have not been added to git
others, err := gitListFiles(path, "--others")
if err != nil {
return nil, err
}
// List files that exist on the filesystem but should be ignored
excluded, err := gitListFiles(path, "--others", "--ignored", "--exclude-standard")
if err != nil {
return nil, err
}
// List files that have been deleted from the filesystem but not git
deleted, err := gitListFiles(path, "--deleted")
if err != nil {
return nil, err
}
// We want cached + others - excluded - deleted
sort.Strings(excluded)
sort.Strings(deleted)
skip := func(f string) bool {
return contains(excluded, f) || contains(deleted, f)
}
filtered := make([]string, 0, len(cached)+len(others))
// add cached
for _, f := range cached {
if skip(f) {
continue
}
filtered = append(filtered, f)
}
// add others
for _, f := range others {
if skip(f) {
continue
}
filtered = append(filtered, f)
}
return filtered, nil
}
// contains reports if item exists in set, the set must be sorted
func contains(set []string, item string) bool {
i := sort.SearchStrings(set, item)
return i < len(set) && set[i] == item
}
// gitListFiles returns a list of files reported using the 'git ls-files' command
func gitListFiles(path string, flags ...string) ([]string, error) {
args := make([]string, 0, 4+len(flags))
args = append(args, "ls-files")
args = append(args, "--full-name")
args = append(args, flags...)
args = append(args, "--")
args = append(args, path)
cmd := exec.Command("git", args...)
out, err := cmd.Output()
if err != nil {
return nil, err
}
var files []string
scanner := bufio.NewScanner(bytes.NewReader(out))
for scanner.Scan() {
files = append(files, scanner.Text())
}
if err := scanner.Err(); err != nil {
return nil, err
}
return files, nil
}
// getLibraryFiles will retrieve a list of all of the
// files that the libflux package depends on.
func getLibraryFiles() ([]string, error) {
var allFiles []string
for _, root := range walkRootPaths {
files, err := lsFiles(root)
if err != nil {
return nil, err
}
allFiles = append(allFiles, files...)
}
files, err := lsFiles(walkFluxPath)
if err != nil {
return nil, err
}
for _, file := range files {
if !strings.HasSuffix(file, ".flux") {
continue
}
allFiles = append(allFiles, file)
}
return allFiles, nil
}
func getRootDir() string {
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
for cwd != "/" {
gitdir := filepath.Join(cwd, ".git")
if _, err := os.Stat(gitdir); err == nil {
return cwd
}
cwd = filepath.Dir(cwd)
}
panic(".git directory not found")
}
func hexdigest(h hash.Hash) string {
return hex.EncodeToString(h.Sum(nil))
}
func writeTemplate(root string, files []string) error {
t := template.New("").Funcs(template.FuncMap{
"hexdigest": func(path string) (string, error) {
f, err := os.Open(filepath.Join(root, path))
if err != nil {
return "", err
}
defer func() { _ = f.Close() }()
shasum := sha256.New()
if _, err := io.Copy(shasum, f); err != nil {
return "", err
}
return hexdigest(shasum), nil
},
})
t = template.Must(t.Parse(`
// Generated by buildinfo
//
// DO NOT EDIT!
package libflux
// sourceHashes is the hash of the build sources for
// the rust components used by cgo.
// This gets generated from the libflux sources
// and forces the cgo library to rebuild and relink
// the sources. This is because non-C/C++ sources
// are not tracked by Go's build system.'
//lint:ignore U1000 generated code
var sourceHashes = map[string]string{
{{range .}}"{{.}}": "{{hexdigest .}}",
{{end}}
}
`))
var buf bytes.Buffer
if err := t.Execute(&buf, files); err != nil {
return err
}
buildinfo, err := format.Source(buf.Bytes())
if err != nil {
return err
}
return ioutil.WriteFile("buildinfo.gen.go", buildinfo, 0644)
}
func main() {
root := getRootDir()
files, err := getLibraryFiles()
if err != nil {
panic(err)
}
sort.Strings(files)
if err := writeTemplate(root, files); err != nil {
panic(err)
}
}