github.com/olliephillips/hugo@v0.42.2/magefile.go (about) 1 // +build mage 2 3 package main 4 5 import ( 6 "bytes" 7 "errors" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path" 12 "path/filepath" 13 "runtime" 14 "strings" 15 "time" 16 17 "github.com/magefile/mage/mg" 18 "github.com/magefile/mage/sh" 19 ) 20 21 const ( 22 packageName = "github.com/gohugoio/hugo" 23 noGitLdflags = "-X $PACKAGE/hugolib.BuildDate=$BUILD_DATE" 24 ) 25 26 var ldflags = "-X $PACKAGE/hugolib.CommitHash=$COMMIT_HASH -X $PACKAGE/hugolib.BuildDate=$BUILD_DATE" 27 28 // allow user to override go executable by running as GOEXE=xxx make ... on unix-like systems 29 var goexe = "go" 30 31 func init() { 32 if exe := os.Getenv("GOEXE"); exe != "" { 33 goexe = exe 34 } 35 } 36 37 func getDep() error { 38 return sh.Run(goexe, "get", "-u", "github.com/golang/dep/cmd/dep") 39 } 40 41 // Install Go Dep and sync Hugo's vendored dependencies 42 func Vendor() error { 43 mg.Deps(getDep) 44 return sh.Run("dep", "ensure") 45 } 46 47 // Build hugo binary 48 func Hugo() error { 49 return sh.RunWith(flagEnv(), goexe, "build", "-ldflags", ldflags, packageName) 50 } 51 52 // Build hugo binary with race detector enabled 53 func HugoRace() error { 54 return sh.RunWith(flagEnv(), goexe, "build", "-race", "-ldflags", ldflags, packageName) 55 } 56 57 // Install hugo binary 58 func Install() error { 59 return sh.RunWith(flagEnv(), goexe, "install", "-ldflags", ldflags, packageName) 60 } 61 62 func flagEnv() map[string]string { 63 hash, _ := sh.Output("git", "rev-parse", "--short", "HEAD") 64 return map[string]string{ 65 "PACKAGE": packageName, 66 "COMMIT_HASH": hash, 67 "BUILD_DATE": time.Now().Format("2006-01-02T15:04:05Z0700"), 68 } 69 } 70 71 func Generate() error { 72 return sh.RunWith(flagEnv(), goexe, "generate", path.Join(packageName, "tpl/tplimpl/embedded/generate")) 73 } 74 75 // Build hugo without git info 76 func HugoNoGitInfo() error { 77 ldflags = noGitLdflags 78 return Hugo() 79 } 80 81 var docker = sh.RunCmd("docker") 82 83 // Build hugo Docker container 84 func Docker() error { 85 if err := docker("build", "-t", "hugo", "."); err != nil { 86 return err 87 } 88 // yes ignore errors here 89 docker("rm", "-f", "hugo-build") 90 if err := docker("run", "--name", "hugo-build", "hugo ls /go/bin"); err != nil { 91 return err 92 } 93 if err := docker("cp", "hugo-build:/go/bin/hugo", "."); err != nil { 94 return err 95 } 96 return docker("rm", "hugo-build") 97 } 98 99 // Run tests and linters 100 func Check() { 101 if strings.Contains(runtime.Version(), "1.8") { 102 // Go 1.8 doesn't play along with go test ./... and /vendor. 103 // We could fix that, but that would take time. 104 fmt.Printf("Skip Check on %s\n", runtime.Version()) 105 return 106 } 107 mg.Deps(Test386, Fmt, Vet) 108 // don't run two tests in parallel, they saturate the CPUs anyway, and running two 109 // causes memory issues in CI. 110 mg.Deps(TestRace) 111 } 112 113 // Run tests in 32-bit mode 114 func Test386() error { 115 return sh.RunWith(map[string]string{"GOARCH": "386"}, goexe, "test", "./...") 116 } 117 118 // Run tests 119 func Test() error { 120 return sh.Run(goexe, "test", "./...") 121 } 122 123 // Run tests with race detector 124 func TestRace() error { 125 return sh.Run(goexe, "test", "-race", "./...") 126 } 127 128 // Run gofmt linter 129 func Fmt() error { 130 if !isGoLatest() { 131 return nil 132 } 133 pkgs, err := hugoPackages() 134 if err != nil { 135 return err 136 } 137 failed := false 138 first := true 139 for _, pkg := range pkgs { 140 files, err := filepath.Glob(filepath.Join(pkg, "*.go")) 141 if err != nil { 142 return nil 143 } 144 for _, f := range files { 145 // gofmt doesn't exit with non-zero when it finds unformatted code 146 // so we have to explicitly look for output, and if we find any, we 147 // should fail this target. 148 s, err := sh.Output("gofmt", "-l", f) 149 if err != nil { 150 fmt.Printf("ERROR: running gofmt on %q: %v\n", f, err) 151 failed = true 152 } 153 if s != "" { 154 if first { 155 fmt.Println("The following files are not gofmt'ed:") 156 first = false 157 } 158 failed = true 159 fmt.Println(s) 160 } 161 } 162 } 163 if failed { 164 return errors.New("improperly formatted go files") 165 } 166 return nil 167 } 168 169 var pkgPrefixLen = len("github.com/gohugoio/hugo") 170 171 func hugoPackages() ([]string, error) { 172 mg.Deps(getDep) 173 s, err := sh.Output(goexe, "list", "./...") 174 if err != nil { 175 return nil, err 176 } 177 pkgs := strings.Split(s, "\n") 178 for i := range pkgs { 179 pkgs[i] = "." + pkgs[i][pkgPrefixLen:] 180 } 181 return pkgs, nil 182 } 183 184 // Run golint linter 185 func Lint() error { 186 pkgs, err := hugoPackages() 187 if err != nil { 188 return err 189 } 190 failed := false 191 for _, pkg := range pkgs { 192 // We don't actually want to fail this target if we find golint errors, 193 // so we don't pass -set_exit_status, but we still print out any failures. 194 if _, err := sh.Exec(nil, os.Stderr, nil, "golint", pkg); err != nil { 195 fmt.Printf("ERROR: running go lint on %q: %v\n", pkg, err) 196 failed = true 197 } 198 } 199 if failed { 200 return errors.New("errors running golint") 201 } 202 return nil 203 } 204 205 // Run go vet linter 206 func Vet() error { 207 mg.Deps(getDep) 208 if err := sh.Run(goexe, "vet", "./..."); err != nil { 209 return fmt.Errorf("error running govendor: %v", err) 210 } 211 return nil 212 } 213 214 // Generate test coverage report 215 func TestCoverHTML() error { 216 mg.Deps(getDep) 217 const ( 218 coverAll = "coverage-all.out" 219 cover = "coverage.out" 220 ) 221 f, err := os.Create(coverAll) 222 if err != nil { 223 return err 224 } 225 defer f.Close() 226 if _, err := f.Write([]byte("mode: count")); err != nil { 227 return err 228 } 229 pkgs, err := hugoPackages() 230 if err != nil { 231 return err 232 } 233 for _, pkg := range pkgs { 234 if err := sh.Run(goexe, "test", "-coverprofile="+cover, "-covermode=count", pkg); err != nil { 235 return err 236 } 237 b, err := ioutil.ReadFile(cover) 238 if err != nil { 239 if os.IsNotExist(err) { 240 continue 241 } 242 return err 243 } 244 idx := bytes.Index(b, []byte{'\n'}) 245 b = b[idx+1:] 246 if _, err := f.Write(b); err != nil { 247 return err 248 } 249 } 250 if err := f.Close(); err != nil { 251 return err 252 } 253 return sh.Run(goexe, "tool", "cover", "-html="+coverAll) 254 } 255 256 // Verify that vendored packages match git HEAD 257 func CheckVendor() error { 258 if err := sh.Run("git", "diff-index", "--quiet", "HEAD", "vendor/"); err != nil { 259 // yes, ignore errors from this, not much we can do. 260 sh.Exec(nil, os.Stdout, os.Stderr, "git", "diff", "vendor/") 261 return errors.New("check-vendor target failed: vendored packages out of sync") 262 } 263 return nil 264 } 265 266 func isGoLatest() bool { 267 return strings.Contains(runtime.Version(), "1.10") 268 }