Dealing with Special Characters in iPhone 4 Graphics Filenames with Subversion
With the iPhone 4’s high-resolution screen, designers need to create two sets of art; the guidelines are to name the files like so: SomeCoolImage.png and SomeCoolImage@2x.png. Unfortunately, if you try to add these files to an SVN repository, the @ symbol throws them off:
$ svn add Icon\@2x~iphone.png svn: warning: 'Icon' not found
The fix, thanks to the subversion_users Google Group, is to add another @ to the end of the filename, like so:
$ svn add ./Icon\@2x~iphone.png@ A (bin) Icon@2x~iphone.png
If you’d like to do this for all of your high-resolution art in a folder, here’s a tiny Bash command for the task:
for x in `ls *\@*`; do svn add $x\@; done
How-To: Run a LaunchDaemon That Requires Networking
I’m a big fan of using launchd to automate things in Mac OS X. That serves me well, as that’s how Apple wants things done moving forward. That said, one of launchd’s biggest shortcomings is a lack of a dependency system. There is currently no way, for instance, to specify in a LaunchDaemon’s property list that the daemon requires the network to be active in order to run. This is problematic for some things, such as a script I wrote to automatically set the computer’s hostname based on the DNS server (more on that later). Luckily, Apple has already defined a function, CheckForNetwork, in /private/etc/rc.common. Here it is in all its glory:
##
# Determine if the network is up by looking for any non-loopback
# internet network interfaces.
##
CheckForNetwork()
{
local test
if [ -z "${NETWORKUP:=}" ]; then
test=$(ifconfig -a inet 2>/dev/null | sed -n -e '/127.0.0.1/d' -e '/0.0.0.0/d' -e '/inet/p' | wc -l)
if [ "${test}" -gt 0 ]; then
NETWORKUP="-YES-"
else
NETWORKUP="-NO-"
fi
fi
}
In your code, simply include rc.common, then call CheckForNetwork as needed. An example:
#!/bin/bash
# Example Daemon Starter
. /etc/rc.common
CheckForNetwork
while [ "${NETWORKUP}" != "-YES-" ]
do
sleep 5
NETWORKUP=
CheckForNetwork
done
# Now do what you need to do.
Note that this will keep the script running indefinitely until CheckForNetwork sets NETWORKUP to “-YES-,” so if there’s a networking problem your code may never execute.
Using Apple’s SimplePing on iPhone OS
If you try out of the box to compile Apple’s “SimplePing” code sample on the iPhone OS, you’ll wind up with a lot of errors as some files don’t exist in those SDKs. Specifically, you need these files (you need more than just these files to compile, obviously, but these are the ones that aren’t included):
/usr/include/netinet/ip.h/usr/include/netinet/in_systm.h/usr/include/netinet/ip_icmp.h/usr/include/netinet/ip_var.h
So here’s a quick Bash script that links the relevant files to your iPhone OS and iPhone Simulator SDKs:
for path in /Developer/Platforms/iPhone*/Developer/SDKs/*; do
for file in /usr/include/netinet/ip.h \
/usr/include/netinet/in_systm.h \
/usr/include/netinet/ip_icmp.h \
/usr/include/netinet/ip_var.h; do
if [ ! -f "${path}${file}" ]; then
sudo ln "${file}" "${path}${file}"
fi;
done;
done
I’ve spoken to an Apple engineer and confirmed that this is the best way to do it, as well as filed a bug, which I encourage you to do as well if this annoys you.
Automatically get the latest Chromium snapshot with launchd
I’ve been checking out the snapshots of Chromium recently, and they’re coming quicker than you can say “multithreaded web browser.” To facilitate always having the latest version, I wrote a quick LaunchAgent that takes care of it on Mac OS X. First, I have a script named ~/bin/chromiupdate:
#!/bin/bash
# Downloads the latest version of Chromium.
remove_working_dir()
{
rm -rf "${WORKING_DIR}"
exit 0
}
USER_DIR=$(dscl . -read /Users/$(whoami) NFSHomeDirectory | awk '{ print $2 }')
USER_APP_DIR="${USER_DIR}/Applications"
CHROMIUM_DIR="${USER_APP_DIR}/Chromium.app"
LATEST_URL="http://build.chromium.org/buildbot/snapshots/sub-rel-mac/LATEST"
TMP_DIR="/private/tmp"
WORKING_DIR="${TMP_DIR}/.chromium_launchd"
URL_BEGIN="http://build.chromium.org/buildbot/snapshots/sub-rel-mac"
if [ ! -d "${CHROMIUM_DIR}" ]; then
mkdir -p "${CHROMIUM_DIR}"
fi
INSTALLED_VERSION="$(defaults read "${CHROMIUM_DIR}/Contents/Info" SVNRevision)"
VERSION=$(curl "${LATEST_URL}")
if [ "${VERSION}" != "${INSTALLED_VERSION}" ]; then
logger Installed Chromium version \(${INSTALLED_VERSION}\) does not equal \
latest version \(${VERSION}\), updating now...
mkdir "${WORKING_DIR}" || exit 1
trap remove_working_dir 1 2 3 6 15
cd "${WORKING_DIR}" || exit 1
curl -O "${URL_BEGIN}/${VERSION}/chrome-mac.zip"
unzip chrome-mac.zip
rsync -HavP --exclude="Contents/MacOS/chrome_debug.log" \
"${WORKING_DIR}/chrome-mac/Chromium.app/" "${CHROMIUM_DIR}/"
if [ "$(ps -aef | grep -i chromium | grep -v grep)" != "" ]; then
open "${USER_DIR}/Library/Scripts/Chromium Update Dialog.app"
fi
logger "Chromium update complete. Version ${VERSION} installed."
remove_working_dir
else
logger Installed Chromium version \(${INSTALLED_VERSION}\) is up-to-date. \
No action needed.
fi
exit 0
Next, I have a property list named ~/Library/LaunchAgents/com.slaunchaman.chromium.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.slaunchaman.chromium</string>
<key>Program</key>
<string>/Users/slauncha/bin/chromiupdate</string>
<key>KeepAlive</key>
<false/>
<key>StartInterval</key>
<integer>3600</integer>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StandardErrorPath</key>
<string>/dev/null</string>
</dict>
</plist>
Finally, I have an AppleScript at ~/Library/Scripts/Chromium Update Dialog.app:
display dialog "Chromium was just updated. You should restart it."
The LaunchAgent runs once an hour, checking to see if the installed version of Chromium is older than the latest snapshot. If so, it downloads it and uses rsync to copy the changes. The script places Chromium in ~/Applications, but it shouldn’t be hard to modify to put it into /Applications.
