bin/sup-sync-back in sup-0.1 vs bin/sup-sync-back in sup-0.2

- old
+ new

@@ -6,100 +6,123 @@ require 'trollop' require "sup" ## save a message 'm' to an open file pointer 'fp' def save m, fp - m.source.each_raw_full_message_line(m.source_info) { |l| fp.print l } + m.source.each_raw_message_line(m.source_info) { |l| fp.print l } end +def die msg + $stderr.puts "Error: #{msg}" + exit(-1) +end opts = Trollop::options do version "sup-sync-back (sup #{Redwood::VERSION})" banner <<EOS -Partially synchronizes a message source with the Sup index by deleting -or moving any messages from the source that are marked as deleted or +Drop or move messages from Sup sources that are marked as deleted or spam in the Sup index. Currently only works with mbox sources. Usage: sup-sync-back [options] <source>* where <source>* is zero or more source URIs. If no sources are given, sync back all usual sources. -You probably want to run sup-sync --changed after this command. +You almost certainly want to run sup-sync --changed after this command. +Running this does not change the index. Options include: EOS - opt :delete_deleted, "Delete deleted messages.", :default => false, :short => "d" + opt :drop_deleted, "Drop deleted messages.", :default => false, :short => "d" opt :move_deleted, "Move deleted messages to a local mbox file.", :type => String, :short => :none - opt :delete_spam, "Delete spam messages.", :default => false, :short => "s" + opt :drop_spam, "Drop spam messages.", :default => false, :short => "s" opt :move_spam, "Move spam messages to a local mbox file.", :type => String, :short => :none + + opt :with_dotlockfile, "Specific dotlockfile location (mbox files only).", :default => "/usr/bin/dotlockfile", :short => :none + opt :dont_use_dotlockfile, "Don't use dotlockfile to lock mbox files. Dangerous if other processes modify them concurrently.", :default => false, :short => :none + opt :verbose, "Print message ids as they're processed." opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n" opt :version, "Show version information", :short => :none - conflicts :delete_deleted, :move_deleted - conflicts :delete_spam, :move_spam + conflicts :drop_deleted, :move_deleted + conflicts :drop_spam, :move_spam end +unless opts[:drop_deleted] || opts[:move_deleted] || opts[:drop_spam] || opts[:move_spam] + puts "Nothing to do." + exit +end + Redwood::start index = Redwood::Index.new index.lock_or_die deleted_fp, spam_fp = nil unless opts[:dry_run] deleted_fp = File.open(opts[:move_deleted], "a") if opts[:move_deleted] spam_fp = File.open(opts[:move_spam], "a") if opts[:move_spam] end +dotlockfile = opts[:with_dotlockfile] || "/usr/bin/dotlockfile" + begin index.load sources = ARGV.map do |uri| - s = index.source_for(uri) or Trollop::die "Unknown source: #{uri}. Did you add it with sup-add first?" - s.is_a?(Redwood::MBox::Loader) or Trollop::die "#{uri} is not an mbox source." + s = index.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?" + s.is_a?(Redwood::MBox::Loader) or die "#{uri} is not an mbox source." s end if sources.empty? sources = index.usual_sources.select { |s| s.is_a? Redwood::MBox::Loader } end + unless sources.all? { |s| s.file_path.nil? } || File.executable?(dotlockfile) || opts[:dont_use_dotlockfile] + die <<EOS +can't execute dotlockfile binary: #{dotlockfile}. Specify --with-dotlockfile +if it's in a nonstandard location, or, if you want to live dangerously, try +--dont-use-dotlockfile +EOS + end + modified_sources = [] sources.each do |source| $stderr.puts "Scanning #{source}..." - unless ((opts[:delete_deleted] || opts[:move_deleted]) && index.has_any_from_source_with_label?(source, :deleted)) || ((opts[:delete_spam] || opts[:move_spam]) && index.has_any_from_source_with_label?(source, :spam)) + unless ((opts[:drop_deleted] || opts[:move_deleted]) && index.has_any_from_source_with_label?(source, :deleted)) || ((opts[:drop_spam] || opts[:move_spam]) && index.has_any_from_source_with_label?(source, :spam)) $stderr.puts "Nothing to do from this source; skipping" next end source.reset! - num_deleted = num_moved = num_scanned = 0 + num_dropped = num_moved = num_scanned = 0 out_fp = Tempfile.new "sup-sync-back-#{source.id}" Redwood::PollManager.add_messages_from source do |m, offset, entry| num_scanned += 1 if entry labels = entry[:label].split.map { |x| x.intern }.to_boolean_h if labels.member? :deleted - if opts[:delete_deleted] + if opts[:drop_deleted] puts "Dropping deleted message #{source}##{offset}" if opts[:verbose] - num_deleted += 1 + num_dropped += 1 elsif opts[:move_deleted] && labels.member?(:deleted) puts "Moving deleted message #{source}##{offset}" if opts[:verbose] save m, deleted_fp unless opts[:dry_run] num_moved += 1 end elsif labels.member? :spam - if opts[:delete_spam] - puts "Deleting spam message #{source}##{offset}" if opts[:verbose] - num_deleted += 1 + if opts[:drop_spam] + puts "Dropping spam message #{source}##{offset}" if opts[:verbose] + num_dropped += 1 elsif opts[:move_spam] && labels.member?(:spam) puts "Moving spam message #{source}##{offset}" if opts[:verbose] save m, spam_fp unless opts[:dry_run] num_moved += 1 end @@ -110,19 +133,25 @@ save m, out_fp unless opts[:dry_run] end nil # don't actually add anything! end - $stderr.puts "Scanned #{num_scanned}, deleted #{num_deleted}, moved #{num_moved} messages from #{source}." - modified_sources << source if num_deleted > 0 || num_moved > 0 + $stderr.puts "Scanned #{num_scanned}, dropped #{num_dropped}, moved #{num_moved} messages from #{source}." + modified_sources << source if num_dropped > 0 || num_moved > 0 out_fp.close unless opts[:dry_run] - unless opts[:dry_run] || (num_deleted == 0 && num_moved == 0) + unless opts[:dry_run] || (num_dropped == 0 && num_moved == 0) deleted_fp.flush if deleted_fp spam_fp.flush if spam_fp - $stderr.puts "Moving #{out_fp.path} to #{source.file_path}" - FileUtils.mv out_fp.path, source.file_path + unless opts[:dont_use_dotlockfile] + puts "Locking #{source.file_path}..." + system "#{opts[:dotlockfile]} -l #{source.file_path}" + puts "Writing #{source.file_path}..." + FileUtils.cp out_fp.path, source.file_path + puts "Unlocking #{source.file_path}..." + system "#{opts[:dotlockfile]} -u #{source.file_path}" + end end end unless opts[:dry_run] deleted_fp.close if deleted_fp @@ -135,9 +164,8 @@ end rescue Exception => e File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace } raise ensure - index.save Redwood::finish index.unlock end