/
things-export.rb
129 lines (108 loc) · 3.74 KB
/
things-export.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
require 'rubygems'
require 'hpricot'
require 'markaby'
require 'ostruct'
if ARGV.index('-v') || ARGV.index('--version')
puts "things-export 1.0"
exit
end
if !ENV['THINGS_REMOTE_PATH']
STDERR.puts "You need to set THINGS_REMOTE_PATH as the URL to copy the index file with scp."
STDERR.puts "Example: username@example.com:/var/www/htdocs/todo/"
exit
end
author = ENV['THINGS_AUTHOR'] ? "#{ENV['THINGS_AUTHOR']}'s" : "My"
things_remote = ENV['THINGS_REMOTE_PATH']
if ARGV.index('--configure') || ARGV.index('-c') || ARGV.index('--install') || ARGV.index('-i')
pub = File.join(File.dirname(__FILE__), 'public')
puts "Installing things-export to #{things_remote}"
system("scp -r #{pub} #{things_remote}")
end
todos = {:done => [], :notdone => []}
$tags = {}
filename = File.expand_path('~/Library/Application Support/Cultured Code/Things/Database.xml')
doc = Hpricot(File.read(filename))
# Get all tags
doc.search('object[@type="TAG"]').each do |tag|
$tags[tag.attributes["id"]] = tag.search('attribute[@name="title"]').text
end
# Loop through todo items
doc.search('object[@type="TODO"]').each do |todo|
next if todo.search('relationship[@name="parent"][@idrefs]').empty?
which = todo.search('attribute[@name="status"]').text.to_i == 3 ? :done : :notdone
obj = OpenStruct.new
obj.tags = []
if which == :done
obj.completed = todo.search('attribute[@name="datecompleted"]').text.to_f
elsif t=todo.search('attribute[@name="datedue"]').first
obj.duedate = t.inner_html.to_f
end
if t=todo.search('relationship[@name="tags"][@idrefs]').first
obj.tags += t.attributes["idrefs"].split(/\s+/)
end
obj.title = todo.search('attribute[@name="title"]').text
obj.index = todo.search('attribute[@name="index"]').text
todos[which] << obj
end
todos[:done] = todos[:done].sort_by {|x| x.index }
todos[:notdone] = todos[:notdone].sort_by {|x| x.index }
def taglist(mab, taglist)
taglist.each do |tag|
mab.span(:class => 'tag') do
span(:class => 'leftcap')
span(:class => 'tagtitle') { $tags[tag] }
span(:class => 'rightcap')
end
end
end
mab = Markaby::Builder.new
mab.html do
head do
title "#{author} ToDo List"
link :rel => 'stylesheet', :href => 'style.css', :type => 'text/css', :charset => 'utf-8'
end
body do
h1 "#{author} Things List"
ul(:id => 'notdone') do
row = 0
todos[:notdone].each do |todo|
row = !row
li(:class => (row ? 'even' : 'odd')) do
span(:class => 'leftcap')
span(:class => 'title') { todo.title }
span(:class => 'rightcap')
span(:class => 'duedate') do
(todo.duedate / 86400000).to_i.to_s + " days left"
end if todo.duedate
span(:class => 'tags') { taglist(mab, todo.tags) }
end
end
end
ul(:id => 'done') do
row = 0
todos[:done].each do |todo|
row = !row
li(:class => (row ? 'even' : 'odd')) do
span(:class => 'leftcap')
span(:class => 'completed') { Time.at(todo.completed).strftime("%b %d, %Y") }
span(:class => 'title') { todo.title }
span(:class => 'rightcap')
span(:class => 'tags') { taglist(mab, todo.tags) }
end
end
end
end
end
index = File.join(File.dirname(__FILE__), 'public', 'index.html')
contents = <<-eof
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
#{mab}
eof
if !ARGV.index('-f') && File.file?(index) && File.read(index) == contents
puts "Todo list is identical to current local copy, no remote update necessary. Use -f to force."
exit
end
File.open(index, "w") {|f| f.write(contents) }
puts "Pushing new list to #{things_remote}"
system("scp #{index} #{things_remote}")