bin/sup-sync in sup-0.11 vs bin/sup-sync in sup-0.12
- old
+ new
@@ -1,11 +1,11 @@
#!/usr/bin/env ruby
require 'uri'
require 'rubygems'
require 'trollop'
-require "sup"; Redwood::check_library_version_against "0.11"
+require "sup"; Redwood::check_library_version_against "0.12"
PROGRESS_UPDATE_INTERVAL = 15 # seconds
class Float
def to_s; sprintf '%.2f', self; end
@@ -51,20 +51,10 @@
where <source>* is zero or more source URIs. If no sources are given,
sync from all usual sources. Supported source URI schemes can be seen
by running "sup-add --help".
-Options controlling WHICH messages sup-sync operates on:
-EOS
- opt :new, "Operate on new messages only. Don't scan over the entire source. (Default.)", :short => :none
- opt :changed, "Scan over the entire source for messages that have been deleted, altered, or moved from another source."
- opt :restored, "Operate only on those messages included in a dump file as specified by --restore which have changed state."
- opt :all, "Operate on all messages in the source, regardless of newness or changedness."
- opt :start_at, "For --changed, --restored and --all, start at a particular offset.", :type => :int
-
-text <<EOS
-
Options controlling HOW message state is altered:
EOS
opt :asis, "If the message is already in the index, preserve its state. Otherwise, use default source state. (Default.)", :short => :none
opt :restore, "Restore message state from a dump file created with sup-dump. If a message is not in this dumpfile, act as --asis.", :type => String, :short => :none
opt :discard, "Discard any message state in the index and use the default source state. Dangerous!", :short => :none
@@ -80,20 +70,13 @@
opt :optimize, "As the final operation, optimize the index."
opt :all_sources, "Scan over all sources.", :short => :none
opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
opt :version, "Show version information", :short => :none
- conflicts :changed, :all, :new, :restored
conflicts :asis, :restore, :discard
end
-Trollop::die :restored, "requires --restore" if opts[:restored] unless opts[:restore]
-if opts[:start_at]
- Trollop::die :start_at, "must be non-negative" if opts[:start_at] < 0
- Trollop::die :start_at, "requires either --changed, --restored or --all" unless opts[:changed] || opts[:restored] || opts[:all]
-end
-target = [:new, :changed, :all, :restored].find { |x| opts[x] } || :new
op = [:asis, :restore, :discard].find { |x| opts[x] } || :asis
Redwood::start
index = Redwood::Index.init
@@ -114,145 +97,97 @@
seen = {}
index.lock_interactively or exit
begin
index.load
+ if(s = Redwood::SourceManager.source_for Redwood::SentManager.source_uri)
+ Redwood::SentManager.source = s
+ else
+ Redwood::SourceManager.add_source Redwood::SentManager.default_source
+ end
+
sources = if opts[:all_sources]
Redwood::SourceManager.sources
elsif ARGV.empty?
Redwood::SourceManager.usual_sources
else
ARGV.map do |uri|
Redwood::SourceManager.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
end
end
- ## for all target specifications except for only-new messages, reset the
- ## source to the beginning (or to the user-specified starting point.)
- unless target == :new
- if opts[:start_at]
- Trollop::die :start_at, "can only be used on one source" unless sources.size == 1
- sources.first.seek_to! opts[:start_at]
- sources.first.correct_offset! if sources.first.respond_to?(:correct_offset!)
- else
- sources.each { |s| s.reset! }
- end
- end
-
sources.each do |source|
puts "Scanning #{source}..."
num_added = num_updated = num_scanned = num_restored = 0
last_info_time = start_time = Time.now
- Redwood::PollManager.each_message_from source do |m|
- num_scanned += 1
- seen[m.id] = true
- old_m = index.build_message m.id
+ Redwood::PollManager.poll_from source do |action,m,old_m,progress|
+ if action == :delete
+ puts "Deleting #{m.id}"
+ elsif action == :add
+ num_scanned += 1
+ seen[m.id] = true
- case target
- when :changed
- ## skip this message if we're operating only on changed messages, the
- ## message is in the index, and it's unchanged from what the source is
- ## reporting.
- next if old_m && old_m.source.id == m.source.id && old_m.source_info == m.source_info
- when :restored
- ## skip if we're operating on restored messages, and this one
- ## ain't (or we wouldn't be making a change)
- next unless old_m && restored_state[m.id] && restored_state[m.id] != old_m.labels
- when :new
- ## nothing to do; we'll consider all messages starting at the start offset, which
- ## hasn't been changed.
- when :all
- ## nothing to do; we'll consider all messages starting at the start offset, which
- ## was reset to the beginning above.
- end
+ ## tweak source labels according to commandline arguments if necessary
+ m.labels.delete :inbox if opts[:archive]
+ m.labels.delete :unread if opts[:read]
+ m.labels += opts[:extra_labels].to_set_of_symbols(",")
- ## tweak source labels according to commandline arguments if necessary
- m.labels.delete :inbox if opts[:archive]
- m.labels.delete :unread if opts[:read]
- m.labels += opts[:extra_labels].to_set_of_symbols(",")
-
- ## decide what to do based on message labels and the operation we're performing
- dothis, new_labels = case
- when (op == :restore) && restored_state[m.id]
- if old_m && (old_m.labels != restored_state[m.id])
- num_restored += 1
- [:update_message_state, restored_state[m.id]]
- elsif old_m.nil?
- num_restored += 1
- m.labels = restored_state[m.id]
- :add_message
+ ## decide what to do based on message labels and the operation we're performing
+ dothis = case
+ when (op == :restore) && restored_state[m.id]
+ if old_m && (old_m.labels != restored_state[m.id])
+ num_restored += 1
+ m.labels = restored_state[m.id]
+ :update_message_state
+ elsif old_m.nil?
+ num_restored += 1
+ m.labels = restored_state[m.id]
+ :add_message
+ else
+ # labels are the same; don't do anything
+ end
+ when op == :discard
+ if old_m && (old_m.labels != m.labels)
+ :update_message_state
+ else
+ # labels are the same; don't do anything
+ end
else
- # labels are the same; don't do anything
+ if old_m
+ :update_message
+ else
+ :add_message
+ end
end
- when op == :discard
- if old_m && (old_m.labels != m.labels)
- [:update_message_state, m.labels]
- else
- # labels are the same; don't do anything
+
+ ## now, actually do the operation
+ case dothis
+ when :add_message
+ puts "Adding new message #{source}##{m.source_info} with labels #{m.labels}" if opts[:verbose]
+ num_added += 1
+ when :update_message
+ puts "Updating message #{source}##{m.source_info}; labels #{old_m.labels} => #{m.labels}; offset #{old_m.source_info} => #{m.source_info}" if opts[:verbose]
+ num_updated += 1
+ when :update_message_state
+ puts "Changing flags for #{source}##{m.source_info} from #{old_m.labels} to #{m.labels}" if opts[:verbose]
+ num_updated += 1
end
- else
- ## duplicate behavior of poll mode: if index_state is non-nil, this is a newer
- ## version of an older message, so merge in any new labels except :unread and
- ## :inbox.
- ##
- ## TODO: refactor such that this isn't duplicated
- if old_m
- m.labels = old_m.labels + (m.labels - [:unread, :inbox])
- :update_message
- else
- :add_message
+
+ if Time.now - last_info_time > PROGRESS_UPDATE_INTERVAL
+ last_info_time = Time.now
+ elapsed = last_info_time - start_time
+ pctdone = progress * 100.0
+ remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
+ printf "## read %dm (~%.0f%%) @ %.1fm/s. %s elapsed, ~%s remaining\n", num_scanned, pctdone, num_scanned / elapsed, elapsed.to_time_s, remaining.to_time_s
end
+ else fail
end
-
- ## now, actually do the operation
- case dothis
- when :add_message
- puts "Adding new message #{source}##{m.source_info} with labels #{m.labels}" if opts[:verbose]
- index.add_message m unless opts[:dry_run]
- num_added += 1
- when :update_message
- puts "Updating message #{source}##{m.source_info}; labels #{old_m.labels} => #{m.labels}; offset #{old_m.source_info} => #{m.source_info}" if opts[:verbose]
- index.update_message m unless opts[:dry_run]
- num_updated += 1
- when :update_message_state
- puts "Changing flags for #{source}##{m.source_info} from #{m.labels} to #{new_labels}" if opts[:verbose]
- m.labels = new_labels
- index.update_message_state m unless opts[:dry_run]
- num_updated += 1
- end
-
- if Time.now - last_info_time > PROGRESS_UPDATE_INTERVAL
- last_info_time = Time.now
- elapsed = last_info_time - start_time
- pctdone = source.respond_to?(:pct_done) ? source.pct_done : 100.0 * (source.cur_offset.to_f - source.start_offset).to_f / (source.end_offset - source.start_offset).to_f
- remaining = (100.0 - pctdone) * (elapsed.to_f / pctdone)
- printf "## read %dm (~%.0f%%) @ %.1fm/s. %s elapsed, ~%s remaining, offset #{source.cur_offset}\n", num_scanned, pctdone, num_scanned / elapsed, elapsed.to_time_s, remaining.to_time_s
- end
+ next if opts[:dry_run]
end
puts "Scanned #{num_scanned}, added #{num_added}, updated #{num_updated} messages from #{source}."
puts "Restored state on #{num_restored} (#{100.0 * num_restored / num_scanned}%) messages." if num_restored > 0
- end
-
- ## delete any messages in the index that claim they're from one of
- ## these sources, but that we didn't see.
- if (target == :all || target == :changed)
- puts "Deleting missing messages from the index..."
- num_del, num_scanned = 0, 0
- sources.each do |source|
- raise "no source id for #{source}" unless source.id
- index.each_message :source_id => source.id, :load_spam => true, :load_deleted => true, :load_killed => true do |m|
- num_scanned += 1
- unless seen[m.id]
- next unless m.source_info >= opts[:start_at] if opts[:start_at]
- puts "Deleting #{m.id}" if opts[:verbose]
- index.delete m.id unless opts[:dry_run]
- num_del += 1
- end
- end
- end
- puts "Deleted #{num_del} / #{num_scanned} messages"
end
index.save
if opts[:optimize]