@@ -40,8 +40,9 @@ func init() {
4040}
4141
4242// Cross compilation docker containers
43- var dockerBase = "techknowlogick/xgo:base"
44- var dockerDist = "techknowlogick/xgo:"
43+ var (
44+ dockerDist = "techknowlogick/xgo:"
45+ )
4546
4647// Command line arguments to fine tune the compilation
4748var (
@@ -240,7 +241,6 @@ func checkDockerImage(image string) (bool, error) {
240241
241242// compare output of docker images and image name
242243func compareOutAndImage (out []byte , image string ) (bool , error ) {
243-
244244 if strings .Contains (image , ":" ) {
245245 // get repository and tag
246246 res := strings .SplitN (image , ":" , 2 )
@@ -251,7 +251,6 @@ func compareOutAndImage(out []byte, image string) (bool, error) {
251251
252252 // default find repository without tag
253253 return bytes .Contains (out , []byte (image )), nil
254-
255254}
256255
257256// Pulls an image from the docker registry.
@@ -265,8 +264,24 @@ func pullDockerImage(image string) error {
265264func compile (image string , config * ConfigFlags , flags * BuildFlags , folder string ) error {
266265 // If a local build was requested, find the import path and mount all GOPATH sources
267266 locals , mounts , paths := []string {}, []string {}, []string {}
268- var usesModules bool
269- if strings .HasPrefix (config .Repository , string (filepath .Separator )) || strings .HasPrefix (config .Repository , "." ) {
267+
268+ usesModules := true
269+ localBuild := strings .HasPrefix (config .Repository , string (filepath .Separator )) || strings .HasPrefix (config .Repository , "." )
270+
271+ // We need to consider our module-aware status
272+ go111module := os .Getenv ("GO111MODULE" )
273+ if go111module == "off" {
274+ usesModules = false
275+ } else if go111module == "auto" {
276+ // we need to look at the current config and determine if we should use modules...
277+
278+ if ! localBuild {
279+ // This implies that we are using an url or module name for `go get`.
280+ // We can't run `go get` here! So we cannot determine if this needs to be module-aware or not!
281+ log .Fatalf ("Can only compile directories with GO111MODULE=auto" )
282+ }
283+
284+ usesModules = false
270285 if _ , err := os .Stat (config .Repository + "/go.mod" ); err == nil {
271286 usesModules = true
272287 }
@@ -278,58 +293,92 @@ func compile(image string, config *ConfigFlags, flags *BuildFlags, folder string
278293 usesModules = true
279294 }
280295 }
296+ if ! usesModules {
297+ // Walk the parents looking for a go.mod file!
298+ goModDir , err := filepath .Abs (config .Repository )
299+ if err != nil {
300+ log .Fatalf ("Failed to locate requested package: %v." , err )
301+ }
302+ // now walk backwards as per go behaviour
303+ for {
304+ if stat , err := os .Stat (filepath .Join (goModDir , "go.mod" )); err == nil {
305+ usesModules = true
306+ break
307+ } else if stat .IsDir () {
308+ break
309+ }
310+ parent := filepath .Dir (goModDir )
311+ if len (parent ) >= len (goModDir ) {
312+ break
313+ }
314+ goModDir = parent
315+ }
316+ }
317+ }
281318
319+ if localBuild && ! usesModules {
320+ // If we're performing a local build and we're not using modules we need to map the gopath over to the docker
321+
322+ // First determine the GOPATH
282323 gopathEnv := os .Getenv ("GOPATH" )
283- if gopathEnv == "" && ! usesModules {
324+ if gopathEnv == "" {
284325 log .Printf ("No $GOPATH is set - defaulting to %s" , build .Default .GOPATH )
285326 gopathEnv = build .Default .GOPATH
286327 }
287328
288- // Iterate over all the local libs and export the mount points
289- if gopathEnv == "" && ! usesModules {
329+ if gopathEnv == "" {
290330 log .Fatalf ("No $GOPATH is set or forwarded to xgo" )
291331 }
292- if ! usesModules {
293332
294- for _ , gopath := range strings .Split (gopathEnv , string (os .PathListSeparator )) {
295- // Since docker sandboxes volumes, resolve any symlinks manually
296- sources := filepath .Join (gopath , "src" )
297- filepath .Walk (sources , func (path string , info os.FileInfo , err error ) error {
298- // Skip any folders that errored out
299- if err != nil {
300- log .Printf ("Failed to access GOPATH element %s: %v" , path , err )
301- return nil
302- }
303- // Skip anything that's not a symlink
304- if info .Mode ()& os .ModeSymlink == 0 {
305- return nil
306- }
307- // Resolve the symlink and skip if it's not a folder
308- target , err := filepath .EvalSymlinks (path )
309- if err != nil {
310- return nil
311- }
312- if info , err = os .Stat (target ); err != nil || ! info .IsDir () {
313- return nil
314- }
315- // Skip if the symlink points within GOPATH
316- if filepath .HasPrefix (target , sources ) {
333+ // Iterate over all the local libs and export the mount points
334+ for _ , gopath := range strings .Split (gopathEnv , string (os .PathListSeparator )) {
335+ // Since docker sandboxes volumes, resolve any symlinks manually
336+ sources := filepath .Join (gopath , "src" )
337+ absSources , err := filepath .Abs (sources )
338+ if err != nil {
339+ log .Fatalf ("Unable to generate absolute path for source directory %s. %v" , sources , err )
340+ }
341+ absSources = filepath .ToSlash (filepath .Join (absSources , string (filepath .Separator )))
342+ _ = filepath .Walk (sources , func (path string , info os.FileInfo , err error ) error {
343+ // Skip any folders that errored out
344+ if err != nil {
345+ log .Printf ("Failed to access GOPATH element %s: %v" , path , err )
346+ return nil
347+ }
348+ // Skip anything that's not a symlink
349+ if info .Mode ()& os .ModeSymlink == 0 {
350+ return nil
351+ }
352+ // Resolve the symlink and skip if it's not a folder
353+ target , err := filepath .EvalSymlinks (path )
354+ if err != nil {
355+ return nil
356+ }
357+ if info , err = os .Stat (target ); err != nil || ! info .IsDir () {
358+ return nil
359+ }
360+ // Skip if the symlink points within GOPATH
361+ absTarget , err := filepath .Abs (target )
362+ if err == nil {
363+ absTarget = filepath .ToSlash (filepath .Join (absTarget , string (filepath .Separator )))
364+ if strings .HasPrefix (absTarget , absSources ) {
317365 return nil
318366 }
367+ }
319368
320- // Folder needs explicit mounting due to docker symlink security
321- locals = append (locals , target )
322- mounts = append (mounts , filepath .Join ("/ext-go" , strconv .Itoa (len (locals )), "src" , strings .TrimPrefix (path , sources )))
323- paths = append (paths , filepath .Join ("/ext-go" , strconv .Itoa (len (locals ))))
324- return nil
325- })
326- // Export the main mount point for this GOPATH entry
327- locals = append (locals , sources )
328- mounts = append (mounts , filepath .Join ("/ext-go" , strconv .Itoa (len (locals )), "src" ))
369+ // Folder needs explicit mounting due to docker symlink security
370+ locals = append (locals , target )
371+ mounts = append (mounts , filepath .Join ("/ext-go" , strconv .Itoa (len (locals )), "src" , strings .TrimPrefix (path , sources )))
329372 paths = append (paths , filepath .Join ("/ext-go" , strconv .Itoa (len (locals ))))
330- }
373+ return nil
374+ })
375+ // Export the main mount point for this GOPATH entry
376+ locals = append (locals , sources )
377+ mounts = append (mounts , filepath .Join ("/ext-go" , strconv .Itoa (len (locals )), "src" ))
378+ paths = append (paths , filepath .Join ("/ext-go" , strconv .Itoa (len (locals ))))
331379 }
332380 }
381+
333382 // Assemble and run the cross compilation command
334383 fmt .Printf ("Cross compiling %s...\n " , config .Repository )
335384
@@ -383,27 +432,32 @@ func compile(image string, config *ConfigFlags, flags *BuildFlags, folder string
383432 // Set ssh agent socket environment variable
384433 args = append (args , "-e" , fmt .Sprintf ("SSH_AUTH_SOCK=%s" , os .Getenv ("SSH_AUTH_SOCK" )))
385434 }
435+
386436 if usesModules {
387437 args = append (args , []string {"-e" , "GO111MODULE=on" }... )
388438 args = append (args , []string {"-v" , build .Default .GOPATH + ":/go" }... )
389-
390- // Map this repository to the /source folder
391- absRepository , err := filepath .Abs (config .Repository )
392- if err != nil {
393- log .Fatalf ("Failed to locate requested module repository: %v." , err )
394- }
395- args = append (args , []string {"-v" , absRepository + ":/source" }... )
439+ // FIXME: consider GOMODCACHE?
396440
397441 fmt .Printf ("Enabled Go module support\n " )
398442
399- // Check whether it has a vendor folder, and if so, use it
400- vendorPath := absRepository + "/vendor"
401- vendorfolder , err := os .Stat (vendorPath )
402- if ! os .IsNotExist (err ) && vendorfolder .Mode ().IsDir () {
403- args = append (args , []string {"-e" , "FLAG_MOD=vendor" }... )
404- fmt .Printf ("Using vendored Go module dependencies\n " )
443+ if localBuild {
444+ // Map this repository to the /source folder
445+ absRepository , err := filepath .Abs (config .Repository )
446+ if err != nil {
447+ log .Fatalf ("Failed to locate requested module repository: %v." , err )
448+ }
449+
450+ args = append (args , []string {"-v" , absRepository + ":/source" }... )
451+ // Check whether it has a vendor folder, and if so, use it
452+ vendorPath := absRepository + "/vendor"
453+ vendorfolder , err := os .Stat (vendorPath )
454+ if ! os .IsNotExist (err ) && vendorfolder .Mode ().IsDir () {
455+ args = append (args , []string {"-e" , "FLAG_MOD=vendor" }... )
456+ fmt .Printf ("Using vendored Go module dependencies\n " )
457+ }
405458 }
406459 } else {
460+ args = append (args , []string {"-e" , "GO111MODULE=off" }... )
407461 for i := 0 ; i < len (locals ); i ++ {
408462 args = append (args , []string {"-v" , fmt .Sprintf ("%s:%s:ro" , locals [i ], mounts [i ])}... )
409463 }
0 commit comments