6 def to_s; sprintf '%.2f', self; end
12 sprintf "%d:%02d:%02d", i / 3600, (i / 60) % 60, i % 60
24 Loads messages into the Sup index, adding sources as needed to the
28 sup-import [options] <source>*
29 where <source>* is zero or more source descriptions (e.g., mbox
32 If the sources listed are not already in the Sup source list,
33 they will be added to it, as parameterized by the following options:
34 --archive: messages from these sources will not appear in the inbox
35 --unusual: these sources will not be polled when the flag --the-usual
38 Regardless of whether the sources are new or not, they will be polled,
39 and any new messages will be added to the index, as parameterized by
40 the following options:
41 --force-archive: regardless of the source "archive" flag, any new
42 messages found will not appear in the inbox.
43 --force-read: any messages found will not be marked as new.
45 The following options can also be specified:
46 --the-usual: import new messages from all usual sources
47 --rebuild: rebuild the index for the specified sources rather than
48 just adding new messages. Useful if the sources
49 have changed in any way *other* than new messages
51 --force-rebuild: force a rebuild of all messages in the inbox, not just
52 ones that have changed. You probably won't need this
53 unless William changes the index format.
54 --optimize: optimize the index after adding any new messages.
55 --help: don't do anything, just show this message.
60 educate_user if ARGV.member? '--help'
62 archive = ARGV.delete "--archive"
63 unusual = ARGV.delete "--unusual"
64 force_archive = ARGV.delete "--force-archive"
65 force_read = ARGV.delete "--force-read"
66 the_usual = ARGV.delete "--the-usual"
67 rebuild = ARGV.delete "--rebuild"
68 force_rebuild = ARGV.delete "--force-rebuild"
69 optimize = ARGV.delete "--optimize"
70 start_at = # ok really need to use optparse or something now
71 if(i = ARGV.index("--start-at"))
72 raise "start-at requires a numeric argument: #{ARGV[i + 1].inspect}" unless ARGV.length > (i + 1) && ARGV[i + 1] =~ /\d/
74 ARGV.delete_at(i).to_i # whoa!
77 if(o = ARGV.find { |x| x =~ /^--/ })
78 $stderr.puts "error: unknown option #{o}"
82 puts "loading index..."
83 index = Redwood::Index.new
86 puts "loaded index of #{index.size} messages"
88 sources = ARGV.map do |fn|
89 source = index.source_for fn
94 print "Username for #{fn}: "
95 username = $stdin.gets.chomp
96 print "Password for #{fn} (warning: cleartext): "
97 password = $stdin.gets.chomp
98 Redwood::IMAP.new(fn, username, password, nil, !unusual, !!archive)
100 Redwood::MBox::Loader.new(fn, nil, !unusual, !!archive)
102 index.add_source source
107 sources = (sources + index.usual_sources).uniq if the_usual
108 if rebuild || force_rebuild
110 sources.each { |s| s.seek_to! start_at }
112 sources.each { |s| s.reset! }
119 sources.each do |source|
121 puts "loading from #{source}... "
124 source.each do |offset, labels|
125 start_offset ||= offset
126 labels -= [:inbox] if force_archive
127 labels -= [:unread] if force_read
129 m = Redwood::Message.new source, offset, labels
131 puts "skipping duplicate message #{m.id}"
136 m.remove_label :unread if m.status == "RO" unless force_read
137 puts "# message at #{offset} labels #{labels.inspect}"
138 if (rebuild || force_rebuild) &&
139 (docid, entry = index.load_entry_for_id(m.id)) && entry
140 if force_rebuild || entry[:source_info].to_i != offset
141 puts "replacing message #{m.id} labels #{entry[:label].inspect} (offset #{entry[:source_info]} => #{offset})"
142 m.labels = entry[:label].split.map { |l| l.intern }
143 num += 1 if index.update_message m, source, offset
146 num += 1 if index.add_message m
148 rescue Redwood::MessageFormatError => e
149 $stderr.puts "ignoring erroneous message at #{source}##{offset}: #{e.message}"
151 if num % 1000 == 0 && num > 0
152 elapsed = Time.now - start
153 pctdone = (offset.to_f - start_offset) / (source.total.to_f - start_offset)
154 remaining = (source.total.to_f - offset.to_f) * (elapsed.to_f / (offset.to_f - start_offset))
155 puts "## #{num} (#{(pctdone * 100.0)}% done) read; #{elapsed.to_time_s} elapsed; est. #{remaining.to_time_s} remaining"
158 puts "loaded #{num} messages" unless num == 0
164 if rebuild || force_rebuild
165 puts "deleting missing messages from the index..."
167 sources.each do |source|
168 raise "no source id for #{source}" unless source.id
169 q = "+source_id:#{source.id}"
170 q += " +source_info: >= #{start_at}" if start_at
172 num += index.index.search_each(q, :limit => :all) do |docid, score|
173 mid = index.index[docid][:message_id]
175 puts "deleting #{mid}"
176 index.index.delete docid
181 puts "deleted #{numdel} / #{num} messages"
185 puts "optimizing index..."
186 optt = time { index.index.optimize }
187 puts "optimized index of size #{index.size} in #{optt}s."