It's been a while since I've written a post here but I stopped by to pick up my script to add an X-Commit-Powered-By header to my git commit messages using a commit-msg hook and realized it's hopelessly broken now. If you want to read what it does, you should read the original post. I decided, it was time to update it for 2020s! This post covers the most interesting thing I learned while doing that.
The original script was:
#!/bin/sh
# Adds the currently playing iTunes track to the commit message
# Add a blank line
echo >> $1
state=`osascript -e 'tell application "iTunes" to player state as string'`;
if [ $state = "playing" ]; then
artist=`osascript -e 'tell application "iTunes" to artist of current track as string'`;
track=`osascript -e 'tell application "iTunes" to name of current track as string'`;
echo "X-Commit-Powered-By: $artist - $track" >> $1;
else
echo "X-Commit-Powered-By: Silent Meditation" >> $1;
fi
It clearly needed to be updated at the very least because the iTunes.app had long since been replaced by Music.app. A quick test of the osascript commands told me that replacing iTunes with Music worked just fine. Since I was going to update the script anyway, I wanted to improve it a bit further for myself.
I decided I wanted to keep a copy of the script in my ~/bin directory at all times for easier linking as a git hook. To that end, I needed a version of the script that would output the X-Commit-Powered-By header to standard output when I ran it from the ~/bin directory but to the commit message when it's run as a git commit-msg hook.
As you can read from the script source, however, it expects a filename as the first argument, $1, and appends the message to that file. Here you can find more details about that and other client-side git hooks. I could wrap all echo statements with an if statement that checks the value of $1 and branch to a version of that echo statement that outputs to the right location.
However, the ideal scenario would be to redirect standard output to a file if one was specified. After all we can do this when calling the script manually by just appending >> /path/to/filename after the script name. Why can't we do this from within the script?
I found myself on this Stack Overflow response to a similar question. Essentially all I had to do is close the file handle for standard output (file handle 1) and re-open that same file handle so it appends all its output to a file - $1 in my case. The bonus is that I don't have to append all of my echo lines with >> $1 any more - that just happens automatically.
With all that, the updated version of the script is:
#!/bin/sh
# Adds the currently playing Music track to the commit message
function displayHelp() {
echo enable this as a git hook using:
echo
echo ln -s $0 /path/to/.git/hooks/commit-msg
}
if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
displayHelp
exit 1
fi
if [ "$1" != "" ]; then
# We were given a file - presumably from git
# Let's ensure all echos go to this file
# https://stackoverflow.com/a/20564208/3766784
# Close standard error file descriptor
exec 2<&-
# Open standard output to append to $1 file for write
exec 1>>$1
fi
# Add a blank line
echo
state=`osascript -e 'tell application "Music" to player state as string'`;
if [ $state = "playing" ]; then
artist=`osascript -e 'tell application "Music" to artist of current track as string'`;
track=`osascript -e 'tell application "Music" to name of current track as string'`;
echo "X-Commit-Powered-By: $artist - $track"
else
echo "X-Commit-Powered-By: Silent Meditation"
fi
Put this script anywhere in your path, chmod +x it so it can be executed and directly linked to your .git/hooks/commit-msg and you can then run it without any arguments to test it out on standard output. Call it with a filename and it'll append its output to that file. Call it with the -h or --help argument to see how to link it to your .git/hooks directory.
One thing to keep in mind running in 2024 is that you should run the script at least once from the Terminal before installing it as a commit hook. It'll ask you for permission to let Terminal access your Music app which I figure will be necessary for it to run as a git commit hook - at least if you run git from the Terminal like I do.