support for modules inside GOPATH
Этот коммит содержится в:
родитель
722f647346
коммит
d3842ecb6a
2 изменённых файлов: 59 добавлений и 76 удалений
132
builder_go110.go
132
builder_go110.go
|
@ -47,6 +47,25 @@ func main() {
|
||||||
}`))
|
}`))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type module struct {
|
||||||
|
Path, Dir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *module) match(name string) *build.Package {
|
||||||
|
if strings.Index(name, mod.Path) == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
suffix := strings.Replace(name, mod.Path, "", 1)
|
||||||
|
add := strings.Replace(suffix, "/", string(filepath.Separator), -1)
|
||||||
|
pkg, err := build.ImportDir(mod.Dir+add, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
// Build creates a test package like go test command at given target path.
|
// Build creates a test package like go test command at given target path.
|
||||||
// If there are no go files in tested directory, then
|
// If there are no go files in tested directory, then
|
||||||
// it simply builds a godog executable to scan features.
|
// it simply builds a godog executable to scan features.
|
||||||
|
@ -79,21 +98,13 @@ func Build(bin string) error {
|
||||||
// if none of test files exist, or there are no contexts found
|
// if none of test files exist, or there are no contexts found
|
||||||
// we will skip test package compilation, since it is useless
|
// we will skip test package compilation, since it is useless
|
||||||
if anyContexts {
|
if anyContexts {
|
||||||
// first of all compile test package dependencies
|
|
||||||
// that will save us many compilations for dependencies
|
|
||||||
// go does it better
|
|
||||||
out, err := exec.Command("go", "test", "-i").CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to compile package: %s, reason: %v, output: %s", pkg.Name, err, string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
// build and compile the tested package.
|
// build and compile the tested package.
|
||||||
// generated test executable will be removed
|
// generated test executable will be removed
|
||||||
// since we do not need it for godog suite.
|
// since we do not need it for godog suite.
|
||||||
// we also print back the temp WORK directory
|
// we also print back the temp WORK directory
|
||||||
// go has built. We will reuse it for our suite workdir.
|
// go has built. We will reuse it for our suite workdir.
|
||||||
temp := fmt.Sprintf(filepath.Join("%s", "temp-%d.test"), os.TempDir(), time.Now().UnixNano())
|
temp := fmt.Sprintf(filepath.Join("%s", "temp-%d.test"), os.TempDir(), time.Now().UnixNano())
|
||||||
out, err = exec.Command("go", "test", "-c", "-work", "-o", temp).CombinedOutput()
|
out, err := exec.Command("go", "test", "-c", "-work", "-o", temp).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to compile tested package: %s, reason: %v, output: %s", pkg.Name, err, string(out))
|
return fmt.Errorf("failed to compile tested package: %s, reason: %v, output: %s", pkg.Name, err, string(out))
|
||||||
}
|
}
|
||||||
|
@ -141,26 +152,13 @@ func Build(bin string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// godog library may not be imported in tested package
|
mods := readModules()
|
||||||
// but we need it for our testmain package.
|
// if it was not located as module
|
||||||
godogPkg := locateModule(godogImportPath)
|
// we look it up in available source paths
|
||||||
if godogPkg == nil {
|
// including vendor directory, supported since 1.5.
|
||||||
// if it was not located as module
|
godogPkg, err := locatePackage(godogImportPath, mods)
|
||||||
// we look it up in available source paths
|
|
||||||
// including vendor directory, supported since 1.5.
|
|
||||||
godogPkg, err = locatePackage(godogImportPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure godog package archive is installed, gherkin
|
|
||||||
// will be installed as dependency of godog
|
|
||||||
cmd := exec.Command("go", "install", "-i", godogPkg.ImportPath)
|
|
||||||
cmd.Env = os.Environ()
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to install godog package: %s, reason: %v", string(out), err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile godog testmain package archive
|
// compile godog testmain package archive
|
||||||
|
@ -184,7 +182,7 @@ func Build(bin string) error {
|
||||||
fmt.Fprintln(in, "# import config")
|
fmt.Fprintln(in, "# import config")
|
||||||
|
|
||||||
deps := make(map[string]string)
|
deps := make(map[string]string)
|
||||||
if err := dependencies(godogPkg, deps, false); err != nil {
|
if err := dependencies(godogPkg, mods, deps, false); err != nil {
|
||||||
in.Close()
|
in.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -204,11 +202,11 @@ func Build(bin string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
deps := make(map[string]string)
|
deps := make(map[string]string)
|
||||||
if err := dependencies(pkg, deps, true); err != nil {
|
if err := dependencies(pkg, mods, deps, true); err != nil {
|
||||||
in.Close()
|
in.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := dependencies(godogPkg, deps, false); err != nil {
|
if err := dependencies(godogPkg, mods, deps, false); err != nil {
|
||||||
in.Close()
|
in.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -222,9 +220,9 @@ func Build(bin string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args, "-pack", testmain)
|
args = append(args, "-pack", testmain)
|
||||||
cmd = exec.Command(compiler, args...)
|
cmd := exec.Command(compiler, args...)
|
||||||
cmd.Env = os.Environ()
|
cmd.Env = os.Environ()
|
||||||
out, err = cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to compile testmain package: %v - output: %s", err, string(out))
|
return fmt.Errorf("failed to compile testmain package: %v - output: %s", err, string(out))
|
||||||
}
|
}
|
||||||
|
@ -268,13 +266,22 @@ func Build(bin string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func locatePackage(name string) (*build.Package, error) {
|
func locatePackage(name string, mods []*module) (*build.Package, error) {
|
||||||
// search vendor paths first since that takes priority
|
// search vendor paths first since that takes priority
|
||||||
dir, err := filepath.Abs(".")
|
dir, err := filepath.Abs(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first of all check modules
|
||||||
|
if mods != nil {
|
||||||
|
for _, mod := range mods {
|
||||||
|
if pkg := mod.match(name); pkg != nil {
|
||||||
|
return pkg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, gopath := range gopaths {
|
for _, gopath := range gopaths {
|
||||||
gopath = filepath.Join(gopath, "src")
|
gopath = filepath.Join(gopath, "src")
|
||||||
for strings.HasPrefix(dir, gopath) && dir != gopath {
|
for strings.HasPrefix(dir, gopath) && dir != gopath {
|
||||||
|
@ -435,7 +442,7 @@ func findToolDir() string {
|
||||||
return filepath.Clean(build.ToolDir)
|
return filepath.Clean(build.ToolDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dependencies(pkg *build.Package, visited map[string]string, vendor bool) error {
|
func dependencies(pkg *build.Package, mods []*module, visited map[string]string, vendor bool) error {
|
||||||
visited[pkg.ImportPath] = pkg.PkgObj
|
visited[pkg.ImportPath] = pkg.PkgObj
|
||||||
imports := pkg.Imports
|
imports := pkg.Imports
|
||||||
if vendor {
|
if vendor {
|
||||||
|
@ -449,60 +456,35 @@ func dependencies(pkg *build.Package, visited map[string]string, vendor bool) er
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
next := locateModule(name) // module takes priority
|
next, err := locatePackage(name, mods)
|
||||||
if next == nil {
|
if err != nil {
|
||||||
var err error
|
return err
|
||||||
next, err = locatePackage(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visited[name] = pkg.PkgObj
|
visited[name] = pkg.PkgObj
|
||||||
if err := dependencies(next, visited, vendor); err != nil {
|
if err := dependencies(next, mods, visited, vendor); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func locateModule(name string) *build.Package {
|
func readModules() []*module {
|
||||||
// for module support, query the module import path
|
// for module support, query the module import path
|
||||||
cmd := exec.Command("go", "mod", "download", "-json")
|
out, err := exec.Command("go", "mod", "download", "-json").Output()
|
||||||
out, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Unable to read stdout
|
// Unable to read stdout
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if cmd.Start() != nil {
|
|
||||||
// Does not using modules
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type module struct {
|
var mods []*module
|
||||||
Dir string
|
reader := json.NewDecoder(bytes.NewReader(out))
|
||||||
Path string
|
for {
|
||||||
|
var mod *module
|
||||||
|
if err := reader.Decode(&mod); err != nil {
|
||||||
|
break // might be also EOF
|
||||||
|
}
|
||||||
|
mods = append(mods, mod)
|
||||||
}
|
}
|
||||||
|
return mods
|
||||||
var mod *module
|
|
||||||
if err := json.NewDecoder(out).Decode(&mod); err != nil {
|
|
||||||
// Unexpected result
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if cmd.Wait() != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Index(name, mod.Path) == -1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
suffix := strings.Replace(name, mod.Path, "", 1)
|
|
||||||
add := strings.Replace(suffix, "/", string(filepath.Separator), -1)
|
|
||||||
pkg, err := build.ImportDir(mod.Dir+add, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkg
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,8 @@ var builderMainCodeFile = `package main
|
||||||
// Godogs available to eat
|
// Godogs available to eat
|
||||||
var Godogs int
|
var Godogs int
|
||||||
|
|
||||||
func main() { /* usual main func */ }
|
func main() {
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func buildTestPackage(dir, feat, src, testSrc string) error {
|
func buildTestPackage(dir, feat, src, testSrc string) error {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче