#!/usr/bin/env ruby require 'fileutils' require 'commander/import' program :name, 'dayone' program :version, File.read(File.join(File.dirname(__FILE__),'../version.txt')) program :description, "Command line interface for the rb-dayone gem" dayone_folder = File.join(ENV['HOME'], '.rb-dayone') dayone_location_file = File.join(dayone_folder, 'location') command :set do |c| c.syntax = "set [key value]" c.description = "Show or set program settings." c.summary = <<-end If sent without arguments, this will show all program settings. If sent with two arguments, this will set to . Note: setting location to "auto" will set it from the DayOne plist file. end c.action do |args| case args.size when 0 puts "location: #{File.read(dayone_location_file)}" when 2 key, val = *args case key when 'location' new_dayone_location = (val == 'auto' ? 'auto' : File.expand_path(val)) File.open(dayone_location_file,'w'){ |io| io << new_dayone_location } puts "#{key}: #{new_dayone_location}" else puts "Key #{key} not recognised" exit 1 end else puts c.syntax puts c.summary exit 1 end end end command :add do |c| c.syntax = "add [--text \"Entry text\"] [--image path/to/image.jpg] [--starred]" c.description = "Add an entry to your DayOne journal." c.summary = <<-end Add an entry to your DayOne journal. By default will add an unstarred entry - use the --starred flag to change this. If you don't specify the --text or --image tag, it will read text from STDIN and use this as the journal entry. end c.option "--text STRING", String, "Specify the journal entry text. If not specified, will read from STDIN" c.option "--starred", "Mark the entry starrd" c.option "--image path/to/image.jpg", "Add an image to the entry" c.action do |args, opts| require 'rb-dayone' entry = DayOne::Entry.new needs_stdin_help = !(opts.image || opts.text) if needs_stdin_help entry.entry_text = $stdin.read.strip else entry.entry_text = opts.text if opts.text if opts.image if File.exists? opts.image entry.image = opts.image else puts "Can't find image: #{opts.image}" exit 1 end end end entry.starred = opts.starred entry.create! end end command :repair do |c| c.syntax = "repair" c.description = "Will repair any damage caused by previous versions of rb-dayone." c.summary = "This command will trawl your DayOne journal archive looking for any malformed DayOne entries created by previous versions of rb-dayone, and will fix them. Currently it fixed malformed doctype declarations and trailing target tags." c.action do |args, opts| require 'rb-dayone' repairs = { 'trailing target' => [ /\Z/, '' ], 'malformed doctype' => [ %r||, %|| ] } DayOne.entries.each do |f| contents = File.read(f) modified = [] repairs.each do |name, (replace_this, with_this)| if replace_this === contents modified << name contents = contents.gsub(replace_this, with_this) end end unless modified.empty? File.open(f,'w'){ |io| io.puts contents } puts "Repaired file #{f}:" modified.each{ |s| puts " Fixed #{s}" } end end puts "All files have been repaired!" end end command :validate do |c| c.syntax = "validate" c.description = "Checks through your DayOne database to see if any of your journal entries break XML validation." c.action do require 'libxml' require 'rb-dayone' LibXML::XML::Error.set_handler(&LibXML::XML::Error::QUIET_HANDLER) failed_entries = [] all_entries = DayOne.entries puts "Checking #{all_entries.size} entr#{all_entries.size == 1 ? 'y' : 'ies'}..." all_entries.each do |f| begin contents = File.read(f) LibXML::XML::Parser.string(contents).parse rescue LibXML::XML::Error failed_entries << f end end if failed_entries.empty? puts "No errors. Everything is OK!" else puts "#{failed_entries.size} error#{failed_entries.size == 1 ? '' : 's'} in validation:" failed_entries.each{ |f| puts " #{f}" } end end end