]> git.cworth.org Git - sup/commitdiff
Merge branch 'parser-user-query-fix' into next
authorWilliam Morgan <wmorgan-sup@masanjin.net>
Mon, 18 May 2009 18:18:01 +0000 (14:18 -0400)
committerWilliam Morgan <wmorgan-sup@masanjin.net>
Mon, 18 May 2009 18:18:01 +0000 (14:18 -0400)
1  2 
bin/sup-tweak-labels
lib/sup/index.rb

diff --combined bin/sup-tweak-labels
index 8a8152d60b18db9c0a0dcfd45637e9070ece1293,b71735922bf60f1e364a543a058ab038ca4c13d4..538db8b38ac402604c6ef5b1f24475895ee7635d
@@@ -46,12 -46,10 +46,12 @@@ EO
  Other options:
  EOS
    opt :verbose, "Print message ids as they're processed."
 +  opt :very_verbose, "Print message names and subjects as they're processed."
    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
  end
 +opts[:verbose] = true if opts[:very_verbose]
  
  add_labels = (opts[:add] || "").split(",").map { |l| l.intern }.uniq
  remove_labels = (opts[:remove] || "").split(",").map { |l| l.intern }.uniq
@@@ -81,19 -79,15 +81,15 @@@ begi
    end
    query += ' ' + opts[:query] if opts[:query]
  
-   qobj, opts = Redwood::Index.parse_user_query_string query
-   query = Redwood::Index.build_query opts.merge(:qobj => qobj)
-   results = index.ferret.search query, :limit => :all
-   num_total = results.total_hits
+   docs = Redwood::Index.run_query query
+   num_total = docs.size
  
    $stderr.puts "Found #{num_total} documents across #{source_ids.length} sources. Scanning..."
  
    num_changed = num_scanned = 0
    last_info_time = start_time = Time.now
-   results.hits.each do |hit|
+   docs.each do |id|
      num_scanned += 1
-     id = hit.doc
  
      m = index.build_message id
      old_labels = m.labels.clone
  
      unless m.labels.sort_by { |s| s.to_s } == old_labels.sort_by { |s| s.to_s }
        num_changed += 1
 +      puts "From #{m.from}, subject: #{m.subj}" if opts[:very_verbose]
        puts "#{m.id}: {#{old_labels.join ','}} => {#{m.labels.join ','}}" if opts[:verbose]
 +      puts if opts[:very_verbose]
        index.sync_message m unless opts[:dry_run]
      end
  
diff --combined lib/sup/index.rb
index 1c82e23adcdb80b042ca35e06a5c5358deda0954,44ecb8bb8549afc3b494a48b347fe1e7877b582e..d96efc85d1e6c66b08aa5270453f23c0713be497
@@@ -177,31 -177,31 +177,31 @@@ EO
      end
    end
  
 -  ## Syncs the message to the index: deleting if it's already there,
 -  ## and adding either way. Index state will be determined by m.labels.
 +  ## Syncs the message to the index, replacing any previous version.  adding
 +  ## either way. Index state will be determined by the message's #labels
 +  ## accessor.
    ##
 -  ## docid and entry can be specified if they're already known.
 -  def sync_message m, docid=nil, entry=nil, opts={}
 -    docid, entry = load_entry_for_id m.id unless docid && entry
 +  ## if need_load is false, docid and entry are assumed to be set to the
 +  ## result of load_entry_for_id (which can be nil).
 +  def sync_message m, need_load=true, docid=nil, entry=nil, opts={}
 +    docid, entry = load_entry_for_id m.id if need_load
  
      raise "no source info for message #{m.id}" unless m.source && m.source_info
      @index_mutex.synchronize do
        raise "trying to delete non-corresponding entry #{docid} with index message-id #{@index[docid][:message_id].inspect} and parameter message id #{m.id.inspect}" if docid && @index[docid][:message_id] != m.id
      end
  
 -    source_id = 
 -      if m.source.is_a? Integer
 -        m.source
 -      else
 -        m.source.id or raise "unregistered source #{m.source} (id #{m.source.id.inspect})"
 -      end
 +    source_id = if m.source.is_a? Integer
 +      m.source
 +    else
 +      m.source.id or raise "unregistered source #{m.source} (id #{m.source.id.inspect})"
 +    end
  
 -    snippet = 
 -      if m.snippet_contains_encrypted_content? && $config[:discard_snippets_from_encrypted_messages]
 -        ""
 -      else
 -        m.snippet
 -      end
 +    snippet = if m.snippet_contains_encrypted_content? && $config[:discard_snippets_from_encrypted_messages]
 +      ""
 +    else
 +      m.snippet
 +    end
  
      ## write the new document to the index. if the entry already exists in the
      ## index, reuse it (which avoids having to reload the entry from the source,
        :refs => (entry[:refs] || (m.refs + m.replytos).uniq.join(" ")),
      }
  
 -    @index_mutex.synchronize  do
 +    @index_mutex.synchronize do
        @index.delete docid if docid
        @index.add_document d
      end
  
 -    docid, entry = load_entry_for_id m.id
 -    ## this hasn't been triggered in a long time. TODO: decide whether it's still a problem.
 -    raise "just added message #{m.id.inspect} but couldn't find it in a search" unless docid
 -    true
 +    ## this hasn't been triggered in a long time.
 +    ## docid, entry = load_entry_for_id m.id
 +    ## raise "just added message #{m.id.inspect} but couldn't find it in a search" unless docid
    end
  
    def save_index fn=File.join(@dir, "ferret")
          "references" => doc[:refs].split.map { |x| "<#{x}>" }.join(" "),
        }
  
 -      Message.new :source => source, :source_info => doc[:source_info].to_i,
 +      m = Message.new :source => source, :source_info => doc[:source_info].to_i,
                    :labels => doc[:label].symbolistize,
 -                  :snippet => doc[:snippet], :header => fake_header
 +                  :snippet => doc[:snippet]
 +      m.parse_header fake_header
 +      m
      end
    end
  
      @index_mutex.synchronize { @index.search(q, :limit => 1).total_hits > 0 }
    end
  
+   ## takes a user query string and returns the list of docids for messages
+   ## that match the query.
+   ##
+   ## messages can then be loaded from the index with #build_message.
+   ##
+   ## raises a ParseError if the parsing failed.
+   def run_query query
+     qobj, opts = Redwood::Index.parse_user_query_string query
+     query = Redwood::Index.build_query opts.merge(:qobj => qobj)
+     results = @index.search query, :limit => (opts[:limit] || :all)
+     results.hits.map { |hit| hit.doc }
+   end
  protected
  
-   ## do any specialized parsing
-   ## returns nil and flashes error message if parsing failed
+   class ParseError < StandardError; end
+   ## parse a query string from the user. returns a query object and a set of
+   ## extra flags; both of these are meant to be passed to #build_query.
+   ##
+   ## raises a ParseError if something went wrong.
    def parse_user_query_string s
      extraopts = {}
  
      end
  
      if $have_chronic
-       chronic_failure = false
        subs = subs.gsub(/\b(before|on|in|during|after):(\((.+?)\)\B|(\S+)\b)/) do
-         break if chronic_failure
          field, datestr = $1, ($3 || $4)
-         realdate = Chronic.parse(datestr, :guess => false, :context => :past)
+         realdate = Chronic.parse datestr, :guess => false, :context => :past
          if realdate
            case field
            when "after"
              "date:(<= #{sprintf "%012d", realdate.end.to_i}) date:(>= #{sprintf "%012d", realdate.begin.to_i})"
            end
          else
-           BufferManager.flash "Can't understand date #{datestr.inspect}!"
-           chronic_failure = true
+           raise ParseError, "can't understand date #{datestr.inspect}"
          end
        end
-       subs = nil if chronic_failure
      end
  
      ## limit:42 restrict the search to 42 results
          extraopts[:limit] = lim.to_i
          ''
        else
-         BufferManager.flash "Can't understand limit #{lim.inspect}!"
-         subs = nil
+         raise ParseError, "non-numeric limit #{lim.inspect}"
        end
      end
      
-     if subs
+     begin
        [@qparser.parse(subs), extraopts]
-     else
-       nil
+     rescue Ferret::QueryParser::QueryParseException => e
+       raise ParseError, e.message
      end
    end