Skip to content

Instantly share code, notes, and snippets.

@skeeet
Forked from tehnoir/set_project_profiles.sh
Created July 4, 2016 13:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skeeet/0cf43838a0e5dd605c7e0afc2c5b4fa5 to your computer and use it in GitHub Desktop.
Save skeeet/0cf43838a0e5dd605c7e0afc2c5b4fa5 to your computer and use it in GitHub Desktop.
Update Xcode project's build settings to point to current provisioning profiles.
#!/bin/bash
##############################################################################################################
### 1. Name your profiles with the convention of ProjectName_TargetName_ConfigurationName.mobileprovision ###
### 2. Create a directory called CodeSign in your project directory ###
### 3. Move all your project's provisioning profiles into the CodeSign directory ###
### ###
### Running this script will update your project file to point to the correct UUIDs of each corresponding ###
### profile in your CodeSign directory. ###
##############################################################################################################
function usage {
echo "Usage: set_project_profiles.sh -m <Profile Map File> -p <Xcode Project File>"
echo "If any arguments are not specified, defaults will be attempted. If defaults don't exist, user will be prompted for value."
echo "OPTIONS:"
echo ' -s: Use when running on Jenkins. Will set the root project directory to ${WORKSPACE}.'
echo " -c <CodeSign Directory>: Relative location of directory containing projects provisioning profiles."
echo " -m <Profile Map File>: Relative location of file which contains target to provisioning profile mappings."
echo " -p <Xcode Project File>: Relative location of Xcode project."
echo " -b: Use PlistBuddy command for UUID replacement instead of sed. (Better handles a couple of edge cases, but makes diffs impossible to read.)"
echo " -x: Show debug logging."
echo " -h: Display usage information."
echo " -v: Verbose logging."
}
plistBuddy="/usr/libexec/PlistBuddy"
profilesDir="${HOME}/Library/MobileDevice/Provisioning Profiles/"
setProfilesWithPlistBuddy=false
verbose=false
useConventionalProfiles=false
while getopts sc:m:p:bxhv option; do
case "${option}" in
s) server=true;;
c) codeSignDirectory=${OPTARG};;
m) profileMapFile=${OPTARG};;
p) xcodeProject=${OPTARG};;
b) setProfilesWithPlistBuddy=true;;
x) set -x;;
v) verbose=true;;
h | help) usage; exit;;
esac
done
function logit() {
if [ $verbose == true ]; then
echo "$@"
fi
}
function checkIfServer {
if [ "$server" == true ]; then
projectRoot="${WORKSPACE}"
else
projectRoot="$PWD"
fi
}
function checkForCodeSignDirectory {
if [ -z "${codeSignDirectory}" ]; then
codeSignDirectory="$projectRoot/CodeSign"
if [ ! -d "${codeSignDirectory}" ]; then
echo "No CodeSign directory found or specified with -c option. Exiting."
exit 1
fi
fi
}
### REMOVE ONCE WE GET RID OF PROFILE MAPS
function checkForProfileMap {
if [ -z "${profileMapFile}" ]; then
if [ -f "$codeSignDirectory/PROFILEMAP" ]; then
profileMapFile=`ls "$codeSignDirectory/PROFILEMAP"`
else
useConventionalProfiles=true
fi
fi
}
function checkForXcodeProject {
if [ -z "${xcodeProject}" ]; then
if [ -f "$codeSignDirectory/XCODEPROJECT" ]; then
xcodeProject=`cat "$codeSignDirectory/XCODEPROJECT"`
else
echo "No XCODEPROJECT file found in CodeSign directory or specified with -p option. Exiting."
exit 1
fi
fi
projectName=`basename "$xcodeProject" | cut -d'.' -f1`
}
function checkForProjectFile {
projectExtension=`basename "$xcodeProject" | cut -d'.' -f2`
if [ "$projectExtension" != "xcodeproj" ]; then
echo "Xcode project should have a .xcodeproj file extension. Instead got a .$projectExtension extension. Exiting."
exit 1
else
projectFile="$xcodeProject/project.pbxproj"
if [ ! -f "$projectFile" ]; then
echo "Project file $projectFile does not exist. Exiting."
exit 1
fi
fi
}
function copyProfiles {
mkdir -p "$profilesDir"
find "$codeSignDirectory" -name *.mobileprovision | egrep '.*' > /dev/null 2>&1
if [ $? -eq 0 ]; then
cp "$codeSignDirectory/"*.mobileprovision "$profilesDir"
if [ $? -ne 0 ]; then
echo "Copying profiles from CodeSign directory failed. Please run script again with -x option for debugging."
exit 1
fi
else
echo "No provisioning profiles found in CodeSign directory: $codeSignDirectory. Will attempt to proceed with profiles already in system profile directory."
fi
}
### REMOVE ONCE WE GET RID OF PROFILE MAPS
function loadProfileMap {
# Dictionary of all targets and corresponding provisioning profiles. Must be defined on a per-project basis.
# Mapping must be must be ordered target:devprofile:adhocprofile:releaseprofile
allProfiles=(`cat "$profileMapFile"`)
}
function getTargets {
rootObject=`$plistBuddy -c "Print :rootObject" $projectFile`
targetList=`$plistBuddy -c "Print :objects:$rootObject:targets" $projectFile | sed -e '/Array {/d' -e '/}/d' -e 's/^[ \t]*//'`
targets=(`echo $targetList`)
}
function setNewProfileUuid {
if [ "$currentProfileUuid" != "$newProfileUuid" ]; then
echo "Changing $configurationName from $currentProfileUuid to $newProfileUuid"
if [ $setProfilesWithPlistBuddy == false ]; then
sed -i '' "s/$currentProfileUuid/$newProfileUuid/g" "$projectFile"
if [ $? -ne 0 ]; then
printf "sed command failed on $cleanTargetName:$configurationName attempting to replace \"$currentProfileUuid\" with \"$newProfileUuid\".\nAborting.\nConsider running script with -b flag to use PlistBuddy instead of sed."
exit 1
fi
elif [ $setProfilesWithPlistBuddy == true ]; then
echo "Detected -b flag, or no profile currently set. Using PlistBuddy instead of sed to set new UUID values..."
if [ $currentProfileUuidIsSet == false ]; then
logit "No PROVISIONING_PROFILE key is defined for $targetName:$configurationName. Adding one..."
$plistBuddy -c "Add :objects:$configurationId:buildSettings:PROVISIONING_PROFILE string $newProfileUuid" "$projectFile"
elif [ $currentProfileUuidIsSet == true ]; then
$plistBuddy -c "Set :objects:$configurationId:buildSettings:PROVISIONING_PROFILE $newProfileUuid" "$projectFile"
fi
fi
else logit "Provisioning Profile UUID is already set to latest. No change made."
fi
}
function getCurrentProfileUuid {
currentProfileUuid=`$plistBuddy -c "Print :objects:$configurationId:buildSettings:PROVISIONING_PROFILE" $projectFile 2> /dev/null`
if [ $? -eq 0 ]; then
currentProfileUuidIsSet=true
if [ $currentProfileUuid == '' ]; then
echo "Current provisioning profile is blank. Unable to replace using sed, proceeding with PlistBuddy instead."
setProfilesWithPlistBuddy=true
fi
else
currentProfileUuidIsSet=false
setProfilesWithPlistBuddy=true
fi
}
function configureProvisioningProfiles {
for targetId in ${targets[@]}; do
targetName=`$plistBuddy -c "Print :objects:$targetId:name" "$projectFile"`
logit "Checking Target: $targetName"
cleanTargetName=${targetName// /_}
buildConfigurationListId=`$plistBuddy -c "Print :objects:$targetId:buildConfigurationList" "$projectFile"`
buildConfigurationList=`$plistBuddy -c "Print :objects:$buildConfigurationListId:buildConfigurations" "$projectFile" | sed -e '/Array {/d' -e '/}/d' -e 's/^[ \t]*//'`
buildConfigurations=(`echo $buildConfigurationList`)
for configurationId in ${buildConfigurations[@]}; do
configurationName=`$plistBuddy -c "Print :objects:$configurationId:name" "$projectFile"`
logit "Checking Configuration: $configurationName"
conventionProfileName=$projectName\_$cleanTargetName\_$configurationName.mobileprovision
logit "Convention Profile Name: $conventionProfileName"
if [ -f "$profilesDir/$conventionProfileName" ]; then
getCurrentProfileUuid
newProfileUuid=`security cms -D -i "$profilesDir/$conventionProfileName" > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for target $targetName with configuration $configurationName. No change made."
fi
done
done
}
### REMOVE ONCE WE GET RID OF PROFILE MAPS
function setProfilesWithProfileMap {
if [ $setProfilesWithPlistBuddy == true ]; then
echo "Detected -b flag. Using PlistBuddy instead of sed to set new UUID values..."
fi
for targetId in ${targets[@]}; do
targetName=`$plistBuddy -c "Print :objects:$targetId:name" $projectFile`
logit "Checking Target: $targetName"
cleanTargetName=${targetName// /}
for profileList in ${allProfiles[@]}; do
profileTargetName=`awk -F: '{ print $1 }' <<< $profileList`
if [ "$cleanTargetName" == "$profileTargetName" ]; then
developmentProfileName=`awk -F: '{ print $2 }' <<< $profileList`
adHocProfileName=`awk -F: '{ print $3 }' <<< $profileList`
appStoreProfileName=`awk -F: '{ print $4 }' <<< $profileList`
buildConfigurationListId=`$plistBuddy -c "Print :objects:$targetId:buildConfigurationList" $projectFile`
buildConfigurationList=`$plistBuddy -c "Print :objects:$buildConfigurationListId:buildConfigurations" $projectFile | sed -e '/Array {/d' -e '/}/d' -e 's/^[ \t]*//'`
buildConfigurations=(`echo $buildConfigurationList`)
for configurationId in ${buildConfigurations[@]}; do
configurationName=`$plistBuddy -c "Print :objects:$configurationId:name" $projectFile`
logit "Checking Configuration: $configurationName"
if [ "$profileTargetName" == "$cleanTargetName" ]; then
if [ "$configurationName" == "Debug" ]; then
getCurrentProfileUuid
if [ $? -eq 0 ]; then
newProfileUuid=`security cms -D -i $codeSignDirectory/$developmentProfileName > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for config $configurationName. No change made."
fi
elif [ "$configurationName" == "AdHoc" ]; then
getCurrentProfileUuid
if [ $? -eq 0 ]; then
newProfileUuid=`security cms -D -i $codeSignDirectory/$adHocProfileName > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for config $configurationName. No change made."
fi
elif [ "$configurationName" == "Release" ]; then
getCurrentProfileUuid
if [ $? -eq 0 ]; then
newProfileUuid=`security cms -D -i $codeSignDirectory/$appStoreProfileName > /tmp/newprofile.plist && /usr/libexec/PlistBuddy -c Print:UUID /tmp/newprofile.plist && rm -f /tmp/newprofile.plist`
setNewProfileUuid
else logit "No provisioning profile set for config $configurationName. No change made."
fi
else logit "Configuration name did not match Debug, AdHoc, or Release. No UUID set."
fi
fi
done
fi
done
done
}
checkIfServer
checkForCodeSignDirectory
checkForProfileMap
checkForXcodeProject
checkForProjectFile
copyProfiles
getTargets
if [ $useConventionalProfiles == true ]; then
configureProvisioningProfiles
else
loadProfileMap
setProfilesWithProfileMap
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment