hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

magefile.go (8378B)

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