├── .gitignore ├── fileutils ├── _testdata │ └── copyfile │ │ └── a │ │ └── rick ├── fileutils_test.go ├── path_test.go └── fileutils.go ├── vendor ├── golang.org │ └── x │ │ └── tools │ │ ├── go │ │ └── ast │ │ │ └── astutil │ │ │ ├── util.go │ │ │ ├── LICENSE │ │ │ ├── imports.go │ │ │ └── enclosing.go │ │ ├── cmd │ │ └── goimports │ │ │ ├── goimports_not_gc.go │ │ │ ├── goimports_gc.go │ │ │ ├── LICENSE │ │ │ ├── doc.go │ │ │ └── goimports.go │ │ ├── imports │ │ ├── fastwalk_dirent_ino.go │ │ ├── fastwalk_dirent_fileno.go │ │ ├── fastwalk_portable.go │ │ ├── LICENSE │ │ ├── mkstdlib.go │ │ ├── fastwalk_unix.go │ │ ├── mkindex.go │ │ ├── fastwalk.go │ │ ├── sortimports.go │ │ ├── imports.go │ │ └── fix.go │ │ └── cover │ │ ├── LICENSE │ │ └── profile.go ├── github.com │ └── wadey │ │ └── gocovmerge │ │ ├── LICENSE │ │ └── gocovmerge.go └── manifest ├── .travis.yml ├── README.md ├── LICENSE ├── list.go ├── delete.go ├── gbvendor ├── discovery.go ├── manifest_test.go ├── repo_test.go ├── imports_test.go ├── imports.go ├── manifest.go └── repo.go ├── help.go ├── main.go ├── downloader.go ├── Makefile ├── alldocs.go ├── update.go ├── restore.go ├── README.old.md └── fetch.go /.gitignore: -------------------------------------------------------------------------------- 1 | /.GOPATH 2 | /bin 3 | -------------------------------------------------------------------------------- /fileutils/_testdata/copyfile/a/rick: -------------------------------------------------------------------------------- 1 | /never/going/to/give/you/up -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/ast/astutil/util.go: -------------------------------------------------------------------------------- 1 | package astutil 2 | 3 | import "go/ast" 4 | 5 | // Unparen returns e with any enclosing parentheses stripped. 6 | func Unparen(e ast.Expr) ast.Expr { 7 | for { 8 | p, ok := e.(*ast.ParenExpr) 9 | if !ok { 10 | return e 11 | } 12 | e = p.X 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !gc 6 | 7 | package main 8 | 9 | func doTrace() func() { 10 | return func() {} 11 | } 12 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/fastwalk_dirent_ino.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build linux,!appengine darwin 6 | 7 | package imports 8 | 9 | import "syscall" 10 | 11 | func direntInode(dirent *syscall.Dirent) uint64 { 12 | return uint64(dirent.Ino) 13 | } 14 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/fastwalk_dirent_fileno.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build freebsd openbsd netbsd 6 | 7 | package imports 8 | 9 | import "syscall" 10 | 11 | func direntInode(dirent *syscall.Dirent) uint64 { 12 | return uint64(dirent.Fileno) 13 | } 14 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build gc 6 | 7 | package main 8 | 9 | import ( 10 | "flag" 11 | "runtime/trace" 12 | ) 13 | 14 | var traceProfile = flag.String("trace", "", "trace profile output") 15 | 16 | func doTrace() func() { 17 | if *traceProfile != "" { 18 | bw, flush := bufferedFileWriter(*traceProfile) 19 | trace.Start(bw) 20 | return func() { 21 | flush() 22 | trace.Stop() 23 | } 24 | } 25 | return func() {} 26 | } 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.5.3 5 | - 1.7.3 6 | - tip 7 | 8 | matrix: 9 | allow_failures: 10 | - go: tip 11 | 12 | sudo: false 13 | 14 | script: 15 | - if [[ "$TRAVIS_GO_VERSION" == "1.5.3" ]]; then make gvt; fi 16 | - if [[ "$TRAVIS_GO_VERSION" != "1.5.3" ]]; then make test; fi 17 | 18 | os: 19 | - linux 20 | - osx 21 | 22 | # ssh_known_hosts is broken on OS X, run ssh-keyscan manually instead 23 | # See https://github.com/travis-ci/travis-ci/issues/5596 24 | # addons: 25 | # ssh_known_hosts: 26 | # - bitbucket.org 27 | before_install: 28 | - ssh-keyscan -t rsa -T 30 -H bitbucket.org | tee -a $HOME/.ssh/known_hosts 29 | 30 | install: 31 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi 32 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install bazaar; fi 33 | -------------------------------------------------------------------------------- /fileutils/fileutils_test.go: -------------------------------------------------------------------------------- 1 | package fileutils 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | "runtime" 8 | "testing" 9 | ) 10 | 11 | func TestCopypathSymlinks(t *testing.T) { 12 | if runtime.GOOS == "windows" { 13 | t.Skip("no symlinks on windows y'all") 14 | } 15 | dst := mktemp(t) 16 | defer RemoveAll(dst) 17 | src := filepath.Join("_testdata", "copyfile") 18 | if err := Copypath(dst, src, true, false); err != nil { 19 | t.Fatalf("copypath(%s, %s): %v", dst, src, err) 20 | } 21 | res, err := os.Readlink(filepath.Join(dst, "a", "rick")) 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | if res != "/never/going/to/give/you/up" { 26 | t.Fatalf("target == %s, expected /never/going/to/give/you/up", res) 27 | } 28 | } 29 | 30 | func mktemp(t *testing.T) string { 31 | s, err := ioutil.TempDir("", "fileutils_test") 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | return s 36 | } 37 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/fastwalk_portable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd 6 | 7 | package imports 8 | 9 | import ( 10 | "io/ioutil" 11 | "os" 12 | ) 13 | 14 | // readDir calls fn for each directory entry in dirName. 15 | // It does not descend into directories or follow symlinks. 16 | // If fn returns a non-nil error, readDir returns with that error 17 | // immediately. 18 | func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { 19 | fis, err := ioutil.ReadDir(dirName) 20 | if err != nil { 21 | return err 22 | } 23 | for _, fi := range fis { 24 | if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { 25 | return err 26 | } 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `gvt` was a minimalistic Go vendoring tool made for the `vendor/` folder (once known as the 2 | [GO15VENDOREXPERIMENT](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo/edit)). 3 | 4 | It was based on [gb-vendor](https://github.com/constabulary/gb) by Dave Cheney. 5 | 6 | Since Go 1.11, the `go` tool supports *modules*, a native solution to the dependency problem. 7 | 8 | The `go` tool understands `gvt` manifest files, so you just have to run 9 | 10 | ``` 11 | GO111MODULE=on go mod init 12 | GO111MODULE=on go mod vendor 13 | ``` 14 | 15 | to migrate and still populate the `vendor/` folder for backwards compatibility. 16 | 17 | Read more [in the docs](https://tip.golang.org/cmd/go/#hdr-Modules__module_versions__and_more) or [on the wiki](https://golang.org/wiki/Modules). 18 | 19 | Modules support is experimental in 1.11, but it will probably serve you better than gvt would. 20 | 21 | — So long, and thanks for all the fish! 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 constabulary 4 | Copyright (c) 2015 Filippo Valsorda 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /vendor/github.com/wadey/gocovmerge/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Wade Simmons 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /list.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "html/template" 7 | "os" 8 | "text/tabwriter" 9 | 10 | "github.com/FiloSottile/gvt/gbvendor" 11 | ) 12 | 13 | var ( 14 | format string 15 | ) 16 | 17 | func addListFlags(fs *flag.FlagSet) { 18 | fs.StringVar(&format, "f", "{{.Importpath}}\t{{.Repository}}{{.Path}}\t{{.Branch}}\t{{.Revision}}", "format template") 19 | } 20 | 21 | var cmdList = &Command{ 22 | Name: "list", 23 | UsageLine: "list [-f format]", 24 | Short: "list dependencies one per line", 25 | Long: `list formats the contents of the manifest file. 26 | 27 | Flags: 28 | -f 29 | controls the template used for printing each manifest entry. If not supplied 30 | the default value is "{{.Importpath}}\t{{.Repository}}{{.Path}}\t{{.Branch}}\t{{.Revision}}" 31 | 32 | `, 33 | Run: func(args []string) error { 34 | m, err := vendor.ReadManifest(manifestFile) 35 | if err != nil { 36 | return fmt.Errorf("could not load manifest: %v", err) 37 | } 38 | tmpl, err := template.New("list").Parse(format) 39 | if err != nil { 40 | return fmt.Errorf("unable to parse template %q: %v", format, err) 41 | } 42 | w := tabwriter.NewWriter(os.Stdout, 1, 2, 1, ' ', 0) 43 | for _, dep := range m.Dependencies { 44 | if err := tmpl.Execute(w, dep); err != nil { 45 | return fmt.Errorf("unable to execute template: %v", err) 46 | } 47 | fmt.Fprintln(w) 48 | } 49 | return w.Flush() 50 | }, 51 | AddFlags: addListFlags, 52 | } 53 | -------------------------------------------------------------------------------- /vendor/manifest: -------------------------------------------------------------------------------- 1 | { 2 | "generator": "github.com/FiloSottile/gvt", 3 | "dependencies": [ 4 | { 5 | "importpath": "github.com/wadey/gocovmerge", 6 | "repository": "https://github.com/wadey/gocovmerge", 7 | "vcs": "git", 8 | "revision": "b5bfa59ec0adc420475f97f89b58045c721d761c", 9 | "branch": "master", 10 | "notests": true 11 | }, 12 | { 13 | "importpath": "golang.org/x/tools/cmd/goimports", 14 | "repository": "https://go.googlesource.com/tools", 15 | "vcs": "git", 16 | "revision": "8b84dae17391c154ca50b0162662aa1fc9ff84c2", 17 | "branch": "master", 18 | "path": "/cmd/goimports", 19 | "notests": true 20 | }, 21 | { 22 | "importpath": "golang.org/x/tools/cover", 23 | "repository": "https://go.googlesource.com/tools", 24 | "vcs": "git", 25 | "revision": "8b84dae17391c154ca50b0162662aa1fc9ff84c2", 26 | "branch": "master", 27 | "path": "/cover", 28 | "notests": true 29 | }, 30 | { 31 | "importpath": "golang.org/x/tools/go/ast/astutil", 32 | "repository": "https://go.googlesource.com/tools", 33 | "vcs": "git", 34 | "revision": "8b84dae17391c154ca50b0162662aa1fc9ff84c2", 35 | "branch": "master", 36 | "path": "go/ast/astutil", 37 | "notests": true 38 | }, 39 | { 40 | "importpath": "golang.org/x/tools/imports", 41 | "repository": "https://go.googlesource.com/tools", 42 | "vcs": "git", 43 | "revision": "8b84dae17391c154ca50b0162662aa1fc9ff84c2", 44 | "branch": "master", 45 | "path": "imports", 46 | "notests": true 47 | } 48 | ] 49 | } -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cover/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cmd/goimports/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/go/ast/astutil/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cmd/goimports/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Command goimports updates your Go import lines, 4 | adding missing ones and removing unreferenced ones. 5 | 6 | $ go get golang.org/x/tools/cmd/goimports 7 | 8 | It's a drop-in replacement for your editor's gofmt-on-save hook. 9 | It has the same command-line interface as gofmt and formats 10 | your code in the same way. 11 | 12 | For emacs, make sure you have the latest go-mode.el: 13 | https://github.com/dominikh/go-mode.el 14 | Then in your .emacs file: 15 | (setq gofmt-command "goimports") 16 | (add-to-list 'load-path "/home/you/somewhere/emacs/") 17 | (require 'go-mode-load) 18 | (add-hook 'before-save-hook 'gofmt-before-save) 19 | 20 | For vim, set "gofmt_command" to "goimports": 21 | https://golang.org/change/39c724dd7f252 22 | https://golang.org/wiki/IDEsAndTextEditorPlugins 23 | etc 24 | 25 | For GoSublime, follow the steps described here: 26 | http://michaelwhatcott.com/gosublime-goimports/ 27 | 28 | For other editors, you probably know what to do. 29 | 30 | To exclude directories in your $GOPATH from being scanned for Go 31 | files, goimports respects a configuration file at 32 | $GOPATH/src/.goimportsignore which may contain blank lines, comment 33 | lines (beginning with '#'), or lines naming a directory relative to 34 | the configuration file to ignore when scanning. No globbing or regex 35 | patterns are allowed. Use the "-v" verbose flag to verify it's 36 | working and see what goimports is doing. 37 | 38 | File bugs or feature requests at: 39 | 40 | https://golang.org/issues/new?title=x/tools/cmd/goimports:+ 41 | 42 | Happy hacking! 43 | 44 | */ 45 | package main // import "golang.org/x/tools/cmd/goimports" 46 | -------------------------------------------------------------------------------- /delete.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "path/filepath" 7 | 8 | "github.com/FiloSottile/gvt/fileutils" 9 | 10 | "github.com/FiloSottile/gvt/gbvendor" 11 | ) 12 | 13 | var ( 14 | deleteAll bool // delete all dependencies 15 | ) 16 | 17 | func addDeleteFlags(fs *flag.FlagSet) { 18 | fs.BoolVar(&deleteAll, "all", false, "delete all dependencies") 19 | } 20 | 21 | var cmdDelete = &Command{ 22 | Name: "delete", 23 | UsageLine: "delete [-all] importpath", 24 | Short: "delete a local dependency", 25 | Long: `delete removes a dependency from the vendor directory and the manifest 26 | 27 | Flags: 28 | -all 29 | remove all dependencies 30 | 31 | `, 32 | Run: func(args []string) error { 33 | if len(args) != 1 && !deleteAll { 34 | return fmt.Errorf("delete: import path or --all flag is missing") 35 | } else if len(args) == 1 && deleteAll { 36 | return fmt.Errorf("delete: you cannot specify path and --all flag at once") 37 | } 38 | 39 | m, err := vendor.ReadManifest(manifestFile) 40 | if err != nil { 41 | return fmt.Errorf("could not load manifest: %v", err) 42 | } 43 | 44 | var dependencies []vendor.Dependency 45 | if deleteAll { 46 | dependencies = make([]vendor.Dependency, len(m.Dependencies)) 47 | copy(dependencies, m.Dependencies) 48 | } else { 49 | p := args[0] 50 | dependency, err := m.GetDependencyForImportpath(p) 51 | if err != nil { 52 | return fmt.Errorf("could not get dependency: %v", err) 53 | } 54 | if p != dependency.Importpath { 55 | return fmt.Errorf("a parent of the specified dependency is vendored, remove that instead: %v", 56 | dependency.Importpath) 57 | } 58 | dependencies = append(dependencies, dependency) 59 | } 60 | 61 | for _, d := range dependencies { 62 | path := d.Importpath 63 | 64 | if err := m.RemoveDependency(d); err != nil { 65 | return fmt.Errorf("dependency could not be deleted: %v", err) 66 | } 67 | 68 | if err := fileutils.RemoveAll(filepath.Join(vendorDir, filepath.FromSlash(path))); err != nil { 69 | // TODO(dfc) need to apply vendor.cleanpath here to remove indermediate directories. 70 | return fmt.Errorf("dependency could not be deleted: %v", err) 71 | } 72 | } 73 | return vendor.WriteManifest(manifestFile, m) 74 | }, 75 | AddFlags: addDeleteFlags, 76 | } 77 | -------------------------------------------------------------------------------- /gbvendor/discovery.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vendor 6 | 7 | import ( 8 | "encoding/xml" 9 | "fmt" 10 | "io" 11 | "strings" 12 | ) 13 | 14 | // charsetReader returns a reader for the given charset. Currently 15 | // it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful 16 | // error which is printed by go get, so the user can find why the package 17 | // wasn't downloaded if the encoding is not supported. Note that, in 18 | // order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters 19 | // greater than 0x7f are not rejected). 20 | func charsetReader(charset string, input io.Reader) (io.Reader, error) { 21 | switch strings.ToLower(charset) { 22 | case "ascii": 23 | return input, nil 24 | default: 25 | return nil, fmt.Errorf("can't decode XML document using charset %q", charset) 26 | } 27 | } 28 | 29 | type metaImport struct { 30 | Prefix, VCS, RepoRoot string 31 | } 32 | 33 | // parseMetaGoImports returns meta imports from the HTML in r. 34 | // Parsing ends at the end of the
section or the beginning of the . 35 | func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { 36 | d := xml.NewDecoder(r) 37 | d.CharsetReader = charsetReader 38 | d.Strict = false 39 | var t xml.Token 40 | for { 41 | t, err = d.RawToken() 42 | if err != nil { 43 | if err == io.EOF || len(imports) > 0 { 44 | err = nil 45 | } 46 | return 47 | } 48 | if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { 49 | return 50 | } 51 | if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { 52 | return 53 | } 54 | e, ok := t.(xml.StartElement) 55 | if !ok || !strings.EqualFold(e.Name.Local, "meta") { 56 | continue 57 | } 58 | if attrValue(e.Attr, "name") != "go-import" { 59 | continue 60 | } 61 | if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { 62 | imports = append(imports, metaImport{ 63 | Prefix: f[0], 64 | VCS: f[1], 65 | RepoRoot: f[2], 66 | }) 67 | } 68 | } 69 | } 70 | 71 | // attrValue returns the attribute value for the case-insensitive key 72 | // `name', or the empty string if nothing is found. 73 | func attrValue(attrs []xml.Attr, name string) string { 74 | for _, a := range attrs { 75 | if strings.EqualFold(a.Name.Local, name) { 76 | return a.Value 77 | } 78 | } 79 | return "" 80 | } 81 | -------------------------------------------------------------------------------- /help.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "os" 9 | "strings" 10 | "text/template" 11 | "unicode" 12 | "unicode/utf8" 13 | ) 14 | 15 | var helpTemplate = `usage: gvt {{.UsageLine}} 16 | 17 | {{.Long | trim}} 18 | ` 19 | 20 | // help implements the 'help' command. 21 | func help(args []string) { 22 | if len(args) == 0 { 23 | printUsage(os.Stdout) 24 | return 25 | } 26 | if len(args) != 1 { 27 | fmt.Fprintf(os.Stderr, "usage: gvt help command\n\nToo many arguments given.\n") 28 | os.Exit(2) 29 | } 30 | 31 | arg := args[0] 32 | 33 | // 'gvt help documentation' generates alldocs.go. 34 | if arg == "documentation" { 35 | var u bytes.Buffer 36 | printUsage(&u) 37 | f, _ := os.Create("alldocs.go") 38 | tmpl(f, documentationTemplate, struct { 39 | Usage string 40 | Commands []*Command 41 | }{ 42 | u.String(), 43 | commands, 44 | }) 45 | f.Close() 46 | return 47 | } 48 | 49 | for _, cmd := range commands { 50 | if cmd.Name == arg { 51 | tmpl(os.Stdout, helpTemplate, cmd) 52 | return 53 | } 54 | } 55 | 56 | fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'gvt help'.\n", arg) 57 | os.Exit(2) 58 | } 59 | 60 | var usageTemplate = `gvt, a simple go vendoring tool based on gb-vendor. 61 | 62 | Usage: 63 | gvt command [arguments] 64 | 65 | The commands are: 66 | {{range .}} 67 | {{.Name | printf "%-11s"}} {{.Short}}{{end}} 68 | 69 | Use "gvt help [command]" for more information about a command. 70 | ` 71 | 72 | var documentationTemplate = `// DO NOT EDIT THIS FILE. 73 | //go:generate gvt help documentation 74 | 75 | /* 76 | {{ .Usage }} 77 | 78 | {{range .Commands}}{{if .Short}}{{.Short | capitalize}} 79 | {{end}} 80 | Usage: 81 | gvt {{.UsageLine}} 82 | 83 | {{.Long | trim}} 84 | 85 | {{end}}*/ 86 | package main 87 | ` 88 | 89 | // tmpl executes the given template text on data, writing the result to w. 90 | func tmpl(w io.Writer, text string, data interface{}) { 91 | t := template.New("top") 92 | t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) 93 | template.Must(t.Parse(text)) 94 | if err := t.Execute(w, data); err != nil { 95 | panic(err) 96 | } 97 | } 98 | 99 | func capitalize(s string) string { 100 | if s == "" { 101 | return s 102 | } 103 | r, n := utf8.DecodeRuneInString(s) 104 | return string(unicode.ToTitle(r)) + s[n:] 105 | } 106 | 107 | func printUsage(w io.Writer) { 108 | bw := bufio.NewWriter(w) 109 | tmpl(bw, usageTemplate, commands) 110 | bw.Flush() 111 | } 112 | -------------------------------------------------------------------------------- /gbvendor/manifest_test.go: -------------------------------------------------------------------------------- 1 | package vendor 2 | 3 | import ( 4 | "bytes" 5 | "os" 6 | "path/filepath" 7 | "testing" 8 | 9 | "github.com/FiloSottile/gvt/fileutils" 10 | ) 11 | 12 | func mktemp(t *testing.T) string { 13 | s, err := mktmp() 14 | if err != nil { 15 | t.Fatal(err) 16 | } 17 | return s 18 | } 19 | 20 | func assertNotExists(t *testing.T, path string) { 21 | _, err := os.Stat(path) 22 | if err == nil || !os.IsNotExist(err) { 23 | t.Fatalf("expected %q to be not found, got %v", path, err) 24 | } 25 | } 26 | 27 | func assertExists(t *testing.T, path string) { 28 | _, err := os.Stat(path) 29 | if err != nil { 30 | t.Fatalf("expected %q to be found, got %v", path, err) 31 | } 32 | } 33 | 34 | func TestManifest(t *testing.T) { 35 | root := mktemp(t) 36 | defer fileutils.RemoveAll(root) 37 | 38 | mf := filepath.Join(root, "vendor") 39 | 40 | // check that reading an nonexistent manifest 41 | // does not return an error 42 | m, err := ReadManifest(mf) 43 | if err != nil { 44 | t.Fatalf("reading a non existant manifest should not fail: %v", err) 45 | } 46 | 47 | // check that no manifest file was created 48 | assertNotExists(t, mf) 49 | 50 | // add a dep 51 | m.Dependencies = append(m.Dependencies, Dependency{ 52 | Importpath: "github.com/foo/bar/baz", 53 | Repository: "https://github.com/foo/bar", 54 | Revision: "cafebad", 55 | Branch: "master", 56 | Path: "/baz", 57 | }) 58 | 59 | // write it back 60 | if err := WriteManifest(mf, m); err != nil { 61 | t.Fatalf("WriteManifest failed: %v", err) 62 | } 63 | 64 | // check the manifest was written 65 | assertExists(t, mf) 66 | 67 | // remove it 68 | m.Dependencies = nil 69 | if err := WriteManifest(mf, m); err != nil { 70 | t.Fatalf("WriteManifest failed: %v", err) 71 | } 72 | 73 | // check that no manifest file was removed 74 | assertNotExists(t, mf) 75 | } 76 | 77 | func TestEmptyPathIsNotWritten(t *testing.T) { 78 | m := Manifest{ 79 | Version: 0, 80 | Dependencies: []Dependency{{ 81 | Importpath: "github.com/foo/bar", 82 | Repository: "https://github.com/foo/bar", 83 | VCS: "git", 84 | Revision: "abcdef", 85 | Branch: "master", 86 | }}, 87 | } 88 | var buf bytes.Buffer 89 | if err := writeManifest(&buf, &m); err != nil { 90 | t.Fatal(err) 91 | } 92 | want := `{ 93 | "version": 0, 94 | "dependencies": [ 95 | { 96 | "importpath": "github.com/foo/bar", 97 | "repository": "https://github.com/foo/bar", 98 | "vcs": "git", 99 | "revision": "abcdef", 100 | "branch": "master" 101 | } 102 | ] 103 | }` 104 | got := buf.String() 105 | if want != got { 106 | t.Fatalf("want: %s, got %s", want, got) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/mkstdlib.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // mkstdlib generates the zstdlib.go file, containing the Go standard 4 | // library API symbols. It's baked into the binary to avoid scanning 5 | // GOPATH in the common case. 6 | package main 7 | 8 | import ( 9 | "bufio" 10 | "bytes" 11 | "fmt" 12 | "go/format" 13 | "io" 14 | "io/ioutil" 15 | "log" 16 | "os" 17 | "path" 18 | "path/filepath" 19 | "regexp" 20 | "sort" 21 | "strings" 22 | ) 23 | 24 | func mustOpen(name string) io.Reader { 25 | f, err := os.Open(name) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | return f 30 | } 31 | 32 | func api(base string) string { 33 | return filepath.Join(os.Getenv("GOROOT"), "api", base) 34 | } 35 | 36 | var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`) 37 | 38 | func main() { 39 | var buf bytes.Buffer 40 | outf := func(format string, args ...interface{}) { 41 | fmt.Fprintf(&buf, format, args...) 42 | } 43 | outf("// AUTO-GENERATED BY mkstdlib.go\n\n") 44 | outf("package imports\n") 45 | outf("var stdlib = map[string]string{\n") 46 | f := io.MultiReader( 47 | mustOpen(api("go1.txt")), 48 | mustOpen(api("go1.1.txt")), 49 | mustOpen(api("go1.2.txt")), 50 | mustOpen(api("go1.3.txt")), 51 | mustOpen(api("go1.4.txt")), 52 | mustOpen(api("go1.5.txt")), 53 | mustOpen(api("go1.6.txt")), 54 | mustOpen(api("go1.7.txt")), 55 | ) 56 | sc := bufio.NewScanner(f) 57 | fullImport := map[string]string{} // "zip.NewReader" => "archive/zip" 58 | ambiguous := map[string]bool{} 59 | var keys []string 60 | for sc.Scan() { 61 | l := sc.Text() 62 | has := func(v string) bool { return strings.Contains(l, v) } 63 | if has("struct, ") || has("interface, ") || has(", method (") { 64 | continue 65 | } 66 | if m := sym.FindStringSubmatch(l); m != nil { 67 | full := m[1] 68 | key := path.Base(full) + "." + m[2] 69 | if exist, ok := fullImport[key]; ok { 70 | if exist != full { 71 | ambiguous[key] = true 72 | } 73 | } else { 74 | fullImport[key] = full 75 | keys = append(keys, key) 76 | } 77 | } 78 | } 79 | if err := sc.Err(); err != nil { 80 | log.Fatal(err) 81 | } 82 | sort.Strings(keys) 83 | for _, key := range keys { 84 | if ambiguous[key] { 85 | outf("\t// %q is ambiguous\n", key) 86 | } else { 87 | outf("\t%q: %q,\n", key, fullImport[key]) 88 | } 89 | } 90 | outf("\n") 91 | for _, sym := range [...]string{"Alignof", "ArbitraryType", "Offsetof", "Pointer", "Sizeof"} { 92 | outf("\t%q: %q,\n", "unsafe."+sym, "unsafe") 93 | } 94 | outf("}\n") 95 | fmtbuf, err := format.Source(buf.Bytes()) 96 | if err != nil { 97 | log.Fatal(err) 98 | } 99 | err = ioutil.WriteFile("zstdlib.go", fmtbuf, 0666) 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "go/build" 7 | "log" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | ) 12 | 13 | var fs = flag.NewFlagSet(os.Args[0], flag.ContinueOnError) 14 | 15 | func init() { 16 | fs.Usage = func() {} 17 | } 18 | 19 | type Command struct { 20 | Name string 21 | UsageLine string 22 | Short string 23 | Long string 24 | Run func(args []string) error 25 | AddFlags func(fs *flag.FlagSet) 26 | } 27 | 28 | var commands = []*Command{ 29 | cmdFetch, 30 | cmdRestore, 31 | cmdUpdate, 32 | cmdList, 33 | cmdDelete, 34 | } 35 | 36 | func main() { 37 | args := os.Args[1:] 38 | 39 | switch { 40 | case len(args) < 1, args[0] == "-h", args[0] == "-help": 41 | printUsage(os.Stdout) 42 | os.Exit(0) 43 | case args[0] == "help": 44 | help(args[1:]) 45 | return 46 | case args[0] == "rebuild": 47 | // rebuild was renamed restore, alias for backwards compatibility 48 | args[0] = "restore" 49 | } 50 | 51 | for _, command := range commands { 52 | if command.Name == args[0] { 53 | 54 | // add extra flags if necessary 55 | if command.AddFlags != nil { 56 | command.AddFlags(fs) 57 | } 58 | 59 | if err := fs.Parse(args[1:]); err != nil { 60 | if err == flag.ErrHelp { 61 | help(args[:1]) 62 | os.Exit(0) 63 | } 64 | fmt.Fprint(os.Stderr, "\n") 65 | help(args[:1]) 66 | os.Exit(3) 67 | } 68 | 69 | if err := command.Run(fs.Args()); err != nil { 70 | log.Fatalf("command %q failed: %v", command.Name, err) 71 | } 72 | if err := GlobalDownloader.Flush(); err != nil { 73 | log.Fatalf("failed to delete tempdirs: %v", err) 74 | } 75 | return 76 | } 77 | } 78 | fmt.Fprintf(os.Stderr, "unknown command: %q\n\n", args[0]) 79 | printUsage(os.Stderr) 80 | os.Exit(3) 81 | } 82 | 83 | var ( 84 | vendorDir, manifestFile string 85 | importPath string 86 | ) 87 | 88 | func init() { 89 | wd, err := os.Getwd() 90 | if err != nil { 91 | log.Fatal(err) 92 | } 93 | vendorDir = filepath.Join(wd, "vendor") 94 | manifestFile = filepath.Join(vendorDir, "manifest") 95 | var srcTree []string 96 | for _, p := range filepath.SplitList(build.Default.GOPATH) { 97 | srcTree = append(srcTree, filepath.Join(p, "src")+string(filepath.Separator)) 98 | } 99 | 100 | var pathMismatch int 101 | for _, p := range srcTree { 102 | if !strings.HasPrefix(wd, p) && wd != p[:len(p)-1] { 103 | pathMismatch++ 104 | continue 105 | } 106 | importPath = filepath.ToSlash(strings.TrimPrefix(wd, p)) 107 | break 108 | } 109 | if _, err := os.Stat(filepath.Join(wd, "Makefile")); os.IsNotExist(err) { 110 | if build.Default.GOPATH == "" || len(srcTree) == pathMismatch { 111 | log.Println("WARNING: for go vendoring to work your project needs to be somewhere under $GOPATH/src/") 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /downloader.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "strings" 5 | "sync" 6 | 7 | "github.com/FiloSottile/gvt/gbvendor" 8 | ) 9 | 10 | type cacheKey struct { 11 | url, repoType string 12 | branch, tag, revision string 13 | } 14 | 15 | type cacheEntry struct { 16 | wg sync.WaitGroup 17 | v vendor.WorkingCopy 18 | err error 19 | } 20 | 21 | // Downloader acts as a cache for downloaded repositories 22 | type Downloader struct { 23 | wcsMu sync.Mutex 24 | wcs map[cacheKey]*cacheEntry 25 | 26 | reposMu sync.RWMutex 27 | repos map[string]vendor.RemoteRepo 28 | reposI map[string]vendor.RemoteRepo 29 | } 30 | 31 | var GlobalDownloader = Downloader{} 32 | 33 | func init() { 34 | GlobalDownloader.wcs = make(map[cacheKey]*cacheEntry) 35 | GlobalDownloader.repos = make(map[string]vendor.RemoteRepo) 36 | GlobalDownloader.reposI = make(map[string]vendor.RemoteRepo) 37 | } 38 | 39 | // Get returns a cached WorkingCopy, or runs RemoteRepo.Checkout 40 | func (d *Downloader) Get(repo vendor.RemoteRepo, branch, tag, revision string) (vendor.WorkingCopy, error) { 41 | key := cacheKey{ 42 | url: repo.URL(), repoType: repo.Type(), 43 | branch: branch, tag: tag, revision: revision, 44 | } 45 | d.wcsMu.Lock() 46 | if entry, ok := d.wcs[key]; ok { 47 | d.wcsMu.Unlock() 48 | entry.wg.Wait() 49 | return entry.v, entry.err 50 | } 51 | 52 | entry := &cacheEntry{} 53 | entry.wg.Add(1) 54 | d.wcs[key] = entry 55 | d.wcsMu.Unlock() 56 | 57 | entry.v, entry.err = repo.Checkout(branch, tag, revision) 58 | entry.wg.Done() 59 | return entry.v, entry.err 60 | } 61 | 62 | func (d *Downloader) Flush() error { 63 | d.wcsMu.Lock() 64 | defer d.wcsMu.Unlock() 65 | 66 | for _, entry := range d.wcs { 67 | entry.wg.Wait() 68 | if entry.err != nil { 69 | continue 70 | } 71 | if err := entry.v.Destroy(); err != nil { 72 | return err 73 | } 74 | } 75 | return nil 76 | } 77 | 78 | // DeduceRemoteRepo is a cached version of vendor.DeduceRemoteRepo 79 | func (d *Downloader) DeduceRemoteRepo(path string, insecure bool) (vendor.RemoteRepo, string, error) { 80 | cache := d.repos 81 | if insecure { 82 | cache = d.reposI 83 | } 84 | 85 | d.reposMu.RLock() 86 | for p, repo := range cache { 87 | if path == p || strings.HasPrefix(path, p+"/") { 88 | d.reposMu.RUnlock() 89 | extra := strings.Trim(strings.TrimPrefix(path, p), "/") 90 | return repo, extra, nil 91 | } 92 | } 93 | d.reposMu.RUnlock() 94 | 95 | repo, extra, err := vendor.DeduceRemoteRepo(path, insecure) 96 | if err != nil { 97 | return repo, extra, err 98 | } 99 | 100 | if !strings.HasSuffix(path, extra) { 101 | // Shouldn't happen, but in case just bypass the cache 102 | return repo, extra, err 103 | } 104 | basePath := strings.Trim(strings.TrimSuffix(path, extra), "/") 105 | d.reposMu.Lock() 106 | cache[basePath] = repo 107 | d.reposMu.Unlock() 108 | 109 | return repo, extra, err 110 | } 111 | -------------------------------------------------------------------------------- /fileutils/path_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | package fileutils 5 | 6 | import ( 7 | "os" 8 | "runtime" 9 | "testing" 10 | ) 11 | 12 | var isReadonlyError = func(error) bool { return false } 13 | 14 | func TestRemoveAll(t *testing.T) { 15 | tmpDir := os.TempDir() 16 | // Work directory. 17 | path := tmpDir + "/_TestRemoveAll_" 18 | fpath := path + "/file" 19 | dpath := path + "/dir" 20 | 21 | // Make directory with 1 file and remove. 22 | if err := os.MkdirAll(path, 0777); err != nil { 23 | t.Fatalf("MkdirAll %q: %s", path, err) 24 | } 25 | fd, err := os.Create(fpath) 26 | if err != nil { 27 | t.Fatalf("create %q: %s", fpath, err) 28 | } 29 | fd.Close() 30 | if err = RemoveAll(path); err != nil { 31 | t.Fatalf("RemoveAll %q (first): %s", path, err) 32 | } 33 | if _, err = os.Lstat(path); err == nil { 34 | t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path) 35 | } 36 | 37 | // Make directory with file and subdirectory and remove. 38 | if err = os.MkdirAll(dpath, 0777); err != nil { 39 | t.Fatalf("MkdirAll %q: %s", dpath, err) 40 | } 41 | fd, err = os.Create(fpath) 42 | if err != nil { 43 | t.Fatalf("create %q: %s", fpath, err) 44 | } 45 | fd.Close() 46 | fd, err = os.Create(dpath + "/file") 47 | if err != nil { 48 | t.Fatalf("create %q: %s", fpath, err) 49 | } 50 | fd.Close() 51 | if err = RemoveAll(path); err != nil { 52 | t.Fatalf("RemoveAll %q (second): %s", path, err) 53 | } 54 | if _, err := os.Lstat(path); err == nil { 55 | t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path) 56 | } 57 | 58 | // Determine if we should run the following test. 59 | testit := true 60 | if runtime.GOOS == "windows" { 61 | // Chmod is not supported under windows. 62 | testit = false 63 | } else { 64 | // Test fails as root. 65 | testit = os.Getuid() != 0 66 | } 67 | if testit { 68 | // Make directory with file and subdirectory and trigger error. 69 | if err = os.MkdirAll(dpath, 0777); err != nil { 70 | t.Fatalf("MkdirAll %q: %s", dpath, err) 71 | } 72 | 73 | for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} { 74 | fd, err = os.Create(s) 75 | if err != nil { 76 | t.Fatalf("create %q: %s", s, err) 77 | } 78 | fd.Close() 79 | } 80 | if err = os.Chmod(dpath, 0); err != nil { 81 | t.Fatalf("Chmod %q 0: %s", dpath, err) 82 | } 83 | 84 | // No error checking here: either RemoveAll 85 | // will or won't be able to remove dpath; 86 | // either way we want to see if it removes fpath 87 | // and path/zzz. Reasons why RemoveAll might 88 | // succeed in removing dpath as well include: 89 | // * running as root 90 | // * running on a file system without permissions (FAT) 91 | RemoveAll(path) 92 | os.Chmod(dpath, 0777) 93 | 94 | for _, s := range []string{fpath, path + "/zzz"} { 95 | if _, err = os.Lstat(s); err == nil { 96 | t.Fatalf("Lstat %q succeeded after partial RemoveAll", s) 97 | } 98 | } 99 | } 100 | if err = RemoveAll(path); err != nil { 101 | t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err) 102 | } 103 | if _, err = os.Lstat(path); err == nil { 104 | t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/wadey/gocovmerge/gocovmerge.go: -------------------------------------------------------------------------------- 1 | // gocovmerge takes the results from multiple `go test -coverprofile` runs and 2 | // merges them into one profile 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "fmt" 8 | "io" 9 | "log" 10 | "os" 11 | "sort" 12 | 13 | "golang.org/x/tools/cover" 14 | ) 15 | 16 | func mergeProfiles(p *cover.Profile, merge *cover.Profile) { 17 | if p.Mode != merge.Mode { 18 | log.Fatalf("cannot merge profiles with different modes") 19 | } 20 | // Since the blocks are sorted, we can keep track of where the last block 21 | // was inserted and only look at the blocks after that as targets for merge 22 | startIndex := 0 23 | for _, b := range merge.Blocks { 24 | startIndex = mergeProfileBlock(p, b, startIndex) 25 | } 26 | } 27 | 28 | func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) int { 29 | sortFunc := func(i int) bool { 30 | pi := p.Blocks[i+startIndex] 31 | return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol) 32 | } 33 | 34 | i := 0 35 | if sortFunc(i) != true { 36 | i = sort.Search(len(p.Blocks)-startIndex, sortFunc) 37 | } 38 | i += startIndex 39 | if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol { 40 | if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol { 41 | log.Fatalf("OVERLAP MERGE: %v %v %v", p.FileName, p.Blocks[i], pb) 42 | } 43 | switch p.Mode { 44 | case "set": 45 | p.Blocks[i].Count |= pb.Count 46 | case "count", "atomic": 47 | p.Blocks[i].Count += pb.Count 48 | default: 49 | log.Fatalf("unsupported covermode: '%s'", p.Mode) 50 | } 51 | } else { 52 | if i > 0 { 53 | pa := p.Blocks[i-1] 54 | if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) { 55 | log.Fatalf("OVERLAP BEFORE: %v %v %v", p.FileName, pa, pb) 56 | } 57 | } 58 | if i < len(p.Blocks)-1 { 59 | pa := p.Blocks[i+1] 60 | if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) { 61 | log.Fatalf("OVERLAP AFTER: %v %v %v", p.FileName, pa, pb) 62 | } 63 | } 64 | p.Blocks = append(p.Blocks, cover.ProfileBlock{}) 65 | copy(p.Blocks[i+1:], p.Blocks[i:]) 66 | p.Blocks[i] = pb 67 | } 68 | return i + 1 69 | } 70 | 71 | func addProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile { 72 | i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName }) 73 | if i < len(profiles) && profiles[i].FileName == p.FileName { 74 | mergeProfiles(profiles[i], p) 75 | } else { 76 | profiles = append(profiles, nil) 77 | copy(profiles[i+1:], profiles[i:]) 78 | profiles[i] = p 79 | } 80 | return profiles 81 | } 82 | 83 | func dumpProfiles(profiles []*cover.Profile, out io.Writer) { 84 | if len(profiles) == 0 { 85 | return 86 | } 87 | fmt.Fprintf(out, "mode: %s\n", profiles[0].Mode) 88 | for _, p := range profiles { 89 | for _, b := range p.Blocks { 90 | fmt.Fprintf(out, "%s:%d.%d,%d.%d %d %d\n", p.FileName, b.StartLine, b.StartCol, b.EndLine, b.EndCol, b.NumStmt, b.Count) 91 | } 92 | } 93 | } 94 | 95 | func main() { 96 | flag.Parse() 97 | 98 | var merged []*cover.Profile 99 | 100 | for _, file := range flag.Args() { 101 | profiles, err := cover.ParseProfiles(file) 102 | if err != nil { 103 | log.Fatalf("failed to parse profiles: %v", err) 104 | } 105 | for _, p := range profiles { 106 | merged = addProfile(merged, p) 107 | } 108 | } 109 | 110 | dumpProfiles(merged, os.Stdout) 111 | } 112 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IMPORT_PATH := github.com/FiloSottile/gvt 2 | V := 1 # When V is 1, print commands and build progress. 3 | IGNORED_PACKAGES := /vendor/ 4 | 5 | .PHONY: gvt 6 | gvt: .GOPATH/.ok 7 | $Q go install $(if $V,-v) $(VERSION_FLAGS) github.com/FiloSottile/gvt 8 | 9 | ##### =====> Utility targets <===== ##### 10 | 11 | .PHONY: clean test list cover format 12 | 13 | clean: 14 | $Q rm -rf bin .GOPATH 15 | 16 | test: .GOPATH/.ok 17 | $Q go test $(if $V,-v) -i -race $(allpackages) # install -race libs to speed up next run 18 | ifndef CI 19 | $Q go vet $(allpackages) 20 | $Q GODEBUG=cgocheck=2 go test -race $(allpackages) 21 | else 22 | $Q ( go vet $(allpackages); echo $$? ) | \ 23 | tee .GOPATH/test/vet.txt | sed '$$ d'; exit $$(tail -1 .GOPATH/test/vet.txt) 24 | $Q ( GODEBUG=cgocheck=2 go test -v -race $(allpackages); echo $$? ) | \ 25 | tee .GOPATH/test/output.txt | sed '$$ d'; exit $$(tail -1 .GOPATH/test/output.txt) 26 | endif 27 | 28 | list: .GOPATH/.ok 29 | @echo $(allpackages) 30 | 31 | cover: bin/gocovmerge .GOPATH/.ok 32 | $Q rm -f .GOPATH/cover/*.out .GOPATH/cover/all.merged 33 | $(if $V,@echo "-- go test -coverpkg=./... -coverprofile=.GOPATH/cover/... ./...") 34 | $Q for MOD in $(allpackages); do \ 35 | go test -coverpkg=`echo $(allpackages)|tr " " ","` \ 36 | -coverprofile=.GOPATH/cover/unit-`echo $$MOD|tr "/" "_"`.out \ 37 | $$MOD 2>&1 | grep -v "no packages being tested depend on" || exit 1; \ 38 | done 39 | $Q ./bin/gocovmerge .GOPATH/cover/*.out > .GOPATH/cover/all.merged 40 | ifndef CI 41 | $Q go tool cover -html .GOPATH/cover/all.merged 42 | else 43 | $Q go tool cover -html .GOPATH/cover/all.merged -o .GOPATH/cover/all.html 44 | endif 45 | @echo "" 46 | @echo "=====> Total test coverage: <=====" 47 | @echo "" 48 | $Q go tool cover -func .GOPATH/cover/all.merged 49 | 50 | format: bin/goimports .GOPATH/.ok 51 | $Q find .GOPATH/src/$(IMPORT_PATH)/ -iname \*.go | grep -v -e "^$$" $(addprefix -e ,$(IGNORED_PACKAGES)) | xargs ./bin/goimports -w 52 | 53 | ##### =====> Internals <===== ##### 54 | 55 | .PHONY: setup 56 | setup: 57 | @if grep "/.GOPATH" .gitignore > /dev/null 2>&1; then \ 58 | echo "This project seems already set up."; exit 1; fi 59 | @if ! which gvt > /dev/null; then echo "You need gvt to run the automated setup."; \ 60 | echo "Install it with: go get -u github.com/FiloSottile/gvt"; exit 1; fi 61 | gvt fetch golang.org/x/tools/cmd/goimports 62 | gvt fetch github.com/wadey/gocovmerge 63 | echo "/.GOPATH" >> .gitignore 64 | echo "/bin" >> .gitignore 65 | 66 | VERSION := $(shell git describe --tags --always --dirty="-dev") 67 | DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC') 68 | VERSION_FLAGS := -ldflags='-X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"' 69 | 70 | # cd into the GOPATH to workaround ./... not following symlinks 71 | _allpackages = $(shell ( cd $(CURDIR)/.GOPATH/src/$(IMPORT_PATH) && \ 72 | GOPATH=$(CURDIR)/.GOPATH go list ./... 2>&1 1>&3 | \ 73 | grep -v -e "^$$" $(addprefix -e ,$(IGNORED_PACKAGES)) 1>&2 ) 3>&1 | \ 74 | grep -v -e "^$$" $(addprefix -e ,$(IGNORED_PACKAGES))) 75 | 76 | # memoize allpackages, so that it's executed only once and only if used 77 | allpackages = $(if $(__allpackages),,$(eval __allpackages := $$(_allpackages)))$(__allpackages) 78 | 79 | export GOPATH := $(CURDIR)/.GOPATH 80 | 81 | Q := $(if $V,,@) 82 | 83 | .GOPATH/.ok: 84 | $Q mkdir -p "$(dir .GOPATH/src/$(IMPORT_PATH))" 85 | $Q ln -s ../../../.. ".GOPATH/src/$(IMPORT_PATH)" 86 | $Q mkdir -p .GOPATH/test .GOPATH/cover 87 | $Q mkdir -p bin 88 | $Q ln -s ../bin .GOPATH/bin 89 | $Q touch $@ 90 | 91 | .PHONY: bin/gocovmerge bin/goimports 92 | bin/gocovmerge: .GOPATH/.ok 93 | $Q go install $(IMPORT_PATH)/vendor/github.com/wadey/gocovmerge 94 | bin/goimports: .GOPATH/.ok 95 | $Q go install $(IMPORT_PATH)/vendor/golang.org/x/tools/cmd/goimports 96 | -------------------------------------------------------------------------------- /alldocs.go: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT THIS FILE. 2 | //go:generate gvt help documentation 3 | 4 | /* 5 | gvt, a simple go vendoring tool based on gb-vendor. 6 | 7 | Usage: 8 | gvt command [arguments] 9 | 10 | The commands are: 11 | 12 | fetch fetch a remote dependency 13 | restore restore dependencies from manifest 14 | update update a local dependency 15 | list list dependencies one per line 16 | delete delete a local dependency 17 | 18 | Use "gvt help [command]" for more information about a command. 19 | 20 | 21 | Fetch a remote dependency 22 | 23 | Usage: 24 | gvt fetch [-branch branch] [-revision rev | -tag tag] [-precaire] [-no-recurse] [-t|-a] importpath 25 | 26 | fetch vendors an upstream import path. 27 | 28 | Recursive dependencies are fetched (at their master/tip/HEAD revision), unless they 29 | or their parent package are already present. 30 | 31 | If a subpackage of a dependency being fetched is already present, it will be deleted. 32 | 33 | The import path may include a url scheme. This may be useful when fetching dependencies 34 | from private repositories that cannot be probed. 35 | 36 | Flags: 37 | -t 38 | fetch also _test.go files and testdata. 39 | -a 40 | fetch all files and subfolders, ignoring ONLY .git, .hg and .bzr. 41 | -branch branch 42 | fetch from the named branch. Will also be used by gvt update. 43 | If not supplied the default upstream branch will be used. 44 | -no-recurse 45 | do not fetch recursively. 46 | -tag tag 47 | fetch the specified tag. 48 | -revision rev 49 | fetch the specific revision from the branch or repository. 50 | If no revision supplied, the latest available will be fetched. 51 | -precaire 52 | allow the use of insecure protocols. 53 | 54 | Restore dependencies from manifest 55 | 56 | Usage: 57 | gvt restore [-precaire] [-connections N] 58 | 59 | restore fetches the dependencies listed in the manifest. 60 | 61 | It's meant for workflows that don't include checking in to VCS the vendored 62 | source, for example if .gitignore includes lines like 63 | 64 | vendor/** 65 | !vendor/manifest 66 | 67 | Note that such a setup requires "gvt restore" to build the source, relies on 68 | the availability of the dependencies repositories and breaks "go get". 69 | 70 | Flags: 71 | -precaire 72 | allow the use of insecure protocols. 73 | -connections 74 | count of parallel download connections. 75 | 76 | Update a local dependency 77 | 78 | Usage: 79 | gvt update [ -all | importpath ] 80 | 81 | update replaces the source with the latest available from the head of the fetched branch. 82 | 83 | Updating from one copy of a dependency to another is ONLY possible when the 84 | dependency was fetched by branch, without using -tag or -revision. It will be 85 | updated to the HEAD of that branch, switching branches is not supported. 86 | 87 | To update across branches, or from one tag/revision to another, you must first 88 | use delete to remove the dependency, then fetch [ -tag | -revision | -branch ] 89 | to replace it. 90 | 91 | Flags: 92 | -all 93 | update all dependencies in the manifest. 94 | -precaire 95 | allow the use of insecure protocols. 96 | 97 | List dependencies one per line 98 | 99 | Usage: 100 | gvt list [-f format] 101 | 102 | list formats the contents of the manifest file. 103 | 104 | Flags: 105 | -f 106 | controls the template used for printing each manifest entry. If not supplied 107 | the default value is "{{.Importpath}}\t{{.Repository}}{{.Path}}\t{{.Branch}}\t{{.Revision}}" 108 | 109 | Delete a local dependency 110 | 111 | Usage: 112 | gvt delete [-all] importpath 113 | 114 | delete removes a dependency from the vendor directory and the manifest 115 | 116 | Flags: 117 | -all 118 | remove all dependencies 119 | 120 | */ 121 | package main 122 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/fastwalk_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build linux,!appengine darwin freebsd openbsd netbsd 6 | 7 | package imports 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "os" 13 | "syscall" 14 | "unsafe" 15 | ) 16 | 17 | const blockSize = 8 << 10 18 | 19 | // unknownFileMode is a sentinel (and bogus) os.FileMode 20 | // value used to represent a syscall.DT_UNKNOWN Dirent.Type. 21 | const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice 22 | 23 | func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { 24 | fd, err := syscall.Open(dirName, 0, 0) 25 | if err != nil { 26 | return err 27 | } 28 | defer syscall.Close(fd) 29 | 30 | // The buffer must be at least a block long. 31 | buf := make([]byte, blockSize) // stack-allocated; doesn't escape 32 | bufp := 0 // starting read position in buf 33 | nbuf := 0 // end valid data in buf 34 | for { 35 | if bufp >= nbuf { 36 | bufp = 0 37 | nbuf, err = syscall.ReadDirent(fd, buf) 38 | if err != nil { 39 | return os.NewSyscallError("readdirent", err) 40 | } 41 | if nbuf <= 0 { 42 | return nil 43 | } 44 | } 45 | consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) 46 | bufp += consumed 47 | if name == "" || name == "." || name == ".." { 48 | continue 49 | } 50 | // Fallback for filesystems (like old XFS) that don't 51 | // support Dirent.Type and have DT_UNKNOWN (0) there 52 | // instead. 53 | if typ == unknownFileMode { 54 | fi, err := os.Lstat(dirName + "/" + name) 55 | if err != nil { 56 | // It got deleted in the meantime. 57 | if os.IsNotExist(err) { 58 | continue 59 | } 60 | return err 61 | } 62 | typ = fi.Mode() & os.ModeType 63 | } 64 | if err := fn(dirName, name, typ); err != nil { 65 | return err 66 | } 67 | } 68 | } 69 | 70 | func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { 71 | // golang.org/issue/15653 72 | dirent := (*syscall.Dirent)(unsafe.Pointer(&buf[0])) 73 | if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { 74 | panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) 75 | } 76 | if len(buf) < int(dirent.Reclen) { 77 | panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) 78 | } 79 | consumed = int(dirent.Reclen) 80 | if direntInode(dirent) == 0 { // File absent in directory. 81 | return 82 | } 83 | switch dirent.Type { 84 | case syscall.DT_REG: 85 | typ = 0 86 | case syscall.DT_DIR: 87 | typ = os.ModeDir 88 | case syscall.DT_LNK: 89 | typ = os.ModeSymlink 90 | case syscall.DT_BLK: 91 | typ = os.ModeDevice 92 | case syscall.DT_FIFO: 93 | typ = os.ModeNamedPipe 94 | case syscall.DT_SOCK: 95 | typ = os.ModeSocket 96 | case syscall.DT_UNKNOWN: 97 | typ = unknownFileMode 98 | default: 99 | // Skip weird things. 100 | // It's probably a DT_WHT (http://lwn.net/Articles/325369/) 101 | // or something. Revisit if/when this package is moved outside 102 | // of goimports. goimports only cares about regular files, 103 | // symlinks, and directories. 104 | return 105 | } 106 | 107 | nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) 108 | nameLen := bytes.IndexByte(nameBuf[:], 0) 109 | if nameLen < 0 { 110 | panic("failed to find terminating 0 byte in dirent") 111 | } 112 | 113 | // Special cases for common things: 114 | if nameLen == 1 && nameBuf[0] == '.' { 115 | name = "." 116 | } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { 117 | name = ".." 118 | } else { 119 | name = string(nameBuf[:nameLen]) 120 | } 121 | return 122 | } 123 | -------------------------------------------------------------------------------- /gbvendor/repo_test.go: -------------------------------------------------------------------------------- 1 | package vendor 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestDeduceRemoteRepo(t *testing.T) { 10 | if testing.Short() { 11 | t.Skipf("skipping network tests in -short mode") 12 | } 13 | tests := []struct { 14 | path string 15 | want RemoteRepo 16 | extra string 17 | err error 18 | insecure bool 19 | }{{ 20 | path: "", 21 | err: fmt.Errorf(`"" is not a valid import path`), 22 | }, { 23 | path: "corporate", 24 | err: fmt.Errorf(`"corporate" is not a valid import path`), 25 | }, { 26 | path: "github.com/cznic/b", 27 | want: &gitrepo{ 28 | url: "https://github.com/cznic/b", 29 | }, 30 | }, { 31 | path: "github.com/pkg/sftp", 32 | want: &gitrepo{ 33 | url: "https://github.com/pkg/sftp", 34 | }, 35 | }, { 36 | path: "github.com/pkg/sftp/examples/gsftp", 37 | want: &gitrepo{ 38 | url: "https://github.com/pkg/sftp", 39 | }, 40 | extra: "/examples/gsftp", 41 | }, { 42 | path: "github.com/coreos/go-etcd", 43 | want: &gitrepo{ 44 | url: "https://github.com/coreos/go-etcd", 45 | }, 46 | /* 47 | bitbucket cannot maintain a stable ssh key across their app servers 48 | and this mucks up ci testing because mercurial does not have any 49 | way of unconditionally accepting new ssh keys for the host. 50 | Great work TEAM. 51 | }, { 52 | path: "bitbucket.org/davecheney/gitrepo/cmd/main", 53 | want: &gitrepo{ 54 | url: "https://bitbucket.org/davecheney/gitrepo", 55 | }, 56 | extra: "/cmd/main", 57 | }, { 58 | path: "bitbucket.org/davecheney/hgrepo/cmd/main", 59 | want: &hgrepo{ 60 | url: "https://bitbucket.org/davecheney/hgrepo", 61 | }, 62 | extra: "/cmd/main", 63 | */ 64 | }, { 65 | path: "git.eclipse.org/gitroot/epf/org.eclipse.epf.docs.git", 66 | want: &gitrepo{ 67 | url: "https://git.eclipse.org/gitroot/epf/org.eclipse.epf.docs.git", 68 | }, 69 | }, { 70 | path: "git.apache.org/thrift.git/lib/go/thrift", 71 | want: &gitrepo{ 72 | url: "https://git.apache.org/thrift.git", 73 | }, 74 | extra: "/lib/go/thrift", 75 | }, { 76 | path: "gopkg.in/check.v1", 77 | want: &gitrepo{ 78 | url: "https://gopkg.in/check.v1", 79 | }, 80 | extra: "", 81 | }, { 82 | path: "goji.io", 83 | want: &gitrepo{ 84 | url: "https://github.com/goji/goji", 85 | }, 86 | extra: "", 87 | }, { 88 | path: "golang.org/x/tools/go/vcs", 89 | want: &gitrepo{ 90 | url: "https://go.googlesource.com/tools", 91 | }, 92 | extra: "/go/vcs", 93 | }, { 94 | path: "labix.org/v2/mgo", 95 | want: &bzrrepo{ 96 | url: "https://launchpad.net/mgo/v2", 97 | }, 98 | insecure: true, 99 | }, { 100 | path: "launchpad.net/gnuflag", 101 | want: &bzrrepo{ 102 | url: "https://launchpad.net/gnuflag", 103 | }, 104 | }, { 105 | path: "https://github.com/pkg/sftp", 106 | want: &gitrepo{ 107 | url: "https://github.com/pkg/sftp", 108 | }, 109 | }, { 110 | path: "git://github.com/pkg/sftp", 111 | want: &gitrepo{ 112 | url: "git://github.com/pkg/sftp", 113 | }, 114 | insecure: true, 115 | }} 116 | 117 | for _, tt := range tests { 118 | t.Run(fmt.Sprintf("DeduceRemoteRepo(%q, %v)", tt.path, tt.insecure), func(t *testing.T) { 119 | got, extra, err := DeduceRemoteRepo(tt.path, tt.insecure) 120 | if !reflect.DeepEqual(err, tt.err) { 121 | t.Fatalf("DeduceRemoteRepo(%q): want err: %v, got err: %v", tt.path, tt.err, err) 122 | } 123 | if !reflect.DeepEqual(got, tt.want) || extra != tt.extra { 124 | t.Errorf("DeduceRemoteRepo(%q): want %#v, %v, got %#v, %v", tt.path, tt.want, tt.extra, got, extra) 125 | } 126 | 127 | if tt.want != nil { 128 | got, err := NewRemoteRepo(tt.want.URL(), tt.want.Type(), tt.insecure) 129 | if err != nil { 130 | t.Fatal(err) 131 | } 132 | if !reflect.DeepEqual(got, tt.want) { 133 | t.Errorf("NewRemoteRepo(%s, %s): want %#v, got %#v", tt.want.URL(), tt.want.Type(), tt.want, got) 134 | } 135 | } 136 | }) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /update.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "path/filepath" 7 | 8 | "github.com/FiloSottile/gvt/fileutils" 9 | "github.com/FiloSottile/gvt/gbvendor" 10 | ) 11 | 12 | var ( 13 | updateAll bool // update all dependencies 14 | ) 15 | 16 | func addUpdateFlags(fs *flag.FlagSet) { 17 | fs.BoolVar(&updateAll, "all", false, "update all dependencies") 18 | fs.BoolVar(&insecure, "precaire", false, "allow the use of insecure protocols") 19 | } 20 | 21 | var cmdUpdate = &Command{ 22 | Name: "update", 23 | UsageLine: "update [ -all | importpath ]", 24 | Short: "update a local dependency", 25 | Long: `update replaces the source with the latest available from the head of the fetched branch. 26 | 27 | Updating from one copy of a dependency to another is ONLY possible when the 28 | dependency was fetched by branch, without using -tag or -revision. It will be 29 | updated to the HEAD of that branch, switching branches is not supported. 30 | 31 | To update across branches, or from one tag/revision to another, you must first 32 | use delete to remove the dependency, then fetch [ -tag | -revision | -branch ] 33 | to replace it. 34 | 35 | Flags: 36 | -all 37 | update all dependencies in the manifest. 38 | -precaire 39 | allow the use of insecure protocols. 40 | 41 | `, 42 | Run: func(args []string) error { 43 | if len(args) != 1 && !updateAll { 44 | return fmt.Errorf("update: import path or -all flag is missing") 45 | } else if len(args) == 1 && updateAll { 46 | return fmt.Errorf("update: you cannot specify path and -all flag at once") 47 | } 48 | 49 | m, err := vendor.ReadManifest(manifestFile) 50 | if err != nil { 51 | return fmt.Errorf("could not load manifest: %v", err) 52 | } 53 | 54 | var dependencies []vendor.Dependency 55 | if updateAll { 56 | dependencies = make([]vendor.Dependency, len(m.Dependencies)) 57 | copy(dependencies, m.Dependencies) 58 | } else { 59 | p := args[0] 60 | dependency, err := m.GetDependencyForImportpath(p) 61 | if err != nil { 62 | return fmt.Errorf("could not get dependency: %v", err) 63 | } 64 | dependencies = append(dependencies, dependency) 65 | } 66 | 67 | for _, d := range dependencies { 68 | err = m.RemoveDependency(d) 69 | if err != nil { 70 | return fmt.Errorf("dependency could not be deleted from manifest: %v", err) 71 | } 72 | 73 | repo, err := vendor.NewRemoteRepo(d.Repository, d.VCS, insecure) 74 | if err != nil { 75 | return fmt.Errorf("could not determine repository for import %q", d.Importpath) 76 | } 77 | 78 | wc, err := GlobalDownloader.Get(repo, d.Branch, "", "") 79 | if err != nil { 80 | return err 81 | } 82 | 83 | rev, err := wc.Revision() 84 | if err != nil { 85 | return err 86 | } 87 | 88 | branch, err := wc.Branch() 89 | if err != nil { 90 | return err 91 | } 92 | 93 | dep := vendor.Dependency{ 94 | Importpath: d.Importpath, 95 | Repository: repo.URL(), 96 | VCS: repo.Type(), 97 | Revision: rev, 98 | Branch: branch, 99 | Path: d.Path, 100 | NoTests: d.NoTests, 101 | AllFiles: d.AllFiles, 102 | } 103 | 104 | if err := fileutils.RemoveAll(filepath.Join(vendorDir, filepath.FromSlash(d.Importpath))); err != nil { 105 | // TODO(dfc) need to apply vendor.cleanpath here to remove intermediate directories. 106 | return fmt.Errorf("dependency could not be deleted: %v", err) 107 | } 108 | 109 | dst := filepath.Join(vendorDir, filepath.FromSlash(dep.Importpath)) 110 | src := filepath.Join(wc.Dir(), dep.Path) 111 | 112 | if err := fileutils.Copypath(dst, src, !d.NoTests, d.AllFiles); err != nil { 113 | return err 114 | } 115 | 116 | if err := fileutils.CopyLicense(dst, wc.Dir()); err != nil { 117 | return err 118 | } 119 | 120 | if err := m.AddDependency(dep); err != nil { 121 | return err 122 | } 123 | 124 | if err := vendor.WriteManifest(manifestFile, m); err != nil { 125 | return err 126 | } 127 | } 128 | 129 | return nil 130 | }, 131 | AddFlags: addUpdateFlags, 132 | } 133 | -------------------------------------------------------------------------------- /gbvendor/imports_test.go: -------------------------------------------------------------------------------- 1 | package vendor 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "reflect" 8 | "testing" 9 | ) 10 | 11 | func TestFetchMetadata(t *testing.T) { 12 | if testing.Short() { 13 | t.Skipf("skipping network tests in -short mode") 14 | } 15 | type testParams struct { 16 | path string 17 | want string 18 | insecure bool 19 | } 20 | tests := []testParams{{ 21 | path: "golang.org/x/tools/cmd/godoc", 22 | want: ` 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | Nothing to see here; move along. 32 | 33 | 34 | `, 35 | }, { 36 | path: "gopkg.in/check.v1", 37 | want: ` 38 | 39 | 40 | 41 | 42 | 43 | 44 | go get gopkg.in/check.v1 45 | 46 | 47 | `, 48 | }} 49 | 50 | for _, tt := range tests { 51 | r, err := FetchMetadata(tt.path, tt.insecure) 52 | if err != nil { 53 | t.Error(err) 54 | continue 55 | } 56 | var buf bytes.Buffer 57 | if _, err := io.Copy(&buf, r); err != nil { 58 | t.Error(err) 59 | r.Close() 60 | continue 61 | } 62 | r.Close() 63 | got := buf.String() 64 | if got != tt.want { 65 | t.Errorf("FetchMetadata(%q): want %q, got %q", tt.path, tt.want, got) 66 | } 67 | } 68 | 69 | // Test for error catch. 70 | errTests := []testParams{{ 71 | path: "any.inaccessible.server/the.project", 72 | want: `unable to determine remote metadata protocol: failed to access url "http://any.inaccessible.server/the.project?go-get=1"`, 73 | insecure: true, 74 | }, { 75 | path: "any.inaccessible.server/the.project", 76 | want: `unable to determine remote metadata protocol: failed to access url "https://any.inaccessible.server/the.project?go-get=1"`, 77 | insecure: false, 78 | }} 79 | 80 | for _, ett := range errTests { 81 | r, err := FetchMetadata(ett.path, ett.insecure) 82 | if err == nil { 83 | t.Errorf("Access to url %q without any error, but the error should be happen.", ett.path) 84 | if r != nil { 85 | r.Close() 86 | } 87 | continue 88 | } 89 | got := err.Error() 90 | if got != ett.want { 91 | t.Errorf("FetchMetadata(%q): want %q, got %q", ett.path, ett.want, got) 92 | } 93 | } 94 | } 95 | 96 | func TestParseMetadata(t *testing.T) { 97 | if testing.Short() { 98 | t.Skipf("skipping network tests in -short mode") 99 | } 100 | tests := []struct { 101 | path string 102 | importpath string 103 | vcs string 104 | reporoot string 105 | insecure bool 106 | err error 107 | }{{ 108 | path: "golang.org/x/tools/cmd/godoc", 109 | importpath: "golang.org/x/tools", 110 | vcs: "git", 111 | reporoot: "https://go.googlesource.com/tools", 112 | }, { 113 | path: "gopkg.in/check.v1", 114 | importpath: "gopkg.in/check.v1", 115 | vcs: "git", 116 | reporoot: "https://gopkg.in/check.v1", 117 | }, { 118 | path: "gopkg.in/mgo.v2/bson", 119 | importpath: "gopkg.in/mgo.v2", 120 | vcs: "git", 121 | reporoot: "https://gopkg.in/mgo.v2", 122 | }, { 123 | path: "speter.net/go/exp", 124 | err: fmt.Errorf("go-import metadata not found"), 125 | }} 126 | 127 | for _, tt := range tests { 128 | importpath, vcs, reporoot, err := ParseMetadata(tt.path, tt.insecure) 129 | if !reflect.DeepEqual(err, tt.err) { 130 | t.Error(err) 131 | continue 132 | } 133 | if importpath != tt.importpath || vcs != tt.vcs || reporoot != tt.reporoot { 134 | t.Errorf("ParseMetadata(%q): want %s %s %s, got %s %s %s ", tt.path, tt.importpath, tt.vcs, tt.reporoot, importpath, vcs, reporoot) 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /restore.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "sync" 10 | "sync/atomic" 11 | 12 | "github.com/FiloSottile/gvt/fileutils" 13 | "github.com/FiloSottile/gvt/gbvendor" 14 | ) 15 | 16 | var ( 17 | rbInsecure bool // Allow the use of insecure protocols 18 | rbConnections uint // Count of concurrent download connections 19 | ) 20 | 21 | func addRestoreFlags(fs *flag.FlagSet) { 22 | fs.BoolVar(&rbInsecure, "precaire", false, "allow the use of insecure protocols") 23 | fs.UintVar(&rbConnections, "connections", 8, "count of parallel download connections") 24 | } 25 | 26 | var cmdRestore = &Command{ 27 | Name: "restore", 28 | UsageLine: "restore [-precaire] [-connections N]", 29 | Short: "restore dependencies from manifest", 30 | Long: `restore fetches the dependencies listed in the manifest. 31 | 32 | It's meant for workflows that don't include checking in to VCS the vendored 33 | source, for example if .gitignore includes lines like 34 | 35 | vendor/** 36 | !vendor/manifest 37 | 38 | Note that such a setup requires "gvt restore" to build the source, relies on 39 | the availability of the dependencies repositories and breaks "go get". 40 | 41 | Flags: 42 | -precaire 43 | allow the use of insecure protocols. 44 | -connections 45 | count of parallel download connections. 46 | `, 47 | Run: func(args []string) error { 48 | switch len(args) { 49 | case 0: 50 | return restore(manifestFile) 51 | default: 52 | return fmt.Errorf("restore takes no arguments") 53 | } 54 | }, 55 | AddFlags: addRestoreFlags, 56 | } 57 | 58 | func restore(manFile string) error { 59 | m, err := vendor.ReadManifest(manFile) 60 | if err != nil { 61 | return fmt.Errorf("could not load manifest: %v", err) 62 | } 63 | 64 | var errors uint32 65 | var wg sync.WaitGroup 66 | depC := make(chan vendor.Dependency) 67 | for i := 0; i < int(rbConnections); i++ { 68 | wg.Add(1) 69 | go func() { 70 | defer wg.Done() 71 | for d := range depC { 72 | if err := downloadDependency(d, &errors, vendorDir, false); err != nil { 73 | log.Printf("%s: %v", d.Importpath, err) 74 | atomic.AddUint32(&errors, 1) 75 | } 76 | } 77 | }() 78 | } 79 | 80 | for _, dep := range m.Dependencies { 81 | depC <- dep 82 | } 83 | close(depC) 84 | wg.Wait() 85 | 86 | if errors > 0 { 87 | return fmt.Errorf("failed to fetch %d dependencies", errors) 88 | } 89 | 90 | return nil 91 | } 92 | 93 | func downloadDependency(dep vendor.Dependency, errors *uint32, vendorDir string, recursive bool) error { 94 | extraMsg := "" 95 | if !dep.NoTests { 96 | extraMsg = "(including tests)" 97 | } 98 | if dep.AllFiles { 99 | extraMsg = "(without file exclusions)" 100 | } 101 | if recursive { 102 | log.Printf("fetching recursive %s %s", dep.Importpath, extraMsg) 103 | } else { 104 | log.Printf("fetching %s %s", dep.Importpath, extraMsg) 105 | } 106 | 107 | repo, err := vendor.NewRemoteRepo(dep.Repository, dep.VCS, rbInsecure) 108 | if err != nil { 109 | return fmt.Errorf("dependency could not be processed: %s", err) 110 | } 111 | // We can't pass the branch here, and benefit from narrow clones, as the 112 | // revision might not be in the branch tree anymore. Thanks rebase. 113 | wc, err := GlobalDownloader.Get(repo, "", "", dep.Revision) 114 | if err != nil { 115 | return fmt.Errorf("dependency could not be fetched: %s", err) 116 | } 117 | dst := filepath.Join(vendorDir, dep.Importpath) 118 | src := filepath.Join(wc.Dir(), dep.Path) 119 | 120 | if _, err := os.Stat(dst); err == nil { 121 | if err := fileutils.RemoveAll(dst); err != nil { 122 | return fmt.Errorf("dependency could not be deleted: %v", err) 123 | } 124 | } 125 | 126 | if err := fileutils.Copypath(dst, src, !dep.NoTests, dep.AllFiles); err != nil { 127 | return err 128 | } 129 | 130 | if err := fileutils.CopyLicense(dst, wc.Dir()); err != nil { 131 | return err 132 | } 133 | 134 | // Check for for manifests in dependencies 135 | man := filepath.Join(dst, "vendor", "manifest") 136 | venDir := filepath.Join(dst, "vendor") 137 | if _, err := os.Stat(man); err == nil { 138 | m, err := vendor.ReadManifest(man) 139 | if err != nil { 140 | return fmt.Errorf("could not load manifest: %v", err) 141 | } 142 | for _, d := range m.Dependencies { 143 | if err := downloadDependency(d, errors, venDir, true); err != nil { 144 | log.Printf("%s: %v", d.Importpath, err) 145 | atomic.AddUint32(errors, 1) 146 | } 147 | } 148 | } 149 | 150 | return nil 151 | } 152 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/mkindex.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Copyright 2013 The Go Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style 5 | // license that can be found in the LICENSE file. 6 | 7 | // Command mkindex creates the file "pkgindex.go" containing an index of the Go 8 | // standard library. The file is intended to be built as part of the imports 9 | // package, so that the package may be used in environments where a GOROOT is 10 | // not available (such as App Engine). 11 | package main 12 | 13 | import ( 14 | "bytes" 15 | "fmt" 16 | "go/ast" 17 | "go/build" 18 | "go/format" 19 | "go/parser" 20 | "go/token" 21 | "io/ioutil" 22 | "log" 23 | "os" 24 | "path" 25 | "path/filepath" 26 | "strings" 27 | ) 28 | 29 | var ( 30 | pkgIndex = make(map[string][]pkg) 31 | exports = make(map[string]map[string]bool) 32 | ) 33 | 34 | func main() { 35 | // Don't use GOPATH. 36 | ctx := build.Default 37 | ctx.GOPATH = "" 38 | 39 | // Populate pkgIndex global from GOROOT. 40 | for _, path := range ctx.SrcDirs() { 41 | f, err := os.Open(path) 42 | if err != nil { 43 | log.Print(err) 44 | continue 45 | } 46 | children, err := f.Readdir(-1) 47 | f.Close() 48 | if err != nil { 49 | log.Print(err) 50 | continue 51 | } 52 | for _, child := range children { 53 | if child.IsDir() { 54 | loadPkg(path, child.Name()) 55 | } 56 | } 57 | } 58 | // Populate exports global. 59 | for _, ps := range pkgIndex { 60 | for _, p := range ps { 61 | e := loadExports(p.dir) 62 | if e != nil { 63 | exports[p.dir] = e 64 | } 65 | } 66 | } 67 | 68 | // Construct source file. 69 | var buf bytes.Buffer 70 | fmt.Fprint(&buf, pkgIndexHead) 71 | fmt.Fprintf(&buf, "var pkgIndexMaster = %#v\n", pkgIndex) 72 | fmt.Fprintf(&buf, "var exportsMaster = %#v\n", exports) 73 | src := buf.Bytes() 74 | 75 | // Replace main.pkg type name with pkg. 76 | src = bytes.Replace(src, []byte("main.pkg"), []byte("pkg"), -1) 77 | // Replace actual GOROOT with "/go". 78 | src = bytes.Replace(src, []byte(ctx.GOROOT), []byte("/go"), -1) 79 | // Add some line wrapping. 80 | src = bytes.Replace(src, []byte("}, "), []byte("},\n"), -1) 81 | src = bytes.Replace(src, []byte("true, "), []byte("true,\n"), -1) 82 | 83 | var err error 84 | src, err = format.Source(src) 85 | if err != nil { 86 | log.Fatal(err) 87 | } 88 | 89 | // Write out source file. 90 | err = ioutil.WriteFile("pkgindex.go", src, 0644) 91 | if err != nil { 92 | log.Fatal(err) 93 | } 94 | } 95 | 96 | const pkgIndexHead = `package imports 97 | 98 | func init() { 99 | pkgIndexOnce.Do(func() { 100 | pkgIndex.m = pkgIndexMaster 101 | }) 102 | loadExports = func(dir string) map[string]bool { 103 | return exportsMaster[dir] 104 | } 105 | } 106 | ` 107 | 108 | type pkg struct { 109 | importpath string // full pkg import path, e.g. "net/http" 110 | dir string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt" 111 | } 112 | 113 | var fset = token.NewFileSet() 114 | 115 | func loadPkg(root, importpath string) { 116 | shortName := path.Base(importpath) 117 | if shortName == "testdata" { 118 | return 119 | } 120 | 121 | dir := filepath.Join(root, importpath) 122 | pkgIndex[shortName] = append(pkgIndex[shortName], pkg{ 123 | importpath: importpath, 124 | dir: dir, 125 | }) 126 | 127 | pkgDir, err := os.Open(dir) 128 | if err != nil { 129 | return 130 | } 131 | children, err := pkgDir.Readdir(-1) 132 | pkgDir.Close() 133 | if err != nil { 134 | return 135 | } 136 | for _, child := range children { 137 | name := child.Name() 138 | if name == "" { 139 | continue 140 | } 141 | if c := name[0]; c == '.' || ('0' <= c && c <= '9') { 142 | continue 143 | } 144 | if child.IsDir() { 145 | loadPkg(root, filepath.Join(importpath, name)) 146 | } 147 | } 148 | } 149 | 150 | func loadExports(dir string) map[string]bool { 151 | exports := make(map[string]bool) 152 | buildPkg, err := build.ImportDir(dir, 0) 153 | if err != nil { 154 | if strings.Contains(err.Error(), "no buildable Go source files in") { 155 | return nil 156 | } 157 | log.Printf("could not import %q: %v", dir, err) 158 | return nil 159 | } 160 | for _, file := range buildPkg.GoFiles { 161 | f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0) 162 | if err != nil { 163 | log.Printf("could not parse %q: %v", file, err) 164 | continue 165 | } 166 | for name := range f.Scope.Objects { 167 | if ast.IsExported(name) { 168 | exports[name] = true 169 | } 170 | } 171 | } 172 | return exports 173 | } 174 | -------------------------------------------------------------------------------- /gbvendor/imports.go: -------------------------------------------------------------------------------- 1 | package vendor 2 | 3 | import ( 4 | "fmt" 5 | "go/parser" 6 | "go/token" 7 | "io" 8 | "io/ioutil" 9 | "log" 10 | "net/http" 11 | "os" 12 | "path" 13 | "path/filepath" 14 | "strings" 15 | 16 | "github.com/FiloSottile/gvt/fileutils" 17 | ) 18 | 19 | // ParseImports parses Go packages from a specific root returning a set of import paths. 20 | // vendorRoot is how deep to go looking for vendor folders, usually the repo root. 21 | // vendorPrefix is the vendorRoot import path. 22 | func ParseImports(root, vendorRoot, vendorPrefix string, tests, all bool) (map[string]bool, error) { 23 | pkgs := make(map[string]bool) 24 | 25 | var walkFn = func(p string, info os.FileInfo, err error) error { 26 | if err != nil { 27 | return err 28 | } 29 | 30 | if fileutils.ShouldSkip(p, info, tests, all) { 31 | if info.IsDir() { 32 | return filepath.SkipDir 33 | } 34 | return nil 35 | } 36 | 37 | if info.IsDir() || filepath.Ext(p) != ".go" { 38 | return nil 39 | } 40 | 41 | fs := token.NewFileSet() 42 | f, err := parser.ParseFile(fs, p, nil, parser.ImportsOnly) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | for _, s := range f.Imports { 48 | pkg := strings.Replace(s.Path.Value, "\"", "", -1) 49 | if strings.HasPrefix(pkg, "./") { 50 | middle, err := filepath.Rel(vendorRoot, filepath.Dir(p)) 51 | if err != nil { 52 | panic(err) 53 | } 54 | pkg = path.Join(vendorPrefix, middle, pkg) 55 | } 56 | if vp := findVendor(vendorRoot, filepath.Dir(p), pkg); vp != "" { 57 | pkg = path.Join(vendorPrefix, vp) 58 | } 59 | pkgs[pkg] = true 60 | } 61 | return nil 62 | } 63 | 64 | err := filepath.Walk(root, walkFn) 65 | return pkgs, err 66 | } 67 | 68 | // findVendor looks for pkgName in a vendor folder at start/vendor or deeper, stopping 69 | // at root. start is expected to match or be a subfolder of root. 70 | // 71 | // It returns the path to pkgName inside the vendor folder, relative to root. 72 | func findVendor(root, start, pkgName string) string { 73 | if !strings.HasPrefix(start, root) { 74 | log.Fatalln("Assertion failed:", root, "prefix of", start) 75 | } 76 | 77 | levels := strings.Split(strings.TrimPrefix(start, root), string(filepath.Separator)) 78 | for { 79 | candidate := filepath.Join(append(append([]string{root}, levels...), "vendor", pkgName)...) 80 | 81 | files, err := ioutil.ReadDir(candidate) 82 | if err != nil { 83 | files = nil 84 | } 85 | isPackage := false 86 | for _, f := range files { 87 | if !f.IsDir() && filepath.Ext(f.Name()) == ".go" { 88 | isPackage = true 89 | break 90 | } 91 | } 92 | 93 | if isPackage { 94 | return strings.TrimPrefix(candidate, root) 95 | } 96 | 97 | if len(levels) == 0 { 98 | return "" 99 | } 100 | levels = levels[:len(levels)-1] 101 | } 102 | } 103 | 104 | // FetchMetadata fetchs the remote metadata for path. 105 | func FetchMetadata(path string, insecure bool) (rc io.ReadCloser, err error) { 106 | defer func() { 107 | if err != nil { 108 | err = fmt.Errorf("unable to determine remote metadata protocol: %s", err) 109 | } 110 | }() 111 | // try https first 112 | rc, err = fetchMetadata("https", path) 113 | if err == nil { 114 | return 115 | } 116 | // try http if supported 117 | if insecure { 118 | rc, err = fetchMetadata("http", path) 119 | } 120 | return 121 | } 122 | 123 | func fetchMetadata(scheme, path string) (io.ReadCloser, error) { 124 | url := fmt.Sprintf("%s://%s?go-get=1", scheme, path) 125 | switch scheme { 126 | case "https", "http": 127 | resp, err := http.Get(url) 128 | if err != nil { 129 | return nil, fmt.Errorf("failed to access url %q", url) 130 | } 131 | return resp.Body, nil 132 | default: 133 | return nil, fmt.Errorf("unknown remote protocol scheme: %q", scheme) 134 | } 135 | } 136 | 137 | // ParseMetadata fetchs and decodes remote metadata for path. 138 | func ParseMetadata(path string, insecure bool) (string, string, string, error) { 139 | rc, err := FetchMetadata(path, insecure) 140 | if err != nil { 141 | return "", "", "", err 142 | } 143 | defer rc.Close() 144 | 145 | imports, err := parseMetaGoImports(rc) 146 | if err != nil { 147 | return "", "", "", err 148 | } 149 | match := -1 150 | for i, im := range imports { 151 | if !strings.HasPrefix(path, im.Prefix) { 152 | continue 153 | } 154 | if match != -1 { 155 | return "", "", "", fmt.Errorf("multiple meta tags match import path %q", path) 156 | } 157 | match = i 158 | } 159 | if match == -1 { 160 | return "", "", "", fmt.Errorf("go-import metadata not found") 161 | } 162 | return imports[match].Prefix, imports[match].VCS, imports[match].RepoRoot, nil 163 | } 164 | -------------------------------------------------------------------------------- /fileutils/fileutils.go: -------------------------------------------------------------------------------- 1 | // package fileutils provides utililty methods to copy and move files and directories. 2 | package fileutils 3 | 4 | import ( 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | "path/filepath" 10 | "runtime" 11 | "strings" 12 | ) 13 | 14 | // https://golang.org/cmd/go/#hdr-File_types 15 | var goFileTypes = []string{ 16 | ".go", 17 | ".c", ".h", 18 | ".cc", ".cpp", ".cxx", ".hh", ".hpp", ".hxx", 19 | ".m", 20 | ".s", ".S", 21 | ".swig", ".swigcxx", 22 | ".syso", 23 | } 24 | 25 | var licenseFiles = []string{ 26 | "LICENSE", "LICENCE", "UNLICENSE", "COPYING", "COPYRIGHT", 27 | } 28 | 29 | func ShouldSkip(path string, info os.FileInfo, tests, all bool) bool { 30 | name := filepath.Base(path) 31 | 32 | relevantFile := false 33 | for _, ext := range goFileTypes { 34 | if strings.HasSuffix(name, ext) { 35 | relevantFile = true 36 | break 37 | } 38 | } 39 | 40 | testdata := false 41 | for _, n := range strings.Split(filepath.Dir(path), string(filepath.Separator)) { 42 | if n == "testdata" || n == "_testdata" { 43 | testdata = true 44 | } 45 | } 46 | 47 | skip := false 48 | switch { 49 | case all && !(name == ".git" && info.IsDir()) && name != ".bzr" && name != ".hg": 50 | skip = false 51 | 52 | // Include all files in a testdata folder 53 | case tests && testdata: 54 | skip = false 55 | 56 | // https://golang.org/cmd/go/#hdr-Description_of_package_lists 57 | case strings.HasPrefix(name, "."): 58 | skip = true 59 | case strings.HasPrefix(name, "_") && name != "_testdata": 60 | skip = true 61 | 62 | case !tests && name == "_testdata" && info.IsDir(): 63 | skip = true 64 | case !tests && name == "testdata" && info.IsDir(): 65 | skip = true 66 | case !tests && strings.HasSuffix(name, "_test.go") && !info.IsDir(): 67 | skip = true 68 | 69 | case !relevantFile && !info.IsDir(): 70 | skip = true 71 | } 72 | 73 | return skip 74 | } 75 | 76 | // Copypath copies the contents of src to dst, excluding any file that is not 77 | // relevant to the Go compiler. 78 | func Copypath(dst string, src string, tests, all bool) error { 79 | err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 80 | if err != nil { 81 | return err 82 | } 83 | 84 | skip := ShouldSkip(path, info, tests, all) 85 | 86 | if skip { 87 | if info.IsDir() { 88 | return filepath.SkipDir 89 | } 90 | return nil 91 | } 92 | 93 | if info.IsDir() { 94 | return nil 95 | } 96 | 97 | dst := filepath.Join(dst, path[len(src):]) 98 | 99 | if info.Mode()&os.ModeSymlink != 0 { 100 | return Copylink(dst, path) 101 | } 102 | 103 | return Copyfile(dst, path) 104 | }) 105 | if err != nil { 106 | // if there was an error during copying, remove the partial copy. 107 | RemoveAll(dst) 108 | } 109 | return err 110 | } 111 | 112 | func Copyfile(dst, src string) error { 113 | err := mkdir(filepath.Dir(dst)) 114 | if err != nil { 115 | return fmt.Errorf("copyfile: mkdirall: %v", err) 116 | } 117 | r, err := os.Open(src) 118 | if err != nil { 119 | return fmt.Errorf("copyfile: open(%q): %v", src, err) 120 | } 121 | defer r.Close() 122 | w, err := os.Create(dst) 123 | if err != nil { 124 | return fmt.Errorf("copyfile: create(%q): %v", dst, err) 125 | } 126 | defer w.Close() 127 | _, err = io.Copy(w, r) 128 | return err 129 | } 130 | 131 | func Copylink(dst, src string) error { 132 | target, err := os.Readlink(src) 133 | if err != nil { 134 | return fmt.Errorf("copylink: readlink: %v", err) 135 | } 136 | if err := mkdir(filepath.Dir(dst)); err != nil { 137 | return fmt.Errorf("copylink: mkdirall: %v", err) 138 | } 139 | if err := os.Symlink(target, dst); err != nil { 140 | return fmt.Errorf("copylink: symlink: %v", err) 141 | } 142 | return nil 143 | } 144 | 145 | // RemoveAll removes path and any children it contains. Unlike os.RemoveAll it 146 | // deletes read only files on Windows. 147 | func RemoveAll(path string) error { 148 | if runtime.GOOS == "windows" { 149 | // Simple case: if Remove works, we're done. 150 | err := os.Remove(path) 151 | if err == nil || os.IsNotExist(err) { 152 | return nil 153 | } 154 | // make sure all files are writable so we can delete them 155 | filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 156 | if err != nil { 157 | // walk gave us some error, give it back. 158 | return err 159 | } 160 | mode := info.Mode() 161 | if mode|0200 == mode { 162 | return nil 163 | } 164 | return os.Chmod(path, mode|0200) 165 | }) 166 | } 167 | return os.RemoveAll(path) 168 | } 169 | 170 | // CopyLicense copies the license file from folder src to folder dst. 171 | func CopyLicense(dst, src string) error { 172 | files, err := ioutil.ReadDir(src) 173 | if err != nil { 174 | return err 175 | } 176 | for _, f := range files { 177 | if f.IsDir() { 178 | continue 179 | } 180 | for _, candidate := range licenseFiles { 181 | if strings.ToLower(candidate) == strings.TrimSuffix( 182 | strings.TrimSuffix(strings.ToLower(f.Name()), ".md"), ".txt") { 183 | if err := Copyfile(filepath.Join(dst, f.Name()), 184 | filepath.Join(src, f.Name())); err != nil { 185 | return err 186 | } 187 | } 188 | } 189 | } 190 | return nil 191 | } 192 | 193 | func mkdir(path string) error { 194 | return os.MkdirAll(path, 0755) 195 | } 196 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/fastwalk.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // A faster implementation of filepath.Walk. 6 | // 7 | // filepath.Walk's design necessarily calls os.Lstat on each file, 8 | // even if the caller needs less info. And goimports only need to know 9 | // the type of each file. The kernel interface provides the type in 10 | // the Readdir call but the standard library ignored it. 11 | // fastwalk_unix.go contains a fork of the syscall routines. 12 | // 13 | // See golang.org/issue/16399 14 | 15 | package imports 16 | 17 | import ( 18 | "errors" 19 | "os" 20 | "path/filepath" 21 | "runtime" 22 | ) 23 | 24 | // traverseLink is a sentinel error for fastWalk, similar to filepath.SkipDir. 25 | var traverseLink = errors.New("traverse symlink, assuming target is a directory") 26 | 27 | // fastWalk walks the file tree rooted at root, calling walkFn for 28 | // each file or directory in the tree, including root. 29 | // 30 | // If fastWalk returns filepath.SkipDir, the directory is skipped. 31 | // 32 | // Unlike filepath.Walk: 33 | // * file stat calls must be done by the user. 34 | // The only provided metadata is the file type, which does not include 35 | // any permission bits. 36 | // * multiple goroutines stat the filesystem concurrently. The provided 37 | // walkFn must be safe for concurrent use. 38 | // * fastWalk can follow symlinks if walkFn returns the traverseLink 39 | // sentinel error. It is the walkFn's responsibility to prevent 40 | // fastWalk from going into symlink cycles. 41 | func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) error { 42 | // TODO(bradfitz): make numWorkers configurable? We used a 43 | // minimum of 4 to give the kernel more info about multiple 44 | // things we want, in hopes its I/O scheduling can take 45 | // advantage of that. Hopefully most are in cache. Maybe 4 is 46 | // even too low of a minimum. Profile more. 47 | numWorkers := 4 48 | if n := runtime.NumCPU(); n > numWorkers { 49 | numWorkers = n 50 | } 51 | w := &walker{ 52 | fn: walkFn, 53 | enqueuec: make(chan walkItem, numWorkers), // buffered for performance 54 | workc: make(chan walkItem, numWorkers), // buffered for performance 55 | donec: make(chan struct{}), 56 | 57 | // buffered for correctness & not leaking goroutines: 58 | resc: make(chan error, numWorkers), 59 | } 60 | defer close(w.donec) 61 | // TODO(bradfitz): start the workers as needed? maybe not worth it. 62 | for i := 0; i < numWorkers; i++ { 63 | go w.doWork() 64 | } 65 | todo := []walkItem{{dir: root}} 66 | out := 0 67 | for { 68 | workc := w.workc 69 | var workItem walkItem 70 | if len(todo) == 0 { 71 | workc = nil 72 | } else { 73 | workItem = todo[len(todo)-1] 74 | } 75 | select { 76 | case workc <- workItem: 77 | todo = todo[:len(todo)-1] 78 | out++ 79 | case it := <-w.enqueuec: 80 | todo = append(todo, it) 81 | case err := <-w.resc: 82 | out-- 83 | if err != nil { 84 | return err 85 | } 86 | if out == 0 && len(todo) == 0 { 87 | // It's safe to quit here, as long as the buffered 88 | // enqueue channel isn't also readable, which might 89 | // happen if the worker sends both another unit of 90 | // work and its result before the other select was 91 | // scheduled and both w.resc and w.enqueuec were 92 | // readable. 93 | select { 94 | case it := <-w.enqueuec: 95 | todo = append(todo, it) 96 | default: 97 | return nil 98 | } 99 | } 100 | } 101 | } 102 | } 103 | 104 | // doWork reads directories as instructed (via workc) and runs the 105 | // user's callback function. 106 | func (w *walker) doWork() { 107 | for { 108 | select { 109 | case <-w.donec: 110 | return 111 | case it := <-w.workc: 112 | w.resc <- w.walk(it.dir, !it.callbackDone) 113 | } 114 | } 115 | } 116 | 117 | type walker struct { 118 | fn func(path string, typ os.FileMode) error 119 | 120 | donec chan struct{} // closed on fastWalk's return 121 | workc chan walkItem // to workers 122 | enqueuec chan walkItem // from workers 123 | resc chan error // from workers 124 | } 125 | 126 | type walkItem struct { 127 | dir string 128 | callbackDone bool // callback already called; don't do it again 129 | } 130 | 131 | func (w *walker) enqueue(it walkItem) { 132 | select { 133 | case w.enqueuec <- it: 134 | case <-w.donec: 135 | } 136 | } 137 | 138 | func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { 139 | joined := dirName + string(os.PathSeparator) + baseName 140 | if typ == os.ModeDir { 141 | w.enqueue(walkItem{dir: joined}) 142 | return nil 143 | } 144 | 145 | err := w.fn(joined, typ) 146 | if typ == os.ModeSymlink { 147 | if err == traverseLink { 148 | // Set callbackDone so we don't call it twice for both the 149 | // symlink-as-symlink and the symlink-as-directory later: 150 | w.enqueue(walkItem{dir: joined, callbackDone: true}) 151 | return nil 152 | } 153 | if err == filepath.SkipDir { 154 | // Permit SkipDir on symlinks too. 155 | return nil 156 | } 157 | } 158 | return err 159 | } 160 | func (w *walker) walk(root string, runUserCallback bool) error { 161 | if runUserCallback { 162 | err := w.fn(root, os.ModeDir) 163 | if err == filepath.SkipDir { 164 | return nil 165 | } 166 | if err != nil { 167 | return err 168 | } 169 | } 170 | 171 | return readDir(root, w.onDirEnt) 172 | } 173 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cover/profile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package cover provides support for parsing coverage profiles 6 | // generated by "go test -coverprofile=cover.out". 7 | package cover // import "golang.org/x/tools/cover" 8 | 9 | import ( 10 | "bufio" 11 | "fmt" 12 | "math" 13 | "os" 14 | "regexp" 15 | "sort" 16 | "strconv" 17 | "strings" 18 | ) 19 | 20 | // Profile represents the profiling data for a specific file. 21 | type Profile struct { 22 | FileName string 23 | Mode string 24 | Blocks []ProfileBlock 25 | } 26 | 27 | // ProfileBlock represents a single block of profiling data. 28 | type ProfileBlock struct { 29 | StartLine, StartCol int 30 | EndLine, EndCol int 31 | NumStmt, Count int 32 | } 33 | 34 | type byFileName []*Profile 35 | 36 | func (p byFileName) Len() int { return len(p) } 37 | func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName } 38 | func (p byFileName) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 39 | 40 | // ParseProfiles parses profile data in the specified file and returns a 41 | // Profile for each source file described therein. 42 | func ParseProfiles(fileName string) ([]*Profile, error) { 43 | pf, err := os.Open(fileName) 44 | if err != nil { 45 | return nil, err 46 | } 47 | defer pf.Close() 48 | 49 | files := make(map[string]*Profile) 50 | buf := bufio.NewReader(pf) 51 | // First line is "mode: foo", where foo is "set", "count", or "atomic". 52 | // Rest of file is in the format 53 | // encoding/base64/base64.go:34.44,37.40 3 1 54 | // where the fields are: name.go:line.column,line.column numberOfStatements count 55 | s := bufio.NewScanner(buf) 56 | mode := "" 57 | for s.Scan() { 58 | line := s.Text() 59 | if mode == "" { 60 | const p = "mode: " 61 | if !strings.HasPrefix(line, p) || line == p { 62 | return nil, fmt.Errorf("bad mode line: %v", line) 63 | } 64 | mode = line[len(p):] 65 | continue 66 | } 67 | m := lineRe.FindStringSubmatch(line) 68 | if m == nil { 69 | return nil, fmt.Errorf("line %q doesn't match expected format: %v", line, lineRe) 70 | } 71 | fn := m[1] 72 | p := files[fn] 73 | if p == nil { 74 | p = &Profile{ 75 | FileName: fn, 76 | Mode: mode, 77 | } 78 | files[fn] = p 79 | } 80 | p.Blocks = append(p.Blocks, ProfileBlock{ 81 | StartLine: toInt(m[2]), 82 | StartCol: toInt(m[3]), 83 | EndLine: toInt(m[4]), 84 | EndCol: toInt(m[5]), 85 | NumStmt: toInt(m[6]), 86 | Count: toInt(m[7]), 87 | }) 88 | } 89 | if err := s.Err(); err != nil { 90 | return nil, err 91 | } 92 | for _, p := range files { 93 | sort.Sort(blocksByStart(p.Blocks)) 94 | } 95 | // Generate a sorted slice. 96 | profiles := make([]*Profile, 0, len(files)) 97 | for _, profile := range files { 98 | profiles = append(profiles, profile) 99 | } 100 | sort.Sort(byFileName(profiles)) 101 | return profiles, nil 102 | } 103 | 104 | type blocksByStart []ProfileBlock 105 | 106 | func (b blocksByStart) Len() int { return len(b) } 107 | func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 108 | func (b blocksByStart) Less(i, j int) bool { 109 | bi, bj := b[i], b[j] 110 | return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol 111 | } 112 | 113 | var lineRe = regexp.MustCompile(`^(.+):([0-9]+).([0-9]+),([0-9]+).([0-9]+) ([0-9]+) ([0-9]+)$`) 114 | 115 | func toInt(s string) int { 116 | i, err := strconv.Atoi(s) 117 | if err != nil { 118 | panic(err) 119 | } 120 | return i 121 | } 122 | 123 | // Boundary represents the position in a source file of the beginning or end of a 124 | // block as reported by the coverage profile. In HTML mode, it will correspond to 125 | // the opening or closing of a tag and will be used to colorize the source 126 | type Boundary struct { 127 | Offset int // Location as a byte offset in the source file. 128 | Start bool // Is this the start of a block? 129 | Count int // Event count from the cover profile. 130 | Norm float64 // Count normalized to [0..1]. 131 | } 132 | 133 | // Boundaries returns a Profile as a set of Boundary objects within the provided src. 134 | func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) { 135 | // Find maximum count. 136 | max := 0 137 | for _, b := range p.Blocks { 138 | if b.Count > max { 139 | max = b.Count 140 | } 141 | } 142 | // Divisor for normalization. 143 | divisor := math.Log(float64(max)) 144 | 145 | // boundary returns a Boundary, populating the Norm field with a normalized Count. 146 | boundary := func(offset int, start bool, count int) Boundary { 147 | b := Boundary{Offset: offset, Start: start, Count: count} 148 | if !start || count == 0 { 149 | return b 150 | } 151 | if max <= 1 { 152 | b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS. 153 | } else if count > 0 { 154 | b.Norm = math.Log(float64(count)) / divisor 155 | } 156 | return b 157 | } 158 | 159 | line, col := 1, 2 // TODO: Why is this 2? 160 | for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); { 161 | b := p.Blocks[bi] 162 | if b.StartLine == line && b.StartCol == col { 163 | boundaries = append(boundaries, boundary(si, true, b.Count)) 164 | } 165 | if b.EndLine == line && b.EndCol == col || line > b.EndLine { 166 | boundaries = append(boundaries, boundary(si, false, 0)) 167 | bi++ 168 | continue // Don't advance through src; maybe the next block starts here. 169 | } 170 | if src[si] == '\n' { 171 | line++ 172 | col = 0 173 | } 174 | col++ 175 | si++ 176 | } 177 | sort.Sort(boundariesByPos(boundaries)) 178 | return 179 | } 180 | 181 | type boundariesByPos []Boundary 182 | 183 | func (b boundariesByPos) Len() int { return len(b) } 184 | func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 185 | func (b boundariesByPos) Less(i, j int) bool { 186 | if b[i].Offset == b[j].Offset { 187 | return !b[i].Start && b[j].Start 188 | } 189 | return b[i].Offset < b[j].Offset 190 | } 191 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/imports/sortimports.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Hacked up copy of go/ast/import.go 6 | 7 | package imports 8 | 9 | import ( 10 | "go/ast" 11 | "go/token" 12 | "sort" 13 | "strconv" 14 | ) 15 | 16 | // sortImports sorts runs of consecutive import lines in import blocks in f. 17 | // It also removes duplicate imports when it is possible to do so without data loss. 18 | func sortImports(fset *token.FileSet, f *ast.File) { 19 | for i, d := range f.Decls { 20 | d, ok := d.(*ast.GenDecl) 21 | if !ok || d.Tok != token.IMPORT { 22 | // Not an import declaration, so we're done. 23 | // Imports are always first. 24 | break 25 | } 26 | 27 | if len(d.Specs) == 0 { 28 | // Empty import block, remove it. 29 | f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) 30 | } 31 | 32 | if !d.Lparen.IsValid() { 33 | // Not a block: sorted by default. 34 | continue 35 | } 36 | 37 | // Identify and sort runs of specs on successive lines. 38 | i := 0 39 | specs := d.Specs[:0] 40 | for j, s := range d.Specs { 41 | if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { 42 | // j begins a new run. End this one. 43 | specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...) 44 | i = j 45 | } 46 | } 47 | specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...) 48 | d.Specs = specs 49 | 50 | // Deduping can leave a blank line before the rparen; clean that up. 51 | if len(d.Specs) > 0 { 52 | lastSpec := d.Specs[len(d.Specs)-1] 53 | lastLine := fset.Position(lastSpec.Pos()).Line 54 | if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 { 55 | fset.File(d.Rparen).MergeLine(rParenLine - 1) 56 | } 57 | } 58 | } 59 | } 60 | 61 | func importPath(s ast.Spec) string { 62 | t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) 63 | if err == nil { 64 | return t 65 | } 66 | return "" 67 | } 68 | 69 | func importName(s ast.Spec) string { 70 | n := s.(*ast.ImportSpec).Name 71 | if n == nil { 72 | return "" 73 | } 74 | return n.Name 75 | } 76 | 77 | func importComment(s ast.Spec) string { 78 | c := s.(*ast.ImportSpec).Comment 79 | if c == nil { 80 | return "" 81 | } 82 | return c.Text() 83 | } 84 | 85 | // collapse indicates whether prev may be removed, leaving only next. 86 | func collapse(prev, next ast.Spec) bool { 87 | if importPath(next) != importPath(prev) || importName(next) != importName(prev) { 88 | return false 89 | } 90 | return prev.(*ast.ImportSpec).Comment == nil 91 | } 92 | 93 | type posSpan struct { 94 | Start token.Pos 95 | End token.Pos 96 | } 97 | 98 | func sortSpecs(fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec { 99 | // Can't short-circuit here even if specs are already sorted, 100 | // since they might yet need deduplication. 101 | // A lone import, however, may be safely ignored. 102 | if len(specs) <= 1 { 103 | return specs 104 | } 105 | 106 | // Record positions for specs. 107 | pos := make([]posSpan, len(specs)) 108 | for i, s := range specs { 109 | pos[i] = posSpan{s.Pos(), s.End()} 110 | } 111 | 112 | // Identify comments in this range. 113 | // Any comment from pos[0].Start to the final line counts. 114 | lastLine := fset.Position(pos[len(pos)-1].End).Line 115 | cstart := len(f.Comments) 116 | cend := len(f.Comments) 117 | for i, g := range f.Comments { 118 | if g.Pos() < pos[0].Start { 119 | continue 120 | } 121 | if i < cstart { 122 | cstart = i 123 | } 124 | if fset.Position(g.End()).Line > lastLine { 125 | cend = i 126 | break 127 | } 128 | } 129 | comments := f.Comments[cstart:cend] 130 | 131 | // Assign each comment to the import spec preceding it. 132 | importComment := map[*ast.ImportSpec][]*ast.CommentGroup{} 133 | specIndex := 0 134 | for _, g := range comments { 135 | for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { 136 | specIndex++ 137 | } 138 | s := specs[specIndex].(*ast.ImportSpec) 139 | importComment[s] = append(importComment[s], g) 140 | } 141 | 142 | // Sort the import specs by import path. 143 | // Remove duplicates, when possible without data loss. 144 | // Reassign the import paths to have the same position sequence. 145 | // Reassign each comment to abut the end of its spec. 146 | // Sort the comments by new position. 147 | sort.Sort(byImportSpec(specs)) 148 | 149 | // Dedup. Thanks to our sorting, we can just consider 150 | // adjacent pairs of imports. 151 | deduped := specs[:0] 152 | for i, s := range specs { 153 | if i == len(specs)-1 || !collapse(s, specs[i+1]) { 154 | deduped = append(deduped, s) 155 | } else { 156 | p := s.Pos() 157 | fset.File(p).MergeLine(fset.Position(p).Line) 158 | } 159 | } 160 | specs = deduped 161 | 162 | // Fix up comment positions 163 | for i, s := range specs { 164 | s := s.(*ast.ImportSpec) 165 | if s.Name != nil { 166 | s.Name.NamePos = pos[i].Start 167 | } 168 | s.Path.ValuePos = pos[i].Start 169 | s.EndPos = pos[i].End 170 | for _, g := range importComment[s] { 171 | for _, c := range g.List { 172 | c.Slash = pos[i].End 173 | } 174 | } 175 | } 176 | 177 | sort.Sort(byCommentPos(comments)) 178 | 179 | return specs 180 | } 181 | 182 | type byImportSpec []ast.Spec // slice of *ast.ImportSpec 183 | 184 | func (x byImportSpec) Len() int { return len(x) } 185 | func (x byImportSpec) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 186 | func (x byImportSpec) Less(i, j int) bool { 187 | ipath := importPath(x[i]) 188 | jpath := importPath(x[j]) 189 | 190 | igroup := importGroup(ipath) 191 | jgroup := importGroup(jpath) 192 | if igroup != jgroup { 193 | return igroup < jgroup 194 | } 195 | 196 | if ipath != jpath { 197 | return ipath < jpath 198 | } 199 | iname := importName(x[i]) 200 | jname := importName(x[j]) 201 | 202 | if iname != jname { 203 | return iname < jname 204 | } 205 | return importComment(x[i]) < importComment(x[j]) 206 | } 207 | 208 | type byCommentPos []*ast.CommentGroup 209 | 210 | func (x byCommentPos) Len() int { return len(x) } 211 | func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 212 | func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } 213 | -------------------------------------------------------------------------------- /gbvendor/manifest.go: -------------------------------------------------------------------------------- 1 | package vendor 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "log" 10 | "os" 11 | "reflect" 12 | "sort" 13 | "strings" 14 | ) 15 | 16 | // gb-vendor manifest support 17 | 18 | // Manifest describes the layout of $PROJECT/vendor/manifest. 19 | type Manifest struct { 20 | // Manifest version. Current manifest version is 0. 21 | Version int `json:"version"` 22 | 23 | // Depenencies is a list of vendored dependencies. 24 | Dependencies []Dependency `json:"dependencies"` 25 | } 26 | 27 | var ( 28 | DepPresent = errors.New("dependency already present") 29 | DepSubPkgPresent = errors.New("subpackages of this dependency are already present") 30 | DepMissing = errors.New("dependency does not exist") 31 | ) 32 | 33 | // AddDependency adds a Dependency to the current Manifest. 34 | // If the dependency exists already then it returns and error. 35 | func (m *Manifest) AddDependency(dep Dependency) error { 36 | if m.HasImportpath(dep.Importpath) { 37 | return DepPresent 38 | } 39 | if m.GetSubpackages(dep.Importpath) != nil { 40 | return DepSubPkgPresent 41 | } 42 | m.Dependencies = append(m.Dependencies, dep) 43 | return nil 44 | } 45 | 46 | // RemoveDependency removes a Dependency from the current Manifest. 47 | // If the dependency does not exist then it returns an error. 48 | func (m *Manifest) RemoveDependency(dep Dependency) error { 49 | for i, d := range m.Dependencies { 50 | if reflect.DeepEqual(d, dep) { 51 | m.Dependencies = append(m.Dependencies[:i], m.Dependencies[i+1:]...) 52 | return nil 53 | } 54 | } 55 | return DepMissing 56 | } 57 | 58 | // HasImportpath reports whether the Manifest contains the import path, 59 | // or a parent of it. 60 | func (m *Manifest) HasImportpath(path string) bool { 61 | _, err := m.GetDependencyForImportpath(path) 62 | return err == nil 63 | } 64 | 65 | // GetDependencyForRepository return a dependency for specified import 66 | // path. Note that it might be a parent of the specified path. 67 | // If the dependency does not exist it returns an error. 68 | func (m *Manifest) GetDependencyForImportpath(path string) (Dependency, error) { 69 | for _, d := range m.Dependencies { 70 | if path == d.Importpath || strings.HasPrefix(path, d.Importpath+"/") { 71 | return d, nil 72 | } 73 | } 74 | return Dependency{}, fmt.Errorf("dependency for %s does not exist", path) 75 | } 76 | 77 | // GetSubpackages returns any Dependency in the Manifest that is a subpackage 78 | // of the given import path. 79 | func (m *Manifest) GetSubpackages(path string) (deps []Dependency) { 80 | for _, d := range m.Dependencies { 81 | if path != d.Importpath && strings.HasPrefix(d.Importpath, path+"/") { 82 | deps = append(deps, d) 83 | } 84 | } 85 | return 86 | } 87 | 88 | // Dependency describes one vendored import path of code 89 | // A Dependency is an Importpath sources from a Respository 90 | // at Revision from Path. 91 | type Dependency struct { 92 | // Importpath is name by which this dependency is known. 93 | Importpath string `json:"importpath"` 94 | 95 | // Repository is the remote DVCS location that this 96 | // dependency was fetched from. 97 | Repository string `json:"repository"` 98 | 99 | // VCS is the DVCS system found at Repository. 100 | VCS string `json:"vcs"` 101 | 102 | // Revision is the revision that describes the dependency's 103 | // remote revision. 104 | Revision string `json:"revision"` 105 | 106 | // Branch is the branch the Revision was located on. 107 | // Can be blank if not needed. 108 | Branch string `json:"branch"` 109 | 110 | // Path is the path inside the Repository where the 111 | // dependency was fetched from. 112 | Path string `json:"path,omitempty"` 113 | 114 | // NoTests indicates that test files were ignored. 115 | // In the negative for backwards compatibility. 116 | NoTests bool `json:"notests,omitempty"` 117 | 118 | // AllFiles indicates that no files were ignored. 119 | AllFiles bool `json:"allfiles,omitempty"` 120 | } 121 | 122 | // WriteManifest writes a Manifest to the path. If the manifest does 123 | // not exist, it is created. If it does exist, it will be overwritten. 124 | // If the manifest file is empty (0 dependencies) it will be deleted. 125 | // The dependencies will be ordered by import path to reduce churn when making 126 | // changes. 127 | // TODO(dfc) write to temporary file and move atomically to avoid 128 | // destroying a working vendorfile. 129 | func WriteManifest(path string, m *Manifest) error { 130 | if len(m.Dependencies) == 0 { 131 | err := os.Remove(path) 132 | if !os.IsNotExist(err) { 133 | return err 134 | } 135 | return nil 136 | } 137 | 138 | f, err := os.Create(path) 139 | if err != nil { 140 | return err 141 | } 142 | if err := writeManifest(f, m); err != nil { 143 | f.Close() 144 | return err 145 | } 146 | return f.Close() 147 | } 148 | 149 | func writeManifest(w io.Writer, m *Manifest) error { 150 | sort.Sort(byImportpath(m.Dependencies)) 151 | buf, err := json.MarshalIndent(m, "", "\t") 152 | if err != nil { 153 | return err 154 | } 155 | _, err = io.Copy(w, bytes.NewReader(buf)) 156 | return err 157 | } 158 | 159 | // ReadManifest reads a Manifest from path. If the Manifest is not 160 | // found, a blank Manifest will be returned. 161 | func ReadManifest(path string) (*Manifest, error) { 162 | f, err := os.Open(path) 163 | if err != nil { 164 | if os.IsNotExist(err) { 165 | return new(Manifest), nil 166 | } 167 | return nil, err 168 | } 169 | defer f.Close() 170 | 171 | var m Manifest 172 | d := json.NewDecoder(f) 173 | if err := d.Decode(&m); err != nil { 174 | return nil, err 175 | } 176 | 177 | // Pass all dependencies through AddDependency to detect overlap 178 | deps := m.Dependencies 179 | m.Dependencies = nil 180 | sort.Sort(byImportpath(deps)) // so that subpackages come after parents 181 | for _, d := range deps { 182 | if err := m.AddDependency(d); err == DepPresent { 183 | log.Println("WARNING: overlapping dependency detected:", d.Importpath) 184 | log.Println("The subpackage will be ignored to fix undefined behavior. See https://git.io/vr8Mu") 185 | } else if err != nil { 186 | return nil, err 187 | } 188 | } 189 | 190 | return &m, err 191 | } 192 | 193 | type byImportpath []Dependency 194 | 195 | func (s byImportpath) Len() int { return len(s) } 196 | func (s byImportpath) Less(i, j int) bool { return s[i].Importpath < s[j].Importpath } 197 | func (s byImportpath) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 198 | -------------------------------------------------------------------------------- /README.old.md: -------------------------------------------------------------------------------- 1 | # gvt, the Go vendoring tool 2 | [](https://godoc.org/github.com/FiloSottile/gvt) 3 | [](https://travis-ci.org/FiloSottile/gvt) 4 | 5 | `gvt` is a simple vendoring tool made for Go native vendoring (aka 6 | [GO15VENDOREXPERIMENT](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo/edit)), 7 | based on [gb-vendor](https://github.com/constabulary/gb). 8 | 9 | It lets you easily and "idiomatically" include external dependencies in your repository to get 10 | reproducible builds. 11 | 12 | * No need to learn a new tool or format! 13 | You already know how to use `gvt`: just run `gvt fetch` when and like you would run `go get`. 14 | You can imagine what `gvt update` and `gvt delete` do. In addition, `gvt` [also allows](https://godoc.org/github.com/FiloSottile/gvt#hdr-Fetch_a_remote_dependency) 15 | fetching specific commits or branch versions in packages, and fully accommodates private repos. 16 | 17 | * No need to change how you build your project! 18 | `gvt` downloads packages to `./vendor/...`. The stock Go compiler will find and use those 19 | dependencies automatically without import path rewriting or GOPATH changes. 20 | (Go 1.6+, or Go 1.5 with `GO15VENDOREXPERIMENT=1` set required.) 21 | 22 | * No need to manually chase, copy or cleanup dependencies! 23 | `gvt` works recursively as you would expect, and lets you update vendored dependencies. It also 24 | writes a manifest to `./vendor/manifest` and never touches your system GOPATH. Finally, it 25 | strips the VCS metadata so that you can commit the vendored source cleanly. 26 | 27 | * No need for your users and occasional contributors to install **or even know about** gvt! 28 | Packages whose dependencies are vendored with `gvt` are `go build`-able and `go get`-able out of 29 | the box by Go 1.6+, or Go 1.5 with `GO15VENDOREXPERIMENT=1` set. 30 | 31 | *Note that projects must live within the GOPATH tree in order to be `go build`-able with native vendoring.* 32 | 33 | ## Installation 34 | 35 | With a [correctly configured](https://golang.org/doc/code.html#GOPATH) Go installation: 36 | 37 | ``` 38 | go get -u github.com/FiloSottile/gvt 39 | ``` 40 | 41 | ## Basic usage 42 | 43 | When you would use `go get`, just use `gvt fetch` instead. 44 | 45 | ``` 46 | $ gvt fetch github.com/fatih/color 47 | 2015/09/05 02:38:06 fetching recursive dependency github.com/mattn/go-isatty 48 | 2015/09/05 02:38:07 fetching recursive dependency github.com/shiena/ansicolor 49 | ``` 50 | 51 | `gvt fetch` downloads the dependency into the `vendor` folder. 52 | 53 | Files and folders starting with `.` or `_` are ignored. Only [files relevant to the Go compiler](https://golang.org/cmd/go/#hdr-File_types) are fetched. LICENSE files are always included, too. 54 | Test files and `testdata` folders can be included with `-t`. To include all files (except the repository metadata), use `-a`. 55 | 56 | ``` 57 | $ tree -d 58 | . 59 | └── vendor 60 | └── github.com 61 | ├── fatih 62 | │ └── color 63 | ├── mattn 64 | │ └── go-isatty 65 | └── shiena 66 | └── ansicolor 67 | └── ansicolor 68 | 69 | 9 directories 70 | ``` 71 | 72 | There's no step 2, you are ready to use the fetched dependency as you would normally do. 73 | 74 | (Requires Go 1.6+, or 1.5 with `GO15VENDOREXPERIMENT=1` set.) 75 | 76 | ``` 77 | $ cat > main.go 78 | package main 79 | import "github.com/fatih/color" 80 | func main() { 81 | color.Red("Hello, world!") 82 | } 83 | 84 | # Only needed with Go 1.5, vendoring is on by default in 1.6 85 | $ export GO15VENDOREXPERIMENT=1 86 | 87 | $ go build . 88 | $ ./hello 89 | Hello, world! 90 | ``` 91 | 92 | Finally, remember to check in and commit the `vendor` folder. 93 | 94 | ``` 95 | $ git add main.go vendor/ && git commit 96 | ``` 97 | 98 | ## Full usage 99 | 100 | `fetch` offers options to download specific versions, and there are `update`, `list` and `delete` commands that do what you would expect. 101 | 102 | View the full manual on GoDoc: https://godoc.org/github.com/FiloSottile/gvt 103 | 104 | ## Alternative: not checking in vendored source 105 | 106 | Some developers prefer not to check in the source of the vendored dependencies. In that case you can 107 | add lines like these to e.g. your `.gitignore` 108 | 109 | vendor/** 110 | !vendor/manifest 111 | 112 | When you check out the source again, you can then run `gvt restore` to fetch all the dependencies at 113 | the revisions specified in the `vendor/manifest` file. 114 | 115 | Please consider that this approach has the following consequences: 116 | 117 | * the package consumer will need gvt to fetch the dependencies 118 | * the dependencies will need to remain available from the source repositories: if the original 119 | repository goes down or rewrites history, build reproducibility is lost 120 | * `go get` won't work on your package 121 | * unless you pin the gvt version, bugs and unintended changes introduced in how `gvt restore` 122 | behaves can affect your build 123 | 124 | ## Vendoring a different fork 125 | 126 | You might have your own version of a repository (i.e. a fork) but still want to 127 | vendor it at the original import path. 128 | 129 | Since this is not a common use-case, there's no support in `gvt fetch` for it, 130 | however, you can manually edit the `vendor/manifest` file, changing `repository` 131 | and `revision`, and then run `gvt restore`. 132 | 133 | `gvt update` will stay on your fork. 134 | 135 | ## Overlapping dependencies 136 | 137 | Since in the current manifest, inherited from gb-vendor, a dependency includes 138 | all subpackages, it is possible to get conflicts in the form of overlapping dependencies. 139 | For example, if we had one version of example.com/a and a different one of example.com/a/b. 140 | 141 | To solve this cleanly, overlaps are disallowed. Subpackages of existing dependencies are 142 | silently treated as existing dependencies. Parents of existing dependencies are treated 143 | as missing and cause the subpackages to be deleted when they are fetched. 144 | 145 | This rule might be arbitrary, but it is required to have determinism in situations like 146 | recursive fetches, where the orders and priorities of fetches are undefined. 147 | If it causes incompatibilities, they were for the human to fix anyway. 148 | 149 | (There's an exception, if you want to nitpick, and it's that if you fetch a package at a revision, 150 | and its parent ends up being fetched by the recursive resolution, the parent will be fetched at 151 | the revision, not at master, because that's probably what you meant.) 152 | 153 | ## Troubleshooting 154 | 155 | ### `fatal: Not a git repository [...]` 156 | ### `error: tag 'fetch' not found.` 157 | 158 | These errors can occur because you have an alias for `gvt` pointing to `git verify-tag` 159 | (default if using oh-my-zsh). 160 | 161 | Recent versions of oh-my-zsh [removed the alias](https://github.com/robbyrussell/oh-my-zsh/pull/4841). You can update with `upgrade_oh_my_zsh`. 162 | 163 | Alternatively, run this, and preferably add it to your `~/.bashrc` / `~/.zshrc`: `unalias gvt`. 164 | 165 | ### `go build` can't find the vendored package 166 | 167 | Make sure you are using at least Go 1.5, set `GO15VENDOREXPERIMENT=1` if you 168 | are using Go 1.5 and didn't set `GO15VENDOREXPERIMENT=0` if you are using Go 1.6. 169 | 170 | Also note that native vendoring does not work outside the GOPATH source tree. 171 | That is, your project MUST be somewhere in a subfolder of `$GOPATH/src/`. 172 | 173 | ## License 174 | 175 | MIT licensed. See the LICENSE file for details. 176 | -------------------------------------------------------------------------------- /fetch.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/url" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/FiloSottile/gvt/fileutils" 13 | "github.com/FiloSottile/gvt/gbvendor" 14 | ) 15 | 16 | var ( 17 | branch string 18 | revision string // revision (commit) 19 | tag string 20 | noRecurse bool 21 | insecure bool // Allow the use of insecure protocols 22 | tests bool 23 | all bool 24 | ) 25 | 26 | func addFetchFlags(fs *flag.FlagSet) { 27 | fs.StringVar(&branch, "branch", "", "branch of the package") 28 | fs.StringVar(&revision, "revision", "", "revision of the package") 29 | fs.StringVar(&tag, "tag", "", "tag of the package") 30 | fs.BoolVar(&noRecurse, "no-recurse", false, "do not fetch recursively") 31 | fs.BoolVar(&insecure, "precaire", false, "allow the use of insecure protocols") 32 | fs.BoolVar(&tests, "t", false, "fetch _test.go files and testdata") 33 | fs.BoolVar(&all, "a", false, "fetch all files and subfolders") 34 | } 35 | 36 | var cmdFetch = &Command{ 37 | Name: "fetch", 38 | UsageLine: "fetch [-branch branch] [-revision rev | -tag tag] [-precaire] [-no-recurse] [-t|-a] importpath", 39 | Short: "fetch a remote dependency", 40 | Long: `fetch vendors an upstream import path. 41 | 42 | Recursive dependencies are fetched (at their master/tip/HEAD revision), unless they 43 | or their parent package are already present. 44 | 45 | If a subpackage of a dependency being fetched is already present, it will be deleted. 46 | 47 | The import path may include a url scheme. This may be useful when fetching dependencies 48 | from private repositories that cannot be probed. 49 | 50 | Flags: 51 | -t 52 | fetch also _test.go files and testdata. 53 | -a 54 | fetch all files and subfolders, ignoring ONLY .git, .hg and .bzr. 55 | -branch branch 56 | fetch from the named branch. Will also be used by gvt update. 57 | If not supplied the default upstream branch will be used. 58 | -no-recurse 59 | do not fetch recursively. 60 | -tag tag 61 | fetch the specified tag. 62 | -revision rev 63 | fetch the specific revision from the branch or repository. 64 | If no revision supplied, the latest available will be fetched. 65 | -precaire 66 | allow the use of insecure protocols. 67 | 68 | `, 69 | Run: func(args []string) error { 70 | switch len(args) { 71 | case 0: 72 | return fmt.Errorf("fetch: import path missing") 73 | case 1: 74 | path := args[0] 75 | return fetch(path) 76 | default: 77 | return fmt.Errorf("more than one import path supplied") 78 | } 79 | }, 80 | AddFlags: addFetchFlags, 81 | } 82 | 83 | var ( 84 | fetchRoot string // where the current session started 85 | rootRepoURL string // the url of the repo from which the root comes from 86 | fetchedToday []string // packages fetched during this session 87 | ) 88 | 89 | func fetch(path string) error { 90 | m, err := vendor.ReadManifest(manifestFile) 91 | if err != nil { 92 | return fmt.Errorf("could not load manifest: %v", err) 93 | } 94 | 95 | fetchRoot = stripscheme(path) 96 | return fetchRecursive(m, path, 0) 97 | } 98 | 99 | func fetchRecursive(m *vendor.Manifest, fullPath string, level int) error { 100 | path := stripscheme(fullPath) 101 | 102 | // Don't even bother the user about skipping packages we just fetched 103 | for _, p := range fetchedToday { 104 | if contains(p, path) { 105 | return nil 106 | } 107 | } 108 | 109 | // First, check if this or a parent is already vendored 110 | if m.HasImportpath(path) { 111 | if level == 0 { 112 | return fmt.Errorf("%s or a parent of it is already vendored", path) 113 | } else { 114 | // TODO: print a different message for packages fetched during this session 115 | logIndent(level, "Skipping (existing):", path) 116 | return nil 117 | } 118 | } 119 | 120 | // Next, check if we are trying to vendor from the same repository we are in 121 | if importPath != "" && contains(importPath, path) { 122 | if level == 0 { 123 | return fmt.Errorf("refusing to vendor a subpackage of \".\"") 124 | } else { 125 | logIndent(level, "Skipping (subpackage of \".\"):", path) 126 | return nil 127 | } 128 | } 129 | 130 | if level == 0 { 131 | log.Println("Fetching:", path) 132 | } else { 133 | logIndent(level, "Fetching recursive dependency:", path) 134 | } 135 | 136 | // Finally, check if we already vendored a subpackage and remove it 137 | for _, subp := range m.GetSubpackages(path) { 138 | if !contains(subp.Importpath, fetchRoot) { // ignore parents of the root 139 | ignore := false 140 | for _, d := range fetchedToday { 141 | if contains(d, subp.Importpath) { 142 | ignore = true // No need to warn the user if we just downloaded it 143 | } 144 | } 145 | if !ignore { 146 | logIndent(level, "Deleting existing subpackage to prevent overlap:", subp.Importpath) 147 | } 148 | } 149 | if err := m.RemoveDependency(subp); err != nil { 150 | return fmt.Errorf("failed to remove subpackage: %v", err) 151 | } 152 | } 153 | if err := fileutils.RemoveAll(filepath.Join(vendorDir, path)); err != nil && !os.IsNotExist(err) { 154 | return fmt.Errorf("failed to remove existing folder: %v", err) 155 | } 156 | 157 | // Find and download the repository 158 | 159 | repo, extra, err := GlobalDownloader.DeduceRemoteRepo(fullPath, insecure) 160 | if err != nil { 161 | return err 162 | } 163 | 164 | if level == 0 { 165 | rootRepoURL = repo.URL() 166 | } 167 | 168 | var wc vendor.WorkingCopy 169 | if repo.URL() == rootRepoURL { 170 | wc, err = GlobalDownloader.Get(repo, branch, tag, revision) 171 | } else { 172 | wc, err = GlobalDownloader.Get(repo, "", "", "") 173 | } 174 | if err != nil { 175 | return err 176 | } 177 | 178 | // Add the dependency to the manifest 179 | 180 | rev, err := wc.Revision() 181 | if err != nil { 182 | return err 183 | } 184 | 185 | b, err := wc.Branch() 186 | if err != nil { 187 | return err 188 | } 189 | 190 | dep := vendor.Dependency{ 191 | Importpath: path, 192 | Repository: repo.URL(), 193 | VCS: repo.Type(), 194 | Revision: rev, 195 | Branch: b, 196 | Path: extra, 197 | NoTests: !tests, 198 | AllFiles: all, 199 | } 200 | 201 | if err := m.AddDependency(dep); err != nil { 202 | return err 203 | } 204 | 205 | // Copy the code to the vendor folder 206 | 207 | dst := filepath.Join(vendorDir, dep.Importpath) 208 | src := filepath.Join(wc.Dir(), dep.Path) 209 | 210 | if err := fileutils.Copypath(dst, src, !dep.NoTests, dep.AllFiles); err != nil { 211 | return err 212 | } 213 | 214 | if err := fileutils.CopyLicense(dst, wc.Dir()); err != nil { 215 | return err 216 | } 217 | 218 | if err := vendor.WriteManifest(manifestFile, m); err != nil { 219 | return err 220 | } 221 | 222 | // Recurse 223 | 224 | fetchedToday = append(fetchedToday, path) 225 | 226 | if !noRecurse { 227 | // Look for dependencies in src, not going past wc.Dir() when looking for /vendor/, 228 | // knowing that wc.Dir() corresponds to rootRepoPath 229 | if !strings.HasSuffix(dep.Importpath, dep.Path) { 230 | return fmt.Errorf("unable to derive the root repo import path") 231 | } 232 | rootRepoPath := strings.TrimRight(strings.TrimSuffix(dep.Importpath, dep.Path), "/") 233 | deps, err := vendor.ParseImports(src, wc.Dir(), rootRepoPath, tests, all) 234 | if err != nil { 235 | return fmt.Errorf("failed to parse imports: %s", err) 236 | } 237 | 238 | for d := range deps { 239 | if strings.Index(d, ".") == -1 { // TODO: replace this silly heuristic 240 | continue 241 | } 242 | if err := fetchRecursive(m, d, level+1); err != nil { 243 | if strings.HasPrefix(err.Error(), "error fetching") { // I know, ok? 244 | return err 245 | } else { 246 | return fmt.Errorf("error fetching %s: %s", d, err) 247 | } 248 | } 249 | } 250 | } 251 | 252 | return nil 253 | } 254 | 255 | func logIndent(level int, v ...interface{}) { 256 | prefix := strings.Repeat("·", level) 257 | v = append([]interface{}{prefix}, v...) 258 | log.Println(v...) 259 | } 260 | 261 | // stripscheme removes any scheme components from url like paths. 262 | func stripscheme(path string) string { 263 | u, err := url.Parse(path) 264 | if err != nil { 265 | panic(err) 266 | } 267 | return u.Host + u.Path 268 | } 269 | 270 | // Package a contains package b? 271 | func contains(a, b string) bool { 272 | return a == b || strings.HasPrefix(b, a+"/") 273 | } 274 | -------------------------------------------------------------------------------- /vendor/golang.org/x/tools/cmd/goimports/goimports.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "errors" 11 | "flag" 12 | "fmt" 13 | "go/scanner" 14 | "io" 15 | "io/ioutil" 16 | "log" 17 | "os" 18 | "os/exec" 19 | "path/filepath" 20 | "runtime" 21 | "runtime/pprof" 22 | "strings" 23 | 24 | "golang.org/x/tools/imports" 25 | ) 26 | 27 | var ( 28 | // main operation modes 29 | list = flag.Bool("l", false, "list files whose formatting differs from goimport's") 30 | write = flag.Bool("w", false, "write result to (source) file instead of stdout") 31 | doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") 32 | srcdir = flag.String("srcdir", "", "choose imports as if source code is from `dir`. When operating on a single file, dir may instead be the complete file name.") 33 | verbose bool // verbose logging 34 | 35 | cpuProfile = flag.String("cpuprofile", "", "CPU profile output") 36 | memProfile = flag.String("memprofile", "", "memory profile output") 37 | memProfileRate = flag.Int("memrate", 0, "if > 0, sets runtime.MemProfileRate") 38 | 39 | options = &imports.Options{ 40 | TabWidth: 8, 41 | TabIndent: true, 42 | Comments: true, 43 | Fragment: true, 44 | } 45 | exitCode = 0 46 | ) 47 | 48 | func init() { 49 | flag.BoolVar(&options.AllErrors, "e", false, "report all errors (not just the first 10 on different lines)") 50 | flag.StringVar(&imports.LocalPrefix, "local", "", "put imports beginning with this string after 3rd-party packages") 51 | } 52 | 53 | func report(err error) { 54 | scanner.PrintError(os.Stderr, err) 55 | exitCode = 2 56 | } 57 | 58 | func usage() { 59 | fmt.Fprintf(os.Stderr, "usage: goimports [flags] [path ...]\n") 60 | flag.PrintDefaults() 61 | os.Exit(2) 62 | } 63 | 64 | func isGoFile(f os.FileInfo) bool { 65 | // ignore non-Go files 66 | name := f.Name() 67 | return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") 68 | } 69 | 70 | // argumentType is which mode goimports was invoked as. 71 | type argumentType int 72 | 73 | const ( 74 | // fromStdin means the user is piping their source into goimports. 75 | fromStdin argumentType = iota 76 | 77 | // singleArg is the common case from editors, when goimports is run on 78 | // a single file. 79 | singleArg 80 | 81 | // multipleArg is when the user ran "goimports file1.go file2.go" 82 | // or ran goimports on a directory tree. 83 | multipleArg 84 | ) 85 | 86 | func processFile(filename string, in io.Reader, out io.Writer, argType argumentType) error { 87 | opt := options 88 | if argType == fromStdin { 89 | nopt := *options 90 | nopt.Fragment = true 91 | opt = &nopt 92 | } 93 | 94 | if in == nil { 95 | f, err := os.Open(filename) 96 | if err != nil { 97 | return err 98 | } 99 | defer f.Close() 100 | in = f 101 | } 102 | 103 | src, err := ioutil.ReadAll(in) 104 | if err != nil { 105 | return err 106 | } 107 | 108 | target := filename 109 | if *srcdir != "" { 110 | // Determine whether the provided -srcdirc is a directory or file 111 | // and then use it to override the target. 112 | // 113 | // See https://github.com/dominikh/go-mode.el/issues/146 114 | if isFile(*srcdir) { 115 | if argType == multipleArg { 116 | return errors.New("-srcdir value can't be a file when passing multiple arguments or when walking directories") 117 | } 118 | target = *srcdir 119 | } else if argType == singleArg && strings.HasSuffix(*srcdir, ".go") && !isDir(*srcdir) { 120 | // For a file which doesn't exist on disk yet, but might shortly. 121 | // e.g. user in editor opens $DIR/newfile.go and newfile.go doesn't yet exist on disk. 122 | // The goimports on-save hook writes the buffer to a temp file 123 | // first and runs goimports before the actual save to newfile.go. 124 | // The editor's buffer is named "newfile.go" so that is passed to goimports as: 125 | // goimports -srcdir=/gopath/src/pkg/newfile.go /tmp/gofmtXXXXXXXX.go 126 | // and then the editor reloads the result from the tmp file and writes 127 | // it to newfile.go. 128 | target = *srcdir 129 | } else { 130 | // Pretend that file is from *srcdir in order to decide 131 | // visible imports correctly. 132 | target = filepath.Join(*srcdir, filepath.Base(filename)) 133 | } 134 | } 135 | 136 | res, err := imports.Process(target, src, opt) 137 | if err != nil { 138 | return err 139 | } 140 | 141 | if !bytes.Equal(src, res) { 142 | // formatting has changed 143 | if *list { 144 | fmt.Fprintln(out, filename) 145 | } 146 | if *write { 147 | err = ioutil.WriteFile(filename, res, 0) 148 | if err != nil { 149 | return err 150 | } 151 | } 152 | if *doDiff { 153 | data, err := diff(src, res) 154 | if err != nil { 155 | return fmt.Errorf("computing diff: %s", err) 156 | } 157 | fmt.Printf("diff %s gofmt/%s\n", filename, filename) 158 | out.Write(data) 159 | } 160 | } 161 | 162 | if !*list && !*write && !*doDiff { 163 | _, err = out.Write(res) 164 | } 165 | 166 | return err 167 | } 168 | 169 | func visitFile(path string, f os.FileInfo, err error) error { 170 | if err == nil && isGoFile(f) { 171 | err = processFile(path, nil, os.Stdout, multipleArg) 172 | } 173 | if err != nil { 174 | report(err) 175 | } 176 | return nil 177 | } 178 | 179 | func walkDir(path string) { 180 | filepath.Walk(path, visitFile) 181 | } 182 | 183 | func main() { 184 | runtime.GOMAXPROCS(runtime.NumCPU()) 185 | 186 | // call gofmtMain in a separate function 187 | // so that it can use defer and have them 188 | // run before the exit. 189 | gofmtMain() 190 | os.Exit(exitCode) 191 | } 192 | 193 | // parseFlags parses command line flags and returns the paths to process. 194 | // It's a var so that custom implementations can replace it in other files. 195 | var parseFlags = func() []string { 196 | flag.BoolVar(&verbose, "v", false, "verbose logging") 197 | 198 | flag.Parse() 199 | return flag.Args() 200 | } 201 | 202 | func bufferedFileWriter(dest string) (w io.Writer, close func()) { 203 | f, err := os.Create(dest) 204 | if err != nil { 205 | log.Fatal(err) 206 | } 207 | bw := bufio.NewWriter(f) 208 | return bw, func() { 209 | if err := bw.Flush(); err != nil { 210 | log.Fatalf("error flushing %v: %v", dest, err) 211 | } 212 | if err := f.Close(); err != nil { 213 | log.Fatal(err) 214 | } 215 | } 216 | } 217 | 218 | func gofmtMain() { 219 | flag.Usage = usage 220 | paths := parseFlags() 221 | 222 | if *cpuProfile != "" { 223 | bw, flush := bufferedFileWriter(*cpuProfile) 224 | pprof.StartCPUProfile(bw) 225 | defer flush() 226 | defer pprof.StopCPUProfile() 227 | } 228 | // doTrace is a conditionally compiled wrapper around runtime/trace. It is 229 | // used to allow goimports to compile under gccgo, which does not support 230 | // runtime/trace. See https://golang.org/issue/15544. 231 | defer doTrace()() 232 | if *memProfileRate > 0 { 233 | runtime.MemProfileRate = *memProfileRate 234 | bw, flush := bufferedFileWriter(*memProfile) 235 | defer func() { 236 | runtime.GC() // materialize all statistics 237 | if err := pprof.WriteHeapProfile(bw); err != nil { 238 | log.Fatal(err) 239 | } 240 | flush() 241 | }() 242 | } 243 | 244 | if verbose { 245 | log.SetFlags(log.LstdFlags | log.Lmicroseconds) 246 | imports.Debug = true 247 | } 248 | if options.TabWidth < 0 { 249 | fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", options.TabWidth) 250 | exitCode = 2 251 | return 252 | } 253 | 254 | if len(paths) == 0 { 255 | if err := processFile("