rsc.io/go@v0.0.0-20150416155037-e040fd465409/misc/ios/detect.go (about) 1 // Copyright 2015 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 // +build ignore 6 7 // detect attempts to autodetect the correct 8 // values of the environment variables 9 // used by go_darwin_arm_exec. 10 package main 11 12 import ( 13 "bytes" 14 "fmt" 15 "io/ioutil" 16 "os" 17 "os/exec" 18 "strings" 19 ) 20 21 func main() { 22 devID := detectDevID() 23 fmt.Printf("export GOIOS_DEV_ID=%s\n", devID) 24 25 udid := detectUDID() 26 mp := detectMobileProvisionFile(udid) 27 28 f, err := ioutil.TempFile("", "go_ios_detect_") 29 check(err) 30 fname := f.Name() 31 defer os.Remove(fname) 32 33 out := combinedOutput(parseMobileProvision(mp)) 34 _, err = f.Write(out) 35 check(err) 36 check(f.Close()) 37 38 appID, err := plistExtract(fname, "ApplicationIdentifierPrefix:0") 39 check(err) 40 fmt.Printf("export GOIOS_APP_ID=%s\n", appID) 41 42 teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier") 43 check(err) 44 fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID) 45 } 46 47 func detectDevID() string { 48 cmd := exec.Command("security", "find-identity", "-p", "codesigning", "-v") 49 lines := getLines(cmd) 50 51 for _, line := range lines { 52 if !bytes.Contains(line, []byte("iPhone Developer")) { 53 continue 54 } 55 fields := bytes.Fields(line) 56 return string(fields[1]) 57 } 58 fail("no code signing identity found") 59 panic("unreachable") 60 } 61 62 var udidPrefix = []byte("UniqueDeviceID: ") 63 64 func detectUDID() []byte { 65 cmd := exec.Command("ideviceinfo") 66 lines := getLines(cmd) 67 for _, line := range lines { 68 if bytes.HasPrefix(line, udidPrefix) { 69 return bytes.TrimPrefix(line, udidPrefix) 70 } 71 } 72 fail("udid not found; is the device connected?") 73 panic("unreachable") 74 } 75 76 func detectMobileProvisionFile(udid []byte) string { 77 cmd := exec.Command("mdfind", "-name", ".mobileprovision") 78 lines := getLines(cmd) 79 80 for _, line := range lines { 81 if len(line) == 0 { 82 continue 83 } 84 xmlLines := getLines(parseMobileProvision(string(line))) 85 for _, xmlLine := range xmlLines { 86 if bytes.Contains(xmlLine, udid) { 87 return string(line) 88 } 89 } 90 } 91 fail("did not find mobile provision matching device udid %s", udid) 92 panic("ureachable") 93 } 94 95 func parseMobileProvision(fname string) *exec.Cmd { 96 return exec.Command("security", "cms", "-D", "-i", string(fname)) 97 } 98 99 func plistExtract(fname string, path string) ([]byte, error) { 100 out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput() 101 if err != nil { 102 return nil, err 103 } 104 return bytes.TrimSpace(out), nil 105 } 106 107 func getLines(cmd *exec.Cmd) [][]byte { 108 out := combinedOutput(cmd) 109 return bytes.Split(out, []byte("\n")) 110 } 111 112 func combinedOutput(cmd *exec.Cmd) []byte { 113 out, err := cmd.CombinedOutput() 114 if err != nil { 115 fmt.Println(strings.Join(cmd.Args, "\n")) 116 fmt.Fprintln(os.Stderr, err) 117 os.Exit(1) 118 } 119 return out 120 } 121 122 func check(err error) { 123 if err != nil { 124 fail(err.Error()) 125 } 126 } 127 128 func fail(msg string, v ...interface{}) { 129 fmt.Fprintf(os.Stderr, msg, v...) 130 fmt.Fprintln(os.Stderr) 131 os.Exit(1) 132 }