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