golang.org/x/build@v0.0.0-20240506185731-218518f32b70/internal/task/darwin_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package task_test 6 7 import ( 8 "flag" 9 "io/fs" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "reflect" 14 "strings" 15 "testing" 16 17 "github.com/google/go-cmp/cmp" 18 "golang.org/x/build/internal/task" 19 ) 20 21 var readPKGFlag = flag.String("read-pkg", "", "Path to a Go macOS .pkg installer to run TestReadBinariesFromPKG with.") 22 23 func TestReadBinariesFromPKG(t *testing.T) { 24 if *readPKGFlag == "" { 25 t.Skip("skipping manual test since -read-pkg flag is not set") 26 } 27 if _, err := exec.LookPath("pkgutil"); err != nil { 28 // Since this is a manual test, we can afford to fail 29 // rather than skip if required dependencies are missing. 30 t.Fatal("required dependency pkgutil not found in PATH:", err) 31 } 32 if ext := filepath.Ext(*readPKGFlag); ext != ".pkg" { 33 t.Fatalf("got input file extension %q, want .pkg", ext) 34 } 35 f, err := os.Open(*readPKGFlag) 36 if err != nil { 37 t.Fatal(err) 38 } 39 defer f.Close() 40 41 got, err := task.ReadBinariesFromPKG(f) 42 if err != nil { 43 t.Fatal(err) 44 } 45 want, err := readBinariesFromPKGUsingXcode(t, *readPKGFlag) 46 if err != nil { 47 t.Fatal(err) 48 } 49 // Compare with reflect.DeepEqual first for speed; 50 // there's 100 MB or so of binary data to compare. 51 if !reflect.DeepEqual(want, got) { 52 t.Log("got files:") 53 for path := range got { 54 t.Log("\t" + path) 55 } 56 t.Log("want files:") 57 for path := range want { 58 t.Log("\t" + path) 59 } 60 t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(want, got)) 61 } 62 } 63 64 // readBinariesFromPKGUsingXcode implements the same functionality as 65 // ReadBinariesFromPKG but uses Xcode's pkgutil as its implementation. 66 func readBinariesFromPKGUsingXcode(t *testing.T, pkgPath string) (map[string][]byte, error) { 67 expanded := filepath.Join(t.TempDir(), "expanded") 68 out, err := exec.Command("pkgutil", "--expand-full", pkgPath, expanded).CombinedOutput() 69 if err != nil { 70 t.Fatalf("pkgutil failed: %v\noutput: %s", err, out) 71 } 72 var binaries = make(map[string][]byte) // Relative path starting with "go/" → binary data. 73 root := filepath.Join(expanded, "org.golang.go.pkg/Payload/usr/local") 74 err = filepath.Walk(root, func(path string, fi fs.FileInfo, err error) error { 75 if err != nil { 76 return err 77 } 78 name, err := filepath.Rel(root, path) 79 if err != nil { 80 return err 81 } 82 if !strings.HasPrefix(name, "go/bin/") && !strings.HasPrefix(name, "go/pkg/tool/") { 83 return nil 84 } 85 if !fi.Mode().IsRegular() || fi.Mode().Perm()&0100 == 0 { 86 return nil 87 } 88 b, err := os.ReadFile(path) 89 if err != nil { 90 return err 91 } 92 binaries[name] = b 93 return nil 94 }) 95 if err != nil { 96 t.Fatal(err) 97 } 98 return binaries, nil 99 }