]> git.cworth.org Git - sup/blobdiff - bin/sup-sync
Merge branches 'completions-hook', 'find-horizontally', 'startup-hook' and 'message...
[sup] / bin / sup-sync
index f71f6b002f1392679d82e0bfcdff221a732555f1..ac5caf6c6b724e2df48db24afb46994e8cfaa683 100644 (file)
@@ -7,6 +7,9 @@ require "sup"
 
 class Float
   def to_s; sprintf '%.2f', self; end
+   def to_time_s
+     infinite? ? "unknown" : super
+   end
 end
 
 class Numeric
@@ -43,14 +46,8 @@ Usage:
   sup-sync [options] <source>*
 
 where <source>* is zero or more source URIs. If no sources are given,
-sync from all usual sources.
-
-Supported source URIs:
-  mbox://<path to mbox file>,      e.g. mbox:///var/spool/mail/me
-  maildir://<path to maildir dir>, e.g. maildir:///home/me/Maildir
-  mbox+ssh://<machine>/<path to mbox file>
-  imap://<machine>/[<folder>]
-  imaps://<machine>/[<folder>]
+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
@@ -95,7 +92,6 @@ op = [:asis, :restore, :discard].find { |x| opts[x] } || :asis
 
 Redwood::start
 index = Redwood::Index.new
-index.load
 
 restored_state =
   if opts[:restore]
@@ -112,30 +108,32 @@ restored_state =
     {}
   end
 
-sources = ARGV.map do |uri|
-  uri = "mbox://#{uri}" unless uri =~ %r!://!
-  index.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
-end
-
-sources = index.usual_sources if sources.empty?
-sources = index.sources if opts[:all_sources]
-
-unless target == :new
-  if opts[:start_at]
-    sources.each { |s| s.seek_to! opts[:start_at] }
-  else
-    sources.each { |s| s.reset! }
-  end
-end
-
 seen = {}
+index.lock_or_die
 begin
+  index.load
+
+  sources = ARGV.map do |uri|
+    index.source_for uri or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?"
+  end
+  
+  sources = index.usual_sources if sources.empty?
+  sources = index.sources if opts[:all_sources]
+
+  unless target == :new
+    if opts[:start_at]
+      sources.each { |s| s.seek_to! opts[:start_at] }
+    else
+      sources.each { |s| s.reset! }
+    end
+  end
+  
   sources.each do |source|
     $stderr.puts "Scanning #{source}..."
     num_added = num_updated = num_scanned = num_restored = 0
     last_info_time = start_time = Time.now
 
-    Redwood::PollManager.add_messages_from source do |m, offset, entry|
+    Redwood::PollManager.add_messages_from source, :force_overwrite => true do |m, offset, entry|
       num_scanned += 1
       seen[m.id] = true
 
@@ -154,7 +152,7 @@ begin
 
       ## skip if we're operating on restored messages, and this one
       ## ain't.
-      next if target == :restored && (!restored_state[m.id] || restored_state[m.id].sort_by { |s| s.to_s } == index_state.sort_by { |s| s.to_s })
+      next if target == :restored && (!restored_state[m.id] || (index_state && restored_state[m.id].sort_by { |s| s.to_s } == index_state.sort_by { |s| s.to_s }))
 
       ## m.labels is the default source labels. tweak these according
       ## to default source state modification flags.
@@ -183,7 +181,7 @@ begin
         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)
-        $stderr.puts "## #{num_added + num_updated} (#{pctdone}% done) read; #{elapsed.to_time_s} elapsed; est. #{remaining.to_time_s} remaining (for this source)"
+        $stderr.puts "## #{num_scanned} (#{pctdone}%) read; #{elapsed.to_time_s} elapsed; #{remaining.to_time_s} remaining"
       end
 
       if index_state.nil?
@@ -199,40 +197,49 @@ begin
     $stderr.puts "Scanned #{num_scanned}, added #{num_added}, updated #{num_updated} messages from #{source}."
     $stderr.puts "Restored state on #{num_restored} (#{100.0 * num_restored / num_scanned}%) messages." if num_restored > 0
   end
-ensure
-  index.save
-  Redwood::finish
-end
 
-## delete any messages in the index that claim they're from one of
-## these sources, but that we didn't see.
-##
-## kinda crappy code here, because we delve directly into the Ferret
-## API.
-##
-## TODO: move this to Index, i suppose.
-if target == :all || target == :changed
-  $stderr.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
-    q = "+source_id:#{source.id}"
-    q += " +source_info: >= #{opts[:start_at]}" if opts[:start_at]
-    index.index.search_each(q, :limit => :all) do |docid, score|
-      num_scanned += 1
-      mid = index.index[docid][:message_id]
-      unless seen[mid]
-        puts "Deleting #{mid}" if opts[:verbose]
-        index.index.delete docid unless opts[:dry_run]
-        num_del += 1
+  ## delete any messages in the index that claim they're from one of
+  ## these sources, but that we didn't see.
+  ##
+  ## kinda crappy code here, because we delve directly into the Ferret
+  ## API.
+  ##
+  ## TODO: move this to Index, i suppose.
+
+
+  if target == :all || target == :changed
+    $stderr.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
+      q = "+source_id:#{source.id}"
+      q += " +source_info: >= #{opts[:start_at]}" if opts[:start_at]
+      index.index.search_each(q, :limit => :all) do |docid, score|
+        num_scanned += 1
+        mid = index.index[docid][:message_id]
+        unless seen[mid]
+          puts "Deleting #{mid}" if opts[:verbose]
+          index.index.delete docid unless opts[:dry_run]
+          num_del += 1
+        end
       end
     end
+    $stderr.puts "Deleted #{num_del} / #{num_scanned} messages"
   end
-  $stderr.puts "Deleted #{num_del} / #{num_scanned} messages"
-end
 
-if opts[:optimize]
-  $stderr.puts "Optimizing index..."
-  optt = time { index.index.optimize unless opts[:dry_run] }
-  $stderr.puts "Optimized index of size #{index.size} in #{optt}s."
+  index.save
+
+  if opts[:optimize]
+    $stderr.puts "Optimizing index..."
+    optt = time { index.index.optimize unless opts[:dry_run] }
+    $stderr.puts "Optimized index of size #{index.size} in #{optt}s."
+  end
+rescue Redwood::FatalSourceError => e
+  $stderr.puts "Sorry, I couldn't communicate with a source: #{e.message}"
+rescue Exception => e
+  File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }
+  raise
+ensure
+  Redwood::finish
+  index.unlock
 end