mirror of
https://github.com/go-gitea/gitea.git
synced 2025-09-13 23:23:32 +02:00
gofumpt now [supports](https://github.com/mvdan/gofumpt/releases/tag/v0.9.0) the [ignore](https://tip.golang.org/ref/mod#go-mod-file-ignore) directive added in go 1.25, make use of it which speeds up `make fmt` by around 30%. Likely this also has similar speed gains in other go-related commands which use the `./...` pattern. The change in `build/code-batch-process.go` was introduced by `gofumpt` because of this change: > A new rule is introduced to "clothe" naked returns for the sake of clarity. While there is nothing wrong with naming results in function signatures, using lone return statements can be confusing to the reader.
282 lines
7.1 KiB
Go
282 lines
7.1 KiB
Go
// Copyright 2021 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"code.gitea.io/gitea/build/codeformat"
|
|
)
|
|
|
|
// Windows has a limitation for command line arguments, the size can not exceed 32KB.
|
|
// So we have to feed the files to some tools (like gofmt) batch by batch
|
|
|
|
// We also introduce a `gitea-fmt` command, it does better import formatting than gofmt/goimports. `gitea-fmt` calls `gofmt` internally.
|
|
|
|
var optionLogVerbose bool
|
|
|
|
func logVerbose(msg string, args ...any) {
|
|
if optionLogVerbose {
|
|
log.Printf(msg, args...)
|
|
}
|
|
}
|
|
|
|
func passThroughCmd(cmd string, args []string) error {
|
|
foundCmd, err := exec.LookPath(cmd)
|
|
if err != nil {
|
|
log.Fatalf("can not find cmd: %s", cmd)
|
|
}
|
|
c := exec.Cmd{
|
|
Path: foundCmd,
|
|
Args: append([]string{cmd}, args...),
|
|
Stdin: os.Stdin,
|
|
Stdout: os.Stdout,
|
|
Stderr: os.Stderr,
|
|
}
|
|
return c.Run()
|
|
}
|
|
|
|
type fileCollector struct {
|
|
dirs []string
|
|
includePatterns []*regexp.Regexp
|
|
excludePatterns []*regexp.Regexp
|
|
batchSize int
|
|
}
|
|
|
|
func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error) {
|
|
co := &fileCollector{batchSize: batchSize}
|
|
if fileFilter == "go-own" {
|
|
co.dirs = []string{
|
|
"build",
|
|
"cmd",
|
|
"contrib",
|
|
"tests",
|
|
"models",
|
|
"modules",
|
|
"routers",
|
|
"services",
|
|
}
|
|
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
|
|
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`models/fixtures`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`models/migrations/fixtures`))
|
|
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`services/gitdiff/testdata`))
|
|
}
|
|
|
|
if co.dirs == nil {
|
|
return nil, fmt.Errorf("unknown file-filter: %s", fileFilter)
|
|
}
|
|
return co, nil
|
|
}
|
|
|
|
func (fc *fileCollector) matchPatterns(path string, regexps []*regexp.Regexp) bool {
|
|
path = strings.ReplaceAll(path, "\\", "/")
|
|
for _, re := range regexps {
|
|
if re.MatchString(path) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (fc *fileCollector) collectFiles() (res [][]string, err error) {
|
|
var batch []string
|
|
for _, dir := range fc.dirs {
|
|
err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
|
|
include := len(fc.includePatterns) == 0 || fc.matchPatterns(path, fc.includePatterns)
|
|
exclude := fc.matchPatterns(path, fc.excludePatterns)
|
|
process := include && !exclude
|
|
if !process {
|
|
if d.IsDir() {
|
|
if exclude {
|
|
logVerbose("exclude dir %s", path)
|
|
return filepath.SkipDir
|
|
}
|
|
// for a directory, if it is not excluded explicitly, we should walk into
|
|
return nil
|
|
}
|
|
// for a file, we skip it if it shouldn't be processed
|
|
logVerbose("skip process %s", path)
|
|
return nil
|
|
}
|
|
if d.IsDir() {
|
|
// skip dir, we don't add dirs to the file list now
|
|
return nil
|
|
}
|
|
if len(batch) >= fc.batchSize {
|
|
res = append(res, batch)
|
|
batch = nil
|
|
}
|
|
batch = append(batch, path)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
res = append(res, batch)
|
|
return res, nil
|
|
}
|
|
|
|
// substArgFiles expands the {file-list} to a real file list for commands
|
|
func substArgFiles(args, files []string) []string {
|
|
for i, s := range args {
|
|
if s == "{file-list}" {
|
|
newArgs := append(args[:i], files...)
|
|
newArgs = append(newArgs, args[i+1:]...)
|
|
return newArgs
|
|
}
|
|
}
|
|
return args
|
|
}
|
|
|
|
func exitWithCmdErrors(subCmd string, subArgs []string, cmdErrors []error) {
|
|
for _, err := range cmdErrors {
|
|
if err != nil {
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
|
exitCode := exitError.ExitCode()
|
|
log.Printf("run command failed (code=%d): %s %v", exitCode, subCmd, subArgs)
|
|
os.Exit(exitCode)
|
|
} else {
|
|
log.Fatalf("run command failed (err=%s) %s %v", err, subCmd, subArgs)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func parseArgs() (mainOptions map[string]string, subCmd string, subArgs []string) {
|
|
mainOptions = map[string]string{}
|
|
for i := 1; i < len(os.Args); i++ {
|
|
arg := os.Args[i]
|
|
if arg == "" {
|
|
break
|
|
}
|
|
if arg[0] == '-' {
|
|
arg = strings.TrimPrefix(arg, "-")
|
|
arg = strings.TrimPrefix(arg, "-")
|
|
fields := strings.SplitN(arg, "=", 2)
|
|
if len(fields) == 1 {
|
|
mainOptions[fields[0]] = "1"
|
|
} else {
|
|
mainOptions[fields[0]] = fields[1]
|
|
}
|
|
} else {
|
|
subCmd = arg
|
|
subArgs = os.Args[i+1:]
|
|
break
|
|
}
|
|
}
|
|
return mainOptions, subCmd, subArgs
|
|
}
|
|
|
|
func showUsage() {
|
|
fmt.Printf(`Usage: %[1]s [options] {command} [arguments]
|
|
|
|
Options:
|
|
--verbose
|
|
--file-filter=go-own
|
|
--batch-size=100
|
|
|
|
Commands:
|
|
%[1]s gofmt ...
|
|
|
|
Arguments:
|
|
{file-list} the file list
|
|
|
|
Example:
|
|
%[1]s gofmt -s -d {file-list}
|
|
|
|
`, "file-batch-exec")
|
|
}
|
|
|
|
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
|
|
fileFilter := mainOptions["file-filter"]
|
|
if fileFilter == "" {
|
|
fileFilter = "go-own"
|
|
}
|
|
batchSize, _ := strconv.Atoi(mainOptions["batch-size"])
|
|
if batchSize == 0 {
|
|
batchSize = 100
|
|
}
|
|
|
|
return newFileCollector(fileFilter, batchSize)
|
|
}
|
|
|
|
func containsString(a []string, s string) bool {
|
|
for _, v := range a {
|
|
if v == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func giteaFormatGoImports(files []string, doWriteFile bool) error {
|
|
for _, file := range files {
|
|
if err := codeformat.FormatGoImports(file, doWriteFile); err != nil {
|
|
log.Printf("failed to format go imports: %s, err=%v", file, err)
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
mainOptions, subCmd, subArgs := parseArgs()
|
|
if subCmd == "" {
|
|
showUsage()
|
|
os.Exit(1)
|
|
}
|
|
optionLogVerbose = mainOptions["verbose"] != ""
|
|
|
|
fc, err := newFileCollectorFromMainOptions(mainOptions)
|
|
if err != nil {
|
|
log.Fatalf("can not create file collector: %s", err.Error())
|
|
}
|
|
|
|
fileBatches, err := fc.collectFiles()
|
|
if err != nil {
|
|
log.Fatalf("can not collect files: %s", err.Error())
|
|
}
|
|
|
|
processed := 0
|
|
var cmdErrors []error
|
|
for _, files := range fileBatches {
|
|
if len(files) == 0 {
|
|
break
|
|
}
|
|
substArgs := substArgFiles(subArgs, files)
|
|
logVerbose("batch cmd: %s %v", subCmd, substArgs)
|
|
switch subCmd {
|
|
case "gitea-fmt":
|
|
if containsString(subArgs, "-d") {
|
|
log.Print("the -d option is not supported by gitea-fmt")
|
|
}
|
|
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
|
|
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
|
|
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
|
|
default:
|
|
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
|
|
}
|
|
processed += len(files)
|
|
}
|
|
|
|
logVerbose("processed %d files", processed)
|
|
exitWithCmdErrors(subCmd, subArgs, cmdErrors)
|
|
}
|