1
0
mirror of https://github.com/golang/go synced 2024-09-23 17:20:13 -06:00
go/misc/ios/detect.go
Elias Naur 7d889af26d misc/ios: include the bundle id in the GOIOS_APP_ID env variable
The iOS exec wrapper use the constant bundle id "golang.gotest" for
running Go programs on iOS. However, that only happens to work on
the old iOS builders where their provisioning profile covers
that bundle id.

Expand the detection script to list all available provisioning
profiles for the attached device and include the bundle id in the
GOIOS_APP_ID environment variable.

To allow the old builders to continue, the "golang.gotest" bundle
id is used as a fallback if only the app id prefix is specified in
GOIOS_APP_ID.

For the new builders.

Change-Id: I8baa1d4d57f845de851c3fad3f178e05e9a01b17
Reviewed-on: https://go-review.googlesource.com/36060
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Run-TryBot: Elias Naur <elias.naur@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-02-01 22:09:16 +00:00

148 lines
3.5 KiB
Go

// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// detect attempts to autodetect the correct
// values of the environment variables
// used by go_darwin_arm_exec.
// detect shells out to ideviceinfo, a third party program that can
// be obtained by following the instructions at
// https://github.com/libimobiledevice/libimobiledevice.
package main
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
)
func main() {
devID := detectDevID()
udid := detectUDID()
mps := detectMobileProvisionFiles(udid)
if len(mps) == 0 {
fail("did not find mobile provision matching device udid %s", udid)
}
fmt.Println("Available provisioning profiles below.")
fmt.Println("NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID")
fmt.Println("will be overwritten when running Go programs.")
for _, mp := range mps {
fmt.Println()
fmt.Printf("export GOIOS_DEV_ID=%s\n", devID)
f, err := ioutil.TempFile("", "go_ios_detect_")
check(err)
fname := f.Name()
defer os.Remove(fname)
out := output(parseMobileProvision(mp))
_, err = f.Write(out)
check(err)
check(f.Close())
appID, err := plistExtract(fname, "Entitlements:application-identifier")
check(err)
fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
check(err)
fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
}
}
func detectDevID() string {
cmd := exec.Command("security", "find-identity", "-p", "codesigning", "-v")
lines := getLines(cmd)
for _, line := range lines {
if !bytes.Contains(line, []byte("iPhone Developer")) {
continue
}
if bytes.Contains(line, []byte("REVOKED")) {
continue
}
fields := bytes.Fields(line)
return string(fields[1])
}
fail("no code signing identity found")
panic("unreachable")
}
var udidPrefix = []byte("UniqueDeviceID: ")
func detectUDID() []byte {
cmd := exec.Command("ideviceinfo")
lines := getLines(cmd)
for _, line := range lines {
if bytes.HasPrefix(line, udidPrefix) {
return bytes.TrimPrefix(line, udidPrefix)
}
}
fail("udid not found; is the device connected?")
panic("unreachable")
}
func detectMobileProvisionFiles(udid []byte) []string {
cmd := exec.Command("mdfind", "-name", ".mobileprovision")
lines := getLines(cmd)
var files []string
for _, line := range lines {
if len(line) == 0 {
continue
}
xmlLines := getLines(parseMobileProvision(string(line)))
for _, xmlLine := range xmlLines {
if bytes.Contains(xmlLine, udid) {
files = append(files, string(line))
}
}
}
return files
}
func parseMobileProvision(fname string) *exec.Cmd {
return exec.Command("security", "cms", "-D", "-i", string(fname))
}
func plistExtract(fname string, path string) ([]byte, error) {
out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
if err != nil {
return nil, err
}
return bytes.TrimSpace(out), nil
}
func getLines(cmd *exec.Cmd) [][]byte {
out := output(cmd)
return bytes.Split(out, []byte("\n"))
}
func output(cmd *exec.Cmd) []byte {
out, err := cmd.Output()
if err != nil {
fmt.Println(strings.Join(cmd.Args, "\n"))
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
return out
}
func check(err error) {
if err != nil {
fail(err.Error())
}
}
func fail(msg string, v ...interface{}) {
fmt.Fprintf(os.Stderr, msg, v...)
fmt.Fprintln(os.Stderr)
os.Exit(1)
}