github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/magefile.go (about) 1 //go:build mage 2 // +build mage 3 4 package main 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 "os" 11 "path" 12 "path/filepath" 13 "runtime" 14 "strings" 15 "sync" 16 "time" 17 18 "github.com/gohugoio/hugo/codegen" 19 "github.com/gohugoio/hugo/resources/page/page_generate" 20 21 "github.com/magefile/mage/mg" 22 "github.com/magefile/mage/sh" 23 ) 24 25 const ( 26 packageName = "github.com/gohugoio/hugo" 27 noGitLdflags = "-X github.com/gohugoio/hugo/common/hugo.vendorInfo=mage" 28 ) 29 30 var ldflags = noGitLdflags 31 32 // allow user to override go executable by running as GOEXE=xxx make ... on unix-like systems 33 var goexe = "go" 34 35 func init() { 36 if exe := os.Getenv("GOEXE"); exe != "" { 37 goexe = exe 38 } 39 40 // We want to use Go 1.11 modules even if the source lives inside GOPATH. 41 // The default is "auto". 42 os.Setenv("GO111MODULE", "on") 43 } 44 45 func runWith(env map[string]string, cmd string, inArgs ...any) error { 46 s := argsToStrings(inArgs...) 47 return sh.RunWith(env, cmd, s...) 48 } 49 50 // Build hugo binary 51 func Hugo() error { 52 return runWith(flagEnv(), goexe, "build", "-ldflags", ldflags, buildFlags(), "-tags", buildTags(), packageName) 53 } 54 55 // Build hugo binary with race detector enabled 56 func HugoRace() error { 57 return runWith(flagEnv(), goexe, "build", "-race", "-ldflags", ldflags, buildFlags(), "-tags", buildTags(), packageName) 58 } 59 60 // Install hugo binary 61 func Install() error { 62 return runWith(flagEnv(), goexe, "install", "-ldflags", ldflags, buildFlags(), "-tags", buildTags(), packageName) 63 } 64 65 // Uninstall hugo binary 66 func Uninstall() error { 67 return sh.Run(goexe, "clean", "-i", packageName) 68 } 69 70 func flagEnv() map[string]string { 71 hash, _ := sh.Output("git", "rev-parse", "--short", "HEAD") 72 return map[string]string{ 73 "PACKAGE": packageName, 74 "COMMIT_HASH": hash, 75 "BUILD_DATE": time.Now().Format("2006-01-02T15:04:05Z0700"), 76 } 77 } 78 79 // Generate autogen packages 80 func Generate() error { 81 generatorPackages := []string{ 82 //"tpl/tplimpl/embedded/generate", 83 //"resources/page/generate", 84 } 85 86 for _, pkg := range generatorPackages { 87 if err := runWith(flagEnv(), goexe, "generate", path.Join(packageName, pkg)); err != nil { 88 return err 89 } 90 } 91 92 dir, _ := os.Getwd() 93 c := codegen.NewInspector(dir) 94 95 if err := page_generate.Generate(c); err != nil { 96 return err 97 } 98 99 goFmtPatterns := []string{ 100 // TODO(bep) check: stat ./resources/page/*autogen*: no such file or directory 101 "./resources/page/page_marshaljson.autogen.go", 102 "./resources/page/page_wrappers.autogen.go", 103 "./resources/page/zero_file.autogen.go", 104 } 105 106 for _, pattern := range goFmtPatterns { 107 if err := sh.Run("gofmt", "-w", filepath.FromSlash(pattern)); err != nil { 108 return err 109 } 110 } 111 112 return nil 113 } 114 115 // Generate docs helper 116 func GenDocsHelper() error { 117 return runCmd(flagEnv(), goexe, "run", "-tags", buildTags(), "main.go", "gen", "docshelper") 118 } 119 120 // Build hugo without git info 121 func HugoNoGitInfo() error { 122 ldflags = noGitLdflags 123 return Hugo() 124 } 125 126 var docker = sh.RunCmd("docker") 127 128 // Build hugo Docker container 129 func Docker() error { 130 if err := docker("build", "-t", "hugo", "."); err != nil { 131 return err 132 } 133 // yes ignore errors here 134 docker("rm", "-f", "hugo-build") 135 if err := docker("run", "--name", "hugo-build", "hugo ls /go/bin"); err != nil { 136 return err 137 } 138 if err := docker("cp", "hugo-build:/go/bin/hugo", "."); err != nil { 139 return err 140 } 141 return docker("rm", "hugo-build") 142 } 143 144 // Run tests and linters 145 func Check() { 146 if runtime.GOARCH == "amd64" && runtime.GOOS != "darwin" { 147 mg.Deps(Test386) 148 } else { 149 fmt.Printf("Skip Test386 on %s and/or %s\n", runtime.GOARCH, runtime.GOOS) 150 } 151 152 mg.Deps(Fmt, Vet) 153 154 // don't run two tests in parallel, they saturate the CPUs anyway, and running two 155 // causes memory issues in CI. 156 mg.Deps(TestRace) 157 } 158 159 func testGoFlags() string { 160 if isCI() { 161 return "" 162 } 163 164 return "-timeout=1m" 165 } 166 167 // Run tests in 32-bit mode 168 // Note that we don't run with the extended tag. Currently not supported in 32 bit. 169 func Test386() error { 170 env := map[string]string{"GOARCH": "386", "GOFLAGS": testGoFlags()} 171 return runCmd(env, goexe, "test", "./...") 172 } 173 174 // Run tests 175 func Test() error { 176 env := map[string]string{"GOFLAGS": testGoFlags()} 177 return runCmd(env, goexe, "test", "./...", "-tags", buildTags()) 178 } 179 180 // Run tests with race detector 181 func TestRace() error { 182 env := map[string]string{"GOFLAGS": testGoFlags()} 183 return runCmd(env, goexe, "test", "-race", "./...", "-tags", buildTags()) 184 } 185 186 // Run gofmt linter 187 func Fmt() error { 188 if !isGoLatest() { 189 return nil 190 } 191 pkgs, err := hugoPackages() 192 if err != nil { 193 return err 194 } 195 failed := false 196 first := true 197 for _, pkg := range pkgs { 198 files, err := filepath.Glob(filepath.Join(pkg, "*.go")) 199 if err != nil { 200 return nil 201 } 202 for _, f := range files { 203 // gofmt doesn't exit with non-zero when it finds unformatted code 204 // so we have to explicitly look for output, and if we find any, we 205 // should fail this target. 206 s, err := sh.Output("gofmt", "-l", f) 207 if err != nil { 208 fmt.Printf("ERROR: running gofmt on %q: %v\n", f, err) 209 failed = true 210 } 211 if s != "" { 212 if first { 213 fmt.Println("The following files are not gofmt'ed:") 214 first = false 215 } 216 failed = true 217 fmt.Println(s) 218 } 219 } 220 } 221 if failed { 222 return errors.New("improperly formatted go files") 223 } 224 return nil 225 } 226 227 var ( 228 pkgPrefixLen = len("github.com/gohugoio/hugo") 229 pkgs []string 230 pkgsInit sync.Once 231 ) 232 233 func hugoPackages() ([]string, error) { 234 var err error 235 pkgsInit.Do(func() { 236 var s string 237 s, err = sh.Output(goexe, "list", "./...") 238 if err != nil { 239 return 240 } 241 pkgs = strings.Split(s, "\n") 242 for i := range pkgs { 243 pkgs[i] = "." + pkgs[i][pkgPrefixLen:] 244 } 245 }) 246 return pkgs, err 247 } 248 249 // Run golint linter 250 func Lint() error { 251 pkgs, err := hugoPackages() 252 if err != nil { 253 return err 254 } 255 failed := false 256 for _, pkg := range pkgs { 257 // We don't actually want to fail this target if we find golint errors, 258 // so we don't pass -set_exit_status, but we still print out any failures. 259 if _, err := sh.Exec(nil, os.Stderr, nil, "golint", pkg); err != nil { 260 fmt.Printf("ERROR: running go lint on %q: %v\n", pkg, err) 261 failed = true 262 } 263 } 264 if failed { 265 return errors.New("errors running golint") 266 } 267 return nil 268 } 269 270 // Run go vet linter 271 func Vet() error { 272 if err := sh.Run(goexe, "vet", "./..."); err != nil { 273 return fmt.Errorf("error running go vet: %v", err) 274 } 275 return nil 276 } 277 278 // Generate test coverage report 279 func TestCoverHTML() error { 280 const ( 281 coverAll = "coverage-all.out" 282 cover = "coverage.out" 283 ) 284 f, err := os.Create(coverAll) 285 if err != nil { 286 return err 287 } 288 defer f.Close() 289 if _, err := f.Write([]byte("mode: count")); err != nil { 290 return err 291 } 292 pkgs, err := hugoPackages() 293 if err != nil { 294 return err 295 } 296 for _, pkg := range pkgs { 297 if err := sh.Run(goexe, "test", "-coverprofile="+cover, "-covermode=count", pkg); err != nil { 298 return err 299 } 300 b, err := os.ReadFile(cover) 301 if err != nil { 302 if os.IsNotExist(err) { 303 continue 304 } 305 return err 306 } 307 idx := bytes.Index(b, []byte{'\n'}) 308 b = b[idx+1:] 309 if _, err := f.Write(b); err != nil { 310 return err 311 } 312 } 313 if err := f.Close(); err != nil { 314 return err 315 } 316 return sh.Run(goexe, "tool", "cover", "-html="+coverAll) 317 } 318 319 func runCmd(env map[string]string, cmd string, args ...any) error { 320 if mg.Verbose() { 321 return runWith(env, cmd, args...) 322 } 323 output, err := sh.OutputWith(env, cmd, argsToStrings(args...)...) 324 if err != nil { 325 fmt.Fprint(os.Stderr, output) 326 } 327 328 return err 329 } 330 331 func isGoLatest() bool { 332 return strings.Contains(runtime.Version(), "1.21") 333 } 334 335 func isCI() bool { 336 return os.Getenv("CI") != "" 337 } 338 339 func buildFlags() []string { 340 if runtime.GOOS == "windows" { 341 return []string{"-buildmode", "exe"} 342 } 343 return nil 344 } 345 346 func buildTags() string { 347 // To build the extended Hugo SCSS/SASS enabled version, build with 348 // HUGO_BUILD_TAGS=extended mage install etc. 349 // To build without `hugo deploy` for smaller binary, use HUGO_BUILD_TAGS=nodeploy 350 if envtags := os.Getenv("HUGO_BUILD_TAGS"); envtags != "" { 351 return envtags 352 } 353 return "none" 354 } 355 356 func argsToStrings(v ...any) []string { 357 var args []string 358 for _, arg := range v { 359 switch v := arg.(type) { 360 case string: 361 if v != "" { 362 args = append(args, v) 363 } 364 case []string: 365 if v != nil { 366 args = append(args, v...) 367 } 368 default: 369 panic("invalid type") 370 } 371 } 372 373 return args 374 }