@@ -607,20 +607,23 @@ func (t *test) run() {
607
607
os .Setenv ("GOARCH" , runtime .GOARCH )
608
608
}
609
609
610
- useTmp := true
611
- runInDir := false
610
+ var (
611
+ runInDir = t .tempDir
612
+ tempDirIsGOPATH = false
613
+ )
612
614
runcmd := func (args ... string ) ([]byte , error ) {
613
615
cmd := exec .Command (args [0 ], args [1 :]... )
614
616
var buf bytes.Buffer
615
617
cmd .Stdout = & buf
616
618
cmd .Stderr = & buf
617
- cmd .Env = os .Environ ()
618
- if useTmp {
619
- cmd .Dir = t .tempDir
620
- cmd .Env = envForDir (cmd .Dir )
619
+ cmd .Env = append (os .Environ (), "GOENV=off" , "GOFLAGS=" )
620
+ if runInDir != "" {
621
+ cmd .Dir = runInDir
622
+ // Set PWD to match Dir to speed up os.Getwd in the child process.
623
+ cmd .Env = append (cmd .Env , "PWD=" + cmd .Dir )
621
624
}
622
- if runInDir {
623
- cmd .Dir = t . goDirName ( )
625
+ if tempDirIsGOPATH {
626
+ cmd .Env = append ( cmd . Env , "GOPATH=" + t . tempDir )
624
627
}
625
628
626
629
var err error
@@ -863,13 +866,31 @@ func (t *test) run() {
863
866
}
864
867
865
868
case "runindir" :
866
- // run "go run ." in t.goDirName()
867
- // It's used when test requires go build and run the binary success.
868
- // Example when long import path require (see issue29612.dir) or test
869
- // contains assembly file (see issue15609.dir).
870
- // Verify the expected output.
871
- useTmp = false
872
- runInDir = true
869
+ // Make a shallow copy of t.goDirName() in its own module and GOPATH, and
870
+ // run "go run ." in it. The module path (and hence import path prefix) of
871
+ // the copy is equal to the basename of the source directory.
872
+ //
873
+ // It's used when test a requires a full 'go build' in order to compile
874
+ // the sources, such as when importing multiple packages (issue29612.dir)
875
+ // or compiling a package containing assembly files (see issue15609.dir),
876
+ // but still needs to be run to verify the expected output.
877
+ tempDirIsGOPATH = true
878
+ srcDir := t .goDirName ()
879
+ modName := filepath .Base (srcDir )
880
+ gopathSrcDir := filepath .Join (t .tempDir , "src" , modName )
881
+ runInDir = gopathSrcDir
882
+
883
+ if err := overlayDir (gopathSrcDir , srcDir ); err != nil {
884
+ t .err = err
885
+ return
886
+ }
887
+
888
+ modFile := fmt .Sprintf ("module %s\n go 1.14\n " , modName )
889
+ if err := ioutil .WriteFile (filepath .Join (gopathSrcDir , "go.mod" ), []byte (modFile ), 0666 ); err != nil {
890
+ t .err = err
891
+ return
892
+ }
893
+
873
894
cmd := []string {goTool (), "run" , goGcflags ()}
874
895
if * linkshared {
875
896
cmd = append (cmd , "-linkshared" )
@@ -1003,7 +1024,7 @@ func (t *test) run() {
1003
1024
// Run Go file if no special go command flags are provided;
1004
1025
// otherwise build an executable and run it.
1005
1026
// Verify the output.
1006
- useTmp = false
1027
+ runInDir = ""
1007
1028
var out []byte
1008
1029
var err error
1009
1030
if len (flags )+ len (args ) == 0 && goGcflagsIsEmpty () && ! * linkshared && goarch == runtime .GOARCH && goos == runtime .GOOS {
@@ -1051,7 +1072,7 @@ func (t *test) run() {
1051
1072
defer func () {
1052
1073
<- rungatec
1053
1074
}()
1054
- useTmp = false
1075
+ runInDir = ""
1055
1076
cmd := []string {goTool (), "run" , goGcflags ()}
1056
1077
if * linkshared {
1057
1078
cmd = append (cmd , "-linkshared" )
@@ -1084,7 +1105,7 @@ func (t *test) run() {
1084
1105
case "errorcheckoutput" :
1085
1106
// Run Go file and write its output into temporary Go file.
1086
1107
// Compile and errorCheck generated Go file.
1087
- useTmp = false
1108
+ runInDir = ""
1088
1109
cmd := []string {goTool (), "run" , goGcflags ()}
1089
1110
if * linkshared {
1090
1111
cmd = append (cmd , "-linkshared" )
@@ -1752,27 +1773,73 @@ func checkShouldTest() {
1752
1773
assert (shouldTest ("// +build !windows !plan9" , "windows" , "amd64" ))
1753
1774
}
1754
1775
1755
- // envForDir returns a copy of the environment
1756
- // suitable for running in the given directory.
1757
- // The environment is the current process's environment
1758
- // but with an updated $PWD, so that an os.Getwd in the
1759
- // child will be faster.
1760
- func envForDir (dir string ) []string {
1761
- env := os .Environ ()
1762
- for i , kv := range env {
1763
- if strings .HasPrefix (kv , "PWD=" ) {
1764
- env [i ] = "PWD=" + dir
1765
- return env
1766
- }
1767
- }
1768
- env = append (env , "PWD=" + dir )
1769
- return env
1770
- }
1771
-
1772
1776
func getenv (key , def string ) string {
1773
1777
value := os .Getenv (key )
1774
1778
if value != "" {
1775
1779
return value
1776
1780
}
1777
1781
return def
1778
1782
}
1783
+
1784
+ // overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added.
1785
+ func overlayDir (dstRoot , srcRoot string ) error {
1786
+ dstRoot = filepath .Clean (dstRoot )
1787
+ if err := os .MkdirAll (dstRoot , 0777 ); err != nil {
1788
+ return err
1789
+ }
1790
+
1791
+ srcRoot , err := filepath .Abs (srcRoot )
1792
+ if err != nil {
1793
+ return err
1794
+ }
1795
+
1796
+ return filepath .Walk (srcRoot , func (srcPath string , info os.FileInfo , err error ) error {
1797
+ if err != nil || srcPath == srcRoot {
1798
+ return err
1799
+ }
1800
+
1801
+ suffix := strings .TrimPrefix (srcPath , srcRoot )
1802
+ for len (suffix ) > 0 && suffix [0 ] == filepath .Separator {
1803
+ suffix = suffix [1 :]
1804
+ }
1805
+ dstPath := filepath .Join (dstRoot , suffix )
1806
+
1807
+ perm := info .Mode () & os .ModePerm
1808
+ if info .Mode ()& os .ModeSymlink != 0 {
1809
+ info , err = os .Stat (srcPath )
1810
+ if err != nil {
1811
+ return err
1812
+ }
1813
+ perm = info .Mode () & os .ModePerm
1814
+ }
1815
+
1816
+ // Always copy directories (don't symlink them).
1817
+ // If we add a file in the overlay, we don't want to add it in the original.
1818
+ if info .IsDir () {
1819
+ return os .MkdirAll (dstPath , perm | 0200 )
1820
+ }
1821
+
1822
+ // If the OS supports symlinks, use them instead of copying bytes.
1823
+ if err := os .Symlink (srcPath , dstPath ); err == nil {
1824
+ return nil
1825
+ }
1826
+
1827
+ // Otherwise, copy the bytes.
1828
+ src , err := os .Open (srcPath )
1829
+ if err != nil {
1830
+ return err
1831
+ }
1832
+ defer src .Close ()
1833
+
1834
+ dst , err := os .OpenFile (dstPath , os .O_WRONLY | os .O_CREATE | os .O_EXCL , perm )
1835
+ if err != nil {
1836
+ return err
1837
+ }
1838
+
1839
+ _ , err = io .Copy (dst , src )
1840
+ if closeErr := dst .Close (); err == nil {
1841
+ err = closeErr
1842
+ }
1843
+ return err
1844
+ })
1845
+ }
0 commit comments