@@ -26,13 +26,14 @@ import (
2626 "go/token"
2727 "io/ioutil"
2828 "log"
29+ "os"
2930 "path"
3031 "path/filepath"
3132 "strconv"
3233 "strings"
3334
3435 "github.com/golang/mock/mockgen/model"
35- "golang.org/x/tools/go/packages "
36+ "golang.org/x/mod/modfile "
3637)
3738
3839var (
@@ -49,7 +50,7 @@ func sourceMode(source string) (*model.Package, error) {
4950 return nil , fmt .Errorf ("failed getting source directory: %v" , err )
5051 }
5152
52- packageImport , err := parsePackageImport (source , srcDir )
53+ packageImport , err := parsePackageImport (srcDir )
5354 if err != nil {
5455 return nil , err
5556 }
@@ -539,31 +540,49 @@ func packageNameOfDir(srcDir string) (string, error) {
539540 return "" , fmt .Errorf ("go source file not found %s" , srcDir )
540541 }
541542
542- packageImport , err := parsePackageImport (goFilePath , srcDir )
543+ packageImport , err := parsePackageImport (srcDir )
543544 if err != nil {
544545 return "" , err
545546 }
546547 return packageImport , nil
547548}
548549
550+ var errOutsideGoPath = errors .New ("Source directory is outside GOPATH" )
551+
549552// parseImportPackage get package import path via source file
550- func parsePackageImport (source , srcDir string ) (string , error ) {
551- cfg := & packages.Config {
552- Mode : packages .NeedName ,
553- Tests : true ,
554- Dir : srcDir ,
553+ // an alternative implementation is to use:
554+ // cfg := &packages.Config{Mode: packages.NeedName, Tests: true, Dir: srcDir}
555+ // pkgs, err := packages.Load(cfg, "file="+source)
556+ // However, it will call "go list" and slow down the performance
557+ func parsePackageImport (srcDir string ) (string , error ) {
558+ moduleMode := os .Getenv ("GO111MODULE" )
559+ // trying to find the module
560+ if moduleMode != "off" {
561+ currentDir := srcDir
562+ for {
563+ dat , err := ioutil .ReadFile (filepath .Join (currentDir , "go.mod" ))
564+ if os .IsNotExist (err ) {
565+ if currentDir == filepath .Dir (currentDir ) {
566+ // at the root
567+ break
568+ }
569+ currentDir = filepath .Dir (currentDir )
570+ continue
571+ } else if err != nil {
572+ return "" , err
573+ }
574+ modulePath := modfile .ModulePath (dat )
575+ return filepath .ToSlash (filepath .Join (modulePath , strings .TrimPrefix (srcDir , currentDir ))), nil
576+ }
555577 }
556- pkgs , err := packages .Load (cfg , "file=" + source )
557- if err != nil {
558- return "" , err
578+ // fall back to GOPATH mode
579+ goPath := os .Getenv ("GOPATH" )
580+ if goPath == "" {
581+ return "" , fmt .Errorf ("GOPATH is not set" )
559582 }
560- if packages .PrintErrors (pkgs ) > 0 || len (pkgs ) == 0 {
561- return "" , errors .New ("loading package failed" )
583+ sourceRoot := filepath .Join (goPath , "src" ) + string (os .PathSeparator )
584+ if ! strings .HasPrefix (srcDir , sourceRoot ) {
585+ return "" , errOutsideGoPath
562586 }
563-
564- packageImport := pkgs [0 ].PkgPath
565-
566- // It is illegal to import a _test package.
567- packageImport = strings .TrimSuffix (packageImport , "_test" )
568- return packageImport , nil
587+ return filepath .ToSlash (strings .TrimPrefix (srcDir , sourceRoot )), nil
569588}
0 commit comments