Home | History | Annotate | Download | only in ios
      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 		fields := bytes.Fields(line)
     59 		return string(fields[1])
     60 	}
     61 	fail("no code signing identity found")
     62 	panic("unreachable")
     63 }
     64 
     65 var udidPrefix = []byte("UniqueDeviceID: ")
     66 
     67 func detectUDID() []byte {
     68 	cmd := exec.Command("ideviceinfo")
     69 	lines := getLines(cmd)
     70 	for _, line := range lines {
     71 		if bytes.HasPrefix(line, udidPrefix) {
     72 			return bytes.TrimPrefix(line, udidPrefix)
     73 		}
     74 	}
     75 	fail("udid not found; is the device connected?")
     76 	panic("unreachable")
     77 }
     78 
     79 func detectMobileProvisionFile(udid []byte) string {
     80 	cmd := exec.Command("mdfind", "-name", ".mobileprovision")
     81 	lines := getLines(cmd)
     82 
     83 	for _, line := range lines {
     84 		if len(line) == 0 {
     85 			continue
     86 		}
     87 		xmlLines := getLines(parseMobileProvision(string(line)))
     88 		for _, xmlLine := range xmlLines {
     89 			if bytes.Contains(xmlLine, udid) {
     90 				return string(line)
     91 			}
     92 		}
     93 	}
     94 	fail("did not find mobile provision matching device udid %s", udid)
     95 	panic("ureachable")
     96 }
     97 
     98 func parseMobileProvision(fname string) *exec.Cmd {
     99 	return exec.Command("security", "cms", "-D", "-i", string(fname))
    100 }
    101 
    102 func plistExtract(fname string, path string) ([]byte, error) {
    103 	out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
    104 	if err != nil {
    105 		return nil, err
    106 	}
    107 	return bytes.TrimSpace(out), nil
    108 }
    109 
    110 func getLines(cmd *exec.Cmd) [][]byte {
    111 	out := combinedOutput(cmd)
    112 	return bytes.Split(out, []byte("\n"))
    113 }
    114 
    115 func combinedOutput(cmd *exec.Cmd) []byte {
    116 	out, err := cmd.CombinedOutput()
    117 	if err != nil {
    118 		fmt.Println(strings.Join(cmd.Args, "\n"))
    119 		fmt.Fprintln(os.Stderr, err)
    120 		os.Exit(1)
    121 	}
    122 	return out
    123 }
    124 
    125 func check(err error) {
    126 	if err != nil {
    127 		fail(err.Error())
    128 	}
    129 }
    130 
    131 func fail(msg string, v ...interface{}) {
    132 	fmt.Fprintf(os.Stderr, msg, v...)
    133 	fmt.Fprintln(os.Stderr)
    134 	os.Exit(1)
    135 }
    136