Updates
ci/woodpecker/push/goreleaser Pipeline was successful Details
ci/woodpecker/tag/goreleaser Pipeline was successful Details

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main v0.0.1
jolheiser 2022-08-09 13:46:36 -05:00
parent c75ed4762a
commit 81144edfe4
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
13 changed files with 348 additions and 252 deletions

3
.gitignore vendored
View File

@ -2,4 +2,5 @@
.idea/
# Binaries
/imp*
/imp
/imp.exe

25
.goreleaser.yaml 100644
View File

@ -0,0 +1,25 @@
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
ldflags:
- "-s -w -X main.Version={{.Version}}"
archives:
- replacements:
386: i386
amd64: x86_64
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
release:
gitea:
owner: jolheiser
name: imp
gitea_urls:
api: https://git.jojodev.com/api/v1/
download: https://git.jojodev.com

View File

@ -0,0 +1,38 @@
clone:
git:
image: woodpeckerci/plugin-git
settings:
tags: true
pipeline:
compliance:
image: golang:1.18
commands:
- go test -race ./...
- go vet ./...
when:
event: pull_request
build:
image: goreleaser/goreleaser
commands:
- goreleaser build --snapshot
when:
event: pull_request
release:
image: goreleaser/goreleaser
commands:
- goreleaser release
secrets: [ gitea_token ]
when:
event: tag
prune:
image: jolheiser/drone-gitea-prune
settings:
base: https://git.jojodev.com
token:
from_secret: gitea_token
when:
event: tag

View File

@ -1,21 +0,0 @@
GO ?= go
.PHONY: build
build:
$(GO) build
.PHONY: fmt
fmt:
$(GO) fmt ./...
.PHONY: test
test:
$(GO) test -race ./...
.PHONY: vet
vet:
$(GO) vet ./...
.PHONY: imp
imp: build
./imp -w

View File

@ -16,15 +16,10 @@ import (
imp includes three flags:
* `--write` will write out the formatting rather than printing
* `--imp-ignore` reads a `.impignore` file for globs to include/exclude (`.impignore` by default)
* `--verbose` will print out extended information
* `--ignore` reads a `.impignore` file for globs to include/exclude (`.impignore` by default)
### `.impignore` format
The `.impignore` file follows a [globber format](https://gitea.com/jolheiser/globber),
which closely resembles a traditional `.gitignore` file.
### Example
https://gitea.com/jolheiser/sip/pulls/17
which closely resembles a traditional `.gitignore` file.

40
format/format.go 100644
View File

@ -0,0 +1,40 @@
package format
import (
"errors"
"regexp"
"strings"
)
var (
importRe = regexp.MustCompile(`(?ms)import \(([^)]+)\)`)
otherRe = regexp.MustCompile(`(?:var|const|func)\s`)
ErrNoImports = errors.New("no imports found")
)
// Source formats a given src's imports
func Source(src []byte, module string) ([]byte, error) {
importStart := importRe.FindIndex(src)
if importStart == nil {
return nil, ErrNoImports
}
otherStart := otherRe.FindIndex(src)
if otherStart != nil && otherStart[0] < importStart[0] {
return nil, ErrNoImports
}
groups := importRe.FindStringSubmatch(string(src))
if groups[0] == "" {
return nil, ErrNoImports
}
imports := strings.Split(groups[1], "\n")
for idx, i := range imports {
imports[idx] = strings.TrimSpace(i)
}
block := parseBlock(module, imports)
replaced := strings.Replace(string(src), groups[0], block.String(), 1)
return []byte(replaced), nil
}

View File

@ -0,0 +1,65 @@
package format
import (
"bytes"
"errors"
"testing"
"github.com/matryer/is"
)
func TestSource(t *testing.T) {
module := "foo.bar"
assert := is.New(t)
_, err := Source(noImports, module)
assert.True(errors.Is(err, ErrNoImports)) // Should get error for no imports
_, err = Source(fakeImports, module)
assert.True(errors.Is(err, ErrNoImports)) // Should get error for no "real" imports
formatted, err := Source(before, module)
assert.NoErr(err) // Should be able to format before block
assert.True(bytes.Equal(formatted, after)) // Formatted should match after block
}
var (
noImports = []byte(`package main
func main() {}`)
fakeImports = []byte(`package main
func main() {
s := "import \"fmt\""
_ = s
}`)
before = []byte(`package main
import (
"foo.bar/baz"
"net/http"
"github.com/peterbourgon/ff/v3"
"io"
"os"
"github.com/matryer/is"
"foo.bar/bux"
)
func main() {}`)
after = []byte(`package main
import (
"io"
"net/http"
"os"
"foo.bar/baz"
"foo.bar/bux"
"github.com/matryer/is"
"github.com/peterbourgon/ff/v3"
)
func main() {}`)
)

107
format/struct.go 100644
View File

@ -0,0 +1,107 @@
package format
import (
"fmt"
"sort"
"strings"
)
type importItem struct {
Comment string
Name string
Path string
}
func (ii importItem) String() string {
var comment string
if ii.Comment != "" {
comment = ii.Comment + "\n\t"
}
var name string
if ii.Name != "" {
name = ii.Name + " "
}
return comment + name + ii.Path
}
type importBlock struct {
Stdlib []importItem
Module []importItem
Other []importItem
}
func importItemSlice(ii []importItem) []string {
iis := make([]string, 0, len(ii))
for _, i := range ii {
iis = append(iis, i.String())
}
return iis
}
func (i importBlock) String() string {
var decl strings.Builder
decl.WriteString(strings.Join(importItemSlice(i.Stdlib), "\n\t"))
if len(i.Stdlib) > 0 {
decl.WriteString("\n\n\t")
}
decl.WriteString(strings.Join(importItemSlice(i.Module), "\n\t"))
if len(i.Module) > 0 {
decl.WriteString("\n\n\t")
}
decl.WriteString(strings.Join(importItemSlice(i.Other), "\n\t"))
return fmt.Sprintf(`import (
%s
)`, decl.String())
}
func parseBlock(module string, imports []string) importBlock {
var block importBlock
var comment string
for _, imp := range imports {
if imp == "" {
continue
}
i := imp
if strings.HasPrefix(i, `//`) {
var nl string
if comment != "" {
nl = "\n"
}
comment = nl + i
continue
}
var name string
if !strings.HasPrefix(i, `"`) {
parts := strings.SplitN(i, " ", 2)
name = parts[0]
i = parts[1]
}
item := importItem{
Comment: comment,
Name: name,
Path: i,
}
switch {
case strings.Contains(i, module):
block.Module = append(block.Module, item)
case strings.Contains(i, "."):
block.Other = append(block.Other, item)
default:
block.Stdlib = append(block.Stdlib, item)
}
comment = ""
}
fn := func(ii []importItem) func(int, int) bool {
return func(i, j int) bool {
return ii[i].Path < ii[j].Path
}
}
sort.Slice(block.Stdlib, fn(block.Stdlib))
sort.Slice(block.Module, fn(block.Module))
sort.Slice(block.Other, fn(block.Other))
return block
}

13
go.mod
View File

@ -1,11 +1,14 @@
module gitea.com/jolheiser/imp
go 1.14
go 1.18
require (
gitea.com/jolheiser/globber v0.0.1
github.com/gobuffalo/here v0.6.2
github.com/urfave/cli/v2 v2.2.0
go.jolheiser.com/beaver v1.0.2
go.jolheiser.com/regexp v0.1.1
github.com/gobuffalo/here v0.6.6
github.com/matryer/is v1.4.0
)
require (
github.com/gobwas/glob v0.2.3 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

43
go.sum
View File

@ -1,40 +1,31 @@
gitea.com/jolheiser/globber v0.0.1 h1:BVoc4Ml9N3ssix5Xy32gpQOO1jnAuzMsYc5h/LP7/jA=
gitea.com/jolheiser/globber v0.0.1/go.mod h1:vr1VkO/biaYgeGj8tRD6SMAWhsqINKFYl9en3YbpQvc=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gobuffalo/here v0.6.2 h1:ZtCqC7F9ou3moLbYfHM1Tj+gwHGgWhjyRjVjsir9BE0=
github.com/gobuffalo/here v0.6.2/go.mod h1:D75Sq0p2BVHdgQu3vCRsXbg85rx943V19urJpqAVWjI=
github.com/gobuffalo/here v0.6.6 h1:/o+jfSwe36pKQ577grsXGoMYql/zheiGwg1XFo3CBJU=
github.com/gobuffalo/here v0.6.6/go.mod h1:C4JZL5PsXWKzP/CAchaIzuUWlaae6CaAiMYQ0ieY62M=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
go.jolheiser.com/beaver v1.0.2 h1:KA2D6iO8MQhZi1nZYi/Chak/f1Cxfrs6b1XO623+Khk=
go.jolheiser.com/beaver v1.0.2/go.mod h1:7X4F5+XOGSC3LejTShoBdqtRCnPWcnRgmYGmG3EKW8g=
go.jolheiser.com/regexp v0.1.1 h1:nMCzilEL/oIcZJwnRT4bb+FNxaeAFBdqSjq7rgoNSGg=
go.jolheiser.com/regexp v0.1.1/go.mod h1:58uCpYxGy/DbqVRuo6oU93kh3B3GeyK5eJznQvy2N6c=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

138
imp.go
View File

@ -1,50 +1,35 @@
package main
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
"gitea.com/jolheiser/imp/format"
"gitea.com/jolheiser/globber"
"github.com/gobuffalo/here"
"github.com/urfave/cli/v2"
"go.jolheiser.com/beaver"
"go.jolheiser.com/beaver/color"
"go.jolheiser.com/regexp"
)
var (
module string
importRe = regexp.MustCompile(`(?ms)import \(([^)]+)\)`)
otherRe = regexp.MustCompile(`(?:var|const|func)\s`)
)
func runImp(ctx *cli.Context) error {
if ctx.Bool("verbose") {
beaver.Console.Level = beaver.DEBUG
}
func runImp(root, ignore string, write bool) error {
info, err := here.Current()
if err != nil {
return err
}
module = info.Module.Path
beaver.Debugf("Current module: %s", module)
globs, err := globber.ParseFile(ctx.String("imp-ignore"))
module := info.Module.Path
globs, err := globber.ParseFile(ignore)
if err != nil {
if !os.IsNotExist(err) {
if !errors.Is(err, fs.ErrNotExist) {
return err
}
globs = globber.New()
}
var failed bool
diffColor := color.New(color.FgGreen, color.BgHiBlack)
if err := filepath.Walk(".", func(walkPath string, walkInfo os.FileInfo, walkErr error) error {
if err := filepath.Walk(root, func(walkPath string, walkInfo os.FileInfo, walkErr error) error {
if walkErr != nil {
return walkErr
}
@ -58,43 +43,21 @@ func runImp(ctx *cli.Context) error {
return nil
}
beaver.Debugf("Checking file %s", walkPath)
data, err := ioutil.ReadFile(walkPath)
data, err := os.ReadFile(walkPath)
if err != nil {
return err
}
formatted, err := format.Source(data, module)
if err != nil {
return err
}
importStart := importRe.FindIndex(data)
if importStart == nil {
return nil
if write {
return os.WriteFile(walkPath, formatted, walkInfo.Mode())
}
otherStart := otherRe.FindIndex(data)
if otherStart != nil && otherStart[0] < importStart[0] {
return nil
}
groups := importRe.Groups(string(data))
if groups.Index(0) == "" {
return nil
}
imports := strings.Split(groups.Index(1), "\n")
for idx, i := range imports {
imports[idx] = strings.TrimSpace(i)
}
formatted := formatImportStmt(splitImports(imports))
if ctx.Bool("write") {
replaced := strings.Replace(string(data), groups.Index(0), formatted, 1)
return ioutil.WriteFile(walkPath, []byte(replaced), walkInfo.Mode())
}
if !strings.EqualFold(groups.Index(0), formatted) {
if !bytes.Equal(data, formatted) {
failed = true
beaver.Infof("File: %s", diffColor.Format(walkPath))
beaver.Infof("Expected:\n%s", diffColor.Format(formatted))
beaver.Infof("Got:\n%s\n", diffColor.Format(groups.Index(0)))
}
return nil
}); err != nil {
@ -107,7 +70,6 @@ func runImp(ctx *cli.Context) error {
}
func checkSkip(walkPath string, walkInfo os.FileInfo, globs *globber.GlobSet) walkStatus {
// Skip current directory
if strings.EqualFold(walkPath, ".") {
return SKIP
@ -115,7 +77,6 @@ func checkSkip(walkPath string, walkInfo os.FileInfo, globs *globber.GlobSet) wa
// Skip hidden paths (starting with ".")
if strings.HasPrefix(walkPath, ".") {
beaver.Debugf("Skipping hidden path %s", walkPath)
if walkInfo.IsDir() {
return SKIPDIR
}
@ -129,75 +90,22 @@ func checkSkip(walkPath string, walkInfo os.FileInfo, globs *globber.GlobSet) wa
// Skip non-Go files
if !strings.HasSuffix(walkInfo.Name(), ".go") {
beaver.Debugf("Skipping non-Go file %s", walkPath)
return SKIP
}
// Skip included (ignored) globs
i, e := globs.Explain(walkPath)
if len(i) > 0 && len(e) == 0 {
beaver.Debugf("Skipping file %s because of .impignore rule %s", walkPath, i[0].Pattern)
return SKIP
}
return CHECK
}
func splitImports(imports []string) []importList {
// 0 -> stdlib
// 1 -> this module
// 2 -> others
split := []importList{{}, {}, {}}
var comment string
for _, imp := range imports {
if imp == "" {
continue
}
i := imp
if strings.HasPrefix(i, `//`) {
var nl string
if comment != "" {
nl = "\n"
}
comment = nl + i
continue
}
type walkStatus int
var name string
if !strings.HasPrefix(i, `"`) {
parts := strings.SplitN(i, " ", 2)
name = parts[0]
i = parts[1]
}
switch {
case strings.HasPrefix(i, `"`+module):
split[1] = append(split[1], importItem{comment, name, i})
case strings.Contains(i, "."):
split[2] = append(split[2], importItem{comment, name, i})
default:
split[0] = append(split[0], importItem{comment, name, i})
}
comment = ""
}
for _, s := range split {
sort.Sort(s)
}
return split
}
func formatImportStmt(imports []importList) string {
var decl string
for _, imp := range imports {
var pre string
if decl != "" {
pre = "\n\n\t"
}
if len(imp) > 0 {
decl += pre + strings.Join(imp.StringSlice(), "\n\t")
}
}
return fmt.Sprintf(`import (
%s
)`, decl)
}
const (
SKIP walkStatus = iota
SKIPDIR
CHECK
)

49
main.go
View File

@ -1,37 +1,30 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/urfave/cli/v2"
"go.jolheiser.com/beaver"
)
func main() {
app := cli.NewApp()
app.Name = "Imp"
app.Usage = "Re-order imports"
app.Flags = []cli.Flag{
&cli.BoolFlag{
Name: "write",
Aliases: []string{"w"},
Usage: "Write the re-ordered imports instead of just printing them",
},
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Print more information",
},
&cli.StringFlag{
Name: "imp-ignore",
Aliases: []string{"i"},
Usage: "Path to a .impignore file for globs",
Value: ".impignore",
},
}
app.Action = runImp
var Version = "develop"
if err := app.Run(os.Args); err != nil {
beaver.Fatal(err)
func main() {
fs := flag.NewFlagSet("imp", flag.ExitOnError)
writeFlag := fs.Bool("write", false, "Write the re-ordered imports instead of just printing them")
fs.BoolVar(writeFlag, "w", *writeFlag, "--write")
ignoreFlag := fs.String("ignore", ".impignore", "Path to .impignore file")
fs.StringVar(ignoreFlag, "i", *ignoreFlag, "--ignore")
if err := fs.Parse(os.Args[1:]); err != nil {
fmt.Println(err)
}
root := "."
if fs.NArg() > 0 {
root = fs.Arg(0)
}
if err := runImp(root, *ignoreFlag, *writeFlag); err != nil {
fmt.Println(err)
}
}

View File

@ -1,49 +0,0 @@
package main
type importItem struct {
Comment string
Name string
Path string
}
func (ii importItem) String() string {
var comment string
if ii.Comment != "" {
comment = ii.Comment + "\n\t"
}
var name string
if ii.Name != "" {
name = ii.Name + " "
}
return comment + name + ii.Path
}
type importList []importItem
func (il importList) Len() int {
return len(il)
}
func (il importList) Less(i, j int) bool {
return il[i].Path < il[j].Path
}
func (il importList) Swap(i, j int) {
il[i], il[j] = il[j], il[i]
}
func (il importList) StringSlice() []string {
s := make([]string, len(il))
for idx, ii := range il {
s[idx] = ii.String()
}
return s
}
type walkStatus int
const (
SKIP walkStatus = iota
SKIPDIR
CHECK
)