github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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  		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  }