I work in the OpenStack community, which is a broad confederation of many teams working on projects that together compose an open source IaaS cloud. With a project of such magnitude, there are a lot of meetings, which in the OpenStack world take place on Freenode IRC. The OpenStack community has set up an automated system to schedule, manage, and log these meetings. You can see the web front end at Eavesdrop.

Eavesdrop provides ICS files so you can import the schedule of meetings that are important to you into your calendar program of choice. When you are involved in multiple projects - or a project with a lot of meetings like Neutron - then you tend to find that you have a half-dozen or a dozen calendar subscriptions in your calendar program. This is bad enough, but when I wanted to share the calendaring information with my wife it became untenable. I needed a single calendar point.

For this I discovered the pyicalmerge project, which is perfect for solving this problem. I wrote a primitive shell script which takes advantage of the predictable naming pattern of the calendar files, fetches them, runs pyicalmerge on them, and dumps the output into a directory served by my personal web server. Now I have a single calendar entry that holds all of the upstream OpenStack meetings of interest to me that I can run from cron, and whose output I can share with my wife.

I did encounter one issue with the script. One of the meetings I attend alternates between two times. The format of that ics file was to have 2 entries, with the same UID. I added a few lines to randomize UIDs whenever I see them, and that resolved the difficulty.

#!/bin/zsh

# Create directory to hold all the ics files, if it does not exist
ics_cache_dir=$HOME/tmp/icalmerge
if [[ ! -d $ics_cache_dir ]]; then
	mkdir -p $ics_cache_dir
fi
cd $ics_cache_dir
rm -f *.ics 2>/dev/null

# fetch all of the ics files
set -A ICS_LIST
ICS_LIST=("neutron-ci")
ICS_LIST=($ICS_LIST "neutron-drivers-meeting")
ICS_LIST=($ICS_LIST "neutron-l3-sub-team-meeting")
ICS_LIST=($ICS_LIST "neutron-performance-meeting")
ICS_LIST=($ICS_LIST "neutron-team-meeting")
ICS_LIST=($ICS_LIST "oslo-team-meeting")
ICS_LIST=($ICS_LIST "api-special-interest-group-meeting")
ICS_LIST=($ICS_LIST "technical-committee-meeting")
ICS_LIST=($ICS_LIST "technical-committee-office-hours")
for target_ics in $ICS_LIST; do 
	target_file="${target_ics}.ics"
	if [[ -e $target_file ]]; then
		target_file=${target_file}.1
	fi
	wget http://eavesdrop.openstack.org/calendars/${target_ics}.ics
	random_uuid1="`uuidgen -r | tr -d -`"
	random_uuid2="`uuidgen -r | tr -d -`"
	uid_line="UID:${random_uuid1}@eavesdrop.openstack.org
"
	sed -i "/BEGIN:VEVENT/a ${uid_line}" ${target_file}
	num_uuids=`grep -c ${random_uuid1} ${target_file}`
	if [[ "$num_uuids" -ge 2 ]]; then
		echo "Deduping multiple UUIDs: /${random_uuid1}/${random_uuid2}/"
		sed -i "0,/${random_uuid1}/! s/${random_uuid1}/${random_uuid2}/" ${target_file}
		cat ${target_file}
	fi
	if [[ -e ${target_ics}.ics.1 ]]; then
		mv ${target_file} ${target_ics}.ics
	fi
done

# run pyicalmerge
consolidated_ics="/web/natejohnston.info/public/openstack.ics"
cd $HOME/git/github.com/nate-johnston/pyicalmerge/src
/usr/bin/python pyicalmerge.py -f "${ics_cache_dir}/*.ics" -i $consolidated_ics
chmod 644 $consolidated_ics