@@ -31,10 +31,19 @@ import (
31
31
32
32
// A Context specifies the supporting context for a build.
33
33
type Context struct {
34
- GOARCH string // target architecture
35
- GOOS string // target operating system
36
- GOROOT string // Go root
37
- GOPATH string // Go path
34
+ GOARCH string // target architecture
35
+ GOOS string // target operating system
36
+ GOROOT string // Go root
37
+ GOPATH string // Go path
38
+
39
+ // WorkingDir is the caller's working directory, or the empty string to use
40
+ // the current directory of the running process. In module mode, this is used
41
+ // to locate the main module.
42
+ //
43
+ // If WorkingDir is non-empty, directories passed to Import and ImportDir must
44
+ // be absolute.
45
+ WorkingDir string
46
+
38
47
CgoEnabled bool // whether cgo files are included
39
48
UseAllFiles bool // use files regardless of +build lines, file names
40
49
Compiler string // compiler to assume when computing target paths
@@ -994,21 +1003,14 @@ var errNoModules = errors.New("not using modules")
994
1003
func (ctxt * Context ) importGo (p * Package , path , srcDir string , mode ImportMode ) error {
995
1004
const debugImportGo = false
996
1005
997
- // To invoke the go command, we must know the source directory,
1006
+ // To invoke the go command,
998
1007
// we must not being doing special things like AllowBinary or IgnoreVendor,
999
1008
// and all the file system callbacks must be nil (we're meant to use the local file system).
1000
- if srcDir == "" || mode & AllowBinary != 0 || mode & IgnoreVendor != 0 ||
1009
+ if mode & AllowBinary != 0 || mode & IgnoreVendor != 0 ||
1001
1010
ctxt .JoinPath != nil || ctxt .SplitPathList != nil || ctxt .IsAbsPath != nil || ctxt .IsDir != nil || ctxt .HasSubdir != nil || ctxt .ReadDir != nil || ctxt .OpenFile != nil || ! equal (ctxt .ReleaseTags , defaultReleaseTags ) {
1002
1011
return errNoModules
1003
1012
}
1004
1013
1005
- // Find the absolute source directory. hasSubdir does not handle
1006
- // relative paths (and can't because the callbacks don't support this).
1007
- absSrcDir , err := filepath .Abs (srcDir )
1008
- if err != nil {
1009
- return errNoModules
1010
- }
1011
-
1012
1014
// Predict whether module aware mode is enabled by checking the value of
1013
1015
// GO111MODULE and looking for a go.mod file in the source directory or
1014
1016
// one of its parents. Running 'go env GOMOD' in the source directory would
@@ -1021,11 +1023,28 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode)
1021
1023
// Maybe use modules.
1022
1024
}
1023
1025
1024
- // If the source directory is in GOROOT, then the in-process code works fine
1025
- // and we should keep using it. Moreover, the 'go list' approach below doesn't
1026
- // take standard-library vendoring into account and will fail.
1027
- if _ , ok := ctxt .hasSubdir (filepath .Join (ctxt .GOROOT , "src" ), absSrcDir ); ok {
1028
- return errNoModules
1026
+ if srcDir != "" {
1027
+ var absSrcDir string
1028
+ if filepath .IsAbs (srcDir ) {
1029
+ absSrcDir = srcDir
1030
+ } else if ctxt .WorkingDir != "" {
1031
+ return fmt .Errorf ("go/build: WorkingDir is non-empty, so relative srcDir is not allowed: %v" , srcDir )
1032
+ } else {
1033
+ // Find the absolute source directory. hasSubdir does not handle
1034
+ // relative paths (and can't because the callbacks don't support this).
1035
+ var err error
1036
+ absSrcDir , err = filepath .Abs (srcDir )
1037
+ if err != nil {
1038
+ return errNoModules
1039
+ }
1040
+ }
1041
+
1042
+ // If the source directory is in GOROOT, then the in-process code works fine
1043
+ // and we should keep using it. Moreover, the 'go list' approach below doesn't
1044
+ // take standard-library vendoring into account and will fail.
1045
+ if _ , ok := ctxt .hasSubdir (filepath .Join (ctxt .GOROOT , "src" ), absSrcDir ); ok {
1046
+ return errNoModules
1047
+ }
1029
1048
}
1030
1049
1031
1050
// For efficiency, if path is a standard library package, let the usual lookup code handle it.
@@ -1039,7 +1058,24 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode)
1039
1058
// Unless GO111MODULE=on, look to see if there is a go.mod.
1040
1059
// Since go1.13, it doesn't matter if we're inside GOPATH.
1041
1060
if go111Module != "on" {
1042
- parent := absSrcDir
1061
+ var (
1062
+ parent string
1063
+ err error
1064
+ )
1065
+ if ctxt .WorkingDir == "" {
1066
+ parent , err = os .Getwd ()
1067
+ if err != nil {
1068
+ // A nonexistent working directory can't be in a module.
1069
+ return errNoModules
1070
+ }
1071
+ } else {
1072
+ parent , err = filepath .Abs (ctxt .WorkingDir )
1073
+ if err != nil {
1074
+ // If the caller passed a bogus WorkingDir explicitly, that's materially
1075
+ // different from not having modules enabled.
1076
+ return err
1077
+ }
1078
+ }
1043
1079
for {
1044
1080
info , err := os .Stat (filepath .Join (parent , "go.mod" ))
1045
1081
if err == nil && ! info .IsDir () {
@@ -1055,10 +1091,9 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode)
1055
1091
1056
1092
cmd := exec .Command ("go" , "list" , "-e" , "-compiler=" + ctxt .Compiler , "-tags=" + strings .Join (ctxt .BuildTags , "," ), "-installsuffix=" + ctxt .InstallSuffix , "-f={{.Dir}}\n {{.ImportPath}}\n {{.Root}}\n {{.Goroot}}\n {{if .Error}}{{.Error}}{{end}}\n " , "--" , path )
1057
1093
1058
- // TODO(bcmills): This is wrong if srcDir is in a vendor directory, or if
1059
- // srcDir is in some module dependency of the main module. The main module
1060
- // chooses what the import paths mean: individual packages don't.
1061
- cmd .Dir = srcDir
1094
+ if ctxt .WorkingDir != "" {
1095
+ cmd .Dir = ctxt .WorkingDir
1096
+ }
1062
1097
1063
1098
var stdout , stderr strings.Builder
1064
1099
cmd .Stdout = & stdout
@@ -1077,7 +1112,7 @@ func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode)
1077
1112
)
1078
1113
1079
1114
if err := cmd .Run (); err != nil {
1080
- return fmt .Errorf ("go/build: importGo %s: %v\n %s\n " , path , err , stderr .String ())
1115
+ return fmt .Errorf ("go/build: go list %s: %v\n %s\n " , path , err , stderr .String ())
1081
1116
}
1082
1117
1083
1118
f := strings .SplitN (stdout .String (), "\n " , 5 )
0 commit comments