I need to be able to set a couple custom values in the Info.plist during the Xcode ARCHIVE process. This is for Xcode 6 and Xcode 7.
I already have a script in place that successfully updates these values as a post-action on the BUILD process. It works great when deploying to the simulator or to a phone from Xcode 6.
However, the Info.plist doesn't seem to be available from within the directory structures during the ARCHIVE process. After a BUILD, I can find the results under .../Build/Products in $CONFIGURATION-iphoneos and $CONFIGURATION-iphonesimulator. But after the ARCHIVE, there isn't anything there and I only find the compiled binaries under .../Build/Intermediates.
Certainly, I can see the Info.plist in the IPA itself. Yet any attempts to update and replace this file after the fact are unsuccessful; the IPA is no longer valid, I assume due to checksum changes or something.
I don't want to update these values in the source Info.plist (e.g., using a pre-action) as it will always make the source dirty every time I archive.
Figured this out. The process is nearly identical to the build -- use a post-action for the build, use a post-action for the archive -- just the path is different (all listed below) for where to find the Info.plist.
Below is my build script where I've used tokens for the "name" and the "value" to be updated in Info.plist. I just copied this script and renamed it for use with the archive post-action. Note that this script also has an example of extracting a value from Info.plist as I am deriving the web services version from the client version.
The path to the build Info.plist is either of:
"$BUILD_DIR/$CONFIGURATION-iphoneos/$PRODUCT_NAME.app/Info.plist"
"$BUILD_DIR/$CONFIGURATION-iphonesimulator/$PRODUCT_NAME.app/Info.plist"
NOTE: Both targets are being updated for a build since I've not figured out a way to identify which build it is doing.
The path to the archive Info.plist is:
"$ARCHIVE_PRODUCTS_PATH/Applications/$PRODUCT_NAME.app/Info.plist"
Build post-action:
$SRCROOT/post_build.sh <value> ~/xcode_build_$PRODUCT_NAME.out
Build script:
#!/bin/bash
# post_build.sh
#
# This script is intended for use by Xcode build process as a post-action.
# It expects the only argument is the value to be updated in Info.plist. It
# derives the WS version for the URL from the version found in Info.plist.
printf "Running $0 using scheme '$SCHEME_NAME' as '$USER'\n"
# If this is a clean operation, just leave
if [ $COPY_PHASE_STRIP == "YES" ]
then
printf "Doing a clean; exiting.\n"
exit 1
fi
# Confirm that PlistBuddy is available
PLIST_BUDDY=/usr/libexec/PlistBuddy
if ![-f "$PLIST_BUDDY"]
then
printf "Unable to access $PLIST_BUDDY\n"
exit 1
else
printf "PLIST_BUDDY=$PLIST_BUDDY\n"
fi
# Function to perform the changes
updatePlist()
{
PLIST_FILE=$1
if [ -f "$PLIST_FILE" ]
then
printf "Determing WS version...\n"
if [[ $SCHEME_NAME == *"Local"* ]]
then
WS_VER=""
else
# Determine the services version
BUILD_VER=$(${PLIST_BUDDY} -c "Print CFBundleShortVersionString" "$PLIST_FILE")
WS_VER=$(printf $BUILD_VER | sed 's/\(.*\)\..*/\1/' | sed 's/\./_/g')
fi
# Update the plist
${PLIST_BUDDY} -c "Set <name> <value>" "$PLIST_FILE"
printf "Updated plist $PLIST_FILE\n"
else
printf "Skipping -- no plist: $PLIST_FILE\n"
fi
}
# Retrieve the supplied URL
BASE_URL=$1
printf "BASE_URL=$BASE_URL\n\n"
# Record the environment settings
printenv | sort > ~/xcode_build_$PRODUCT_NAME.env
# Locate the plist in the device build
printf "Checking device build...\n"
updatePlist "$BUILD_DIR/$CONFIGURATION-iphoneos/$PRODUCT_NAME.app/Info.plist"
printf "\n"
# Locate the plist in the simulator build
printf "Checking simulator build...\n"
updatePlist "$BUILD_DIR/$CONFIGURATION-iphonesimulator/$PRODUCT_NAME.app/Info.plist"
printf "\n"
Related
I user flutter flavors (dev and prod) and my respective GoogleServices-Info.plist file is present in a Firebase/dev Firebase/prod folders respectively
I use a "Build Phases" script to copy the file to Runner/ directory at build-time with the below script
if [ "${CONFIGURATION}" == "Debug-prod" ] || [ "${CONFIGURATION}" == "Release-prod" ] || [ "${CONFIGURATION}" == "Release" ]; then
cp -r "${PROJECT_DIR}/Firebase/prod/GoogleService-Info.plist" "${PROJECT_DIR}/Runner/GoogleService-Info.plist"
echo "Production plist copied"
elif [ "${CONFIGURATION}" == "Debug-dev" ] || [ "${CONFIGURATION}" == "Release-dev" ] || [ "${CONFIGURATION}" == "Debug" ]; then
cp -r "${PROJECT_DIR}/Firebase/dev/GoogleService-Info.plist" "${PROJECT_DIR}/Runner/GoogleService-Info.plist"
echo "Development plist copied"
fi
Was all working OK, till I tried to use CI/CD with codemagic.
(1) First I got this error from codemagic build(But worked fine locally)
error: Build input file cannot be found: >'/Users/builder/clone/ios/Runner/GoogleService-Info.plist'
(2) I then removed the file from "Copy bundle resources" from my Xcode Target. Now I get below error(Both locally as well as with codemagic):
error: Could not get GOOGLE_APP_ID in Google Services file from build environment
What is the correct setting I should keep to get the build working both locally as well as in codemagic?
Update: After a bit of pondering, looks like (1) is the correct setting. > GoogleServices-Info.plist should be part of the copy bundle resources. >ADDITIONALLY, Runner/GoogleServices-Info.plist MUST exist before build >starts. So I placed a default plist file in the directory and it worked. >My Build Phases script will override this default plist file to >appropriate file based on the flavor
After a bit of pondering, looks like (1) is the correct setting. GoogleServices-Info.plist should be part of the copy bundle resources.
ADDITIONALLY, Runner/GoogleServices-Info.plist MUST exist before build starts. So I placed a default plist file in the directory and it worked. My Build Phases script will override this default plist file to >appropriate file based on the flavor
sorry to make another bother.
I'm implement an app, with localization of English and Japanese in xcode 5, using the script file created by André Pinto, based on SIngle Storyboard for multiple languages. Well, before upgrade to xcode 5 (xcode 4.6, I mean), things work properly. But since xcode 5, this error occurs when run the script file:
<?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>com.apple.ibtool.errors</key>
<array>
<dict>
<key>description</key>
<string>Interface Builder could not open the document "xx.storyboard" because it does not exist.</string>
</dict>
</array>
</dict>
</plist>
Iconv: ./xx/Base.lproj/xx.strings.new: No such file or directory
Rm: ./xx/Base.lproj/xx.strings.new: No such file or directory
Merging xx.strings changes for en.lproj...
Merging xx.strings changes for ja.lproj...
Command /bin/sh emitted errors but did not return a nonzero exit code to indicate failure
In the storyboard, there are 2 sub-files: xx.storyboard(Base) and xx.storyboard(Japanese)
In the first build, no error occur. Everything went fine. App localize so good.
In the second build, I made somechange in storyboard (add some new feature), then error occur. Also, the xx.storyboard(Japanese) become blank, and this is weird. I put lots of effort translate those things, and now I have to do it again...
I think there's some problem with the script, the strings.new and strings.old...
Here's the script:
#!/bin/sh
# Update storyboard string files
#
# by 2013 André Pinto andredsp#gmail.com
# based on http://forums.macrumors.com/showthread.php?t=1467446
storyboardExt=".storyboard"
stringsExt=".strings"
newStringsExt=".strings.new"
oldStringsExt=".strings.old"
localeDirExt=".lproj"
baselprojName="Base.lproj"
# Find Base internationalization folders
find . -name "$baselprojName" | while read baselprojPath
do
# Get Base project dir
baselprojDir=$(dirname "$baselprojPath")
# Find storyboard file full path inside base project folder
find "$baselprojPath" -name "*$storyboardExt" | while read storyboardPath
do
# Get Base strings file full path
baseStringsPath=$(echo "$storyboardPath" | sed "s/$storyboardExt/$stringsExt/")
# Get storyboard file name and folder
storyboardFile=$(basename "$storyboardPath")
storyboardDir=$(dirname "$storyboardPath")
# Create strings file only when storyboard file newer
newer=$(find "$storyboardPath" -prune -newer "$baseStringsPath")
[ -f "$baseStringsPath" -a -z "$newer" ] && {
echo "$storyboardFile file not modified."
continue
}
# Get New Base strings file full path and strings file name
newBaseStringsPath=$(echo "$storyboardPath" | sed "s/$storyboardExt/$newStringsExt/")
stringsFile=$(basename "$baseStringsPath")
echo "Creating default $stringsFile for $storyboardFile..."
ibtool --export-strings-file "$newBaseStringsPath" "$storyboardPath"
iconv -f UTF-16 -t UTF-8 "$newBaseStringsPath" > "$baseStringsPath"
rm "$newBaseStringsPath"
# Get all locale strings folder with same parent as Base
ls -d "$baselprojDir/"*"$localeDirExt" | while read localeStringsDir
do
# Skip Base strings folder
[ "$localeStringsDir" = "$storyboardDir" ] && continue
localeDir=$(basename "$localeStringsDir")
localeStringsPath="$localeStringsDir/$stringsFile"
# Just copy base strings file on first time
if [ ! -e "$localeStringsPath" ]; then
echo "Copying default $stringsFile for $localeDir..."
cp "$baseStringsPath" "$localeStringsPath"
else
echo "Merging $stringsFile changes for $localeDir..."
oldLocaleStringsPath=$(echo "$localeStringsPath" | sed "s/$stringsExt/$oldStringsExt/")
cp "$localeStringsPath" "$oldLocaleStringsPath"
# Merge baseStringsPath to localeStringsPath
awk '
NR == FNR && /^\/\*/ {
x=$0
getline
a[x]=$0
next
}
/^\/\*/ {
x=$0
print
getline
$0=a[x]?a[x]:$0
printf $0"\n\n"
}' "$oldLocaleStringsPath" "$baseStringsPath" > "$localeStringsPath"
rm "$oldLocaleStringsPath"
fi
done
done
done
Localizable.strings and InfoPlist.strings are still good.
Anyone has experience with this kind of things help me please... Is that something with xcode, or script file or xx.strings file? I don't get it...
I may ask it directly the script's creator, but I think post the question here will be better. I'm a SO lover :)
I was using same script as you, and had the same issues as you. Then I found these articles from AppliedIS, detailing their process of I18n and L10n. They used an updated version of this script that seems to be slightly more robust.
They also have a script for extracting keys from NSLocalizedString statements and generate Localizable.strings for every locale as well. This script uses the comment as the value when generating the new entries, which is quite clever.
I have switched to these now, and it seems faster (that might be just me; ooh, new == faster), has more output (nice for debugging) and it also works without the Run script only when installing.
Check it out! (I'm not associated with them in any way, just a happy user)
I think this is the solution:
go to xx.xcodeproj-> Target-> Build phases-> Run Script-> Tick on "Run script only when installing"
I don't know how, why but this seems to solve the problem... I think because the script run when install on ios simulator, so when I build, it can't find the xx.storyboard...
Any other answers are still welcome. I still can't satisfy with this one, because there's no guarantee with this solution.
I believe localization only occurs during the install of an app. Therefore your workaround has every reason to work since the script deals with localizing resources. Please note that many things in localization have changed and it would be worthwhile to review the linked internationalization guide located on the Apple developer website. The link contains specific videos and programming topics that provider further explanations. Some things worth considering is that you should use Autolayout if you only plan on using a single view controller. This will ensure your translations size correctly in each language.
I am building a new Xcode project template and I want to include a library that is non-ARC. But my whole project is ARC, so the only way how to build the project is to specify a compiler flag (-fno-objc-arc) on the files from that library.
How do I do that in an Xcode project template?
I tried setting it on specific files in the Definitions dictionary, both as COMPILER_FLAG and CompilerFlag. Neither of them works.
I have found absolutely no documentation on this, but I am pretty sure it can be done.
UPDATE:
Apple replied to my support request stating that there is no way of doing that right now. So unfortunately, we are out of luck, until they finally do something about the templates and their documentation.
UPDATE 2:
I've got an idea how to hack this a little bit by using a build phases script, that will check the Xcode project and add the required flags. I will post an answer soon.
I know this page is old but I wanted to offer my take on the provided scripts:
echo "Checking compiler flags."
PROJ_FILE="${PROJECT_FILE_PATH}/project.pbxproj"
REQUIRE_ARC=("File1ThatNeedsARC.m" "File2ThatNeedsARC.m")
REQUIRE_NO_ARC=("File1ThatNeedsARC.m" "File2ThatNeedsARC.m")
STR_TEST_CASE="File1ThatNeedsARC.m \*/; };"
if grep "${STR_TEST_CASE}" "$PROJ_FILE"
then
echo "Adding compiler flags."
for file in ${REQUIRE_ARC[#]}
do
STR_SRCH_ARC=$file" \*/; };"
STR_RPLC_ARC=$file" \*/; settings = {COMPILER_FLAGS = \"-fobjc-arc\"; }; };"
if grep "${STR_SRCH_ARC}" "$PROJ_FILE"
then
sed -i "" "s|${STR_SRCH_ARC}|${STR_RPLC_ARC}|g" "$PROJ_FILE"
fi
done
for file in ${REQUIRE_NO_ARC[#]}
do
STR_SRCH_NOARC=$file" \*/; };"
STR_RPLC_NOARC=$file" \*/; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; }; };"
if grep "${STR_SRCH_NOARC}" "$PROJ_FILE"
then
sed -i "" "s|${STR_SRCH_NOARC}|${STR_RPLC_NOARC}|g" "$PROJ_FILE"
fi
done
else
echo "Compiler flags already added."
exit 0
fi
just update the arrays REQUIRE_ARC and REQUIRE_NO_ARC (content separated by spaces) with the .m files appropriately.
Also update the test case STR_TEST_CASE
This script should be added to the build phases (Editor>Add Build Phase > Add Run Script Build Phase) of your xcode project (above Compile Sources).
Thank you to every one for there help that led to this script.
-
Dan
Ok, so even though I got a negative response from Apple (they don't support this in their template parser) I've found a way how to do it.
I would basically add new build phase to the template - run script. This script woudl flag the required files with the -fno-objc-arc flag and then delete itself from the project.
This is how you can add the flags:
PROJ_FILE="${PROJECT_FILE_PATH}/project.pbxproj"
STR_SRCH="\* Class.m \*\/"
STR_RPLC="\* Class.m *\/; settings = {COMPILER_FLAGS = \"-fno-objc-arc\"; };"
sed -i "" "s|${STR_SRCH};|${STR_RPLC}|g" "$PROJ_FILE"
Then in a similar manner you scan the project file and remove the build phase (with the script), so it doesn't get run each time.
I will update this answer with complete code soon.
After trying to make sure my script doesn't run after it's initial build, I've done the following:
echo "Adding compiler flags"
PROJ_FILE="${PROJECT_FILE_PATH}/project.pbxproj"
STR_SRCH="SomeClass.m \*/; };"
STR_RPLC="SomeClass.m \*/; settings = {COMPILER_FLAGS = \"-fobjc-arc\"; }; };"
if grep "${STR_SRCH}" "$PROJ_FILE"
then
sed -i "" "s|${STR_SRCH}|${STR_RPLC}|g" "$PROJ_FILE"
else
exit 0
fi
the grep will make sure that I have that exact string to replace. Otherwise, I'm assuming the fobjc-arc flag has already been added and I no longer need this script. This allowed me to run the build without removing the actual script.
You can add this flag int the project Build Phases>Compile sources as shown in the screenshot below. Put this flag in all .m files of this library:
I have found a few other posts that show how to add a script to increment the build number with a script:
Better way of incrementing build number?
Xcode project's "Build number"
Can Xcode insert the version number into a library's filename when building?
But what I want to do, is only increase the build number when I use ARCHIVE (both before and after).
Example:
If current build number is 21, then when I choose Product > Archive the build number will be increased to 22, it will go through its process of building and creating the Archive file with the build number of 22, and then when it is finished archiving, it will increase the build number to 23.
Add the following script, as in the example listed in the first link that you posted, BUT do it twice. Once at the beginning of the build and once at the end:
if [ $CONFIGURATION == Release ]; then
echo "Bumping build number..."
plist=${PROJECT_DIR}/${INFOPLIST_FILE}
# increment the build number (ie 115 to 116)
buildnum=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${plist}")
if [[ "${buildnum}" == "" ]]; then
echo "No build number in $plist"
exit 2
fi
buildnum=$(expr $buildnum + 1)
/usr/libexec/Plistbuddy -c "Set CFBundleVersion $buildnum" "${plist}"
echo "Bumped build number to $buildnum"
else
echo $CONFIGURATION " build - Not bumping build number."
fi
Many thanks to the authors of the questions that you have linked to in your question for the information that got me started on this answer!
This is very similar to #Inafziger's answer, but a more concise set of code, with the added benefit that the check for "Release" is done with a checkbox in XCode rather than a runtime variable:
Follow these instructions twice, dragging one to the beginning and one to the end (one to run before build and one to run after build):
# xcode-build-bump.sh
# #desc Auto-increment the build number every time the project is run.
# #usage
# 1. Select: your Target in Xcode
# 2. Select: Build Phases Tab
# 3. Select: Add Build Phase -> Add Run Script
# 4. Paste code below in to new "Run Script" section
# 5. Drag the "Run Script" below "Link Binaries With Libraries"
# 6. Ensure that your starting build number is set to a whole integer and not a float (e.g. 1, not 1.0)
# 7. Check the checkbox "Run script only when installing"
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
See https://gist.github.com/sekati/3172554
Xcode includes the command line tool agvtool to increase version numbers. So you don't have to do everything manually with PListBuddy.
xcrun agvtool next-version -all
increases your build number.
xcrun agvtool new-marketing-version 2.0
sets a new user visible version number.
See the full documentation for details.
I would like to insert the current Subversion revision number (as reported by svnversion) into my Xcode project. I managed to insert the revision number into the Info.plist in the $PROJECT_DIR, but this is not a good solution, since the file is versioned. I tried to insert the revision into the Info.plist in the build directory, but then I get an error during the code signing phase (this is an iPhone application).
Is there a simple way to get the revision number into the application using some build files, so that the changing revision does not change versioned files? I thought maybe I could create a temporary source file that would link with the others and provide a function to get the revision number. But I don’t know how to do that.
I am not much interested in other solutions, ie. the agvtool. All I want is the revision number available to the application, without too much magic.
There's a much simpler solution: using PlistBuddy, included at /usr/libexec/PlistBuddy in Leopard. See my answer to a related SO question for details.
PlistBuddy can be used in a Run Script build phase from within Xcode, and can be used to only affect the processed plist file. Just put it after the Copy Resources phase, and you don't even have to clean the target for it to run each time. You don't even have to print the value to a header file and make SVN ignore it, either.
echo -n ${TARGET_BUILD_DIR}/${INFOPLIST_PATH} \
| xargs -0 /usr/libexec/PlistBuddy -c "Set :CFBundleVersion `svnversion -n`"
Assuming you add the build phase before code signing occurs, your plist should be signed with the substituted value.
For posterity, I did something similar to zoul for iPhone applications, by adding a revision.h to my project, then adding the following as a Run Script build phase:
REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "#define kRevisionNumber #\"$REV\"" > ${PROJECT_DIR}/revision.h
I did this to grab a simple revision number, as opposed to the more detailed string that svnversion produces in zoul's solution.
For Mac applications, I based my approach on this post, and instead created a buildnumber.xcconfig file. Under the build settings for the target, I changed the Based On value in the lower-right-hand corner of the dialog to buildnumber.xcconfig. Within the Info.plist, I edited the following lines:
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>CFBundleShortVersionString</key>
<string>Version 1.0</string>
So that my About dialog would display a version string similar to Version 1.0 (1234), where 1234 is the Subversion revision number. Finally, I created a Run Script build phase with the following code:
REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "BUILD_NUMBER = $REV" > ${PROJECT_DIR}/buildnumber.xcconfig
This may not be the cleanest way, as it requires a clean cycle before building for the new revision to take hold in the application, but it works.
As a new user to Stack Overflow, I can't comment on Quinn's post, but I have a small change to make his solution a bit more accurate if you're using a SVN repository that has multiple projects going on at once.
Using his approach, the svnversion number that is returned is the last check-in for the entire repository, not necessarily your code base. This tweak allows for the update to be specific to your code base.
REV=`svnversion -nc | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $REV" "${TARGET_BUILD_DIR}"/${INFOPLIST_PATH}
Using the -c flag will gather the last commit done in the active branch/tag/trunk for your codebase in the form of :, then chop off the bits you don't want to store as the Revision number.
Also, notice the double quotes around the ${TARGET_BUILD_DIR}. Those are needed for users that decide to place their project in a directory structure with spaces in the name.
Hope this helps others!
I found this page when trying to do a similar thing for my iPhone app and thought it might be helpful to share the code I decided on. I was trying to have a base version number set in my Target Info (for example 0.9.5) but then append my SVN revision number at the end of it. I needed this stored in CFBundleVersion so that AdHoc users would be able to update via iTunes even if I didn't remember to rev the version number in my Target Info pane. That's why I couldn't use the "revision.h" method which otherwise worked beautifully. Here's the final code I settled on which I've placed as a Run Script phase just after the "Copy Bundle Resources" build phase:
BASEVERNUM=`/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "${INFOPLIST_FILE}" | sed 's/,/, /g'`
REV=`svnversion -n`
SVNDATE=`LC_ALL=C svn info | awk '/^Last Changed Date:/ {print $4,$5}'`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BASEVERNUM.$REV" "${TARGET_BUILD_DIR}"/${INFOPLIST_PATH}
/usr/libexec/PlistBuddy -c "Set :BuildDateString $SVNDATE" "${TARGET_BUILD_DIR}"/${INFOPLIST_PATH}
It should append the results of svnversion to the end of whatever is set in the base Info.plist as the version. This way you can have something like 0.9.5 in your info plist and still have the .189 revision number appended at the end, giving a final version number of 0.9.5.189
Hope this helps someone else!
# Xcode auto-versioning script for Subversion
# by Axel Andersson, modified by Daniel Jalkut to add
# "--revision HEAD" to the svn info line, which allows
# the latest revision to always be used.
#
# modified by JM Marino to change only [BUILD] motif
# into CFBundleGetInfoString key.
#
# HOW TO USE IT: just add [BUILD] motif to your Info.plist key :
# CFBundleVersion
#
# EXAMPLE: version 1.3.0 copyright 2003-2009 by JM Marino
# with [BUILD] into CFBundleVersion key
use strict;
die "$0: Must be run from Xcode" unless $ENV{"BUILT_PRODUCTS_DIR"};
# Get the current subversion revision number and use it to set the CFBundleVersion value
#my $REV = `/usr/local/bin/svnversion -n ./`;
my $REV = `/usr/bin/svnversion -n ./`;
my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Contents/Info.plist";
my $version = $REV;
# (Match the last group of digits without optional letter M | S):
($version =~ m/(\d+)[MS]*$/) && ($version = "" . $1);
die "$0: No Subversion revision found" unless $version;
open(FH, "$INFO") or die "$0: $INFO: $!";
my $info = join("", <FH>);
close(FH);
#$info =~ s/([\t ]+<key>CFBundleVersion<\/key>\n[\t ]+<string>.+)\[BUILD\](<\/string>)/$1$version$2/;
$info =~ s/([\t ]+<key>CFBundleVersion<\/key>\n[\t ]+<string>)\[BUILD\](<\/string>)/$1$version$2/;
open(FH, ">$INFO") or die "$0: $INFO: $!";
print FH $info;
close(FH);
Since I can't comment on Quinn's answer:
if you're using the MacPorts svn client, it may be necessary to include the full path of the svnversion command, /opt/local/bin/svnversion in my case. I also added the -c option to svnversion.
Also, if you're only interested in the second version number of mixed revisions, add a 'cut' command to the invocation, like this:
echo -n "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" \
| xargs -0 /usr/libexec/PlistBuddy -c "Set :CFBundleVersion `/opt/local/bin/svnversion -nc | cut -f2 -d:`"
Another version, written in the Apple Script. Regexp for the previousValue could be changed, currently it supports only versions in XX.XX.XX format (major, minor, svn rev).
Run by /usr/bin/osascript
set myVersion to do shell script "svn info | grep \"^Revision:\""
set myVersion to do shell script "echo " & quoted form of myVersion & "| sed 's/Revision: \\([0-9]\\)/\\1/'" as string
set myFile to do shell script "echo ${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}/"
set theOutputFolder to myFile as string
set thePListPath to POSIX path of (theOutputFolder & "Info.plist")
tell application "System Events"
tell property list file thePListPath
tell contents
set previousValue to value of property list item "CFBundleVersion"
set previousValue to do shell script "echo " & quoted form of previousValue & "| sed 's/\\([0-9]*\\.[0-9]*\\)\\(\\.[0-9]*\\)*/\\1/'" as string
set value of property list item "CFBundleVersion" to (previousValue & "." & myVersion)
end tell
end tell
end tell