Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F78156708
gyp-mac-tool
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Aug 18, 19:32
Size
22 KB
Mime Type
text/x-python
Expires
Tue, Aug 20, 19:32 (1 d, 22 h)
Engine
blob
Format
Raw Data
Handle
19972368
Attached To
R2664 SHRINE MedCo Fork
gyp-mac-tool
View Options
#!/usr/bin/env python
# Generated by gyp. Do not edit.
# Copyright (c) 2012 Google Inc. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Utility functions to perform Xcode-style build steps.
These functions are executed via gyp-mac-tool when using the Makefile generator.
"""
import
fcntl
import
fnmatch
import
glob
import
json
import
os
import
plistlib
import
re
import
shutil
import
string
import
subprocess
import
sys
import
tempfile
def
main
(
args
):
executor
=
MacTool
()
exit_code
=
executor
.
Dispatch
(
args
)
if
exit_code
is
not
None
:
sys
.
exit
(
exit_code
)
class
MacTool
(
object
):
"""This class performs all the Mac tooling steps. The methods can either be
executed directly, or dispatched from an argument list."""
def
Dispatch
(
self
,
args
):
"""Dispatches a string command to a method."""
if
len
(
args
)
<
1
:
raise
Exception
(
"Not enough arguments"
)
method
=
"Exec
%s
"
%
self
.
_CommandifyName
(
args
[
0
])
return
getattr
(
self
,
method
)(
*
args
[
1
:])
def
_CommandifyName
(
self
,
name_string
):
"""Transforms a tool name like copy-info-plist to CopyInfoPlist"""
return
name_string
.
title
()
.
replace
(
'-'
,
''
)
def
ExecCopyBundleResource
(
self
,
source
,
dest
,
convert_to_binary
):
"""Copies a resource file to the bundle/Resources directory, performing any
necessary compilation on each resource."""
extension
=
os
.
path
.
splitext
(
source
)[
1
]
.
lower
()
if
os
.
path
.
isdir
(
source
):
# Copy tree.
# TODO(thakis): This copies file attributes like mtime, while the
# single-file branch below doesn't. This should probably be changed to
# be consistent with the single-file branch.
if
os
.
path
.
exists
(
dest
):
shutil
.
rmtree
(
dest
)
shutil
.
copytree
(
source
,
dest
)
elif
extension
==
'.xib'
:
return
self
.
_CopyXIBFile
(
source
,
dest
)
elif
extension
==
'.storyboard'
:
return
self
.
_CopyXIBFile
(
source
,
dest
)
elif
extension
==
'.strings'
:
self
.
_CopyStringsFile
(
source
,
dest
,
convert_to_binary
)
else
:
shutil
.
copy
(
source
,
dest
)
def
_CopyXIBFile
(
self
,
source
,
dest
):
"""Compiles a XIB file with ibtool into a binary plist in the bundle."""
# ibtool sometimes crashes with relative paths. See crbug.com/314728.
base
=
os
.
path
.
dirname
(
os
.
path
.
realpath
(
__file__
))
if
os
.
path
.
relpath
(
source
):
source
=
os
.
path
.
join
(
base
,
source
)
if
os
.
path
.
relpath
(
dest
):
dest
=
os
.
path
.
join
(
base
,
dest
)
args
=
[
'xcrun'
,
'ibtool'
,
'--errors'
,
'--warnings'
,
'--notices'
,
'--output-format'
,
'human-readable-text'
,
'--compile'
,
dest
,
source
]
ibtool_section_re
=
re
.
compile
(
r'/\*.*\*/'
)
ibtool_re
=
re
.
compile
(
r'.*note:.*is clipping its content'
)
ibtoolout
=
subprocess
.
Popen
(
args
,
stdout
=
subprocess
.
PIPE
)
current_section_header
=
None
for
line
in
ibtoolout
.
stdout
:
if
ibtool_section_re
.
match
(
line
):
current_section_header
=
line
elif
not
ibtool_re
.
match
(
line
):
if
current_section_header
:
sys
.
stdout
.
write
(
current_section_header
)
current_section_header
=
None
sys
.
stdout
.
write
(
line
)
return
ibtoolout
.
returncode
def
_ConvertToBinary
(
self
,
dest
):
subprocess
.
check_call
([
'xcrun'
,
'plutil'
,
'-convert'
,
'binary1'
,
'-o'
,
dest
,
dest
])
def
_CopyStringsFile
(
self
,
source
,
dest
,
convert_to_binary
):
"""Copies a .strings file using iconv to reconvert the input into UTF-16."""
input_code
=
self
.
_DetectInputEncoding
(
source
)
or
"UTF-8"
# Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
# CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
# CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
# semicolon in dictionary.
# on invalid files. Do the same kind of validation.
import
CoreFoundation
s
=
open
(
source
,
'rb'
)
.
read
()
d
=
CoreFoundation
.
CFDataCreate
(
None
,
s
,
len
(
s
))
_
,
error
=
CoreFoundation
.
CFPropertyListCreateFromXMLData
(
None
,
d
,
0
,
None
)
if
error
:
return
fp
=
open
(
dest
,
'wb'
)
fp
.
write
(
s
.
decode
(
input_code
)
.
encode
(
'UTF-16'
))
fp
.
close
()
if
convert_to_binary
==
'True'
:
self
.
_ConvertToBinary
(
dest
)
def
_DetectInputEncoding
(
self
,
file_name
):
"""Reads the first few bytes from file_name and tries to guess the text
encoding. Returns None as a guess if it can't detect it."""
fp
=
open
(
file_name
,
'rb'
)
try
:
header
=
fp
.
read
(
3
)
except
e
:
fp
.
close
()
return
None
fp
.
close
()
if
header
.
startswith
(
"
\xFE\xFF
"
):
return
"UTF-16"
elif
header
.
startswith
(
"
\xFF\xFE
"
):
return
"UTF-16"
elif
header
.
startswith
(
"
\xEF\xBB\xBF
"
):
return
"UTF-8"
else
:
return
None
def
ExecCopyInfoPlist
(
self
,
source
,
dest
,
convert_to_binary
,
*
keys
):
"""Copies the |source| Info.plist to the destination directory |dest|."""
# Read the source Info.plist into memory.
fd
=
open
(
source
,
'r'
)
lines
=
fd
.
read
()
fd
.
close
()
# Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
plist
=
plistlib
.
readPlistFromString
(
lines
)
if
keys
:
plist
=
dict
(
plist
.
items
()
+
json
.
loads
(
keys
[
0
])
.
items
())
lines
=
plistlib
.
writePlistToString
(
plist
)
# Go through all the environment variables and replace them as variables in
# the file.
IDENT_RE
=
re
.
compile
(
r'[/\s]'
)
for
key
in
os
.
environ
:
if
key
.
startswith
(
'_'
):
continue
evar
=
'${
%s
}'
%
key
evalue
=
os
.
environ
[
key
]
lines
=
string
.
replace
(
lines
,
evar
,
evalue
)
# Xcode supports various suffices on environment variables, which are
# all undocumented. :rfc1034identifier is used in the standard project
# template these days, and :identifier was used earlier. They are used to
# convert non-url characters into things that look like valid urls --
# except that the replacement character for :identifier, '_' isn't valid
# in a URL either -- oops, hence :rfc1034identifier was born.
evar
=
'${
%s
:identifier}'
%
key
evalue
=
IDENT_RE
.
sub
(
'_'
,
os
.
environ
[
key
])
lines
=
string
.
replace
(
lines
,
evar
,
evalue
)
evar
=
'${
%s
:rfc1034identifier}'
%
key
evalue
=
IDENT_RE
.
sub
(
'-'
,
os
.
environ
[
key
])
lines
=
string
.
replace
(
lines
,
evar
,
evalue
)
# Remove any keys with values that haven't been replaced.
lines
=
lines
.
split
(
'
\n
'
)
for
i
in
range
(
len
(
lines
)):
if
lines
[
i
]
.
strip
()
.
startswith
(
"<string>${"
):
lines
[
i
]
=
None
lines
[
i
-
1
]
=
None
lines
=
'
\n
'
.
join
(
filter
(
lambda
x
:
x
is
not
None
,
lines
))
# Write out the file with variables replaced.
fd
=
open
(
dest
,
'w'
)
fd
.
write
(
lines
)
fd
.
close
()
# Now write out PkgInfo file now that the Info.plist file has been
# "compiled".
self
.
_WritePkgInfo
(
dest
)
if
convert_to_binary
==
'True'
:
self
.
_ConvertToBinary
(
dest
)
def
_WritePkgInfo
(
self
,
info_plist
):
"""This writes the PkgInfo file from the data stored in Info.plist."""
plist
=
plistlib
.
readPlist
(
info_plist
)
if
not
plist
:
return
# Only create PkgInfo for executable types.
package_type
=
plist
[
'CFBundlePackageType'
]
if
package_type
!=
'APPL'
:
return
# The format of PkgInfo is eight characters, representing the bundle type
# and bundle signature, each four characters. If that is missing, four
# '?' characters are used instead.
signature_code
=
plist
.
get
(
'CFBundleSignature'
,
'????'
)
if
len
(
signature_code
)
!=
4
:
# Wrong length resets everything, too.
signature_code
=
'?'
*
4
dest
=
os
.
path
.
join
(
os
.
path
.
dirname
(
info_plist
),
'PkgInfo'
)
fp
=
open
(
dest
,
'w'
)
fp
.
write
(
'
%s%s
'
%
(
package_type
,
signature_code
))
fp
.
close
()
def
ExecFlock
(
self
,
lockfile
,
*
cmd_list
):
"""Emulates the most basic behavior of Linux's flock(1)."""
# Rely on exception handling to report errors.
fd
=
os
.
open
(
lockfile
,
os
.
O_RDONLY
|
os
.
O_NOCTTY
|
os
.
O_CREAT
,
0
o666
)
fcntl
.
flock
(
fd
,
fcntl
.
LOCK_EX
)
return
subprocess
.
call
(
cmd_list
)
def
ExecFilterLibtool
(
self
,
*
cmd_list
):
"""Calls libtool and filters out '/path/to/libtool: file: foo.o has no
symbols'."""
libtool_re
=
re
.
compile
(
r'^.*libtool: file: .* has no symbols$'
)
libtool_re5
=
re
.
compile
(
r'^.*libtool: warning for library: '
+
r'.* the table of contents is empty '
+
r'\(no object file members in the library define global symbols\)$'
)
env
=
os
.
environ
.
copy
()
# Ref:
# http://www.opensource.apple.com/source/cctools/cctools-809/misc/libtool.c
# The problem with this flag is that it resets the file mtime on the file to
# epoch=0, e.g. 1970-1-1 or 1969-12-31 depending on timezone.
env
[
'ZERO_AR_DATE'
]
=
'1'
libtoolout
=
subprocess
.
Popen
(
cmd_list
,
stderr
=
subprocess
.
PIPE
,
env
=
env
)
_
,
err
=
libtoolout
.
communicate
()
for
line
in
err
.
splitlines
():
if
not
libtool_re
.
match
(
line
)
and
not
libtool_re5
.
match
(
line
):
print
>>
sys
.
stderr
,
line
# Unconditionally touch the output .a file on the command line if present
# and the command succeeded. A bit hacky.
if
not
libtoolout
.
returncode
:
for
i
in
range
(
len
(
cmd_list
)
-
1
):
if
cmd_list
[
i
]
==
"-o"
and
cmd_list
[
i
+
1
]
.
endswith
(
'.a'
):
os
.
utime
(
cmd_list
[
i
+
1
],
None
)
break
return
libtoolout
.
returncode
def
ExecPackageFramework
(
self
,
framework
,
version
):
"""Takes a path to Something.framework and the Current version of that and
sets up all the symlinks."""
# Find the name of the binary based on the part before the ".framework".
binary
=
os
.
path
.
basename
(
framework
)
.
split
(
'.'
)[
0
]
CURRENT
=
'Current'
RESOURCES
=
'Resources'
VERSIONS
=
'Versions'
if
not
os
.
path
.
exists
(
os
.
path
.
join
(
framework
,
VERSIONS
,
version
,
binary
)):
# Binary-less frameworks don't seem to contain symlinks (see e.g.
# chromium's out/Debug/org.chromium.Chromium.manifest/ bundle).
return
# Move into the framework directory to set the symlinks correctly.
pwd
=
os
.
getcwd
()
os
.
chdir
(
framework
)
# Set up the Current version.
self
.
_Relink
(
version
,
os
.
path
.
join
(
VERSIONS
,
CURRENT
))
# Set up the root symlinks.
self
.
_Relink
(
os
.
path
.
join
(
VERSIONS
,
CURRENT
,
binary
),
binary
)
self
.
_Relink
(
os
.
path
.
join
(
VERSIONS
,
CURRENT
,
RESOURCES
),
RESOURCES
)
# Back to where we were before!
os
.
chdir
(
pwd
)
def
_Relink
(
self
,
dest
,
link
):
"""Creates a symlink to |dest| named |link|. If |link| already exists,
it is overwritten."""
if
os
.
path
.
lexists
(
link
):
os
.
remove
(
link
)
os
.
symlink
(
dest
,
link
)
def
ExecCompileXcassets
(
self
,
keys
,
*
inputs
):
"""Compiles multiple .xcassets files into a single .car file.
This invokes 'actool' to compile all the inputs .xcassets files. The
|keys| arguments is a json-encoded dictionary of extra arguments to
pass to 'actool' when the asset catalogs contains an application icon
or a launch image.
Note that 'actool' does not create the Assets.car file if the asset
catalogs does not contains imageset.
"""
command_line
=
[
'xcrun'
,
'actool'
,
'--output-format'
,
'human-readable-text'
,
'--compress-pngs'
,
'--notices'
,
'--warnings'
,
'--errors'
,
]
is_iphone_target
=
'IPHONEOS_DEPLOYMENT_TARGET'
in
os
.
environ
if
is_iphone_target
:
platform
=
os
.
environ
[
'CONFIGURATION'
]
.
split
(
'-'
)[
-
1
]
if
platform
not
in
(
'iphoneos'
,
'iphonesimulator'
):
platform
=
'iphonesimulator'
command_line
.
extend
([
'--platform'
,
platform
,
'--target-device'
,
'iphone'
,
'--target-device'
,
'ipad'
,
'--minimum-deployment-target'
,
os
.
environ
[
'IPHONEOS_DEPLOYMENT_TARGET'
],
'--compile'
,
os
.
path
.
abspath
(
os
.
environ
[
'CONTENTS_FOLDER_PATH'
]),
])
else
:
command_line
.
extend
([
'--platform'
,
'macosx'
,
'--target-device'
,
'mac'
,
'--minimum-deployment-target'
,
os
.
environ
[
'MACOSX_DEPLOYMENT_TARGET'
],
'--compile'
,
os
.
path
.
abspath
(
os
.
environ
[
'UNLOCALIZED_RESOURCES_FOLDER_PATH'
]),
])
if
keys
:
keys
=
json
.
loads
(
keys
)
for
key
,
value
in
keys
.
iteritems
():
arg_name
=
'--'
+
key
if
isinstance
(
value
,
bool
):
if
value
:
command_line
.
append
(
arg_name
)
elif
isinstance
(
value
,
list
):
for
v
in
value
:
command_line
.
append
(
arg_name
)
command_line
.
append
(
str
(
v
))
else
:
command_line
.
append
(
arg_name
)
command_line
.
append
(
str
(
value
))
# Note: actool crashes if inputs path are relative, so use os.path.abspath
# to get absolute path name for inputs.
command_line
.
extend
(
map
(
os
.
path
.
abspath
,
inputs
))
subprocess
.
check_call
(
command_line
)
def
ExecMergeInfoPlist
(
self
,
output
,
*
inputs
):
"""Merge multiple .plist files into a single .plist file."""
merged_plist
=
{}
for
path
in
inputs
:
plist
=
self
.
_LoadPlistMaybeBinary
(
path
)
self
.
_MergePlist
(
merged_plist
,
plist
)
plistlib
.
writePlist
(
merged_plist
,
output
)
def
ExecCodeSignBundle
(
self
,
key
,
resource_rules
,
entitlements
,
provisioning
):
"""Code sign a bundle.
This function tries to code sign an iOS bundle, following the same
algorithm as Xcode:
1. copy ResourceRules.plist from the user or the SDK into the bundle,
2. pick the provisioning profile that best match the bundle identifier,
and copy it into the bundle as embedded.mobileprovision,
3. copy Entitlements.plist from user or SDK next to the bundle,
4. code sign the bundle.
"""
resource_rules_path
=
self
.
_InstallResourceRules
(
resource_rules
)
substitutions
,
overrides
=
self
.
_InstallProvisioningProfile
(
provisioning
,
self
.
_GetCFBundleIdentifier
())
entitlements_path
=
self
.
_InstallEntitlements
(
entitlements
,
substitutions
,
overrides
)
subprocess
.
check_call
([
'codesign'
,
'--force'
,
'--sign'
,
key
,
'--resource-rules'
,
resource_rules_path
,
'--entitlements'
,
entitlements_path
,
os
.
path
.
join
(
os
.
environ
[
'TARGET_BUILD_DIR'
],
os
.
environ
[
'FULL_PRODUCT_NAME'
])])
def
_InstallResourceRules
(
self
,
resource_rules
):
"""Installs ResourceRules.plist from user or SDK into the bundle.
Args:
resource_rules: string, optional, path to the ResourceRules.plist file
to use, default to "${SDKROOT}/ResourceRules.plist"
Returns:
Path to the copy of ResourceRules.plist into the bundle.
"""
source_path
=
resource_rules
target_path
=
os
.
path
.
join
(
os
.
environ
[
'BUILT_PRODUCTS_DIR'
],
os
.
environ
[
'CONTENTS_FOLDER_PATH'
],
'ResourceRules.plist'
)
if
not
source_path
:
source_path
=
os
.
path
.
join
(
os
.
environ
[
'SDKROOT'
],
'ResourceRules.plist'
)
shutil
.
copy2
(
source_path
,
target_path
)
return
target_path
def
_InstallProvisioningProfile
(
self
,
profile
,
bundle_identifier
):
"""Installs embedded.mobileprovision into the bundle.
Args:
profile: string, optional, short name of the .mobileprovision file
to use, if empty or the file is missing, the best file installed
will be used
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
Returns:
A tuple containing two dictionary: variables substitutions and values
to overrides when generating the entitlements file.
"""
source_path
,
provisioning_data
,
team_id
=
self
.
_FindProvisioningProfile
(
profile
,
bundle_identifier
)
target_path
=
os
.
path
.
join
(
os
.
environ
[
'BUILT_PRODUCTS_DIR'
],
os
.
environ
[
'CONTENTS_FOLDER_PATH'
],
'embedded.mobileprovision'
)
shutil
.
copy2
(
source_path
,
target_path
)
substitutions
=
self
.
_GetSubstitutions
(
bundle_identifier
,
team_id
+
'.'
)
return
substitutions
,
provisioning_data
[
'Entitlements'
]
def
_FindProvisioningProfile
(
self
,
profile
,
bundle_identifier
):
"""Finds the .mobileprovision file to use for signing the bundle.
Checks all the installed provisioning profiles (or if the user specified
the PROVISIONING_PROFILE variable, only consult it) and select the most
specific that correspond to the bundle identifier.
Args:
profile: string, optional, short name of the .mobileprovision file
to use, if empty or the file is missing, the best file installed
will be used
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
Returns:
A tuple of the path to the selected provisioning profile, the data of
the embedded plist in the provisioning profile and the team identifier
to use for code signing.
Raises:
SystemExit: if no .mobileprovision can be used to sign the bundle.
"""
profiles_dir
=
os
.
path
.
join
(
os
.
environ
[
'HOME'
],
'Library'
,
'MobileDevice'
,
'Provisioning Profiles'
)
if
not
os
.
path
.
isdir
(
profiles_dir
):
print
>>
sys
.
stderr
,
(
'cannot find mobile provisioning for
%s
'
%
bundle_identifier
)
sys
.
exit
(
1
)
provisioning_profiles
=
None
if
profile
:
profile_path
=
os
.
path
.
join
(
profiles_dir
,
profile
+
'.mobileprovision'
)
if
os
.
path
.
exists
(
profile_path
):
provisioning_profiles
=
[
profile_path
]
if
not
provisioning_profiles
:
provisioning_profiles
=
glob
.
glob
(
os
.
path
.
join
(
profiles_dir
,
'*.mobileprovision'
))
valid_provisioning_profiles
=
{}
for
profile_path
in
provisioning_profiles
:
profile_data
=
self
.
_LoadProvisioningProfile
(
profile_path
)
app_id_pattern
=
profile_data
.
get
(
'Entitlements'
,
{})
.
get
(
'application-identifier'
,
''
)
for
team_identifier
in
profile_data
.
get
(
'TeamIdentifier'
,
[]):
app_id
=
'
%s
.
%s
'
%
(
team_identifier
,
bundle_identifier
)
if
fnmatch
.
fnmatch
(
app_id
,
app_id_pattern
):
valid_provisioning_profiles
[
app_id_pattern
]
=
(
profile_path
,
profile_data
,
team_identifier
)
if
not
valid_provisioning_profiles
:
print
>>
sys
.
stderr
,
(
'cannot find mobile provisioning for
%s
'
%
bundle_identifier
)
sys
.
exit
(
1
)
# If the user has multiple provisioning profiles installed that can be
# used for ${bundle_identifier}, pick the most specific one (ie. the
# provisioning profile whose pattern is the longest).
selected_key
=
max
(
valid_provisioning_profiles
,
key
=
lambda
v
:
len
(
v
))
return
valid_provisioning_profiles
[
selected_key
]
def
_LoadProvisioningProfile
(
self
,
profile_path
):
"""Extracts the plist embedded in a provisioning profile.
Args:
profile_path: string, path to the .mobileprovision file
Returns:
Content of the plist embedded in the provisioning profile as a dictionary.
"""
with
tempfile
.
NamedTemporaryFile
()
as
temp
:
subprocess
.
check_call
([
'security'
,
'cms'
,
'-D'
,
'-i'
,
profile_path
,
'-o'
,
temp
.
name
])
return
self
.
_LoadPlistMaybeBinary
(
temp
.
name
)
def
_MergePlist
(
self
,
merged_plist
,
plist
):
"""Merge |plist| into |merged_plist|."""
for
key
,
value
in
plist
.
iteritems
():
if
isinstance
(
value
,
dict
):
merged_value
=
merged_plist
.
get
(
key
,
{})
if
isinstance
(
merged_value
,
dict
):
self
.
_MergePlist
(
merged_value
,
value
)
merged_plist
[
key
]
=
merged_value
else
:
merged_plist
[
key
]
=
value
else
:
merged_plist
[
key
]
=
value
def
_LoadPlistMaybeBinary
(
self
,
plist_path
):
"""Loads into a memory a plist possibly encoded in binary format.
This is a wrapper around plistlib.readPlist that tries to convert the
plist to the XML format if it can't be parsed (assuming that it is in
the binary format).
Args:
plist_path: string, path to a plist file, in XML or binary format
Returns:
Content of the plist as a dictionary.
"""
try
:
# First, try to read the file using plistlib that only supports XML,
# and if an exception is raised, convert a temporary copy to XML and
# load that copy.
return
plistlib
.
readPlist
(
plist_path
)
except
:
pass
with
tempfile
.
NamedTemporaryFile
()
as
temp
:
shutil
.
copy2
(
plist_path
,
temp
.
name
)
subprocess
.
check_call
([
'plutil'
,
'-convert'
,
'xml1'
,
temp
.
name
])
return
plistlib
.
readPlist
(
temp
.
name
)
def
_GetSubstitutions
(
self
,
bundle_identifier
,
app_identifier_prefix
):
"""Constructs a dictionary of variable substitutions for Entitlements.plist.
Args:
bundle_identifier: string, value of CFBundleIdentifier from Info.plist
app_identifier_prefix: string, value for AppIdentifierPrefix
Returns:
Dictionary of substitutions to apply when generating Entitlements.plist.
"""
return
{
'CFBundleIdentifier'
:
bundle_identifier
,
'AppIdentifierPrefix'
:
app_identifier_prefix
,
}
def
_GetCFBundleIdentifier
(
self
):
"""Extracts CFBundleIdentifier value from Info.plist in the bundle.
Returns:
Value of CFBundleIdentifier in the Info.plist located in the bundle.
"""
info_plist_path
=
os
.
path
.
join
(
os
.
environ
[
'TARGET_BUILD_DIR'
],
os
.
environ
[
'INFOPLIST_PATH'
])
info_plist_data
=
self
.
_LoadPlistMaybeBinary
(
info_plist_path
)
return
info_plist_data
[
'CFBundleIdentifier'
]
def
_InstallEntitlements
(
self
,
entitlements
,
substitutions
,
overrides
):
"""Generates and install the ${BundleName}.xcent entitlements file.
Expands variables "$(variable)" pattern in the source entitlements file,
add extra entitlements defined in the .mobileprovision file and the copy
the generated plist to "${BundlePath}.xcent".
Args:
entitlements: string, optional, path to the Entitlements.plist template
to use, defaults to "${SDKROOT}/Entitlements.plist"
substitutions: dictionary, variable substitutions
overrides: dictionary, values to add to the entitlements
Returns:
Path to the generated entitlements file.
"""
source_path
=
entitlements
target_path
=
os
.
path
.
join
(
os
.
environ
[
'BUILT_PRODUCTS_DIR'
],
os
.
environ
[
'PRODUCT_NAME'
]
+
'.xcent'
)
if
not
source_path
:
source_path
=
os
.
path
.
join
(
os
.
environ
[
'SDKROOT'
],
'Entitlements.plist'
)
shutil
.
copy2
(
source_path
,
target_path
)
data
=
self
.
_LoadPlistMaybeBinary
(
target_path
)
data
=
self
.
_ExpandVariables
(
data
,
substitutions
)
if
overrides
:
for
key
in
overrides
:
if
key
not
in
data
:
data
[
key
]
=
overrides
[
key
]
plistlib
.
writePlist
(
data
,
target_path
)
return
target_path
def
_ExpandVariables
(
self
,
data
,
substitutions
):
"""Expands variables "$(variable)" in data.
Args:
data: object, can be either string, list or dictionary
substitutions: dictionary, variable substitutions to perform
Returns:
Copy of data where each references to "$(variable)" has been replaced
by the corresponding value found in substitutions, or left intact if
the key was not found.
"""
if
isinstance
(
data
,
str
):
for
key
,
value
in
substitutions
.
iteritems
():
data
=
data
.
replace
(
'$(
%s
)'
%
key
,
value
)
return
data
if
isinstance
(
data
,
list
):
return
[
self
.
_ExpandVariables
(
v
,
substitutions
)
for
v
in
data
]
if
isinstance
(
data
,
dict
):
return
{
k
:
self
.
_ExpandVariables
(
data
[
k
],
substitutions
)
for
k
in
data
}
return
data
if
__name__
==
'__main__'
:
sys
.
exit
(
main
(
sys
.
argv
[
1
:]))
Event Timeline
Log In to Comment