All pastes #993529 Raw Edit

sup-tweak-maildir script

public ruby v1 · immutable
#993529 ·published 2008-04-22 18:13 UTC
rendered paste body
#!/usr/bin/ruby -w$LOAD_PATH.unshift '/home/tnks/src/builds/sup/lib'require 'rubygems'require 'chronic'require 'ftools'require 'singleton'require 'sup'require 'tempfile'require 'trollop'require 'uri'class Redwood::Maildir  attr_reader :ids_to_fnsendclass Redwood::Index  public :parse_user_query_stringendclass Redwood::Message  def maildir_filepath    raise "message not in a Maildir" if not @source.is_a? Redwood::Maildir    @source.scan_mailbox    return @source.ids_to_fns[@source_info]  endendclass SupTweakMaildir  include Singleton  VERSION = 0.1  PROG = $0.split("/")[-1]  USAGE = <<EOSManipulate large amounts of Maildir mail regardless of source.Usage: #{PROG} [options] <query string>All messages Maildir messages matching the supplied query string areidentified.  These messages can then be trashed (-t), purged (-p), or havetheir labels modifed (-a or -r).Note:  * The supplied query string can be of any format valid in the Sup query    buffer.  * You don't have to quote the query string to keep it one argument, but    quoting may be useful if you don't want to escape special shell characters    like '(' or ')'.  * There are four switches that effect changes to either the index or backend    Maildirs: -t, -p, -a, and -r.  Not specifying one of these switches will    just show the messages that would be acted upon, but do nothing to the    permanent stores (a dry run).  * When using the -t or -p option, you may want to exempt messages in threads    that have certain labels.  Use the -e option for this, for example    "-e starred,save".  * This script /only/ considers messages stored on a Maildir backend.  * This script does /not/ skip over Spam, Deleted, or Killed mail.Options:EOS  def initialize    self.class.i_am_the_instance self  end  def parse_options    @opts = Trollop::options do      version "#{PROG} v#{VERSION}"      banner USAGE      opt :trash, "trash matching messages from index and backend",          :short => "-t"      opt :backup, "when trashing move messages to Maildir <s>; created if" \              " missing",          :type => String,          :short => "-b",          :default => Time.now.strftime("./#{PROG}.trash.%y%m%d.%H%M%S")      opt :purge, "like --trash, but without moving messages to a backup" \              " directory",          :short => "-p"      opt :add_labels, "add labels in <s> (comma-separated) to messages",          :type => String,          :short => "-a"      opt :remove_labels, "remove labels in <s> (comma-separated) to messages",          :type => String,          :short => "-r"      opt :exempt_threads_labeled,          "exempt messages of threads with labels in <s> (comma-separated)",          :type => String,          :short => "-e"      opt :thread_by_subj, "use subject for threading",          :short => "-s"      opt :file, "dump backend filenames of matches to file <s> (one per line)",          :type => String,          :short => "-f"      conflicts :backup, :purge, :add_labels      conflicts :backup, :purge, :remove_labels      conflicts :trash, :purge, :add_labels      conflicts :trash, :purge, :remove_labels    end    Trollop::die "query string required" if ARGV.empty?  end  def gather_msgs    # building query    #    query = ARGV.join " "    real_query, opts = @index.parse_user_query_string query    opts = {      :load_spam => true,      :load_deleted => true,      :skip_killed => false    }    # getting messages matching query    #    hits = Hash.new    if @opts[:exempt_threads_labeled]      thread_set = Redwood::ThreadSet.new @index, @opts[:thread_by_subj]    end    @index.ferret.search_each(real_query, :limit => :all) do |doc_id, score|      msg = @index.build_message doc_id      next if not msg.source.is_a? Redwood::Maildir      hits[msg.maildir_filepath] = {"msg" => msg, "doc_id" => doc_id}      if @opts[:exempt_threads_labeled]        thread_set.load_thread_for_message msg, opts      end    end    Redwood::log "hits found: #{hits.length}"    # pruning threads as per specifications from command line before returning    #    if @opts[:exempt_threads_labeled]      thread_must_not_have = @opts[:exempt_threads_labeled].tr(",", " ").split.          map {|elem| elem.downcase.intern}      thread_set.threads.each do |thread|        thread_must_not_have.each do |label|          if thread.has_label? label            thread.each do |msg, depth, parent|              hits.delete msg.maildir_filepath            end            break          end        end      end      Redwood::log "removing messages in threads labeled: "\          "#{thread_must_not_have}"      Redwood::log "hits remaining: #{hits.length}"    end    return hits  end  def perform_action hits    if @opts[:file]      Redwood::log "dumping filenames of matches to '#{@opts[:file]}'"      dump_file = File.open @opts[:file], "w"      hits.keys.each {|filepath| dump_file.puts filepath}      dump_file.close    end    if @opts[:trash]      Redwood::log "action: trashing messages"      path = @opts[:backup]      File.makedirs path, "#{path}/tmp", "#{path}/cur", "#{path}/new"      hits.each do |filepath, record|        filename = filepath.split("/")[-1]        File.move filepath, "#{path}/new/#{filename}"        @index.ferret.delete record["doc_id"]      end    elsif @opts[:purge]      Redwood::log "action: purging messages"      hits.each do |filepath, record|        File.unlink filepath        @index.ferret.delete record["doc_id"]      end    elsif @opts[:add_labels] or @opts[:remove_labels]      Redwood::log "action: modifying labels."      hits.values.each do |record|        msg = record["msg"]        labels = Hash.new        msg.labels.each do |label|          labels[label] = true        end        (@opts[:add_labels] or "").tr(",", " ").split.each do |label|          labels[label.downcase.intern] = true        end        (@opts[:remove_labels] or "").tr(",", " ").split.each do |label|          labels.delete(label.downcase.intern)        end        msg.labels = labels.keys        @index.sync_message msg      end    else      Redwood::log "no action: doing nothing to permanent stores"    end  end  def main    parse_options    Redwood::start    @index = Redwood::Index.new    @index.lock_or_die    begin      @index.load      hits = gather_msgs      perform_action hits      @index.save    rescue Exception => e      File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }      raise    ensure      Redwood::finish      @index.unlock    end  endendSupTweakMaildir.new.main if $0 == __FILE__