-
Notifications
You must be signed in to change notification settings - Fork 0
/
magefile.go
213 lines (171 loc) · 4.47 KB
/
magefile.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
// +build mage
package main
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/magefile/mage/mg"
)
// TODO: use github.com/magefile/mage/target to skip unnecessary steps
// ------------------------------------------------------------
// Constants and const-like variables
const mainCss = "resources/css/main.css"
const mainScss = "scss/main.scss"
// TODO: figure out how to document these and/or make them CL options
const envSkipTests = "ADLER_SKIP_TESTS"
const envSkipValidation = "ADLER_SKIP_VALIDATION"
var scssDir = filepath.Dir(mainScss)
var cssDir = filepath.Dir(mainCss)
// ------------------------------------------------------------
// Targets
// Build builds an executable, but does not install it (depends on: test)
//goland:noinspection GoUnusedExportedFunction
func Build() error {
cmd := exec.Command("go", "build")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
println("Building")
if mg.Verbose() {
println(strings.Join(cmd.Args, " "))
}
return cmd.Run()
}
// Install builds and installs the executable (depends on: test)
//goland:noinspection GoUnusedExportedFunction
func Install() error {
mg.Deps(Test, Assets.Compile)
cmd := exec.Command("go", "install")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
println("Installing")
if mg.Verbose() {
println(strings.Join(cmd.Args, " "))
}
return cmd.Run()
}
// Test runs all tests
func Test() error {
if skipTests() {
warn("Skipping tests")
return nil
}
cmd := exec.Command("go", "test", "./...")
cmd.Stderr = os.Stderr
println("Running tests")
if mg.Verbose() {
println(strings.Join(cmd.Args, " "))
cmd.Stdout = os.Stdout
return cmd.Run()
}
var sb strings.Builder
cmd.Stdout = &sb
err := cmd.Run()
if err != nil {
print(sb.String())
}
return err
}
//goland:noinspection GoUnusedExportedType
type Assets mg.Namespace
// Validate validates SCSS (requires sass-lint: https://www.npmjs.com/package/sass-lint)
func (Assets) Validate() error {
if skipValidation() {
warn("Skipping validation")
return nil
}
var errors []error
//goland:noinspection GoUnhandledErrorResult
filepath.Walk(scssDir, func(path string, info os.FileInfo, err error) error {
if filepath.Ext(path) == ".scss" && !info.IsDir() && !ignored(path) {
if err := sassLint(path); err != nil {
errors = append(errors, err)
}
}
return nil
})
if len(errors) > 0 {
for _, err := range errors {
warn(err.Error())
}
return errors[len(errors)-1]
}
return nil
}
// Compile compiles SCSS (depends on: assets:validate)
func (Assets) Compile() error {
mg.Deps(Assets.Validate)
if mg.Verbose() {
println("Ensuring output directory " + cssDir)
}
err := os.MkdirAll(cssDir, 0755)
if err != nil {
return err
}
sass := ensureCommand("sass", "sass not found; did you run brew install sass/sass/sass or npm install -g sass?")
var sassQuietArg string
if mg.Verbose() {
sassQuietArg = "--no-quiet"
} else {
sassQuietArg = "--quiet"
}
cmd := exec.Command(sass, sassQuietArg, "--stop-on-error", scssDir+":"+cssDir)
cmd.Stdout = os.Stdout
if mg.Verbose() {
cmd.Stderr = os.Stderr
println(strings.Join(cmd.Args, " "))
}
return cmd.Run()
}
// ------------------------------------------------------------
// Helper functions
func skipTests() bool {
return os.Getenv(envSkipTests) != ""
}
func skipValidation() bool {
return os.Getenv(envSkipValidation) != ""
}
// TODO: put all this timestamp business in a struct, or find a utility library for it (does mage have one?)
var timeZero = time.Time{}
func ignored(path string) bool {
gi, err := gitIgnore()
if err != nil {
panic(err)
}
return gi.MatchesPath(path)
}
func sassLint(scssFile string) error {
var sassLint = ensureCommand("sass-lint", "sass-lint not found; did you run npm install -g sass-lint?")
cmd := exec.Command(sassLint, "-v", "--max-warnings", "0", "-c", "scss/.sass-lint.yml", scssFile)
cmd.Stdout = os.Stdout
if mg.Verbose() {
cmd.Stderr = os.Stderr
println(strings.Join(cmd.Args, " "))
}
return cmd.Run()
}
func ensureCommand(cmdName, failureMsg string) string {
result, err := which(cmdName)
if err != nil {
warn(failureMsg)
os.Exit(1)
}
return result
}
func which(command string) (string, error) {
var stdout bytes.Buffer
cmd := exec.Command("which", command)
cmd.Stdout = &stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return "", err
}
result := stdout.String()
return strings.TrimSpace(result), nil
}
func warn(msg string) {
_, _ = fmt.Fprintln(os.Stderr, msg)
}