]> git.cworth.org Git - sup/blob - bin/sup-recover-sources
skip system buffers when rolling
[sup] / bin / sup-recover-sources
1 #!/usr/bin/env ruby
2
3 require 'optparse'
4
5 $opts = {
6   :unusual => false,
7   :archive => false,
8   :scan_num => 10,
9 }
10
11
12 OPTIONPARSERSUCKS = "\n" + " " * 38
13 OptionParser.new do |opts|
14   opts.banner = <<EOS
15 Usage: sup-recover-sources [options] <source>+
16
17 Rebuilds a lost sources.yaml file by reading messages from a list of
18 sources and determining, for each source, the most prevalent
19 'source_id' field of messages from that source in the index.
20
21 The only non-deterministic component to this is that if the same
22 message appears in multiple sources, those sources may be
23 mis-diagnosed by this program.
24
25 If the first N messages (--scan-num below) all have the same source_id
26 in the index, the source will be added to sources.yaml. Otherwise, the
27 distribution will be printed, and you will have to add it by hand.
28
29 The offset pointer into the sources will be set to the end of the source,
30 so you will have to run sup-import --rebuild for each new source after
31 doing this.
32
33 Options include:
34 EOS
35
36   opts.on("--unusual", "Mark sources as 'unusual'. Only usual#{OPTIONPARSERSUCKS}sources will be polled by hand. Default:#{OPTIONPARSERSUCKS}#{$opts[:unusual]}.") { $opts[:unusual] = true }
37
38   opts.on("--archive", "Mark sources as 'archive'. New messages#{OPTIONPARSERSUCKS}from these sources will not appear in#{OPTIONPARSERSUCKS}the inbox. Default: #{$opts[:archive]}.") { $opts[:archive] = true }
39
40   opts.on("--scan-num N", Integer, "Number of messages to scan per source.#{OPTIONPARSERSUCKS}Default: #{$opts[:scan_num]}.") do |n|
41     $opts[:scan_num] = n
42   end
43
44   opts.on_tail("-h", "--help", "Show this message") do
45     puts opts
46     exit
47   end
48 end.parse(ARGV)
49
50 require "sup"
51 Redwood::start
52 puts "loading index..."
53 index = Redwood::Index.new
54 index.load
55 puts "loaded index of #{index.size} messages"
56
57 ARGV.each do |fn|
58   next if Redwood::SourceManager.source_for fn
59
60   ## TODO: merge this code with the same snippet in import
61   source = 
62     case fn
63     when %r!^imaps?://!
64       print "Username for #{fn}: "
65       username = $stdin.gets.chomp
66       print "Password for #{fn} (warning: cleartext): "
67       password = $stdin.gets.chomp
68       Redwood::IMAP.new(fn, username, password, nil, !$opts[:unusual], $opts[:archive])
69     else
70       Redwood::MBox::Loader.new(fn, nil, !$opts[:unusual], $opts[:archive])
71     end
72
73   source_ids = Hash.new 0
74   count = 0
75   source.each do |offset, labels|
76     m = Redwood::Message.new :source => source, :source_info => offset
77     m.load_from_source!
78     source_id = Redwood::SourceManager.source_for_id m.id
79     next unless source_id
80     source_ids[source_id] += 1
81     count += 1
82     break if count == $opts[:scan_num]
83   end
84
85   if source_ids.size == 1
86     id = source_ids.keys.first.to_i
87     puts "assigned #{source} to #{source_ids.keys.first}"
88     source.id = id
89     Redwood::SourceManager.add_source source
90   else
91     puts ">> unable to determine #{source}: #{source_ids.inspect}"
92   end
93 end
94
95 index.save