Compare commits
9 Commits
01da9ebb16
...
b3769056e7
Author | SHA1 | Date |
---|---|---|
sudo pacman -Syu | b3769056e7 | |
sudo pacman -Syu | 76665bed73 | |
sudo pacman -Syu | 248f118186 | |
sudo pacman -Syu | 635255864b | |
sudo pacman -Syu | bd64964fc1 | |
sudo pacman -Syu | cf624ad2ea | |
sudo pacman -Syu | 6bbfd7b94c | |
sudo pacman -Syu | 031a349461 | |
sudo pacman -Syu | 7fc100d359 |
|
@ -13,6 +13,7 @@
|
|||
# Go
|
||||
coverage.out
|
||||
vendor
|
||||
*.prof
|
||||
|
||||
# GoReleaser
|
||||
dist
|
||||
|
|
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -1,5 +1,29 @@
|
|||
# CHANGELOG
|
||||
|
||||
## v0.0.4 (2023-01-17)
|
||||
|
||||
### Added
|
||||
|
||||
- feat: improve perf by use astFile for dstFile (2023-01-17)
|
||||
|
||||
- feat: use errgroup to improve perf (2023-01-17)
|
||||
|
||||
- feat: use uber-go/automaxprocs (2023-01-17)
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix: update 2 times with dstFile (2023-01-17)
|
||||
|
||||
### Others
|
||||
|
||||
- chore: re-format (2023-01-17)
|
||||
|
||||
- chore: log flags when verbose (2023-01-17)
|
||||
|
||||
- chore: remove buggy side effect (2023-01-17)
|
||||
|
||||
- chore(changelog): generate v0.0.3 (2023-01-17)
|
||||
|
||||
## v0.0.3 (2023-01-17)
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import "github.com/haunt98/gofimports/internal/cli"
|
||||
import (
|
||||
"github.com/haunt98/gofimports/internal/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cli.NewApp().Run()
|
||||
|
|
1
go.mod
1
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
|
||||
github.com/urfave/cli/v2 v2.23.7
|
||||
golang.org/x/mod v0.7.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/tools v0.5.0
|
||||
)
|
||||
|
||||
|
|
1
go.sum
1
go.sum
|
@ -24,6 +24,7 @@ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsr
|
|||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
|
@ -2,6 +2,9 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
|
@ -15,6 +18,7 @@ type action struct {
|
|||
write bool
|
||||
diff bool
|
||||
verbose bool
|
||||
profiler bool
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,11 +27,16 @@ func (a *action) RunHelp(c *cli.Context) error {
|
|||
}
|
||||
|
||||
func (a *action) getFlags(c *cli.Context) {
|
||||
a.flags.companyPrefix = c.String(flagCompanyPrefixName)
|
||||
a.flags.list = c.Bool(flagListName)
|
||||
a.flags.write = c.Bool(flagWriteName)
|
||||
a.flags.diff = c.Bool(flagDiffName)
|
||||
a.flags.verbose = c.Bool(flagVerboseName)
|
||||
a.flags.companyPrefix = c.String(flagCompanyPrefixName)
|
||||
a.flags.profiler = c.Bool(flagProfilerName)
|
||||
|
||||
if a.flags.verbose {
|
||||
fmt.Printf("flags: %+v\n", a.flags)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *action) Run(c *cli.Context) error {
|
||||
|
@ -45,6 +54,19 @@ func (a *action) Run(c *cli.Context) error {
|
|||
return a.RunHelp(c)
|
||||
}
|
||||
|
||||
if a.flags.profiler {
|
||||
f, err := os.Create("cpu.prof")
|
||||
if err != nil {
|
||||
return fmt.Errorf("os: failed to create: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
return fmt.Errorf("pprof: failed to start cpu profile: %w", err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
ft, err := imports.NewFormmater(
|
||||
imports.FormatterWithList(a.flags.list),
|
||||
imports.FormatterWithWrite(a.flags.write),
|
||||
|
@ -61,5 +83,18 @@ func (a *action) Run(c *cli.Context) error {
|
|||
return fmt.Errorf("imports formatter: failed to format %v: %w", args, err)
|
||||
}
|
||||
|
||||
if a.flags.profiler {
|
||||
f, err := os.Create("mem.prof")
|
||||
if err != nil {
|
||||
return fmt.Errorf("os: failed to create: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
runtime.GC()
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
return fmt.Errorf("pprof: failed to write heap profile: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ const (
|
|||
usage = "goimports with my opinionated preferences"
|
||||
|
||||
// Inspiration from gofmt flags
|
||||
flagCompanyPrefixName = "company"
|
||||
flagCompanyPrefixUsage = "company prefix, for example github.com/haunt98"
|
||||
|
||||
flagListName = "list"
|
||||
flagListUsage = "list files will be changed"
|
||||
|
||||
|
@ -25,8 +28,8 @@ const (
|
|||
flagVerboseName = "verbose"
|
||||
flagVerboseUsage = "show verbose output, for debug only"
|
||||
|
||||
flagCompanyPrefixName = "company"
|
||||
flagCompanyPrefixUsage = "company prefix, for example github.com/haunt98"
|
||||
flagProfilerName = "profiler"
|
||||
flagProfilerUsage = "go profiler, for debug only"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -47,6 +50,10 @@ func NewApp() *App {
|
|||
Name: name,
|
||||
Usage: usage,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: flagCompanyPrefixName,
|
||||
Usage: flagCompanyPrefixUsage,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: flagListName,
|
||||
Usage: flagListUsage,
|
||||
|
@ -66,9 +73,9 @@ func NewApp() *App {
|
|||
Name: flagVerboseName,
|
||||
Usage: flagVerboseUsage,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: flagCompanyPrefixName,
|
||||
Usage: flagCompanyPrefixUsage,
|
||||
&cli.BoolFlag{
|
||||
Name: flagProfilerName,
|
||||
Usage: flagProfilerUsage,
|
||||
},
|
||||
},
|
||||
Action: a.Run,
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/dave/dst/decorator"
|
||||
"github.com/pkg/diff"
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
|
@ -46,6 +47,7 @@ type Formatter struct {
|
|||
stdPackages map[string]struct{}
|
||||
moduleNames map[string]string
|
||||
formattedPaths map[string]struct{}
|
||||
eg errgroup.Group
|
||||
companyPrefix string
|
||||
muModuleNames sync.RWMutex
|
||||
muFormattedPaths sync.RWMutex
|
||||
|
@ -87,7 +89,7 @@ func (ft *Formatter) Format(paths ...string) error {
|
|||
|
||||
// Logic switch case copy from goimports, gofumpt
|
||||
for _, path := range paths {
|
||||
path = strings.TrimSpace(path)
|
||||
path := strings.TrimSpace(path)
|
||||
if path == "" {
|
||||
continue
|
||||
}
|
||||
|
@ -100,16 +102,24 @@ func (ft *Formatter) Format(paths ...string) error {
|
|||
return err
|
||||
}
|
||||
default:
|
||||
if err := ft.formatFile(path); err != nil {
|
||||
if ft.isIgnoreError(err) {
|
||||
continue
|
||||
ft.eg.Go(func() error {
|
||||
if err := ft.formatFile(path); err != nil {
|
||||
if ft.isIgnoreError(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if err := ft.eg.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -128,13 +138,17 @@ func (ft *Formatter) formatDir(path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
if err := ft.formatFile(path); err != nil {
|
||||
if ft.isIgnoreError(err) {
|
||||
return nil
|
||||
ft.eg.Go(func() error {
|
||||
if err := ft.formatFile(path); err != nil {
|
||||
if ft.isIgnoreError(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
|
@ -230,11 +244,12 @@ func (ft *Formatter) formatImports(
|
|||
return nil, ErrGoGeneratedFile
|
||||
}
|
||||
|
||||
dstFile, err := decorator.Parse(pathBytes)
|
||||
dec := decorator.NewDecorator(fset)
|
||||
dstFile, err := dec.DecorateFile(astFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decorator: failed to parse file [%s]: %w", path, err)
|
||||
}
|
||||
if len(dstFile.Imports) == 0 {
|
||||
if len(dstFile.Imports) == 0 || len(dstFile.Decls) == 0 {
|
||||
return nil, ErrEmptyImport
|
||||
}
|
||||
ft.logDSTImportSpecs("formatImports: dstImportSpecs", dstFile.Imports)
|
||||
|
@ -250,8 +265,28 @@ func (ft *Formatter) formatImports(
|
|||
}
|
||||
ft.logDSTImportSpecs("formatImports: formattedDSTImportSpecs: ", formattedDSTImportSpecs)
|
||||
|
||||
// First update
|
||||
dstFile.Imports = formattedDSTImportSpecs
|
||||
|
||||
genSpecs := dstFile.Decls[0].(*dst.GenDecl).Specs
|
||||
formattedGenSpecs := make([]dst.Spec, 0, len(genSpecs))
|
||||
|
||||
// Append all imports first
|
||||
for _, importSpec := range formattedDSTImportSpecs {
|
||||
formattedGenSpecs = append(formattedGenSpecs, importSpec)
|
||||
}
|
||||
|
||||
// Append all non imports later
|
||||
for _, genSpec := range genSpecs {
|
||||
if _, ok := genSpec.(*dst.ImportSpec); !ok {
|
||||
formattedGenSpecs = append(formattedGenSpecs, genSpec)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Second update
|
||||
dstFile.Decls[0].(*dst.GenDecl).Specs = formattedGenSpecs
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := decorator.Fprint(&buf, dstFile); err != nil {
|
||||
return nil, fmt.Errorf("decorator: failed to fprint [%s]: %w", path, err)
|
||||
|
|
Loading…
Reference in New Issue