package main import ( "bytes" "errors" "fmt" "io/fs" "os" "path/filepath" "strings" "go.jolheiser.com/imp/format" "gitea.com/jolheiser/globber" gofumptFormat "mvdan.cc/gofumpt/format" ) func runImp(root, ignore string, write, gofumpt, gofumptExtra bool) error { mod := modInfo(root) globs, err := globber.ParseFile(ignore) if err != nil { if !errors.Is(err, fs.ErrNotExist) { return err } globs = globber.New() } var failed bool if err := filepath.Walk(root, func(walkPath string, walkInfo os.FileInfo, walkErr error) error { if walkErr != nil { return walkErr } walkPath = filepath.ToSlash(walkPath) if s := checkSkip(walkPath, walkInfo, globs); s != CHECK { if s == SKIPDIR { return filepath.SkipDir } return nil } data, err := os.ReadFile(walkPath) if err != nil { return fmt.Errorf("could not read file %q: %w", walkPath, err) } formatted, err := impFormat(data, mod, gofumpt, gofumptExtra) if err != nil && !errors.Is(err, format.ErrNoImports) { return fmt.Errorf("could not format file %q: %w", walkPath, err) } if write { if err := os.WriteFile(walkPath, formatted, walkInfo.Mode()); err != nil { return fmt.Errorf("could not write file %q: %w", walkPath, err) } return nil } if !bytes.Equal(data, formatted) { failed = true } return nil }); err != nil { return err } if failed { return errors.New("imports are formatted incorrectly; this can be fixed with the `--write` flag") } return nil } func impFormat(src []byte, mod module, gofumpt, gofumptExtra bool) ([]byte, error) { formatted, err := format.Source(src, mod.Path) if err != nil { return src, err } if gofumpt { formatted, err = gofumptFormat.Source(formatted, gofumptFormat.Options{ LangVersion: mod.GoVersion, ModulePath: mod.Path, ExtraRules: gofumptExtra, }) if err != nil { return src, err } } return formatted, nil } func checkSkip(walkPath string, walkInfo os.FileInfo, globs *globber.GlobSet) walkStatus { // Skip current directory if strings.EqualFold(walkPath, ".") { return SKIP } // Skip hidden paths (starting with ".") if strings.HasPrefix(walkPath, ".") { if walkInfo.IsDir() { return SKIPDIR } return SKIP } // Skip directories if walkInfo.IsDir() { return SKIP } // Skip non-Go files if !strings.HasSuffix(walkInfo.Name(), ".go") { return SKIP } // Skip included (ignored) globs i, e := globs.Explain(walkPath) if len(i) > 0 && len(e) == 0 { return SKIP } return CHECK } type walkStatus int const ( SKIP walkStatus = iota SKIPDIR CHECK )