2013-12-17 19:21:03 -07:00
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package imports
import (
2015-12-10 23:32:07 -07:00
"bytes"
2018-04-24 14:05:29 -06:00
"context"
2013-12-17 19:21:03 -07:00
"flag"
"go/build"
"io/ioutil"
"os"
"path/filepath"
2015-12-10 23:32:07 -07:00
"runtime"
2016-07-17 18:47:35 -06:00
"strings"
2014-01-26 10:47:31 -07:00
"sync"
2013-12-17 19:21:03 -07:00
"testing"
)
var only = flag . String ( "only" , "" , "If non-empty, the fix test to run" )
var tests = [ ] struct {
2016-04-05 10:10:15 -06:00
name string
formatOnly bool
in , out string
2013-12-17 19:21:03 -07:00
} {
// Adding an import to an existing parenthesized import
{
name : "factored_imports_add" ,
in : ` package foo
import (
"fmt"
)
func bar ( ) {
var b bytes . Buffer
fmt . Println ( b . String ( ) )
}
` ,
out : ` package foo
import (
"bytes"
"fmt"
)
func bar ( ) {
var b bytes . Buffer
fmt . Println ( b . String ( ) )
}
` ,
} ,
// Adding an import to an existing parenthesized import,
// verifying it goes into the first section.
{
name : "factored_imports_add_first_sec" ,
in : ` package foo
import (
"fmt"
"appengine"
)
func bar ( ) {
var b bytes . Buffer
_ = appengine . IsDevServer
fmt . Println ( b . String ( ) )
}
` ,
out : ` package foo
import (
"bytes"
"fmt"
"appengine"
)
func bar ( ) {
var b bytes . Buffer
_ = appengine . IsDevServer
fmt . Println ( b . String ( ) )
}
` ,
} ,
// Adding an import to an existing parenthesized import,
// verifying it goes into the first section. (test 2)
{
name : "factored_imports_add_first_sec_2" ,
in : ` package foo
import (
"fmt"
"appengine"
)
func bar ( ) {
_ = math . NaN
_ = fmt . Sprintf
_ = appengine . IsDevServer
}
` ,
out : ` package foo
import (
"fmt"
"math"
"appengine"
)
func bar ( ) {
_ = math . NaN
_ = fmt . Sprintf
_ = appengine . IsDevServer
}
` ,
} ,
// Adding a new import line, without parens
{
name : "add_import_section" ,
in : ` package foo
func bar ( ) {
var b bytes . Buffer
}
` ,
out : ` package foo
import "bytes"
func bar ( ) {
var b bytes . Buffer
}
` ,
} ,
// Adding two new imports, which should make a parenthesized import decl.
{
name : "add_import_paren_section" ,
in : ` package foo
func bar ( ) {
_ , _ := bytes . Buffer , zip . NewReader
}
` ,
out : ` package foo
import (
"archive/zip"
"bytes"
)
func bar ( ) {
_ , _ := bytes . Buffer , zip . NewReader
}
` ,
} ,
// Make sure we don't add things twice
{
name : "no_double_add" ,
in : ` package foo
func bar ( ) {
_ , _ := bytes . Buffer , bytes . NewReader
}
` ,
out : ` package foo
import "bytes"
func bar ( ) {
_ , _ := bytes . Buffer , bytes . NewReader
}
` ,
} ,
// Remove unused imports, 1 of a factored block
{
name : "remove_unused_1_of_2" ,
in : ` package foo
import (
"bytes"
"fmt"
)
func bar ( ) {
_ , _ := bytes . Buffer , bytes . NewReader
}
` ,
out : ` package foo
2017-02-09 02:39:36 -07:00
import (
"bytes"
)
2013-12-17 19:21:03 -07:00
func bar ( ) {
_ , _ := bytes . Buffer , bytes . NewReader
}
` ,
} ,
// Remove unused imports, 2 of 2
{
name : "remove_unused_2_of_2" ,
in : ` package foo
import (
"bytes"
"fmt"
)
func bar ( ) {
}
` ,
out : ` package foo
func bar ( ) {
}
` ,
} ,
// Remove unused imports, 1 of 1
{
name : "remove_unused_1_of_1" ,
in : ` package foo
import "fmt"
func bar ( ) {
}
` ,
out : ` package foo
func bar ( ) {
}
` ,
} ,
// Don't remove empty imports.
{
name : "dont_remove_empty_imports" ,
in : ` package foo
import (
_ "image/png"
_ "image/jpeg"
)
` ,
out : ` package foo
import (
_ "image/jpeg"
_ "image/png"
)
` ,
} ,
// Don't remove dot imports.
{
name : "dont_remove_dot_imports" ,
in : ` package foo
import (
. "foo"
. "bar"
)
` ,
out : ` package foo
import (
. "bar"
. "foo"
)
` ,
} ,
// Skip refs the parser can resolve.
{
name : "skip_resolved_refs" ,
in : ` package foo
func f ( ) {
type t struct { Println func ( string ) }
fmt := t { Println : func ( string ) { } }
fmt . Println ( "foo" )
}
` ,
out : ` package foo
func f ( ) {
type t struct { Println func ( string ) }
fmt := t { Println : func ( string ) { } }
fmt . Println ( "foo" )
}
` ,
} ,
// Do not add a package we already have a resolution for.
{
name : "skip_template" ,
in : ` package foo
import "html/template"
func f ( ) { t = template . New ( "sometemplate" ) }
` ,
out : ` package foo
import "html/template"
func f ( ) { t = template . New ( "sometemplate" ) }
` ,
} ,
// Don't touch cgo
{
name : "cgo" ,
in : ` package foo
/ *
# include < foo . h >
* /
import "C"
` ,
out : ` package foo
/ *
# include < foo . h >
* /
import "C"
` ,
} ,
// Put some things in their own section
{
name : "make_sections" ,
in : ` package foo
import (
"os"
)
func foo ( ) {
_ , _ = os . Args , fmt . Println
_ , _ = appengine . FooSomething , user . Current
}
` ,
out : ` package foo
import (
"fmt"
"os"
"appengine"
"appengine/user"
)
func foo ( ) {
_ , _ = os . Args , fmt . Println
_ , _ = appengine . FooSomething , user . Current
}
` ,
} ,
// Delete existing empty import block
{
name : "delete_empty_import_block" ,
in : ` package foo
import ( )
` ,
out : ` package foo
` ,
} ,
// Use existing empty import block
{
name : "use_empty_import_block" ,
in : ` package foo
import ( )
func f ( ) {
_ = fmt . Println
}
` ,
out : ` package foo
import "fmt"
func f ( ) {
_ = fmt . Println
}
` ,
} ,
// Blank line before adding new section.
{
name : "blank_line_before_new_group" ,
in : ` package foo
import (
"fmt"
"net"
)
func f ( ) {
_ = net . Dial
_ = fmt . Printf
_ = snappy . Foo
}
` ,
out : ` package foo
import (
"fmt"
"net"
"code.google.com/p/snappy-go/snappy"
)
func f ( ) {
_ = net . Dial
_ = fmt . Printf
_ = snappy . Foo
}
` ,
} ,
// Blank line between standard library and third-party stuff.
{
name : "blank_line_separating_std_and_third_party" ,
in : ` package foo
import (
"code.google.com/p/snappy-go/snappy"
"fmt"
"net"
)
func f ( ) {
_ = net . Dial
_ = fmt . Printf
_ = snappy . Foo
}
` ,
out : ` package foo
import (
"fmt"
"net"
"code.google.com/p/snappy-go/snappy"
)
func f ( ) {
_ = net . Dial
_ = fmt . Printf
_ = snappy . Foo
}
2013-12-18 10:09:37 -07:00
` ,
} ,
// golang.org/issue/6884
{
name : "issue 6884" ,
in : ` package main
// A comment
func main ( ) {
fmt . Println ( "Hello, world" )
}
` ,
out : ` package main
import "fmt"
// A comment
func main ( ) {
fmt . Println ( "Hello, world" )
}
2014-02-07 18:03:34 -07:00
` ,
} ,
// golang.org/issue/7132
{
name : "issue 7132" ,
in : ` package main
import (
"fmt"
"gu"
"github.com/foo/bar"
)
var (
a = bar . a
b = gu . a
c = fmt . Printf
)
` ,
out : ` package main
import (
"fmt"
"gu"
"github.com/foo/bar"
)
var (
a = bar . a
b = gu . a
c = fmt . Printf
)
2014-03-25 07:37:10 -06:00
` ,
} ,
{
name : "renamed package" ,
in : ` package main
var _ = str . HasPrefix
` ,
out : ` package main
import str "strings"
var _ = str . HasPrefix
2013-12-17 19:21:03 -07:00
` ,
} ,
2014-04-28 15:15:33 -06:00
{
name : "fragment with main" ,
in : ` func main() { fmt.Println("Hello, world")} ` ,
out : ` package main
import "fmt"
func main ( ) { fmt . Println ( "Hello, world" ) }
` ,
} ,
{
name : "fragment without main" ,
in : ` func notmain() { fmt.Println("Hello, world")} ` ,
out : ` import "fmt"
func notmain ( ) { fmt . Println ( "Hello, world" ) } ` ,
} ,
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
// Remove first import within in a 2nd/3rd/4th/etc. section.
// golang.org/issue/7679
{
name : "issue 7679" ,
in : ` package main
import (
"fmt"
"github.com/foo/bar"
"github.com/foo/qux"
)
func main ( ) {
var _ = fmt . Println
//var _ = bar.A
var _ = qux . B
}
` ,
out : ` package main
import (
"fmt"
"github.com/foo/qux"
)
func main ( ) {
var _ = fmt . Println
//var _ = bar.A
var _ = qux . B
}
2014-05-20 15:02:16 -06:00
` ,
} ,
// Blank line can be added before all types of import declarations.
// golang.org/issue/7866
{
name : "issue 7866" ,
in : ` package main
import (
"fmt"
renamed_bar "github.com/foo/bar"
. "github.com/foo/baz"
"io"
_ "github.com/foo/qux"
"strings"
)
func main ( ) {
_ , _ , _ , _ , _ = fmt . Errorf , io . Copy , strings . Contains , renamed_bar . A , B
}
` ,
out : ` package main
import (
"fmt"
renamed_bar "github.com/foo/bar"
"io"
. "github.com/foo/baz"
"strings"
_ "github.com/foo/qux"
)
func main ( ) {
_ , _ , _ , _ , _ = fmt . Errorf , io . Copy , strings . Contains , renamed_bar . A , B
}
2014-07-28 18:15:17 -06:00
` ,
} ,
// Non-idempotent comment formatting
// golang.org/issue/8035
{
name : "issue 8035" ,
in : ` package main
import (
"fmt" // A
"go/ast" // B
_ "launchpad.net/gocheck" // C
)
func main ( ) { _ , _ = fmt . Print , ast . Walk }
` ,
out : ` package main
import (
"fmt" // A
"go/ast" // B
_ "launchpad.net/gocheck" // C
)
func main ( ) { _ , _ = fmt . Print , ast . Walk }
2014-08-14 12:51:51 -06:00
` ,
} ,
// Failure to delete all duplicate imports
// golang.org/issue/8459
{
name : "issue 8459" ,
in : ` package main
import (
"fmt"
"log"
"log"
"math"
)
func main ( ) { fmt . Println ( "pi:" , math . Pi ) }
` ,
out : ` package main
import (
"fmt"
"math"
)
func main ( ) { fmt . Println ( "pi:" , math . Pi ) }
2015-03-25 12:52:44 -06:00
` ,
} ,
// Too aggressive prefix matching
// golang.org/issue/9961
{
name : "issue 9961" ,
in : ` package p
import (
"zip"
"rsc.io/p"
)
var (
_ = fmt . Print
_ = zip . Store
_ p . P
_ = regexp . Compile
)
` ,
out : ` package p
import (
"fmt"
"regexp"
"zip"
"rsc.io/p"
)
var (
_ = fmt . Print
_ = zip . Store
_ p . P
_ = regexp . Compile
)
2015-08-07 09:16:12 -06:00
` ,
} ,
// Unused named import is mistaken for unnamed import
// golang.org/issue/8149
{
name : "issue 8149" ,
in : ` package main
import foo "fmt"
func main ( ) { fmt . Println ( ) }
` ,
out : ` package main
import "fmt"
2016-02-25 12:09:00 -07:00
func main ( ) { fmt . Println ( ) }
` ,
} ,
// Unused named import is mistaken for unnamed import
// golang.org/issue/8149
{
name : "issue 8149" ,
in : ` package main
import (
"fmt"
x "fmt"
)
func main ( ) { fmt . Println ( ) }
` ,
out : ` package main
2017-02-09 02:39:36 -07:00
import (
"fmt"
)
2015-08-07 09:16:12 -06:00
func main ( ) { fmt . Println ( ) }
2016-04-05 10:10:15 -06:00
` ,
} ,
// FormatOnly
{
name : "format only" ,
formatOnly : true ,
in : ` package main
import (
"fmt"
"golang.org/x/foo"
)
func main ( ) { }
` ,
out : ` package main
import (
"fmt"
"golang.org/x/foo"
)
func main ( ) { }
2017-02-09 02:39:36 -07:00
` ,
} ,
{
name : "do not make grouped imports non-grouped" ,
in : ` package p
import (
"bytes"
"fmt"
)
var _ = fmt . Sprintf
` ,
out : ` package p
import (
"fmt"
)
var _ = fmt . Sprintf
go/ast/astutil: new third-party imports shouldn't go in the std group
Before this change, astutil would only do a prefix match of a new import
with all the existing ones, to try to place it in the correct group. If
none was found, the new import would be placed at the beginning of the
first import group.
This works well for new std imports, but it doesn't work well for new
third-party packages that don't share any prefix with any of the
existing imports.
Example:
import (
"time"
"github.com/golang/snappy"
)
When adding "golang.org/x/sys/unix" with astutil.AddImport, the import
is inserted as follows:
import (
"golang.org/x/sys/unix"
"time"
"github.com/golang/snappy"
)
And goimports reorganizes the imports to separate std and third-party
packages:
import (
"time"
"golang.org/x/sys/unix"
"github.com/golang/snappy"
)
We usually don't want to introduce a new import group; in most cases,
the desired behavior is separating std from third-party packages.
With this CL, new imports that don't share prefix with any existing ones
will be placed with the first group of third-party imports, if any
exist. If no third-party import group exists, a new one will be added.
In the case of our example above, this will be the new outcome:
import (
"time"
"github.com/golang/snappy"
"golang.org/x/sys/unix"
)
Fixes golang/go#19190.
Change-Id: Id4630015c029bd815234a6c8726cb97f4af16f1c
Reviewed-on: https://go-review.googlesource.com/37552
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-03-01 01:02:44 -07:00
` ,
} ,
{
name : "issue #19190 1" ,
in : ` package main
import (
"time"
)
func main ( ) {
_ = snappy . Encode
_ = p . P
_ = time . Parse
}
` ,
out : ` package main
import (
"time"
"code.google.com/p/snappy-go/snappy"
"rsc.io/p"
)
func main ( ) {
_ = snappy . Encode
_ = p . P
_ = time . Parse
}
` ,
} ,
{
name : "issue #19190 2" ,
in : ` package main
import (
"time"
"code.google.com/p/snappy-go/snappy"
)
func main ( ) {
_ = snappy . Encode
_ = p . P
_ = time . Parse
}
` ,
out : ` package main
import (
"time"
"code.google.com/p/snappy-go/snappy"
"rsc.io/p"
)
func main ( ) {
_ = snappy . Encode
_ = p . P
_ = time . Parse
}
2018-02-10 04:48:53 -07:00
` ,
} ,
{
name : "issue #12097" ,
in : ` // a
// b
// c
func main ( ) {
_ = fmt . Println
} ` ,
out : ` package main
import "fmt"
// a
// b
// c
func main ( ) {
_ = fmt . Println
}
go.tools/astutil: fix edge case in DeleteImport causing merging of import sections.
The issue occurs only when deleting an import that has a blank line immediately preceding,
and other imports before that.
Currently, DeleteImport assumes there's a blank line-sized hole left behind
where the import was, and always deletes it. That blank line-sized hole is there in all cases
except the above edge case.
This fix checks for that edge case, and does not remove the blank line-sized hole.
The CL also adds a previously failing test case that catches this scenario. After the change to
DeleteImport, the new test passes (along with all other tests).
Fixes golang/go#7679.
Note that there is no attempt to ensure the result *ast.File and *token.FileSet are perfectly
matching to what you would get if you printed the AST and parsed it back. This is how the
rest of the package and the current tests work (i.e., they only check that printing the AST gives
the correct output).
Changing that is very hard, if not impossible, at least not
without resorting to manipulating AST via printing, text manipulation and parsing.
This is okay for most usages, but it does create potential problems. For example,
astutil.Imports() currently only works correctly on freshly parsed AST. If that AST
is manipulated via astutil funcs, then Imports() may not always generate correct
output. However, thas is a separate issue and should be treated as such.
LGTM=bradfitz
R=golang-codereviews, gobot, adonovan, bradfitz
CC=golang-codereviews
https://golang.org/cl/92250045
2014-05-19 15:04:30 -06:00
` ,
} ,
2013-12-17 19:21:03 -07:00
}
func TestFixImports ( t * testing . T ) {
simplePkgs := map [ string ] string {
"appengine" : "appengine" ,
"bytes" : "bytes" ,
2015-03-25 12:52:44 -06:00
"fmt" : "fmt" ,
"math" : "math" ,
"os" : "os" ,
"p" : "rsc.io/p" ,
"regexp" : "regexp" ,
2013-12-17 19:21:03 -07:00
"snappy" : "code.google.com/p/snappy-go/snappy" ,
2014-03-25 07:37:10 -06:00
"str" : "strings" ,
2015-03-25 12:52:44 -06:00
"user" : "appengine/user" ,
"zip" : "archive/zip" ,
2013-12-17 19:21:03 -07:00
}
2015-12-10 23:32:07 -07:00
old := findImport
defer func ( ) {
findImport = old
} ( )
2018-04-24 14:05:29 -06:00
findImport = func ( _ context . Context , pkgName string , symbols map [ string ] bool , filename string ) ( string , bool , error ) {
2014-03-25 07:37:10 -06:00
return simplePkgs [ pkgName ] , pkgName == "str" , nil
2013-12-17 19:21:03 -07:00
}
2014-04-28 15:15:33 -06:00
options := & Options {
TabWidth : 8 ,
TabIndent : true ,
Comments : true ,
Fragment : true ,
}
2013-12-17 19:21:03 -07:00
for _ , tt := range tests {
2016-04-05 10:10:15 -06:00
options . FormatOnly = tt . formatOnly
2013-12-17 19:21:03 -07:00
if * only != "" && tt . name != * only {
continue
}
2014-04-28 15:15:33 -06:00
buf , err := Process ( tt . name + ".go" , [ ] byte ( tt . in ) , options )
2013-12-17 19:21:03 -07:00
if err != nil {
t . Errorf ( "error on %q: %v" , tt . name , err )
2017-03-23 23:58:37 -06:00
continue
}
if got := string ( buf ) ; got != tt . out {
t . Errorf ( "results diff on %q\nGOT:\n%s\nWANT:\n%s\n" , tt . name , got , tt . out )
}
}
}
func TestProcess_nil_src ( t * testing . T ) {
dir , err := ioutil . TempDir ( "" , "goimports-" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( dir )
tests := [ ] struct {
name string
in , out string
} {
{
name : "nil-src" ,
in : ` package foo
func bar ( ) {
fmt . Println ( "hi" )
}
` ,
out : ` package foo
import "fmt"
func bar ( ) {
fmt . Println ( "hi" )
}
` ,
} ,
{
name : "missing package" ,
in : `
func bar ( ) {
fmt . Println ( "hi" )
}
` ,
out : `
import "fmt"
func bar ( ) {
fmt . Println ( "hi" )
}
` ,
} ,
}
options := & Options {
TabWidth : 8 ,
TabIndent : true ,
Comments : true ,
Fragment : true ,
}
for _ , tt := range tests {
filename := filepath . Join ( dir , tt . name + ".go" )
if err := ioutil . WriteFile ( filename , [ ] byte ( tt . in ) , 0666 ) ; err != nil {
t . Fatal ( err )
}
buf , err := Process ( filename , nil , options )
if err != nil {
t . Errorf ( "error on %q: %v" , tt . name , err )
2013-12-17 19:21:03 -07:00
continue
}
2013-12-18 04:44:50 -07:00
if got := string ( buf ) ; got != tt . out {
2013-12-17 19:21:03 -07:00
t . Errorf ( "results diff on %q\nGOT:\n%s\nWANT:\n%s\n" , tt . name , got , tt . out )
}
}
}
2016-06-07 14:47:49 -06:00
// Test support for packages in GOPATH that are actually symlinks.
// Also test that a symlink loop does not block the process.
func TestImportSymlinks ( t * testing . T ) {
2016-07-17 10:24:21 -06:00
switch runtime . GOOS {
case "windows" , "plan9" :
2016-07-21 00:51:57 -06:00
t . Skipf ( "skipping test on %q as there are no symlinks" , runtime . GOOS )
2016-06-07 14:47:49 -06:00
}
newGoPath , err := ioutil . TempDir ( "" , "symlinktest" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( newGoPath )
2017-03-08 15:01:44 -07:00
// Create:
// $GOPATH/target/
// $GOPATH/target/f.go // package mypkg\nvar Foo = 123\n
// $GOPATH/src/x/
// $GOPATH/src/x/mypkg => $GOPATH/target // symlink
// $GOPATH/src/x/apkg => $GOPATH/src/x // symlink loop
// Test:
// $GOPATH/src/myotherpkg/toformat.go referencing mypkg.Foo
2016-06-07 14:47:49 -06:00
targetPath := newGoPath + "/target"
if err := os . MkdirAll ( targetPath , 0755 ) ; err != nil {
t . Fatal ( err )
}
if err := ioutil . WriteFile ( targetPath + "/f.go" , [ ] byte ( "package mypkg\nvar Foo = 123\n" ) , 0666 ) ; err != nil {
t . Fatal ( err )
}
symlinkPath := newGoPath + "/src/x/mypkg"
if err := os . MkdirAll ( filepath . Dir ( symlinkPath ) , 0755 ) ; err != nil {
t . Fatal ( err )
}
if err := os . Symlink ( targetPath , symlinkPath ) ; err != nil {
t . Fatal ( err )
}
// Add a symlink loop.
if err := os . Symlink ( newGoPath + "/src/x" , newGoPath + "/src/x/apkg" ) ; err != nil {
t . Fatal ( err )
}
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
withEmptyGoPath ( func ( ) {
build . Default . GOPATH = newGoPath
2016-06-07 14:47:49 -06:00
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
input := ` package p
2016-06-07 14:47:49 -06:00
var (
_ = fmt . Print
_ = mypkg . Foo
)
`
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
output := ` package p
2016-06-07 14:47:49 -06:00
import (
"fmt"
"x/mypkg"
)
var (
_ = fmt . Print
_ = mypkg . Foo
)
`
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
buf , err := Process ( newGoPath + "/src/myotherpkg/toformat.go" , [ ] byte ( input ) , & Options { } )
if err != nil {
t . Fatal ( err )
}
if got := string ( buf ) ; got != output {
t . Fatalf ( "results differ\nGOT:\n%s\nWANT:\n%s\n" , got , output )
}
} )
2016-11-15 09:48:37 -07:00
// Add a .goimportsignore and ensure it is respected.
if err := ioutil . WriteFile ( newGoPath + "/src/.goimportsignore" , [ ] byte ( "x/mypkg\n" ) , 0666 ) ; err != nil {
t . Fatal ( err )
}
withEmptyGoPath ( func ( ) {
build . Default . GOPATH = newGoPath
input := ` package p
var (
_ = fmt . Print
_ = mypkg . Foo
)
`
output := ` package p
import "fmt"
var (
_ = fmt . Print
_ = mypkg . Foo
)
`
buf , err := Process ( newGoPath + "/src/myotherpkg/toformat.go" , [ ] byte ( input ) , & Options { } )
if err != nil {
t . Fatal ( err )
}
if got := string ( buf ) ; got != output {
t . Fatalf ( "ignored results differ\nGOT:\n%s\nWANT:\n%s\n" , got , output )
}
} )
2016-06-07 14:47:49 -06:00
}
2016-04-13 15:57:13 -06:00
// Test for correctly identifying the name of a vendored package when it
// differs from its directory name. In this test, the import line
// "mypkg.com/mypkg.v1" would be removed if goimports wasn't able to detect
// that the package name is "mypkg".
func TestFixImportsVendorPackage ( t * testing . T ) {
// Skip this test on go versions with no vendor support.
if _ , err := os . Stat ( filepath . Join ( runtime . GOROOT ( ) , "src/vendor" ) ) ; err != nil {
t . Skip ( err )
}
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
testConfig {
gopathFiles : map [ string ] string {
"mypkg.com/outpkg/vendor/mypkg.com/mypkg.v1/f.go" : "package mypkg\nvar Foo = 123\n" ,
} ,
} . test ( t , func ( t * goimportTest ) {
input := ` package p
2016-04-13 15:57:13 -06:00
import (
"fmt"
"mypkg.com/mypkg.v1"
)
var (
_ = fmt . Print
_ = mypkg . Foo
)
`
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
buf , err := Process ( filepath . Join ( t . gopath , "src/mypkg.com/outpkg/toformat.go" ) , [ ] byte ( input ) , & Options { } )
if err != nil {
t . Fatal ( err )
}
if got := string ( buf ) ; got != input {
t . Fatalf ( "results differ\nGOT:\n%s\nWANT:\n%s\n" , got , input )
}
} )
2016-04-13 15:57:13 -06:00
}
2013-12-17 19:21:03 -07:00
func TestFindImportGoPath ( t * testing . T ) {
goroot , err := ioutil . TempDir ( "" , "goimports-" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( goroot )
2014-01-26 10:47:31 -07:00
origStdlib := stdlib
defer func ( ) {
stdlib = origStdlib
} ( )
stdlib = nil
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
withEmptyGoPath ( func ( ) {
// Test against imaginary bits/bytes package in std lib
bytesDir := filepath . Join ( goroot , "src" , "pkg" , "bits" , "bytes" )
for _ , tag := range build . Default . ReleaseTags {
// Go 1.4 rearranged the GOROOT tree to remove the "pkg" path component.
if tag == "go1.4" {
bytesDir = filepath . Join ( goroot , "src" , "bits" , "bytes" )
}
2014-10-12 15:44:37 -06:00
}
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err := os . MkdirAll ( bytesDir , 0755 ) ; err != nil {
t . Fatal ( err )
}
bytesSrcPath := filepath . Join ( bytesDir , "bytes.go" )
bytesPkgPath := "bits/bytes"
bytesSrc := [ ] byte ( ` package bytes
2013-12-17 19:21:03 -07:00
type Buffer2 struct { }
` )
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err := ioutil . WriteFile ( bytesSrcPath , bytesSrc , 0775 ) ; err != nil {
t . Fatal ( err )
}
build . Default . GOROOT = goroot
2013-12-17 19:21:03 -07:00
2018-04-24 14:05:29 -06:00
got , rename , err := findImportGoPath ( context . Background ( ) , "bytes" , map [ string ] bool { "Buffer2" : true } , "x.go" )
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t . Fatal ( err )
}
if got != bytesPkgPath || rename {
t . Errorf ( ` findImportGoPath("bytes", Buffer2 ...)=%q, %t, want "%s", false ` , got , rename , bytesPkgPath )
}
2013-12-17 19:21:03 -07:00
2018-04-24 14:05:29 -06:00
got , rename , err = findImportGoPath ( context . Background ( ) , "bytes" , map [ string ] bool { "Missing" : true } , "x.go" )
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t . Fatal ( err )
}
if got != "" || rename {
t . Errorf ( ` findImportGoPath("bytes", Missing ...)=%q, %t, want "", false ` , got , rename )
}
} )
2013-12-17 19:21:03 -07:00
}
2014-01-26 10:47:31 -07:00
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
func withEmptyGoPath ( fn func ( ) ) {
2016-07-17 18:47:35 -06:00
populateIgnoreOnce = sync . Once { }
2016-07-16 15:48:20 -06:00
scanGoRootOnce = sync . Once { }
scanGoPathOnce = sync . Once { }
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
dirScan = nil
2016-07-15 12:28:37 -06:00
ignoredDirs = nil
2016-07-17 18:47:35 -06:00
scanGoRootDone = make ( chan struct { } )
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
2015-12-10 23:32:07 -07:00
oldGOPATH := build . Default . GOPATH
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
oldGOROOT := build . Default . GOROOT
2015-12-10 23:32:07 -07:00
build . Default . GOPATH = ""
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
testHookScanDir = func ( string ) { }
2016-07-17 18:47:35 -06:00
2015-12-10 23:32:07 -07:00
defer func ( ) {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
testHookScanDir = func ( string ) { }
2015-12-10 23:32:07 -07:00
build . Default . GOPATH = oldGOPATH
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
build . Default . GOROOT = oldGOROOT
2015-12-10 23:32:07 -07:00
} ( )
2016-07-17 18:47:35 -06:00
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
fn ( )
}
2015-12-10 23:32:07 -07:00
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
func TestFindImportInternal ( t * testing . T ) {
withEmptyGoPath ( func ( ) {
// Check for src/internal/race, not just src/internal,
// so that we can run this test also against go1.5
// (which doesn't contain that file).
_ , err := os . Stat ( filepath . Join ( runtime . GOROOT ( ) , "src/internal/race" ) )
if err != nil {
t . Skip ( err )
}
2015-12-10 23:32:07 -07:00
2018-04-24 14:05:29 -06:00
got , rename , err := findImportGoPath ( context . Background ( ) , "race" , map [ string ] bool { "Acquire" : true } , filepath . Join ( runtime . GOROOT ( ) , "src/math/x.go" ) )
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
if err != nil {
t . Fatal ( err )
}
if got != "internal/race" || rename {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
t . Errorf ( ` findImportGoPath("race", Acquire ...) = %q, %t; want "internal/race", false ` , got , rename )
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
}
2015-12-10 23:32:07 -07:00
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
// should not be able to use internal from outside that tree
2018-04-24 14:05:29 -06:00
got , rename , err = findImportGoPath ( context . Background ( ) , "race" , map [ string ] bool { "Acquire" : true } , filepath . Join ( runtime . GOROOT ( ) , "x.go" ) )
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
if err != nil {
t . Fatal ( err )
}
if got != "" || rename {
t . Errorf ( ` findImportGoPath("race", Acquire ...)=%q, %t, want "", false ` , got , rename )
}
} )
}
// rand.Read should prefer crypto/rand.Read, not math/rand.Read.
func TestFindImportRandRead ( t * testing . T ) {
withEmptyGoPath ( func ( ) {
file := filepath . Join ( runtime . GOROOT ( ) , "src/foo/x.go" ) // dummy
tests := [ ] struct {
syms [ ] string
want string
} {
{
syms : [ ] string { "Read" } ,
want : "crypto/rand" ,
} ,
{
syms : [ ] string { "Read" , "NewZipf" } ,
want : "math/rand" ,
} ,
{
syms : [ ] string { "NewZipf" } ,
want : "math/rand" ,
} ,
{
syms : [ ] string { "Read" , "Prime" } ,
want : "crypto/rand" ,
} ,
}
for _ , tt := range tests {
m := map [ string ] bool { }
for _ , sym := range tt . syms {
m [ sym ] = true
}
2018-04-24 14:05:29 -06:00
got , _ , err := findImportGoPath ( context . Background ( ) , "rand" , m , file )
imports: special case rand.Read, prevent math/rand by chance
In Go 1.7, math/rand.Read was added. Previously, the only package
containing "rand.Read" was "crypto/rand".
goimports was updated to know that, and zstdlib.go contains a note
that it's ambiguous:
"rand.Perm": "math/rand",
"rand.Prime": "crypto/rand",
"rand.Rand": "math/rand",
// "rand.Read" is ambiguous
"rand.Reader": "crypto/rand",
"rand.Seed": "math/rand",
"rand.Source": "math/rand",
The intention originally was that such ambiguous things would
never be resolved, even randomly.
But a later change added support for build.Default.SrcDirs, which
meant GOROOT was also searched for ambiguous things. Or maybe I forget
the history.
In any case, when goimports tried to resolve "rand.Read", the
findImportStdlib check was returning nothing, which lead to the
$GOROOT being searched, where math/rand was picked by chance. That's a
dangerous default when the intentional might've been crypto/rand.
Special case it and prefer crypto/rand if there's no more specific
clue either way.
Change-Id: Ib5f8f297f72fa309d5ca9b15a37493df2e17567c
Reviewed-on: https://go-review.googlesource.com/24847
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Andrew Gerrand <adg@golang.org>
2016-07-11 16:38:22 -06:00
if err != nil {
t . Errorf ( "for %q: %v" , tt . syms , err )
continue
}
if got != tt . want {
t . Errorf ( "for %q, findImportGoPath = %q; want %q" , tt . syms , got , tt . want )
}
}
} )
2015-12-10 23:32:07 -07:00
}
func TestFindImportVendor ( t * testing . T ) {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
testConfig {
gorootFiles : map [ string ] string {
"vendor/golang.org/x/net/http2/hpack/huffman.go" : "package hpack\nfunc HuffmanDecode() { }\n" ,
} ,
} . test ( t , func ( t * goimportTest ) {
2018-04-24 14:05:29 -06:00
got , rename , err := findImportGoPath ( context . Background ( ) , "hpack" , map [ string ] bool { "HuffmanDecode" : true } , filepath . Join ( t . goroot , "src/math/x.go" ) )
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t . Fatal ( err )
}
want := "golang.org/x/net/http2/hpack"
if got != want || rename {
t . Errorf ( ` findImportGoPath("hpack", HuffmanDecode ...) = %q, %t; want %q, false ` , got , rename , want )
}
} )
2015-12-10 23:32:07 -07:00
}
func TestProcessVendor ( t * testing . T ) {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
withEmptyGoPath ( func ( ) {
_ , err := os . Stat ( filepath . Join ( runtime . GOROOT ( ) , "src/vendor" ) )
if err != nil {
t . Skip ( err )
}
2015-12-10 23:32:07 -07:00
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
target := filepath . Join ( runtime . GOROOT ( ) , "src/math/x.go" )
out , err := Process ( target , [ ] byte ( "package http\nimport \"bytes\"\nfunc f() { strings.NewReader(); hpack.HuffmanDecode() }\n" ) , nil )
2015-12-10 23:32:07 -07:00
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
if err != nil {
t . Fatal ( err )
}
2015-12-10 23:32:07 -07:00
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
want := "golang_org/x/net/http2/hpack"
if _ , err := os . Stat ( filepath . Join ( runtime . GOROOT ( ) , "src/vendor" , want ) ) ; os . IsNotExist ( err ) {
want = "golang.org/x/net/http2/hpack"
}
if ! bytes . Contains ( out , [ ] byte ( want ) ) {
t . Fatalf ( "Process(%q) did not add expected hpack import %q; got:\n%s" , target , want , out )
}
} )
2015-12-10 23:32:07 -07:00
}
2014-01-26 10:47:31 -07:00
func TestFindImportStdlib ( t * testing . T ) {
tests := [ ] struct {
pkg string
symbols [ ] string
want string
} {
{ "http" , [ ] string { "Get" } , "net/http" } ,
{ "http" , [ ] string { "Get" , "Post" } , "net/http" } ,
{ "http" , [ ] string { "Get" , "Foo" } , "" } ,
{ "bytes" , [ ] string { "Buffer" } , "bytes" } ,
{ "ioutil" , [ ] string { "Discard" } , "io/ioutil" } ,
}
for _ , tt := range tests {
2018-02-13 07:24:18 -07:00
got , ok := findImportStdlib ( tt . pkg , strSet ( tt . symbols ) )
2014-01-26 10:47:31 -07:00
if ( got != "" ) != ok {
t . Error ( "findImportStdlib return value inconsistent" )
}
2018-02-13 07:24:18 -07:00
if got != tt . want {
t . Errorf ( "findImportStdlib(%q, %q) = %q, want %q" , tt . pkg , tt . symbols , got , tt . want )
2014-01-26 10:47:31 -07:00
}
}
}
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
type testConfig struct {
2016-07-25 09:05:58 -06:00
// goroot and gopath optionally specifies the path on disk
// to use for the GOROOT and GOPATH. If empty, a temp directory
// is made if needed.
goroot , gopath string
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
// gorootFiles optionally specifies the complete contents of GOROOT to use,
// If nil, the normal current $GOROOT is used.
gorootFiles map [ string ] string // paths relative to $GOROOT/src to contents
// gopathFiles is like gorootFiles, but for $GOPATH.
// If nil, there is no GOPATH, though.
gopathFiles map [ string ] string // paths relative to $GOPATH/src to contents
}
func mustTempDir ( t * testing . T , prefix string ) string {
dir , err := ioutil . TempDir ( "" , prefix )
if err != nil {
t . Fatal ( err )
}
return dir
}
func mapToDir ( destDir string , files map [ string ] string ) error {
for path , contents := range files {
file := filepath . Join ( destDir , "src" , path )
if err := os . MkdirAll ( filepath . Dir ( file ) , 0755 ) ; err != nil {
return err
}
2016-07-17 18:47:35 -06:00
var err error
if strings . HasPrefix ( contents , "LINK:" ) {
err = os . Symlink ( strings . TrimPrefix ( contents , "LINK:" ) , file )
} else {
err = ioutil . WriteFile ( file , [ ] byte ( contents ) , 0644 )
}
if err != nil {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
return err
}
}
return nil
}
func ( c testConfig ) test ( t * testing . T , fn func ( * goimportTest ) ) {
2016-07-25 09:05:58 -06:00
goroot := c . goroot
gopath := c . gopath
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
2016-07-25 09:05:58 -06:00
if c . gorootFiles != nil && goroot == "" {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
goroot = mustTempDir ( t , "goroot-" )
defer os . RemoveAll ( goroot )
}
2016-07-25 09:05:58 -06:00
if err := mapToDir ( goroot , c . gorootFiles ) ; err != nil {
t . Fatal ( err )
}
if c . gopathFiles != nil && gopath == "" {
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
gopath = mustTempDir ( t , "gopath-" )
defer os . RemoveAll ( gopath )
2016-07-25 09:05:58 -06:00
}
if err := mapToDir ( gopath , c . gopathFiles ) ; err != nil {
t . Fatal ( err )
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
}
withEmptyGoPath ( func ( ) {
if goroot != "" {
build . Default . GOROOT = goroot
}
build . Default . GOPATH = gopath
it := & goimportTest {
T : t ,
goroot : build . Default . GOROOT ,
gopath : gopath ,
ctx : & build . Default ,
}
fn ( it )
} )
}
type goimportTest struct {
* testing . T
ctx * build . Context
goroot string
gopath string
}
// Tests that added imports are renamed when the import path's base doesn't
// match its package name. For example, we want to generate:
//
// import cloudbilling "google.golang.org/api/cloudbilling/v1"
func TestRenameWhenPackageNameMismatch ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"foo/bar/v1/x.go" : "package bar \n const X = 1" ,
} ,
} . test ( t , func ( t * goimportTest ) {
buf , err := Process ( t . gopath + "/src/test/t.go" , [ ] byte ( "package main \n const Y = bar.X" ) , & Options { } )
if err != nil {
t . Fatal ( err )
}
const want = ` package main
import bar "foo/bar/v1"
const Y = bar . X
`
if string ( buf ) != want {
t . Errorf ( "Got:\n%s\nWant:\n%s" , buf , want )
}
} )
}
2016-07-21 19:35:08 -06:00
// Tests that the LocalPrefix option causes imports
// to be added into a later group (num=3).
func TestLocalPrefix ( t * testing . T ) {
2017-12-23 01:05:04 -07:00
tests := [ ] struct {
config testConfig
localPrefix string
src string
want string
} {
{
config : testConfig {
gopathFiles : map [ string ] string {
"foo/bar/bar.go" : "package bar \n const X = 1" ,
} ,
} ,
localPrefix : "foo/" ,
src : "package main \n const Y = bar.X \n const _ = runtime.GOOS" ,
want : ` package main
2016-07-21 19:35:08 -06:00
2017-12-23 01:05:04 -07:00
import (
"runtime"
"foo/bar"
)
const Y = bar . X
const _ = runtime . GOOS
2018-03-13 15:48:25 -06:00
` ,
} ,
{
config : testConfig {
gopathFiles : map [ string ] string {
"foo/foo.go" : "package foo \n const X = 1" ,
"foo/bar/bar.go" : "package bar \n const X = 1" ,
} ,
} ,
localPrefix : "foo/" ,
src : "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS" ,
want : ` package main
import (
"runtime"
"foo"
"foo/bar"
)
const Y = bar . X
const Z = foo . X
const _ = runtime . GOOS
2017-12-23 01:05:04 -07:00
` ,
2016-07-21 19:35:08 -06:00
} ,
2017-12-23 01:05:04 -07:00
{
config : testConfig {
gopathFiles : map [ string ] string {
"example.org/pkg/pkg.go" : "package pkg \n const A = 1" ,
"foo/bar/bar.go" : "package bar \n const B = 1" ,
"code.org/r/p/expproj/expproj.go" : "package expproj \n const C = 1" ,
} ,
} ,
localPrefix : "example.org/pkg,foo/,code.org" ,
src : "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS" ,
want : ` package main
2016-07-21 19:35:08 -06:00
import (
"runtime"
2017-12-23 01:05:04 -07:00
"code.org/r/p/expproj"
"example.org/pkg"
2016-07-21 19:35:08 -06:00
"foo/bar"
)
2017-12-23 01:05:04 -07:00
const X = pkg . A
const Y = bar . B
const Z = expproj . C
2016-07-21 19:35:08 -06:00
const _ = runtime . GOOS
2017-12-23 01:05:04 -07:00
` ,
} ,
}
for _ , tt := range tests {
tt . config . test ( t , func ( t * goimportTest ) {
defer func ( s string ) { LocalPrefix = s } ( LocalPrefix )
LocalPrefix = tt . localPrefix
buf , err := Process ( t . gopath + "/src/test/t.go" , [ ] byte ( tt . src ) , & Options { } )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != tt . want {
t . Errorf ( "Got:\n%s\nWant:\n%s" , buf , tt . want )
}
} )
}
2016-07-21 19:35:08 -06:00
}
cmd/goimports, imports: make goimports great again
I felt the burn of my laptop on my legs, spinning away while processing
goimports, and felt that it was time to make goimports great again.
Over the past few years goimports fell into a slow state of disrepair
with too many feature additions and no attention to the performance
death by a thousand cuts. This was particularly terrible on OS X with
its lackluster filesystem buffering.
This CL makes goimports stronger, together with various optimizations
and more visibility into what goimports is doing.
* adds more internal documentation
* avoids scanning $GOPATH for answers when running goimports on a file
under $GOROOT (for Go core hackers)
* don't read all $GOROOT & $GOPATH directories' Go code looking for
their package names until much later. Require the package name of
missing imports to be present in the last two directory path
components. Then only try importing them in order from best to
worst (shortest to longest, as before), so we can stop early.
* when adding imports, add names to imports when the imported package name
doesn't match the baes of its import path. For example:
import foo "example.net/foo/v1"
* don't read all *.go files in a package directory once the first file
in a directory has revealed itself to be a package we're not looking
for. For example, if we're looking for the right "client" for "client.Foo",
we used to consider a directory "bar/client" as a candidate and read
all 50 of its *.go files instead of stopping after its first *.go
file had a "package main" line.
* add some fast paths to remove allocations
* add some fast paths to remove disk I/O when looking up the base
package name of a standard library import (of existing imports in a
file, which are very common)
* adds a special case for import "C", to avoid some disk I/O.
* add a -verbose flag to goimports for debugging
On my Mac laptop with a huge $GOPATH, with a test file like:
package foo
import (
"fmt"
"net/http"
)
/*
*/
import "C"
var _ = cloudbilling.New
var _ = http.NewRequest
var _ = client.New
... this took like 10 seconds before, and now 1.3 seconds. (Still
slow; disk-based caching can come later)
Updates golang/go#16367 (goimports is slow)
Updates golang/go#16384 (refactor TestRename is broken on Windows)
Change-Id: I97e85d3016afc9f2ad5501f97babad30c7989183
Reviewed-on: https://go-review.googlesource.com/24941
Reviewed-by: Andrew Gerrand <adg@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-07-14 18:08:27 -06:00
// Tests that running goimport on files in GOROOT (for people hacking
// on Go itself) don't cause the GOPATH to be scanned (which might be
// much bigger).
func TestOptimizationWhenInGoroot ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"foo/foo.go" : "package foo\nconst X = 1\n" ,
} ,
} . test ( t , func ( t * goimportTest ) {
testHookScanDir = func ( dir string ) {
if dir != filepath . Join ( build . Default . GOROOT , "src" ) {
t . Errorf ( "unexpected dir scan of %s" , dir )
}
}
const in = "package foo\n\nconst Y = bar.X\n"
buf , err := Process ( t . goroot + "/src/foo/foo.go" , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != in {
t . Errorf ( "got:\n%q\nwant unchanged:\n%q\n" , in , buf )
}
} )
}
// Tests that "package documentation" files are ignored.
func TestIgnoreDocumentationPackage ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"foo/foo.go" : "package foo\nconst X = 1\n" ,
"foo/doc.go" : "package documentation \n // just to confuse things\n" ,
} ,
} . test ( t , func ( t * goimportTest ) {
const in = "package x\n\nconst Y = foo.X\n"
const want = "package x\n\nimport \"foo\"\n\nconst Y = foo.X\n"
buf , err := Process ( t . gopath + "/src/x/x.go" , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != want {
t . Errorf ( "wrong output.\ngot:\n%q\nwant:\n%q\n" , in , want )
}
} )
}
2016-07-15 09:24:26 -06:00
// Tests importPathToNameGoPathParse and in particular that it stops
// after finding the first non-documentation package name, not
// reporting an error on inconsistent package names (since it should
// never make it that far).
func TestImportPathToNameGoPathParse ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"example.net/pkg/doc.go" : "package documentation\n" , // ignored
"example.net/pkg/gen.go" : "package main\n" , // also ignored
"example.net/pkg/pkg.go" : "package the_pkg_name_to_find\n and this syntax error is ignored because of parser.PackageClauseOnly" ,
"example.net/pkg/z.go" : "package inconsistent\n" , // inconsistent but ignored
} ,
} . test ( t , func ( t * goimportTest ) {
got , err := importPathToNameGoPathParse ( "example.net/pkg" , filepath . Join ( t . gopath , "src" , "other.net" ) )
if err != nil {
t . Fatal ( err )
}
const want = "the_pkg_name_to_find"
if got != want {
t . Errorf ( "importPathToNameGoPathParse(..) = %q; want %q" , got , want )
}
} )
}
2016-07-15 12:28:37 -06:00
func TestIgnoreConfiguration ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
2018-04-24 14:05:29 -06:00
".goimportsignore" : "# comment line\n\n example.net" , // tests comment, blank line, whitespace trimming
"example.net/pkg/pkg.go" : "package pkg\nconst X = 1" ,
2016-07-15 12:28:37 -06:00
"otherwise-longer-so-worse.example.net/foo/pkg/pkg.go" : "package pkg\nconst X = 1" ,
} ,
} . test ( t , func ( t * goimportTest ) {
const in = "package x\n\nconst _ = pkg.X\n"
const want = "package x\n\nimport \"otherwise-longer-so-worse.example.net/foo/pkg\"\n\nconst _ = pkg.X\n"
buf , err := Process ( t . gopath + "/src/x/x.go" , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != want {
t . Errorf ( "wrong output.\ngot:\n%q\nwant:\n%q\n" , buf , want )
}
} )
}
2016-07-18 22:42:54 -06:00
// Skip "node_modules" directory.
func TestSkipNodeModules ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"example.net/node_modules/pkg/a.go" : "package pkg\nconst X = 1" ,
"otherwise-longer.net/not_modules/pkg/a.go" : "package pkg\nconst X = 1" ,
} ,
} . test ( t , func ( t * goimportTest ) {
const in = "package x\n\nconst _ = pkg.X\n"
const want = "package x\n\nimport \"otherwise-longer.net/not_modules/pkg\"\n\nconst _ = pkg.X\n"
buf , err := Process ( t . gopath + "/src/x/x.go" , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != want {
t . Errorf ( "wrong output.\ngot:\n%q\nwant:\n%q\n" , buf , want )
}
} )
}
2016-07-25 09:05:58 -06:00
// golang.org/issue/16458 -- if GOROOT is a prefix of GOPATH, GOPATH is ignored.
func TestGoRootPrefixOfGoPath ( t * testing . T ) {
dir := mustTempDir ( t , "importstest" )
defer os . RemoveAll ( dir )
testConfig {
goroot : filepath . Join ( dir , "go" ) ,
gopath : filepath . Join ( dir , "gopath" ) ,
gopathFiles : map [ string ] string {
"example.com/foo/pkg.go" : "package foo\nconst X = 1" ,
} ,
} . test ( t , func ( t * goimportTest ) {
const in = "package x\n\nconst _ = foo.X\n"
const want = "package x\n\nimport \"example.com/foo\"\n\nconst _ = foo.X\n"
buf , err := Process ( t . gopath + "/src/x/x.go" , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != want {
t . Errorf ( "wrong output.\ngot:\n%q\nwant:\n%q\n" , buf , want )
}
} )
}
2016-05-25 17:35:48 -06:00
const testGlobalImportsUsesGlobal = ` package globalimporttest
func doSomething ( ) {
t := time . Now ( )
}
`
const testGlobalImportsGlobalDecl = ` package globalimporttest
type Time struct { }
func ( t Time ) Now ( ) Time {
return Time { }
}
var time Time
`
// Tests that package global variables with the same name and function name as
// a function in a separate package do not result in an import which masks
// the global variable
func TestGlobalImports ( t * testing . T ) {
const pkg = "globalimporttest"
const usesGlobalFile = pkg + "/uses_global.go"
testConfig {
gopathFiles : map [ string ] string {
usesGlobalFile : testGlobalImportsUsesGlobal ,
pkg + "/global.go" : testGlobalImportsGlobalDecl ,
} ,
} . test ( t , func ( t * goimportTest ) {
buf , err := Process (
t . gopath + "/src/" + usesGlobalFile , [ ] byte ( testGlobalImportsUsesGlobal ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != testGlobalImportsUsesGlobal {
t . Errorf ( "wrong output.\ngot:\n%q\nwant:\n%q\n" , buf , testGlobalImportsUsesGlobal )
}
} )
}
2017-05-12 14:54:58 -06:00
// Tests that sibling files - other files in the same package - can provide an
// import that may not be the default one otherwise.
func TestSiblingImports ( t * testing . T ) {
// provide is the sibling file that provides the desired import.
const provide = ` package siblingimporttest
import "local/log"
2017-12-08 07:26:14 -07:00
import "my/bytes"
2017-05-12 14:54:58 -06:00
func LogSomething ( ) {
log . Print ( "Something" )
2017-12-08 07:26:14 -07:00
bytes . SomeFunc ( )
2017-05-12 14:54:58 -06:00
}
`
// need is the file being tested that needs the import.
const need = ` package siblingimporttest
2017-12-08 07:26:14 -07:00
var _ = bytes . Buffer { }
2017-05-12 14:54:58 -06:00
func LogSomethingElse ( ) {
log . Print ( "Something else" )
}
`
// want is the expected result file
const want = ` package siblingimporttest
2017-12-08 07:26:14 -07:00
import (
"bytes"
"local/log"
)
var _ = bytes . Buffer { }
2017-05-12 14:54:58 -06:00
func LogSomethingElse ( ) {
log . Print ( "Something else" )
}
`
const pkg = "siblingimporttest"
const siblingFile = pkg + "/needs_import.go"
testConfig {
gopathFiles : map [ string ] string {
siblingFile : need ,
pkg + "/provides_import.go" : provide ,
} ,
} . test ( t , func ( t * goimportTest ) {
buf , err := Process (
t . gopath + "/src/" + siblingFile , [ ] byte ( need ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( buf ) != want {
t . Errorf ( "wrong output.\ngot:\n%q\nwant:\n%q\n" , buf , want )
}
} )
}
2014-01-26 10:47:31 -07:00
func strSet ( ss [ ] string ) map [ string ] bool {
m := make ( map [ string ] bool )
for _ , s := range ss {
m [ s ] = true
}
return m
}
2016-07-18 15:58:52 -06:00
func TestPkgIsCandidate ( t * testing . T ) {
tests := [ ... ] struct {
filename string
pkgIdent string
pkg * pkg
want bool
} {
// normal match
0 : {
filename : "/gopath/src/my/pkg/pkg.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/client" ,
importPath : "client" ,
importPathShort : "client" ,
} ,
want : true ,
} ,
// not a match
1 : {
filename : "/gopath/src/my/pkg/pkg.go" ,
pkgIdent : "zzz" ,
pkg : & pkg {
dir : "/gopath/src/client" ,
importPath : "client" ,
importPathShort : "client" ,
} ,
want : false ,
} ,
// would be a match, but "client" appears too deep.
2 : {
filename : "/gopath/src/my/pkg/pkg.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/client/foo/foo/foo" ,
importPath : "client/foo/foo" ,
importPathShort : "client/foo/foo" ,
} ,
want : false ,
} ,
// not an exact match, but substring is good enough.
3 : {
filename : "/gopath/src/my/pkg/pkg.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/foo/go-client" ,
importPath : "foo/go-client" ,
importPathShort : "foo/go-client" ,
} ,
want : true ,
} ,
// "internal" package, and not visible
4 : {
filename : "/gopath/src/my/pkg/pkg.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/foo/internal/client" ,
importPath : "foo/internal/client" ,
importPathShort : "foo/internal/client" ,
} ,
want : false ,
} ,
// "internal" package but visible
5 : {
filename : "/gopath/src/foo/bar.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/foo/internal/client" ,
importPath : "foo/internal/client" ,
importPathShort : "foo/internal/client" ,
} ,
want : true ,
} ,
// "vendor" package not visible
6 : {
filename : "/gopath/src/foo/bar.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/other/vendor/client" ,
importPath : "other/vendor/client" ,
importPathShort : "client" ,
} ,
want : false ,
} ,
// "vendor" package, visible
7 : {
filename : "/gopath/src/foo/bar.go" ,
pkgIdent : "client" ,
pkg : & pkg {
dir : "/gopath/src/foo/vendor/client" ,
importPath : "other/foo/client" ,
importPathShort : "client" ,
} ,
want : true ,
} ,
// Ignore hyphens.
8 : {
filename : "/gopath/src/foo/bar.go" ,
pkgIdent : "socketio" ,
pkg : & pkg {
dir : "/gopath/src/foo/socket-io" ,
importPath : "foo/socket-io" ,
importPathShort : "foo/socket-io" ,
} ,
want : true ,
} ,
// Ignore case.
9 : {
filename : "/gopath/src/foo/bar.go" ,
pkgIdent : "fooprod" ,
pkg : & pkg {
dir : "/gopath/src/foo/FooPROD" ,
importPath : "foo/FooPROD" ,
importPathShort : "foo/FooPROD" ,
} ,
want : true ,
} ,
// Ignoring both hyphens and case together.
10 : {
filename : "/gopath/src/foo/bar.go" ,
pkgIdent : "fooprod" ,
pkg : & pkg {
dir : "/gopath/src/foo/Foo-PROD" ,
importPath : "foo/Foo-PROD" ,
importPathShort : "foo/Foo-PROD" ,
} ,
want : true ,
} ,
}
for i , tt := range tests {
got := pkgIsCandidate ( tt . filename , tt . pkgIdent , tt . pkg )
if got != tt . want {
t . Errorf ( "test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v" ,
i , tt . filename , tt . pkgIdent , * tt . pkg , got , tt . want )
}
}
}
2017-03-08 15:01:44 -07:00
func TestShouldTraverse ( t * testing . T ) {
switch runtime . GOOS {
case "windows" , "plan9" :
t . Skipf ( "skipping symlink-requiring test on %s" , runtime . GOOS )
}
dir , err := ioutil . TempDir ( "" , "goimports-" )
if err != nil {
t . Fatal ( err )
}
defer os . RemoveAll ( dir )
// Note: mapToDir prepends "src" to each element, since
// mapToDir was made for creating GOPATHs.
if err := mapToDir ( dir , map [ string ] string {
"foo/foo2/file.txt" : "" ,
"foo/foo2/link-to-src" : "LINK:" + dir + "/src" ,
"foo/foo2/link-to-src-foo" : "LINK:" + dir + "/src/foo" ,
"foo/foo2/link-to-dot" : "LINK:." ,
"bar/bar2/file.txt" : "" ,
"bar/bar2/link-to-src-foo" : "LINK:" + dir + "/src/foo" ,
"a/b/c" : "LINK:" + dir + "/src/a/d" ,
"a/d/e" : "LINK:" + dir + "/src/a/b" ,
} ) ; err != nil {
t . Fatal ( err )
}
tests := [ ] struct {
dir string
file string
want bool
} {
{
dir : dir + "/src/foo/foo2" ,
file : "link-to-src-foo" ,
want : false , // loop
} ,
{
dir : dir + "/src/foo/foo2" ,
file : "link-to-src" ,
want : false , // loop
} ,
{
dir : dir + "/src/foo/foo2" ,
file : "link-to-dot" ,
want : false , // loop
} ,
{
dir : dir + "/src/bar/bar2" ,
file : "link-to-src-foo" ,
want : true , // not a loop
} ,
{
dir : dir + "/src/a/b/c" ,
file : "e" ,
want : false , // loop: "e" is the same as "b".
} ,
}
for i , tt := range tests {
fi , err := os . Stat ( filepath . Join ( tt . dir , tt . file ) )
if err != nil {
t . Errorf ( "%d. Stat = %v" , i , err )
continue
}
got := shouldTraverse ( tt . dir , fi )
if got != tt . want {
t . Errorf ( "%d. shouldTraverse(%q, %q) = %v; want %v" , i , tt . dir , tt . file , got , tt . want )
}
}
}
2017-07-07 10:16:50 -06:00
// Issue 20941: this used to panic on Windows.
func TestProcessStdin ( t * testing . T ) {
got , err := Process ( "<standard input>" , [ ] byte ( "package main\nfunc main() {\n\tfmt.Println(123)\n}\n" ) , nil )
if err != nil {
t . Fatal ( err )
}
if ! strings . Contains ( string ( got ) , ` "fmt" ` ) {
t . Errorf ( "expected fmt import; got: %s" , got )
}
}
2017-02-15 06:46:03 -07:00
// Tests LocalPackagePromotion when there is a local package that matches, it
// should be the closest match.
// https://golang.org/issues/17557
func TestLocalPackagePromotion ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"config.net/config/config.go" : "package config\n type SystemConfig struct {}" , // Will match but should not be first choice
"mycompany.net/config/config.go" : "package config\n type SystemConfig struct {}" , // Will match but should not be first choice
"mycompany.net/tool/config/config.go" : "package config\n type SystemConfig struct {}" , // Local package should be promoted over shorter package
} ,
} . test ( t , func ( t * goimportTest ) {
const in = "package main\n var c = &config.SystemConfig{}"
const want = ` package main
import "mycompany.net/tool/config"
var c = & config . SystemConfig { }
`
got , err := Process ( filepath . Join ( t . gopath , "src" , "mycompany.net/tool/main.go" ) , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( got ) != want {
t . Errorf ( "Process = %q; want %q" , got , want )
}
} )
}
// Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the
// local directory, since the user is likely to import the same packages in the current
// Go file. If an import is found that satisfies the need, it should be used over the
// standard library.
// https://golang.org/issues/17557
func TestFindImportInLocalGoFiles ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string {
"bytes.net/bytes/bytes.go" : "package bytes\n type Buffer struct {}" , // Should be selected over standard library
"mycompany.net/tool/io.go" : "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}" , // Contains package import that will cause stdlib to be ignored
"mycompany.net/tool/err.go" : "package main\n import \"bogus.net/bytes\"\n var _ = &bytes.Buffer{}" , // Contains import which is not resolved, so it is ignored
} ,
} . test ( t , func ( t * goimportTest ) {
const in = "package main\n var _ = &bytes.Buffer{}"
const want = ` package main
import "bytes.net/bytes"
var _ = & bytes . Buffer { }
`
got , err := Process ( filepath . Join ( t . gopath , "src" , "mycompany.net/tool/main.go" ) , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( got ) != want {
t . Errorf ( "Process = got %q; want %q" , got , want )
}
} )
}
func TestImportNoGoFiles ( t * testing . T ) {
testConfig {
gopathFiles : map [ string ] string { } ,
} . test ( t , func ( t * goimportTest ) {
const in = "package main\n var _ = &bytes.Buffer{}"
const want = ` package main
import "bytes"
var _ = & bytes . Buffer { }
`
got , err := Process ( filepath . Join ( t . gopath , "src" , "mycompany.net/tool/main.go" ) , [ ] byte ( in ) , nil )
if err != nil {
t . Fatal ( err )
}
if string ( got ) != want {
t . Errorf ( "Process = got %q; want %q" , got , want )
}
} )
}
2017-12-15 06:15:17 -07:00
// A happy path test for Process
func TestProcess ( t * testing . T ) {
in := ` package testimports
var s = fmt . Sprintf ( "%s" , "value" )
`
out , err := Process ( "foo" , [ ] byte ( in ) , nil )
if err != nil {
t . Errorf ( "Process returned error.\n got:\n%v\nwant:\nnil" , err )
}
want := ` package testimports
import "fmt"
var s = fmt . Sprintf ( "%s" , "value" )
`
if got := string ( out ) ; got != want {
t . Errorf ( "Process returned unexpected result.\ngot:\n%v\nwant:\n%v" , got , want )
}
}
// Ensures a token as large as 500000 bytes can be handled
// https://golang.org/issues/18201
func TestProcessLargeToken ( t * testing . T ) {
largeString := strings . Repeat ( "x" , 500000 )
in := ` package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt . Sprintf ( "%s" , "` + largeString + `" )
const x = mypkg . Sprintf ( "%s" , "my package" )
// end
`
out , err := Process ( "foo" , [ ] byte ( in ) , nil )
if err != nil {
t . Errorf ( "Process returned error.\n got:\n%v\nwant:\nnil" , err )
}
want := ` package testimports
import (
"fmt"
"mydomain.mystuff/mypkg"
)
const s = fmt . Sprintf ( "%s" , "` + largeString + `" )
const x = mypkg . Sprintf ( "%s" , "my package" )
// end
`
if got := string ( out ) ; got != want {
2018-03-12 17:32:48 -06:00
t . Errorf ( "Process returned unexpected result.\ngot:\n%.100v\nwant:\n%.100v" , got , want )
2017-12-15 06:15:17 -07:00
}
}