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  }