Skip to content

Commit

Permalink
Merge pull request #36 from dnephin/relative-path-with-go-mod
Browse files Browse the repository at this point in the history
Support relative pkg paths with go modules
  • Loading branch information
dnephin committed Dec 8, 2018
2 parents 795813a + ec29767 commit a9981c9
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 39 deletions.
126 changes: 126 additions & 0 deletions testjson/pkgpathprefix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package testjson

import (
"bytes"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)

func relativePackagePath(pkgpath string) string {
if pkgpath == pkgPathPrefix {
return "."
}
return strings.TrimPrefix(pkgpath, pkgPathPrefix+"/")
}

func getPkgPathPrefix() string {
cwd, _ := os.Getwd()
if isGoModuleEnabled() {
prefix := getPkgPathPrefixFromGoModule(cwd)
if prefix != "" {
return prefix
}
}
return getPkgPathPrefixGoPath(cwd)
}

func isGoModuleEnabled() bool {
version := runtime.Version()
if strings.HasPrefix(version, "go1.10") {
return false
}
// Go modules may not be enabled if env var is unset, or set to auto, however
// we can always fall back to using GOPATH as the prefix if a go.mod is not
// found.
return os.Getenv("GO111MODULE") != "off"
}

// TODO: might not work on windows
func getPkgPathPrefixGoPath(cwd string) string {
gopaths := strings.Split(build.Default.GOPATH, string(filepath.ListSeparator))
for _, gopath := range gopaths {
gosrcpath := gopath + "/src/"
if strings.HasPrefix(cwd, gosrcpath) {
return strings.TrimPrefix(cwd, gosrcpath)
}
}
return ""
}

func getPkgPathPrefixFromGoModule(cwd string) string {
filename := goModuleFilePath(cwd)
if filename == "" {
return ""
}
raw, err := ioutil.ReadFile(filename)
if err != nil {
// TODO: log.Warn
return ""
}
return pkgPathFromGoModuleFile(raw)
}

var (
slashSlash = []byte("//")
moduleStr = []byte("module")
)

// Copy of ModulePath from golang.org/src/cmd/go/internal/modfile/read.go
func pkgPathFromGoModuleFile(mod []byte) string {
for len(mod) > 0 {
line := mod
mod = nil
if i := bytes.IndexByte(line, '\n'); i >= 0 {
line, mod = line[:i], line[i+1:]
}
if i := bytes.Index(line, slashSlash); i >= 0 {
line = line[:i]
}
line = bytes.TrimSpace(line)
if !bytes.HasPrefix(line, moduleStr) {
continue
}
line = line[len(moduleStr):]
n := len(line)
line = bytes.TrimSpace(line)
if len(line) == n || len(line) == 0 {
continue
}

if line[0] == '"' || line[0] == '`' {
p, err := strconv.Unquote(string(line))
if err != nil {
return "" // malformed quoted string or multi-line module path
}
return p
}

return string(line)
}
return "" // missing module path
}

// A rough re-implementation of FindModuleRoot from
// golang.org/src/cmd/go/internal/modload/init.go
func goModuleFilePath(cwd string) string {
dir := filepath.Clean(cwd)

for {
path := filepath.Join(dir, "go.mod")
if _, err := os.Stat(path); err == nil {
return path
}
parent := filepath.Dir(dir)
if parent == dir {
return ""
}
dir = parent
}
}

var pkgPathPrefix = getPkgPathPrefix()
29 changes: 29 additions & 0 deletions testjson/pkgpathprefix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package testjson

import (
"testing"

"gotest.tools/assert"
"gotest.tools/skip"
)

func TestRelativePackagePath(t *testing.T) {
prefix := "gotest.tools/gotestsum/testjson"
defer patchPkgPathPrefix(prefix)()
relPath := relativePackagePath(prefix + "/extra/relpath")
assert.Equal(t, relPath, "extra/relpath")

relPath = relativePackagePath(prefix)
assert.Equal(t, relPath, ".")
}

func TestGetPkgPathPrefix(t *testing.T) {
t.Run("with go path", func(t *testing.T) {
skip.If(t, isGoModuleEnabled())
assert.Equal(t, getPkgPathPrefix(), "gotest.tools/gotestsum/testjson")
})
t.Run("with go modules", func(t *testing.T) {
skip.If(t, !isGoModuleEnabled())
assert.Equal(t, getPkgPathPrefix(), "gotest.tools/gotestsum")
})
}
25 changes: 0 additions & 25 deletions testjson/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package testjson

import (
"fmt"
"go/build"
"os"
"path/filepath"
"strings"

"github.com/fatih/color"
Expand Down Expand Up @@ -157,28 +154,6 @@ func colorEvent(event TestEvent) func(format string, a ...interface{}) string {
return color.WhiteString
}

func relativePackagePath(pkgpath string) string {
if pkgpath == pkgPathPrefix {
return "."
}
return strings.TrimPrefix(pkgpath, pkgPathPrefix+"/")
}

// TODO: might not work on windows
func getPkgPathPrefix() string {
cwd, _ := os.Getwd()
gopaths := strings.Split(build.Default.GOPATH, string(filepath.ListSeparator))
for _, gopath := range gopaths {
gosrcpath := gopath + "/src/"
if strings.HasPrefix(cwd, gosrcpath) {
return strings.TrimPrefix(cwd, gosrcpath)
}
}
return ""
}

var pkgPathPrefix = getPkgPathPrefix()

// NewEventFormatter returns a formatter for printing events.
func NewEventFormatter(format string) EventFormatter {
switch format {
Expand Down
14 changes: 0 additions & 14 deletions testjson/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,6 @@ func patchPkgPathPrefix(val string) func() {
return func() { pkgPathPrefix = oldVal }
}

func TestRelativePackagePath(t *testing.T) {
relPath := relativePackagePath(
"gotest.tools/gotestsum/testjson/extra/relpath")
assert.Equal(t, relPath, "extra/relpath")

relPath = relativePackagePath(
"gotest.tools/gotestsum/testjson")
assert.Equal(t, relPath, ".")
}

func TestGetPkgPathPrefix(t *testing.T) {
assert.Equal(t, pkgPathPrefix, "gotest.tools/gotestsum/testjson")
}

func TestScanTestOutputWithShortVerboseFormat(t *testing.T) {
defer patchPkgPathPrefix("github.com/gotestyourself/gotestyourself")()

Expand Down

0 comments on commit a9981c9

Please sign in to comment.