My previous post scheduling system revolved around the Unix at command to schedule one-off future tasks. In the most recent version of OS X (10.10.4), that atrun command is utterly broken. Running at, atq, or atrm will give you:

atq: cannot regain privs: Operation not permitted

I couldn’t find any way to fix it, so I revamped the system. It now uses a lightweight launchd task that polls for dates listed in a simple text file. This is a simple solution that works well because I can easily edit the file remotely and modify it with other scripts.

The code that follows uses my notifyutil-based system to trigger the rake generate_deploy command that builds and uploads my static blog. You can also experiment with just running that command directly from a script, but because Jekyll has specific dependencies and most people use bundler/rvm/rbenv with it, the fact that launchd doesn’t load your shell environment may be problematic. The idea remains the same, though.

First, the script that the launchd task uses to check for new date triggers. It just reads in a file called “scheduled_deploys.txt” in the root of your Jekyll directory, parses each line, and if a line contains a date that’s before the time the task runs, it deletes the line and runs the build command.

#!/usr/bin/ruby
require 'time'

sched_file = File.expand_path('[[YOUR JEKYLL DIR]]/scheduled_deploys.txt')
if File.exists?(sched_file)
  deploys = IO.read(sched_file).strip.split(/\n/)
  deploys.delete_if {|d|
    if Time.parse(d) < Time.now
      system "/usr/bin/notifyutil -p jekyll.gendep"
      true
    else
      false
    end
  }
  File.open(sched_file,'w') {|f| f.puts deploys.join("\n")}
end

And here’s the launchd job that polls every 5 minutes. To load it, edit the script path in the file and save it to ~/Library/LaunchAgents/rb.jekyllpoller.plist (or whatever name you like), then run sudo launchctl load ~/Library/LaunchAgents/rb.jekyllpoller.plist.

<?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>Disabled</key>
    <false/>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>local.job</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/env</string>
        <string>ruby</string>
        <string>/Users/[[USER]]/[[SCRIPT PATH]]/check_jekyll_deploys.rb</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>300</integer>
</dict>
</plist>