@@ -184,12 +184,12 @@ func main() {
184
184
distinctStacks ++
185
185
186
186
info := Info {
187
- Program : prog .Program ,
188
- Version : prog .Version ,
189
- GoVersion : prog .GoVersion ,
190
- GOOS : prog .GOOS ,
191
- GOARCH : prog .GOARCH ,
192
- Client : clientSuffix ,
187
+ Program : prog .Program ,
188
+ ProgramVersion : prog .Version ,
189
+ GoVersion : prog .GoVersion ,
190
+ GOOS : prog .GOOS ,
191
+ GOARCH : prog .GOARCH ,
192
+ Client : clientSuffix ,
193
193
}
194
194
for stack , count := range prog .Stacks {
195
195
counts := stacks [stack ]
@@ -432,15 +432,15 @@ func main() {
432
432
// Info is used as a key for de-duping and aggregating.
433
433
// Do not add detail about particular records (e.g. data, telemetry URL).
434
434
type Info struct {
435
- Program string // "golang.org/x/tools/gopls"
436
- Version , GoVersion string // e.g. "gopls/ v0.16.1", "go1.23"
437
- GOOS , GOARCH string
438
- Client string // e.g. "vscode"
435
+ Program string // "golang.org/x/tools/gopls"
436
+ ProgramVersion , GoVersion string // e.g. "v0.16.1", "go1.23"
437
+ GOOS , GOARCH string
438
+ Client string // e.g. "vscode"
439
439
}
440
440
441
441
func (info Info ) String () string {
442
442
return fmt .Sprintf ("%s@%s %s %s/%s %s" ,
443
- info .Program , info .Version ,
443
+ info .Program , info .ProgramVersion ,
444
444
info .GoVersion , info .GOOS , info .GOARCH ,
445
445
info .Client )
446
446
}
@@ -543,7 +543,7 @@ func writeStackComment(body *bytes.Buffer, stack, id string, jsonURL string, cou
543
543
id , jsonURL )
544
544
545
545
// Read the mapping from symbols to file/line.
546
- pclntab , err := readPCLineTable (info )
546
+ pclntab , err := readPCLineTable (info , defaultStacksDir )
547
547
if err != nil {
548
548
log .Fatal (err )
549
549
}
@@ -631,7 +631,7 @@ func frameURL(pclntab map[string]FileLine, info Info, frame string) string {
631
631
}
632
632
633
633
return fmt .Sprintf ("https://cs.opensource.google/go/x/tools/+/%s:%s;l=%d" ,
634
- "gopls/" + info .Version , rest , linenum )
634
+ "gopls/" + info .ProgramVersion , rest , linenum )
635
635
}
636
636
637
637
// other x/ module dependency?
@@ -770,63 +770,90 @@ type FileLine struct {
770
770
line int
771
771
}
772
772
773
+ const defaultStacksDir = "/tmp/stacks-cache"
774
+
773
775
// readPCLineTable builds the gopls executable specified by info,
774
776
// reads its PC-to-line-number table, and returns the file/line of
775
777
// each TEXT symbol.
776
- func readPCLineTable (info Info ) (map [string ]FileLine , error ) {
778
+ //
779
+ // stacksDir is a semi-durable temp directory (i.e. lasts for at least a few
780
+ // hours) to hold recent sources and executables.
781
+ func readPCLineTable (info Info , stacksDir string ) (map [string ]FileLine , error ) {
777
782
// The stacks dir will be a semi-durable temp directory
778
783
// (i.e. lasts for at least hours) holding source trees
779
784
// and executables we have built recently.
780
785
//
781
786
// Each subdir will hold a specific revision.
782
- stacksDir := "/tmp/gopls-stacks"
783
787
if err := os .MkdirAll (stacksDir , 0777 ); err != nil {
784
788
return nil , fmt .Errorf ("can't create stacks dir: %v" , err )
785
789
}
786
790
787
- // Fetch the source for the tools repo,
788
- // shallow-cloning just the desired revision.
789
- // (Skip if it's already cloned.)
790
- revDir := filepath .Join (stacksDir , info .Version )
791
- if ! fileExists (filepath .Join (revDir , "go.mod" )) {
792
- // We check for presence of the go.mod file,
793
- // not just the directory itself, as the /tmp reaper
794
- // often removes stale files before removing their directories.
795
- // Remove those stale directories now.
796
- _ = os .RemoveAll (revDir ) // ignore errors
797
-
798
- log .Printf ("cloning tools@gopls/%s" , info .Version )
799
- if err := shallowClone (revDir , "https://go.googlesource.com/tools" , "gopls/" + info .Version ); err != nil {
791
+ // When building a subrepo tool, we must clone the source of the
792
+ // subrepo, and run go build from that checkout.
793
+ //
794
+ // When building a main repo tool, no need to clone or change
795
+ // directories. GOTOOLCHAIN is sufficient to fetch and build the
796
+ // appropriate version.
797
+ var buildDir string
798
+ switch info .Program {
799
+ case "golang.org/x/tools/gopls" :
800
+ // Fetch the source for the tools repo,
801
+ // shallow-cloning just the desired revision.
802
+ // (Skip if it's already cloned.)
803
+ revDir := filepath .Join (stacksDir , info .ProgramVersion )
804
+ if ! fileExists (filepath .Join (revDir , "go.mod" )) {
805
+ // We check for presence of the go.mod file,
806
+ // not just the directory itself, as the /tmp reaper
807
+ // often removes stale files before removing their directories.
808
+ // Remove those stale directories now.
800
809
_ = os .RemoveAll (revDir ) // ignore errors
801
- return nil , fmt .Errorf ("clone: %v" , err )
810
+
811
+ log .Printf ("cloning tools@gopls/%s" , info .ProgramVersion )
812
+ if err := shallowClone (revDir , "https://go.googlesource.com/tools" , "gopls/" + info .ProgramVersion ); err != nil {
813
+ _ = os .RemoveAll (revDir ) // ignore errors
814
+ return nil , fmt .Errorf ("clone: %v" , err )
815
+ }
802
816
}
817
+
818
+ // gopls is in its own module, we must build from there.
819
+ buildDir = filepath .Join (revDir , "gopls" )
820
+ case "cmd/compile" :
821
+ // Nothing to do, GOTOOLCHAIN is sufficient.
822
+ default :
823
+ return nil , fmt .Errorf ("don't know how to build unknown program %s" , info .Program )
803
824
}
804
825
826
+ // No slashes in file name.
827
+ escapedProg := strings .Replace (info .Program , "/" , "_" , - 1 )
828
+
805
829
// Build the executable with the correct GOTOOLCHAIN, GOOS, GOARCH.
806
830
// Use -trimpath for normalized file names.
807
831
// (Skip if it's already built.)
808
- exe := fmt .Sprintf ("exe-%s.%s-%s" , info .GoVersion , info .GOOS , info .GOARCH )
809
- cmd := exec .Command ("go" , "build" , "-trimpath" , "-o" , "../" + exe )
810
- cmd .Stderr = os .Stderr
811
- cmd .Dir = filepath .Join (revDir , "gopls" )
812
- cmd .Env = append (os .Environ (),
813
- "GOTOOLCHAIN=" + info .GoVersion ,
814
- "GOOS=" + info .GOOS ,
815
- "GOARCH=" + info .GOARCH ,
816
- )
817
- if ! fileExists (filepath .Join (revDir , exe )) {
832
+ exe := fmt .Sprintf ("exe-%s-%s.%s-%s" , escapedProg , info .GoVersion , info .GOOS , info .GOARCH )
833
+ exe = filepath .Join (stacksDir , exe )
834
+
835
+ if ! fileExists (exe ) {
818
836
log .Printf ("building %s@%s with %s for %s/%s" ,
819
- info .Program , info .Version , info .GoVersion , info .GOOS , info .GOARCH )
837
+ info .Program , info .ProgramVersion , info .GoVersion , info .GOOS , info .GOARCH )
838
+
839
+ cmd := exec .Command ("go" , "build" , "-trimpath" , "-o" , exe , info .Program )
840
+ cmd .Stderr = os .Stderr
841
+ cmd .Dir = buildDir
842
+ cmd .Env = append (os .Environ (),
843
+ "GOTOOLCHAIN=" + info .GoVersion ,
844
+ "GOOS=" + info .GOOS ,
845
+ "GOARCH=" + info .GOARCH ,
846
+ "GOWORK=off" ,
847
+ )
820
848
if err := cmd .Run (); err != nil {
821
- return nil , fmt .Errorf ("building: %v (rm -fr /tmp/gopls-stacks ?)" , err )
849
+ return nil , fmt .Errorf ("building: %v (rm -fr %s ?)" , err , stacksDir )
822
850
}
823
851
}
824
852
825
853
// Read pclntab of executable.
826
- cmd = exec .Command ("go" , "tool" , "objdump" , exe )
854
+ cmd : = exec .Command ("go" , "tool" , "objdump" , exe )
827
855
cmd .Stdout = new (strings.Builder )
828
856
cmd .Stderr = os .Stderr
829
- cmd .Dir = revDir
830
857
cmd .Env = append (os .Environ (),
831
858
"GOTOOLCHAIN=" + info .GoVersion ,
832
859
"GOOS=" + info .GOOS ,
0 commit comments