Skip to content

Commit

Permalink
add gomod support
Browse files Browse the repository at this point in the history
  • Loading branch information
3Xpl0it3r committed Sep 30, 2022
1 parent 647a43f commit 23f8fe5
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 90 deletions.
106 changes: 66 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
## fork from: https://github.com/haya14busa/gopkgs

## gopkgs - List Go packages FAST by using the same implementation as [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports)

[![Travis Build Status](https://travis-ci.org/haya14busa/gopkgs.svg?branch=master)](https://travis-ci.org/haya14busa/gopkgs)
[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/9tr7p8hclfypvwun?svg=true)](https://ci.appveyor.com/project/haya14busa/gopkgs)
[![Releases](https://img.shields.io/github/tag/haya14busa/gopkgs.svg)](https://github.com/haya14busa/gopkgs/releases)

[![Travis Build Status](https://travis-ci.org/3Xpl0it3r/gopkgs.svg?branch=master)](https://travis-ci.org/3Xpl0it3r/gopkgs)
[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/9tr7p8hclfypvwun?svg=true)](https://ci.appveyor.com/project/3Xpl0it3r/gopkgs)
[![Releases](https://img.shields.io/github/tag/3Xpl0it3r/gopkgs.svg)](https://github.com/3Xpl0it3r/gopkgs/releases)
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![GoDoc](https://godoc.org/github.com/haya14busa/gopkgs?status.svg)](https://godoc.org/github.com/haya14busa/gopkgs)
[![GoDoc](https://godoc.org/github.com/3Xpl0it3r/gopkgs?status.svg)](https://godoc.org/github.com/3Xpl0it3r/gopkgs)

gopkgs outputs list of importable Go packages.

Expand All @@ -14,69 +17,92 @@ it's faster than [go list ...](https://golang.org/cmd/go/#hdr-List_packages) and
gopkgs cares .goimportsignore which was introduced by https://github.com/golang/go/issues/16386
since it uses the same implementation as [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports).

![gopkgs_usage.gif (890×542)](https://raw.githubusercontent.com/haya14busa/i/3bdf4c81118c4f0261073a7f3144903623240edc/gopkgs/gopkgs_usage.gif)
![gopkgs_usage.gif (890×542)](https://raw.githubusercontent.com/3Xpl0it3r/i/3bdf4c81118c4f0261073a7f3144903623240edc/gopkgs/gopkgs_usage.gif)
Sample usage of gopkgs with other tools like [godoc](https://godoc.org/golang.org/x/tools/cmd/godoc) and filtering tools ([peco](https://github.com/peco/peco)).

Here I modified some code, add some functionnal code for gomod support , also remove many code for some functionnal are unnecessary when we writing code with vim/nvim.


### Installation

#### Install Binary from GitHub Releases

https://github.com/haya14busa/gopkgs/releases
https://github.com/3Xpl0it3r/gopkgs/releases

#### go get

```
go get -u github.com/haya14busa/gopkgs/cmd/gopkgs
go get -u github.com/3Xpl0it3r/gopkgs/cmd/gopkgs
```

### SYNOPSIS

> In fact we don't need this to list all importpakcage. You may need use `go list ./...` for this ;
> This tools should be used with neovim for `go list ` are too slow.
```
$ gopkgs -h
➜ gopkgs git:(master) gopkgs -h
Usage of gopkgs:
-f string
alternate format for the output using the syntax of template package. e.g. {{.Name}};{{ImportPathShort}}
-fullpath
output absolute file path to package directory. ("/usr/lib/go/src/net/http")
-include-name
fill Pkg.Name which can be used with -f flag
-short
output vendorless import path ("net/http", "foo/bar/vendor/a/b") (default true)
fill Pkg.Name which can be used with -f flag
-no-vendor
exclude vendor dependencies except under workDir
Use -f to custom the output using template syntax. The struct being passed to template is:
type Pkg struct {
Dir string // absolute file path to Pkg directory ("/usr/lib/go/src/net/http")
ImportPath string // full Pkg import path ("net/http", "foo/bar/vendor/a/b")
ImportPathShort string // vendorless import path ("net/http", "a/b")
type Pkg struct {
Dir string // absolute file path to Pkg directory ("/usr/lib/go/src/net/http")
ImportPath string // full Pkg import path ("net/http", "foo/bar/vendor/a/b")
ImportPathShort string // vendorless import path ("net/http", "a/b")
// It can be empty. It's filled only when -include-name flag is true.
Name string // package name ("http")
}
// It can be empty. It's filled only when -include-name flag is true.
Name string // package name ("http")
}
```

### Vim

![gopkgs_vim.gif (890×542)](https://raw.githubusercontent.com/haya14busa/i/3bdf4c81118c4f0261073a7f3144903623240edc/gopkgs/gopkgs_vim.gif)

Sample usage of gopkgs in Vim: open godoc and import with [vim-go](https://github.com/fatih/vim-go) and [fzf](https://github.com/junegunn/fzf)
![](./images/vim.png)
```lua
function _G._Go_Package_Complete()
local get_pkgs = function()
local results = {}
local list_pkg = io.popen("gopkgs"):read("*all")
for line in list_pkg:gmatch("[^\n\r]+") do
table.insert(results, line)
end
return results
end

local co = coroutine.create(function()
local selectco = assert(coroutine.running(), 'main thread!')
local items = get_pkgs()
vim.ui.select(items, { prompt = "Import Packages Path" }, function(choice)
coroutine.resume(selectco, choice)
end)
local value = coroutine.yield()
-- if cancel when select , then skip the following step, only return
if (value == nil or value == '') then
return
end

local inputco = coroutine.running()
vim.ui.input({ prompt = "Input Alias Pkg Name:" }, function(input)
coroutine.resume(inputco, input)
end)
local aliase = coroutine.yield()

local pos = vim.api.nvim_win_get_cursor(0)[2]
local line = vim.api.nvim_get_current_line()
local next_line = line:sub(0, pos + 1) .. "\t" .. aliase .. "\"" .. value .. "\"" .. line:sub(pos + 2)
vim.api.nvim_set_current_line(next_line)
vim.lsp.buf.formatting()
end)
coroutine.resume(co)
end

vim.keymap.set("n", "<leader>lI", "<cmd>lua _Go_Package_Complete()<cr>", { desc = "Import Package" })

```vim
augroup gopkgs
autocmd!
autocmd FileType go command! -buffer Import exe 'GoImport' fzf#run({'source': 'gopkgs'})[0]
autocmd FileType go command! -buffer Doc exe 'GoDoc' fzf#run({'source': 'gopkgs'})[0]
augroup END
```

Above Vim script is just a sample and isn't robust. I'm planning to create or contribute Vim plugins to include the same feature.

- https://github.com/rhysd/unite-go-import.vim
- [unite.vim](https://github.com/Shougo/unite.vim) (and
[vim-go](https://github.com/fatih/vim-go)) intergration for importing
package or opening godoc in Vim.

### LICENSE

[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
Expand Down
38 changes: 4 additions & 34 deletions cmd/gopkgs/main.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
package main

import (
"bufio"
"flag"
"fmt"
"github.com/3Xpl0it3r/gopkgs"
"os"
"sort"
"strings"
"text/template"
)

var (
fullpath = flag.Bool("fullpath", false, `output absolute file path to package directory. ("/usr/lib/go/src/net/http")`)
short = flag.Bool("short", true, `output vendorless import path ("net/http", "foo/bar/vendor/a/b")`)
f = flag.String("f", "", "alternate format for the output using the syntax of template package. e.g. {{.Name}};{{ImportPathShort}}")
includeName = flag.Bool("include-name", false, "fill Pkg.Name which can be used with -f flag")
noVendor = flag.Bool("no-vendor", false, "exclude vendor dependencies except under workDir ")
)
Expand Down Expand Up @@ -105,39 +100,14 @@ func main() {
os.Exit(2)
}

tplFormat := "{{.ImportPath}}"
if *f != "" {
tplFormat = *f
} else if *fullpath {
tplFormat = "{{.Dir}}"
} else if *short {
tplFormat = "{{.ImportPathShort}}"
}

tpl, err := template.New("out").Parse(tplFormat)
if err != nil {
fmt.Fprintln(os.Stderr)
os.Exit(2)
}

w := bufio.NewWriter(os.Stdout)
defer w.Flush()
opt := gopkgs.DefaultOption()
opt.IncludeName = *includeName
pkgs := gopkgs.Packages(opt)
if *fullpath {
sort.Sort(ByFullPath(pkgs))
// Fullpaths is already unique
} else if *short {
sort.Sort(ByShortPath(pkgs))
pkgs = uniq(pkgs, func(p *gopkgs.Pkg) string { return p.ImportPathShort })
} else {
sort.Sort(ByPath(pkgs))
pkgs = uniq(pkgs, func(p *gopkgs.Pkg) string { return p.ImportPath })
}

sort.Sort(ByPath(pkgs))
pkgs = uniq(pkgs, func(p *gopkgs.Pkg) string { return p.ImportPath })

for _, pkg := range pkgs {
tpl.Execute(w, pkg)
fmt.Fprintln(w)
fmt.Fprintln(os.Stdout, pkg.ImportPathShort)
}
}
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/3Xpl0it3r/gopkgs

go 1.18

require golang.org/x/tools v0.1.12 // indirect
require (
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/tools v0.1.12
)
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
Binary file added images/vim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 27 additions & 15 deletions x/tools/imports/fix.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"go/build"
"go/parser"
"go/token"
"golang.org/x/mod/modfile"
"io/ioutil"
"log"
"os"
Expand Down Expand Up @@ -492,28 +493,38 @@ var scanGoRootDone = make(chan struct{}) // closed when scanGoRoot is done

func scanGoRoot() {
go func() {
scanGoDirs(true, nil)
scanGoDirs(true, "", nil)
close(scanGoRootDone)
}()
}

func scanGoPath() { scanGoDirs(false, nil) }
func scanGoPath() { scanGoDirs(false, "", nil) }

func scanGoMod() {
curDir, err := os.Getwd()
if err != nil {
return
}
if rootDir, ok := findGoModPath(curDir); ok {
scanGoDirs(false, []string{rootDir})
rootDir, ok := findGoModPath(curDir)
if !ok {
return
}
fileRaw, err := ioutil.ReadFile(path.Join(rootDir, "go.mod"))
if err != nil {
return
}
f, err := modfile.Parse("go.mod", fileRaw, nil)
if err != nil {
panic(err)
}
scanGoDirs(false, f.Module.Mod.String(), []string{rootDir})
}

func scanGoWorkspace() {

}

func scanGoDirs(goRoot bool, extPath []string) {
func scanGoDirs(goRoot bool, goMod string, extPath []string) {
if Debug {
which := "$GOROOT"
if !goRoot {
Expand Down Expand Up @@ -556,9 +567,13 @@ func scanGoDirs(goRoot bool, extPath []string) {
if _, dup := dirScan[dir]; !dup {
importpath := filepath.ToSlash(dir[len(srcDir)+len("/"):])
dirScan[dir] = &pkg{
importPath: importpath,
importPathShort: vendorlessImportPath(importpath),
dir: dir,
importPath: importpath,
dir: dir,
}
if importPathShort, isVendor := vendorlessImportPath(importpath); isVendor || goMod == "" {
dirScan[dir].importPathShort = importPathShort
} else {
dirScan[dir].importPathShort = goMod + "/" + importPathShort
}
}
dirScanMu.Unlock()
Expand Down Expand Up @@ -604,15 +619,15 @@ func scanGoDirs(goRoot bool, extPath []string) {

// vendorlessImportPath returns the devendorized version of the provided import path.
// e.g. "foo/bar/vendor/a/b" => "a/b"
func vendorlessImportPath(ipath string) string {
func vendorlessImportPath(ipath string) (string, bool) {
// Devendorize for use in import statement.
if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
return ipath[i+len("/vendor/"):]
return ipath[i+len("/vendor/"):], true
}
if strings.HasPrefix(ipath, "vendor/") {
return ipath[len("vendor/"):]
return ipath[len("vendor/"):], true
}
return ipath
return ipath, false
}

// loadExports returns the set of exported symbols in the package at dir.
Expand Down Expand Up @@ -1012,9 +1027,6 @@ func findGoModPath(path string) (string, bool) {
if strings.Compare(fi.Name(), "go.mod") == 0 {
return path, true
}
if strings.Compare(fi.Name(), ".git") == 0 {
return path, true
}
}
return findGoModPath(getParentDirectory(path))
}
Expand Down

0 comments on commit 23f8fe5

Please sign in to comment.