Apple Development Program was introduced in WWDC2015. It is 2021 today, and there should have no possibility to use iPhone Developer certificate for code signing. This CL replaces "iPhone Developer" by "Apple Development" so that cmd/gomobile can use the correct certificate to sign the building application. Otherwise, gomobile throws an error gomobile: failed to pull the signing certificate to determine your team ID: exit status 44 Updates golang/go#47238 Change-Id: Ia48c03ff7cda39a95159e0f77e7ba7042776f9ef Reviewed-on: https://go-review.googlesource.com/c/mobile/+/346151 Reviewed-by: Hajime Hoshi <hajimehoshi@gmail.com> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> Run-TryBot: Hajime Hoshi <hajimehoshi@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Hajime Hoshi <hajimehoshi@gmail.com> Trust: Dmitri Shuralyov <dmitshur@golang.org>
609 lines
17 KiB
Go
609 lines
17 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.
|
||
|
||
package main
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto/x509"
|
||
"encoding/pem"
|
||
"fmt"
|
||
"io/ioutil"
|
||
"os"
|
||
"os/exec"
|
||
"path"
|
||
"path/filepath"
|
||
"strings"
|
||
"text/template"
|
||
|
||
"golang.org/x/tools/go/packages"
|
||
)
|
||
|
||
func goIOSBuild(pkg *packages.Package, bundleID string, archs []string) (map[string]bool, error) {
|
||
src := pkg.PkgPath
|
||
if buildO != "" && !strings.HasSuffix(buildO, ".app") {
|
||
return nil, fmt.Errorf("-o must have an .app for -target=ios")
|
||
}
|
||
|
||
productName := rfc1034Label(path.Base(pkg.PkgPath))
|
||
if productName == "" {
|
||
productName = "ProductName" // like xcode.
|
||
}
|
||
|
||
projPbxproj := new(bytes.Buffer)
|
||
if err := projPbxprojTmpl.Execute(projPbxproj, projPbxprojTmplData{
|
||
BitcodeEnabled: bitcodeEnabled,
|
||
}); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
infoplist := new(bytes.Buffer)
|
||
if err := infoplistTmpl.Execute(infoplist, infoplistTmplData{
|
||
// TODO: better bundle id.
|
||
BundleID: bundleID + "." + productName,
|
||
Name: strings.Title(path.Base(pkg.PkgPath)),
|
||
}); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
files := []struct {
|
||
name string
|
||
contents []byte
|
||
}{
|
||
{tmpdir + "/main.xcodeproj/project.pbxproj", projPbxproj.Bytes()},
|
||
{tmpdir + "/main/Info.plist", infoplist.Bytes()},
|
||
{tmpdir + "/main/Images.xcassets/AppIcon.appiconset/Contents.json", []byte(contentsJSON)},
|
||
}
|
||
|
||
for _, file := range files {
|
||
if err := mkdir(filepath.Dir(file.name)); err != nil {
|
||
return nil, err
|
||
}
|
||
if buildX {
|
||
printcmd("echo \"%s\" > %s", file.contents, file.name)
|
||
}
|
||
if !buildN {
|
||
if err := ioutil.WriteFile(file.name, file.contents, 0644); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
}
|
||
|
||
// We are using lipo tool to build multiarchitecture binaries.
|
||
cmd := exec.Command(
|
||
"xcrun", "lipo",
|
||
"-o", filepath.Join(tmpdir, "main/main"),
|
||
"-create",
|
||
)
|
||
var nmpkgs map[string]bool
|
||
for _, arch := range archs {
|
||
path := filepath.Join(tmpdir, arch)
|
||
// Disable DWARF; see golang.org/issues/25148.
|
||
if err := goBuild(src, darwinEnv[arch], "-ldflags=-w", "-o="+path); err != nil {
|
||
return nil, err
|
||
}
|
||
if nmpkgs == nil {
|
||
var err error
|
||
nmpkgs, err = extractPkgs(darwinArmNM, path)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
cmd.Args = append(cmd.Args, path)
|
||
}
|
||
|
||
if err := runCmd(cmd); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// TODO(jbd): Set the launcher icon.
|
||
if err := iosCopyAssets(pkg, tmpdir); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// Detect the team ID
|
||
teamID, err := detectTeamID()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// Build and move the release build to the output directory.
|
||
cmdStrings := []string{
|
||
"xcodebuild",
|
||
"-configuration", "Release",
|
||
"-project", tmpdir + "/main.xcodeproj",
|
||
"-allowProvisioningUpdates",
|
||
"DEVELOPMENT_TEAM=" + teamID,
|
||
}
|
||
|
||
cmd = exec.Command("xcrun", cmdStrings...)
|
||
if err := runCmd(cmd); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// TODO(jbd): Fallback to copying if renaming fails.
|
||
if buildO == "" {
|
||
n := pkg.PkgPath
|
||
if n == "." {
|
||
// use cwd name
|
||
cwd, err := os.Getwd()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("cannot create .app; cannot get the current working dir: %v", err)
|
||
}
|
||
n = cwd
|
||
}
|
||
n = path.Base(n)
|
||
buildO = n + ".app"
|
||
}
|
||
if buildX {
|
||
printcmd("mv %s %s", tmpdir+"/build/Release-iphoneos/main.app", buildO)
|
||
}
|
||
if !buildN {
|
||
// if output already exists, remove.
|
||
if err := os.RemoveAll(buildO); err != nil {
|
||
return nil, err
|
||
}
|
||
if err := os.Rename(tmpdir+"/build/Release-iphoneos/main.app", buildO); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
return nmpkgs, nil
|
||
}
|
||
|
||
func detectTeamID() (string, error) {
|
||
// Grabs the certificate for "Apple Development"; will not work if there
|
||
// are multiple certificates and the first is not desired.
|
||
cmd := exec.Command(
|
||
"security", "find-certificate",
|
||
"-c", "Apple Development", "-p",
|
||
)
|
||
pemString, err := cmd.Output()
|
||
if err != nil {
|
||
err = fmt.Errorf("failed to pull the signing certificate to determine your team ID: %v", err)
|
||
return "", err
|
||
}
|
||
|
||
block, _ := pem.Decode(pemString)
|
||
if block == nil {
|
||
err = fmt.Errorf("failed to decode the PEM to determine your team ID: %s", pemString)
|
||
return "", err
|
||
}
|
||
|
||
cert, err := x509.ParseCertificate(block.Bytes)
|
||
if err != nil {
|
||
err = fmt.Errorf("failed to parse your signing certificate to determine your team ID: %v", err)
|
||
return "", err
|
||
}
|
||
|
||
if len(cert.Subject.OrganizationalUnit) == 0 {
|
||
err = fmt.Errorf("the signing certificate has no organizational unit (team ID).")
|
||
return "", err
|
||
}
|
||
|
||
return cert.Subject.OrganizationalUnit[0], nil
|
||
}
|
||
|
||
func iosCopyAssets(pkg *packages.Package, xcodeProjDir string) error {
|
||
dstAssets := xcodeProjDir + "/main/assets"
|
||
if err := mkdir(dstAssets); err != nil {
|
||
return err
|
||
}
|
||
|
||
// TODO(hajimehoshi): This works only with Go tools that assume all source files are in one directory.
|
||
// Fix this to work with other Go tools.
|
||
srcAssets := filepath.Join(filepath.Dir(pkg.GoFiles[0]), "assets")
|
||
fi, err := os.Stat(srcAssets)
|
||
if err != nil {
|
||
if os.IsNotExist(err) {
|
||
// skip walking through the directory to deep copy.
|
||
return nil
|
||
}
|
||
return err
|
||
}
|
||
if !fi.IsDir() {
|
||
// skip walking through to deep copy.
|
||
return nil
|
||
}
|
||
// if assets is a symlink, follow the symlink.
|
||
srcAssets, err = filepath.EvalSymlinks(srcAssets)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return filepath.Walk(srcAssets, func(path string, info os.FileInfo, err error) error {
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if name := filepath.Base(path); strings.HasPrefix(name, ".") {
|
||
// Do not include the hidden files.
|
||
return nil
|
||
}
|
||
if info.IsDir() {
|
||
return nil
|
||
}
|
||
dst := dstAssets + "/" + path[len(srcAssets)+1:]
|
||
return copyFile(dst, path)
|
||
})
|
||
}
|
||
|
||
type infoplistTmplData struct {
|
||
BundleID string
|
||
Name string
|
||
}
|
||
|
||
var infoplistTmpl = template.Must(template.New("infoplist").Parse(`<?xml version="1.0" encoding="UTF-8"?>
|
||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||
<plist version="1.0">
|
||
<dict>
|
||
<key>CFBundleDevelopmentRegion</key>
|
||
<string>en</string>
|
||
<key>CFBundleExecutable</key>
|
||
<string>main</string>
|
||
<key>CFBundleIdentifier</key>
|
||
<string>{{.BundleID}}</string>
|
||
<key>CFBundleInfoDictionaryVersion</key>
|
||
<string>6.0</string>
|
||
<key>CFBundleName</key>
|
||
<string>{{.Name}}</string>
|
||
<key>CFBundlePackageType</key>
|
||
<string>APPL</string>
|
||
<key>CFBundleShortVersionString</key>
|
||
<string>1.0</string>
|
||
<key>CFBundleSignature</key>
|
||
<string>????</string>
|
||
<key>CFBundleVersion</key>
|
||
<string>1</string>
|
||
<key>LSRequiresIPhoneOS</key>
|
||
<true/>
|
||
<key>UILaunchStoryboardName</key>
|
||
<string>LaunchScreen</string>
|
||
<key>UIRequiredDeviceCapabilities</key>
|
||
<array>
|
||
<string>armv7</string>
|
||
</array>
|
||
<key>UISupportedInterfaceOrientations</key>
|
||
<array>
|
||
<string>UIInterfaceOrientationPortrait</string>
|
||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||
</array>
|
||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||
<array>
|
||
<string>UIInterfaceOrientationPortrait</string>
|
||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||
</array>
|
||
</dict>
|
||
</plist>
|
||
`))
|
||
|
||
type projPbxprojTmplData struct {
|
||
BitcodeEnabled bool
|
||
}
|
||
|
||
var projPbxprojTmpl = template.Must(template.New("projPbxproj").Parse(`// !$*UTF8*$!
|
||
{
|
||
archiveVersion = 1;
|
||
classes = {
|
||
};
|
||
objectVersion = 46;
|
||
objects = {
|
||
|
||
/* Begin PBXBuildFile section */
|
||
254BB84F1B1FD08900C56DE9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 254BB84E1B1FD08900C56DE9 /* Images.xcassets */; };
|
||
254BB8681B1FD16500C56DE9 /* main in Resources */ = {isa = PBXBuildFile; fileRef = 254BB8671B1FD16500C56DE9 /* main */; };
|
||
25FB30331B30FDEE0005924C /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 25FB30321B30FDEE0005924C /* assets */; };
|
||
/* End PBXBuildFile section */
|
||
|
||
/* Begin PBXFileReference section */
|
||
254BB83E1B1FD08900C56DE9 /* main.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = main.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||
254BB8421B1FD08900C56DE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||
254BB84E1B1FD08900C56DE9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||
254BB8671B1FD16500C56DE9 /* main */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = main; sourceTree = "<group>"; };
|
||
25FB30321B30FDEE0005924C /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = assets; path = main/assets; sourceTree = "<group>"; };
|
||
/* End PBXFileReference section */
|
||
|
||
/* Begin PBXGroup section */
|
||
254BB8351B1FD08900C56DE9 = {
|
||
isa = PBXGroup;
|
||
children = (
|
||
25FB30321B30FDEE0005924C /* assets */,
|
||
254BB8401B1FD08900C56DE9 /* main */,
|
||
254BB83F1B1FD08900C56DE9 /* Products */,
|
||
);
|
||
sourceTree = "<group>";
|
||
usesTabs = 0;
|
||
};
|
||
254BB83F1B1FD08900C56DE9 /* Products */ = {
|
||
isa = PBXGroup;
|
||
children = (
|
||
254BB83E1B1FD08900C56DE9 /* main.app */,
|
||
);
|
||
name = Products;
|
||
sourceTree = "<group>";
|
||
};
|
||
254BB8401B1FD08900C56DE9 /* main */ = {
|
||
isa = PBXGroup;
|
||
children = (
|
||
254BB8671B1FD16500C56DE9 /* main */,
|
||
254BB84E1B1FD08900C56DE9 /* Images.xcassets */,
|
||
254BB8411B1FD08900C56DE9 /* Supporting Files */,
|
||
);
|
||
path = main;
|
||
sourceTree = "<group>";
|
||
};
|
||
254BB8411B1FD08900C56DE9 /* Supporting Files */ = {
|
||
isa = PBXGroup;
|
||
children = (
|
||
254BB8421B1FD08900C56DE9 /* Info.plist */,
|
||
);
|
||
name = "Supporting Files";
|
||
sourceTree = "<group>";
|
||
};
|
||
/* End PBXGroup section */
|
||
|
||
/* Begin PBXNativeTarget section */
|
||
254BB83D1B1FD08900C56DE9 /* main */ = {
|
||
isa = PBXNativeTarget;
|
||
buildConfigurationList = 254BB8611B1FD08900C56DE9 /* Build configuration list for PBXNativeTarget "main" */;
|
||
buildPhases = (
|
||
254BB83C1B1FD08900C56DE9 /* Resources */,
|
||
);
|
||
buildRules = (
|
||
);
|
||
dependencies = (
|
||
);
|
||
name = main;
|
||
productName = main;
|
||
productReference = 254BB83E1B1FD08900C56DE9 /* main.app */;
|
||
productType = "com.apple.product-type.application";
|
||
};
|
||
/* End PBXNativeTarget section */
|
||
|
||
/* Begin PBXProject section */
|
||
254BB8361B1FD08900C56DE9 /* Project object */ = {
|
||
isa = PBXProject;
|
||
attributes = {
|
||
LastUpgradeCheck = 0630;
|
||
ORGANIZATIONNAME = Developer;
|
||
TargetAttributes = {
|
||
254BB83D1B1FD08900C56DE9 = {
|
||
CreatedOnToolsVersion = 6.3.1;
|
||
};
|
||
};
|
||
};
|
||
buildConfigurationList = 254BB8391B1FD08900C56DE9 /* Build configuration list for PBXProject "main" */;
|
||
compatibilityVersion = "Xcode 3.2";
|
||
developmentRegion = English;
|
||
hasScannedForEncodings = 0;
|
||
knownRegions = (
|
||
en,
|
||
Base,
|
||
);
|
||
mainGroup = 254BB8351B1FD08900C56DE9;
|
||
productRefGroup = 254BB83F1B1FD08900C56DE9 /* Products */;
|
||
projectDirPath = "";
|
||
projectRoot = "";
|
||
targets = (
|
||
254BB83D1B1FD08900C56DE9 /* main */,
|
||
);
|
||
};
|
||
/* End PBXProject section */
|
||
|
||
/* Begin PBXResourcesBuildPhase section */
|
||
254BB83C1B1FD08900C56DE9 /* Resources */ = {
|
||
isa = PBXResourcesBuildPhase;
|
||
buildActionMask = 2147483647;
|
||
files = (
|
||
25FB30331B30FDEE0005924C /* assets in Resources */,
|
||
254BB8681B1FD16500C56DE9 /* main in Resources */,
|
||
254BB84F1B1FD08900C56DE9 /* Images.xcassets in Resources */,
|
||
);
|
||
runOnlyForDeploymentPostprocessing = 0;
|
||
};
|
||
/* End PBXResourcesBuildPhase section */
|
||
|
||
/* Begin XCBuildConfiguration section */
|
||
254BB8601B1FD08900C56DE9 /* Release */ = {
|
||
isa = XCBuildConfiguration;
|
||
buildSettings = {
|
||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||
CLANG_CXX_LIBRARY = "libc++";
|
||
CLANG_ENABLE_MODULES = YES;
|
||
CLANG_ENABLE_OBJC_ARC = YES;
|
||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||
CLANG_WARN_EMPTY_BODY = YES;
|
||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||
CLANG_WARN_INT_CONVERSION = YES;
|
||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||
COPY_PHASE_STRIP = NO;
|
||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||
ENABLE_NS_ASSERTIONS = NO;
|
||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||
GCC_NO_COMMON_BLOCKS = YES;
|
||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||
MTL_ENABLE_DEBUG_INFO = NO;
|
||
SDKROOT = iphoneos;
|
||
TARGETED_DEVICE_FAMILY = "1,2";
|
||
VALIDATE_PRODUCT = YES;
|
||
{{if not .BitcodeEnabled}}ENABLE_BITCODE = NO;{{end}}
|
||
};
|
||
name = Release;
|
||
};
|
||
254BB8631B1FD08900C56DE9 /* Release */ = {
|
||
isa = XCBuildConfiguration;
|
||
buildSettings = {
|
||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||
INFOPLIST_FILE = main/Info.plist;
|
||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||
};
|
||
name = Release;
|
||
};
|
||
/* End XCBuildConfiguration section */
|
||
|
||
/* Begin XCConfigurationList section */
|
||
254BB8391B1FD08900C56DE9 /* Build configuration list for PBXProject "main" */ = {
|
||
isa = XCConfigurationList;
|
||
buildConfigurations = (
|
||
254BB8601B1FD08900C56DE9 /* Release */,
|
||
);
|
||
defaultConfigurationIsVisible = 0;
|
||
defaultConfigurationName = Release;
|
||
};
|
||
254BB8611B1FD08900C56DE9 /* Build configuration list for PBXNativeTarget "main" */ = {
|
||
isa = XCConfigurationList;
|
||
buildConfigurations = (
|
||
254BB8631B1FD08900C56DE9 /* Release */,
|
||
);
|
||
defaultConfigurationIsVisible = 0;
|
||
defaultConfigurationName = Release;
|
||
};
|
||
/* End XCConfigurationList section */
|
||
};
|
||
rootObject = 254BB8361B1FD08900C56DE9 /* Project object */;
|
||
}
|
||
`))
|
||
|
||
const contentsJSON = `{
|
||
"images" : [
|
||
{
|
||
"idiom" : "iphone",
|
||
"size" : "29x29",
|
||
"scale" : "2x"
|
||
},
|
||
{
|
||
"idiom" : "iphone",
|
||
"size" : "29x29",
|
||
"scale" : "3x"
|
||
},
|
||
{
|
||
"idiom" : "iphone",
|
||
"size" : "40x40",
|
||
"scale" : "2x"
|
||
},
|
||
{
|
||
"idiom" : "iphone",
|
||
"size" : "40x40",
|
||
"scale" : "3x"
|
||
},
|
||
{
|
||
"idiom" : "iphone",
|
||
"size" : "60x60",
|
||
"scale" : "2x"
|
||
},
|
||
{
|
||
"idiom" : "iphone",
|
||
"size" : "60x60",
|
||
"scale" : "3x"
|
||
},
|
||
{
|
||
"idiom" : "ipad",
|
||
"size" : "29x29",
|
||
"scale" : "1x"
|
||
},
|
||
{
|
||
"idiom" : "ipad",
|
||
"size" : "29x29",
|
||
"scale" : "2x"
|
||
},
|
||
{
|
||
"idiom" : "ipad",
|
||
"size" : "40x40",
|
||
"scale" : "1x"
|
||
},
|
||
{
|
||
"idiom" : "ipad",
|
||
"size" : "40x40",
|
||
"scale" : "2x"
|
||
},
|
||
{
|
||
"idiom" : "ipad",
|
||
"size" : "76x76",
|
||
"scale" : "1x"
|
||
},
|
||
{
|
||
"idiom" : "ipad",
|
||
"size" : "76x76",
|
||
"scale" : "2x"
|
||
}
|
||
],
|
||
"info" : {
|
||
"version" : 1,
|
||
"author" : "xcode"
|
||
}
|
||
}
|
||
`
|
||
|
||
// rfc1034Label sanitizes the name to be usable in a uniform type identifier.
|
||
// The sanitization is similar to xcode's rfc1034identifier macro that
|
||
// replaces illegal characters (not conforming the rfc1034 label rule) with '-'.
|
||
func rfc1034Label(name string) string {
|
||
// * Uniform type identifier:
|
||
//
|
||
// According to
|
||
// https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html
|
||
//
|
||
// A uniform type identifier is a Unicode string that usually contains characters
|
||
// in the ASCII character set. However, only a subset of the ASCII characters are
|
||
// permitted. You may use the Roman alphabet in upper and lower case (A–Z, a–z),
|
||
// the digits 0 through 9, the dot (“.”), and the hyphen (“-”). This restriction
|
||
// is based on DNS name restrictions, set forth in RFC 1035.
|
||
//
|
||
// Uniform type identifiers may also contain any of the Unicode characters greater
|
||
// than U+007F.
|
||
//
|
||
// Note: the actual implementation of xcode does not allow some unicode characters
|
||
// greater than U+007f. In this implementation, we just replace everything non
|
||
// alphanumeric with "-" like the rfc1034identifier macro.
|
||
//
|
||
// * RFC1034 Label
|
||
//
|
||
// <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
|
||
// <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
|
||
// <let-dig-hyp> ::= <let-dig> | "-"
|
||
// <let-dig> ::= <letter> | <digit>
|
||
const surrSelf = 0x10000
|
||
begin := false
|
||
|
||
var res []rune
|
||
for i, r := range name {
|
||
if r == '.' && !begin {
|
||
continue
|
||
}
|
||
begin = true
|
||
|
||
switch {
|
||
case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z':
|
||
res = append(res, r)
|
||
case '0' <= r && r <= '9':
|
||
if i == 0 {
|
||
res = append(res, '-')
|
||
} else {
|
||
res = append(res, r)
|
||
}
|
||
default:
|
||
if r < surrSelf {
|
||
res = append(res, '-')
|
||
} else {
|
||
res = append(res, '-', '-')
|
||
}
|
||
}
|
||
}
|
||
return string(res)
|
||
}
|