github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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  
    27  	udid := detectUDID()
    28  	mps := detectMobileProvisionFiles(udid)
    29  	if len(mps) == 0 {
    30  		fail("did not find mobile provision matching device udid %s", udid)
    31  	}
    32  
    33  	fmt.Println("Available provisioning profiles below.")
    34  	fmt.Println("NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID")
    35  	fmt.Println("will be overwritten when running Go programs.")
    36  	for _, mp := range mps {
    37  		fmt.Println()
    38  		fmt.Printf("export GOIOS_DEV_ID=%s\n", devID)
    39  		f, err := ioutil.TempFile("", "go_ios_detect_")
    40  		check(err)
    41  		fname := f.Name()
    42  		defer os.Remove(fname)
    43  
    44  		out := output(parseMobileProvision(mp))
    45  		_, err = f.Write(out)
    46  		check(err)
    47  		check(f.Close())
    48  
    49  		appID, err := plistExtract(fname, "Entitlements:application-identifier")
    50  		check(err)
    51  		fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
    52  
    53  		teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
    54  		check(err)
    55  		fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
    56  	}
    57  }
    58  
    59  func detectDevID() string {
    60  	cmd := exec.Command("security", "find-identity", "-p", "codesigning", "-v")
    61  	lines := getLines(cmd)
    62  
    63  	for _, line := range lines {
    64  		if !bytes.Contains(line, []byte("iPhone Developer")) {
    65  			continue
    66  		}
    67  		if bytes.Contains(line, []byte("REVOKED")) {
    68  			continue
    69  		}
    70  		fields := bytes.Fields(line)
    71  		return string(fields[1])
    72  	}
    73  	fail("no code signing identity found")
    74  	panic("unreachable")
    75  }
    76  
    77  var udidPrefix = []byte("UniqueDeviceID: ")
    78  
    79  func detectUDID() []byte {
    80  	cmd := exec.Command("ideviceinfo")
    81  	lines := getLines(cmd)
    82  	for _, line := range lines {
    83  		if bytes.HasPrefix(line, udidPrefix) {
    84  			return bytes.TrimPrefix(line, udidPrefix)
    85  		}
    86  	}
    87  	fail("udid not found; is the device connected?")
    88  	panic("unreachable")
    89  }
    90  
    91  func detectMobileProvisionFiles(udid []byte) []string {
    92  	cmd := exec.Command("mdfind", "-name", ".mobileprovision")
    93  	lines := getLines(cmd)
    94  
    95  	var files []string
    96  	for _, line := range lines {
    97  		if len(line) == 0 {
    98  			continue
    99  		}
   100  		xmlLines := getLines(parseMobileProvision(string(line)))
   101  		for _, xmlLine := range xmlLines {
   102  			if bytes.Contains(xmlLine, udid) {
   103  				files = append(files, string(line))
   104  			}
   105  		}
   106  	}
   107  	return files
   108  }
   109  
   110  func parseMobileProvision(fname string) *exec.Cmd {
   111  	return exec.Command("security", "cms", "-D", "-i", string(fname))
   112  }
   113  
   114  func plistExtract(fname string, path string) ([]byte, error) {
   115  	out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	return bytes.TrimSpace(out), nil
   120  }
   121  
   122  func getLines(cmd *exec.Cmd) [][]byte {
   123  	out := output(cmd)
   124  	return bytes.Split(out, []byte("\n"))
   125  }
   126  
   127  func output(cmd *exec.Cmd) []byte {
   128  	out, err := cmd.Output()
   129  	if err != nil {
   130  		fmt.Println(strings.Join(cmd.Args, "\n"))
   131  		fmt.Fprintln(os.Stderr, err)
   132  		os.Exit(1)
   133  	}
   134  	return out
   135  }
   136  
   137  func check(err error) {
   138  	if err != nil {
   139  		fail(err.Error())
   140  	}
   141  }
   142  
   143  func fail(msg string, v ...interface{}) {
   144  	fmt.Fprintf(os.Stderr, msg, v...)
   145  	fmt.Fprintln(os.Stderr)
   146  	os.Exit(1)
   147  }