github.com/kristoff-it/hugo@v0.47.1/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, "-tags", buildTags(), 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, "-tags", buildTags(), packageName) 55 } 56 57 // Install hugo binary 58 func Install() error { 59 return sh.RunWith(flagEnv(), goexe, "install", "-ldflags", ldflags, "-tags", buildTags(), 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 // Note that we don't run with the extended tag. Currently not supported in 32 bit. 115 func Test386() error { 116 return sh.RunWith(map[string]string{"GOARCH": "386"}, goexe, "test", "./...") 117 } 118 119 // Run tests 120 func Test() error { 121 return sh.Run(goexe, "test", "./...", "-tags", buildTags()) 122 } 123 124 // Run tests with race detector 125 func TestRace() error { 126 return sh.Run(goexe, "test", "-race", "./...", "-tags", buildTags()) 127 } 128 129 // Run gofmt linter 130 func Fmt() error { 131 if !isGoLatest() { 132 return nil 133 } 134 pkgs, err := hugoPackages() 135 if err != nil { 136 return err 137 } 138 failed := false 139 first := true 140 for _, pkg := range pkgs { 141 files, err := filepath.Glob(filepath.Join(pkg, "*.go")) 142 if err != nil { 143 return nil 144 } 145 for _, f := range files { 146 // gofmt doesn't exit with non-zero when it finds unformatted code 147 // so we have to explicitly look for output, and if we find any, we 148 // should fail this target. 149 s, err := sh.Output("gofmt", "-l", f) 150 if err != nil { 151 fmt.Printf("ERROR: running gofmt on %q: %v\n", f, err) 152 failed = true 153 } 154 if s != "" { 155 if first { 156 fmt.Println("The following files are not gofmt'ed:") 157 first = false 158 } 159 failed = true 160 fmt.Println(s) 161 } 162 } 163 } 164 if failed { 165 return errors.New("improperly formatted go files") 166 } 167 return nil 168 } 169 170 var pkgPrefixLen = len("github.com/gohugoio/hugo") 171 172 func hugoPackages() ([]string, error) { 173 mg.Deps(getDep) 174 s, err := sh.Output(goexe, "list", "./...") 175 if err != nil { 176 return nil, err 177 } 178 pkgs := strings.Split(s, "\n") 179 for i := range pkgs { 180 pkgs[i] = "." + pkgs[i][pkgPrefixLen:] 181 } 182 return pkgs, nil 183 } 184 185 // Run golint linter 186 func Lint() error { 187 pkgs, err := hugoPackages() 188 if err != nil { 189 return err 190 } 191 failed := false 192 for _, pkg := range pkgs { 193 // We don't actually want to fail this target if we find golint errors, 194 // so we don't pass -set_exit_status, but we still print out any failures. 195 if _, err := sh.Exec(nil, os.Stderr, nil, "golint", pkg); err != nil { 196 fmt.Printf("ERROR: running go lint on %q: %v\n", pkg, err) 197 failed = true 198 } 199 } 200 if failed { 201 return errors.New("errors running golint") 202 } 203 return nil 204 } 205 206 // Run go vet linter 207 func Vet() error { 208 mg.Deps(getDep) 209 if err := sh.Run(goexe, "vet", "./..."); err != nil { 210 return fmt.Errorf("error running govendor: %v", err) 211 } 212 return nil 213 } 214 215 // Generate test coverage report 216 func TestCoverHTML() error { 217 mg.Deps(getDep) 218 const ( 219 coverAll = "coverage-all.out" 220 cover = "coverage.out" 221 ) 222 f, err := os.Create(coverAll) 223 if err != nil { 224 return err 225 } 226 defer f.Close() 227 if _, err := f.Write([]byte("mode: count")); err != nil { 228 return err 229 } 230 pkgs, err := hugoPackages() 231 if err != nil { 232 return err 233 } 234 for _, pkg := range pkgs { 235 if err := sh.Run(goexe, "test", "-coverprofile="+cover, "-covermode=count", pkg); err != nil { 236 return err 237 } 238 b, err := ioutil.ReadFile(cover) 239 if err != nil { 240 if os.IsNotExist(err) { 241 continue 242 } 243 return err 244 } 245 idx := bytes.Index(b, []byte{'\n'}) 246 b = b[idx+1:] 247 if _, err := f.Write(b); err != nil { 248 return err 249 } 250 } 251 if err := f.Close(); err != nil { 252 return err 253 } 254 return sh.Run(goexe, "tool", "cover", "-html="+coverAll) 255 } 256 257 // Verify that vendored packages match git HEAD 258 func CheckVendor() error { 259 if err := sh.Run("git", "diff-index", "--quiet", "HEAD", "vendor/"); err != nil { 260 // yes, ignore errors from this, not much we can do. 261 sh.Exec(nil, os.Stdout, os.Stderr, "git", "diff", "vendor/") 262 return errors.New("check-vendor target failed: vendored packages out of sync") 263 } 264 return nil 265 } 266 267 func isGoLatest() bool { 268 return strings.Contains(runtime.Version(), "1.10") 269 } 270 271 func buildTags() string { 272 // To build the extended Hugo SCSS/SASS enabled version, build with 273 // HUGO_BUILD_TAGS=extended mage install etc. 274 if envtags := os.Getenv("HUGO_BUILD_TAGS"); envtags != "" { 275 return envtags 276 } 277 return "none" 278 279 }