Initial Chef repository
This commit is contained in:
74
cookbooks/chef-solo-search/libraries/search.rb
Normal file
74
cookbooks/chef-solo-search/libraries/search.rb
Normal file
@@ -0,0 +1,74 @@
|
||||
#
|
||||
# Copyright 2011, edelight GmbH
|
||||
#
|
||||
# Authors:
|
||||
# Markus Korn <markus.korn@edelight.de>
|
||||
# Seth Chisamore <schisamo@opscode.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
if Chef::Config[:solo]
|
||||
|
||||
# add currrent dir to load path
|
||||
$: << File.dirname(__FILE__)
|
||||
|
||||
# All chef/solr_query/* classes were removed in Chef 11; Load vendored copy
|
||||
# that ships with this cookbook
|
||||
$: << File.expand_path("vendor", File.dirname(__FILE__)) if Chef::VERSION.to_i >= 11
|
||||
|
||||
# Ensure the treetop gem is installed and available
|
||||
begin
|
||||
require 'treetop'
|
||||
rescue LoadError
|
||||
run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new)
|
||||
chef_gem = Chef::Resource::ChefGem.new("treetop", run_context)
|
||||
chef_gem.version('>= 1.4')
|
||||
chef_gem.run_action(:install)
|
||||
end
|
||||
|
||||
require 'search/overrides'
|
||||
require 'search/parser'
|
||||
|
||||
module Search; class Helper; end; end
|
||||
|
||||
# The search and data_bag related methods moved form `Chef::Mixin::Language`
|
||||
# to `Chef::DSL::DataQuery` in Chef 11.
|
||||
if Chef::VERSION.to_i >= 11
|
||||
module Chef::DSL::DataQuery
|
||||
def self.included(base)
|
||||
base.send(:include, Search::Overrides)
|
||||
end
|
||||
end
|
||||
Search::Helper.send(:include, Chef::DSL::DataQuery)
|
||||
else
|
||||
module Chef::Mixin::Language
|
||||
def self.included(base)
|
||||
base.send(:include, Search::Overrides)
|
||||
end
|
||||
end
|
||||
Search::Helper.send(:include, Chef::Mixin::Language)
|
||||
end
|
||||
|
||||
class Chef
|
||||
class Search
|
||||
class Query
|
||||
def initialize(*args)
|
||||
end
|
||||
def search(*args, &block)
|
||||
::Search::Helper.new.search(*args, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
100
cookbooks/chef-solo-search/libraries/search/overrides.rb
Normal file
100
cookbooks/chef-solo-search/libraries/search/overrides.rb
Normal file
@@ -0,0 +1,100 @@
|
||||
#
|
||||
# Copyright 2011, edelight GmbH
|
||||
#
|
||||
# Authors:
|
||||
# Markus Korn <markus.korn@edelight.de>
|
||||
# Seth Chisamore <schisamo@opscode.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
module Search
|
||||
module Overrides
|
||||
# Overwrite the search method of recipes to operate locally by using
|
||||
# data found in data_bags.
|
||||
# Only very basic lucene syntax is supported and also sorting the result
|
||||
# is not implemented, if this search method does not support a given query
|
||||
# an exception is raised.
|
||||
# This search() method returns a block iterator or an Array, depending
|
||||
# on how this method is called.
|
||||
def search(obj, query=nil, sort=nil, start=0, rows=1000, &block)
|
||||
if !sort.nil?
|
||||
raise "Sorting search results is not supported"
|
||||
end
|
||||
_query = Query.parse(query)
|
||||
if _query.nil?
|
||||
raise "Query #{query} is not supported"
|
||||
end
|
||||
_result = []
|
||||
|
||||
case obj
|
||||
when :node
|
||||
nodes = search_nodes(_query, start, rows, &block)
|
||||
_result += nodes
|
||||
when :role
|
||||
roles = search_roles(_query, start, rows, &block)
|
||||
_result += roles
|
||||
else
|
||||
bags = search_data_bag(_query, obj, start, rows, &block)
|
||||
_result += bags
|
||||
end
|
||||
|
||||
|
||||
if block_given?
|
||||
pos = 0
|
||||
while (pos >= start and pos < (start + rows) and pos < _result.size)
|
||||
yield _result[pos]
|
||||
pos += 1
|
||||
end
|
||||
else
|
||||
return _result.slice(start, rows)
|
||||
end
|
||||
end
|
||||
|
||||
def search_nodes(_query, start, rows, &block)
|
||||
_result = []
|
||||
node_path = Chef::Config[:nodes_path] || File.join(Chef::Config[:data_bag_path], "node")
|
||||
Dir.glob(File.join(node_path, "*.json")).map do |f|
|
||||
# parse and hashify the node
|
||||
node = Chef::JSONCompat.from_json(IO.read(f))
|
||||
if _query.match(node.to_hash)
|
||||
_result << node
|
||||
end
|
||||
end
|
||||
return _result
|
||||
end
|
||||
|
||||
def search_roles(_query, start, rows, &block)
|
||||
_result = []
|
||||
Dir.glob(File.join(Chef::Config[:role_path], "*.json")).map do |f|
|
||||
# parse and hashify the role
|
||||
role = Chef::JSONCompat.from_json(IO.read(f))
|
||||
if _query.match(role.to_hash)
|
||||
_result << role
|
||||
end
|
||||
end
|
||||
return _result
|
||||
end
|
||||
|
||||
def search_data_bag(_query, bag_name, start, rows, &block)
|
||||
_result = []
|
||||
data_bag(bag_name.to_s).each do |bag_item_id|
|
||||
bag_item = data_bag_item(bag_name.to_s, bag_item_id)
|
||||
if _query.match(bag_item)
|
||||
_result << bag_item
|
||||
end
|
||||
end
|
||||
return _result
|
||||
end
|
||||
end
|
||||
end
|
||||
222
cookbooks/chef-solo-search/libraries/search/parser.rb
Normal file
222
cookbooks/chef-solo-search/libraries/search/parser.rb
Normal file
@@ -0,0 +1,222 @@
|
||||
#
|
||||
# Copyright 2011, edelight GmbH
|
||||
#
|
||||
# Authors:
|
||||
# Markus Korn <markus.korn@edelight.de>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
require 'chef/solr_query/query_transform'
|
||||
|
||||
# mock QueryTransform such that we can access the location of the lucene grammar
|
||||
class Chef
|
||||
class SolrQuery
|
||||
class QueryTransform
|
||||
def self.base_path
|
||||
class_variable_get(:@@base_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def build_flat_hash(hsh, prefix="")
|
||||
result = {}
|
||||
hsh.each_pair do |key, value|
|
||||
if value.kind_of?(Hash)
|
||||
result.merge!(build_flat_hash(value, "#{prefix}#{key}_"))
|
||||
else
|
||||
result[prefix+key] = value
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
module Lucene
|
||||
|
||||
class Term < Treetop::Runtime::SyntaxNode
|
||||
# compares a query value and a value, tailing '*'-wildcards are handled correctly.
|
||||
# Value can either be a string or an array, all other objects are converted
|
||||
# to a string and than checked.
|
||||
def match( value )
|
||||
if value.is_a?(Array)
|
||||
value.any?{ |x| self.match(x) }
|
||||
else
|
||||
File.fnmatch(self.text_value, value.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Field < Treetop::Runtime::SyntaxNode
|
||||
# simple field -> value matches, supporting tailing '*'-wildcards in keys
|
||||
# as well as in values
|
||||
def match( item )
|
||||
keys = self.elements[0].match(item)
|
||||
if keys.nil?
|
||||
false
|
||||
else
|
||||
keys.any?{ |key| self.elements[1].match(item[key]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# we don't support range matches
|
||||
# range of integers would be easy to implement
|
||||
# but string ranges are hard
|
||||
class FiledRange < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
# we handle '[* TO *]' as a special case since it is common in
|
||||
# cookbooks for matching the existence of keys
|
||||
class InclFieldRange
|
||||
def match(item)
|
||||
field = self.elements[0].text_value
|
||||
range_start = self.elements[1].transform
|
||||
range_end = self.elements[2].transform
|
||||
if range_start == "*" and range_end == "*"
|
||||
!!item[field]
|
||||
else
|
||||
raise "Ranges not really supported yet"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ExclFieldRange < FieldRange
|
||||
end
|
||||
|
||||
class RangeValue < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
class FieldName < Treetop::Runtime::SyntaxNode
|
||||
def match( item )
|
||||
if self.text_value.count("_") > 0
|
||||
item.merge!(build_flat_hash(item))
|
||||
end
|
||||
if self.text_value.end_with?("*")
|
||||
part = self.text_value.chomp("*")
|
||||
item.keys.collect{ |key| key.start_with?(part)? key: nil}.compact
|
||||
else
|
||||
if item.has_key?(self.text_value)
|
||||
[self.text_value,]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Body < Treetop::Runtime::SyntaxNode
|
||||
def match( item )
|
||||
self.elements[0].match( item )
|
||||
end
|
||||
end
|
||||
|
||||
class Group < Treetop::Runtime::SyntaxNode
|
||||
def match( item )
|
||||
self.elements[0].match(item)
|
||||
end
|
||||
end
|
||||
|
||||
class BinaryOp < Treetop::Runtime::SyntaxNode
|
||||
def match( item )
|
||||
self.elements[1].match(
|
||||
self.elements[0].match(item),
|
||||
self.elements[2].match(item)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class OrOperator < Treetop::Runtime::SyntaxNode
|
||||
def match( cond1, cond2 )
|
||||
cond1 or cond2
|
||||
end
|
||||
end
|
||||
|
||||
class AndOperator < Treetop::Runtime::SyntaxNode
|
||||
def match( cond1, cond2 )
|
||||
cond1 and cond2
|
||||
end
|
||||
end
|
||||
|
||||
# we don't support fuzzy string matching
|
||||
class FuzzyOp < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
class BoostOp < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
class FuzzyParam < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
class UnaryOp < Treetop::Runtime::SyntaxNode
|
||||
def match( item )
|
||||
self.elements[0].match(
|
||||
self.elements[1].match(item)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class NotOperator < Treetop::Runtime::SyntaxNode
|
||||
def match( cond )
|
||||
not cond
|
||||
end
|
||||
end
|
||||
|
||||
class RequiredOperator < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
class ProhibitedOperator < Treetop::Runtime::SyntaxNode
|
||||
end
|
||||
|
||||
class Phrase < Treetop::Runtime::SyntaxNode
|
||||
# a quoted ::Term
|
||||
def match( value )
|
||||
self.elements[0].match(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Query
|
||||
# initialize the parser by using the grammar shipped with chef
|
||||
@@grammar = File.join(Chef::SolrQuery::QueryTransform.base_path, "lucene.treetop")
|
||||
Treetop.load(@@grammar)
|
||||
@@parser = LuceneParser.new
|
||||
|
||||
def self.parse(data)
|
||||
# parse the query into a query tree
|
||||
if data.nil?
|
||||
data = "*:*"
|
||||
end
|
||||
tree = @@parser.parse(data)
|
||||
if tree.nil?
|
||||
msg = "Parse error at offset: #{@@parser.index}\n"
|
||||
msg += "Reason: #{@@parser.failure_reason}"
|
||||
raise "Query #{data} is not supported: #{msg}"
|
||||
end
|
||||
self.clean_tree(tree)
|
||||
tree
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.clean_tree(root_node)
|
||||
# remove all SyntaxNode elements from the tree, we don't need them as
|
||||
# the related ruby class already knowns what to do.
|
||||
return if root_node.elements.nil?
|
||||
root_node.elements.delete_if do |node|
|
||||
node.class.name == "Treetop::Runtime::SyntaxNode"
|
||||
end
|
||||
root_node.elements.each { |node| self.clean_tree(node) }
|
||||
end
|
||||
end
|
||||
|
||||
150
cookbooks/chef-solo-search/libraries/vendor/chef/solr_query/lucene.treetop
vendored
Normal file
150
cookbooks/chef-solo-search/libraries/vendor/chef/solr_query/lucene.treetop
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
#
|
||||
# Author:: Seth Falcon (<seth@opscode.com>)
|
||||
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
||||
# License:: Apache License, Version 2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
grammar Lucene
|
||||
|
||||
rule body
|
||||
(expression / space)* <Body>
|
||||
end
|
||||
|
||||
rule expression
|
||||
operation / group / field / field_range / term / string
|
||||
end
|
||||
|
||||
rule term
|
||||
keyword valid_letter+ <Term> / !keyword !"?" valid_letter <Term>
|
||||
end
|
||||
|
||||
rule field
|
||||
field_name ":" (term/string/group) <Field>
|
||||
end
|
||||
|
||||
rule field_range
|
||||
field_name ":" "[" range_value " TO " range_value "]" <InclFieldRange>
|
||||
/
|
||||
field_name ":" "{" range_value " TO " range_value "}" <ExclFieldRange>
|
||||
end
|
||||
|
||||
rule field_name
|
||||
!keyword valid_letter+ <FieldName>
|
||||
end
|
||||
|
||||
rule range_value
|
||||
valid_letter+ <RangeValue> / "*" <RangeValue>
|
||||
end
|
||||
|
||||
rule group
|
||||
space? '(' body ')' space? <Group>
|
||||
end
|
||||
|
||||
rule operation
|
||||
binary_op / unary_op / fuzzy_op / boost_op
|
||||
end
|
||||
|
||||
rule unary_op
|
||||
not_op / required_op / prohibited_op
|
||||
end
|
||||
|
||||
rule binary_op
|
||||
(group / field / field_range / term) space? boolean_operator space+ body <BinaryOp>
|
||||
end
|
||||
|
||||
rule boolean_operator
|
||||
and_operator / or_operator
|
||||
end
|
||||
|
||||
rule and_operator
|
||||
'AND' <AndOperator> / '&&' <AndOperator>
|
||||
end
|
||||
|
||||
rule or_operator
|
||||
'OR' <OrOperator> / '||' <OrOperator>
|
||||
end
|
||||
|
||||
rule not_op
|
||||
not_operator space (group / field / field_range / term / string) <UnaryOp>
|
||||
/
|
||||
bang_operator space? (group / field / field_range / term / string) <UnaryOp>
|
||||
end
|
||||
|
||||
rule not_operator
|
||||
'NOT' <NotOperator>
|
||||
end
|
||||
|
||||
rule bang_operator
|
||||
'!' <NotOperator>
|
||||
end
|
||||
|
||||
rule required_op
|
||||
!valid_letter required_operator (term/string) <UnaryOp>
|
||||
/
|
||||
required_operator (term/string) <UnaryOp>
|
||||
end
|
||||
|
||||
rule required_operator
|
||||
'+' <RequiredOperator>
|
||||
end
|
||||
|
||||
rule prohibited_op
|
||||
!valid_letter prohibited_operator (field/field_range/term/string) <UnaryOp>
|
||||
end
|
||||
|
||||
rule prohibited_operator
|
||||
'-' <ProhibitedOperator>
|
||||
end
|
||||
|
||||
rule boost_op
|
||||
(term/string) '^' fuzzy_param <BoostOp>
|
||||
end
|
||||
|
||||
rule fuzzy_op
|
||||
(term/string) '~' fuzzy_param? (space / !valid_letter) <FuzzyOp>
|
||||
end
|
||||
|
||||
rule fuzzy_param
|
||||
[0-9] '.'? [0-9] <FuzzyParam> / [0-9]+ <FuzzyParam>
|
||||
end
|
||||
|
||||
rule string
|
||||
'"' term (space term)* '"' <Phrase>
|
||||
end
|
||||
|
||||
rule keyword
|
||||
'AND' / 'OR' / 'NOT'
|
||||
end
|
||||
|
||||
rule valid_letter
|
||||
start_letter+ ([a-zA-Z0-9@*?_.-] / '\\' special_char)*
|
||||
end
|
||||
|
||||
rule start_letter
|
||||
[a-zA-Z0-9@._*] / '\\' special_char
|
||||
end
|
||||
|
||||
rule end_letter
|
||||
[a-zA-Z0-9*?_.] / '\\' special_char
|
||||
end
|
||||
|
||||
rule special_char
|
||||
[-+&|!(){}\[\]^"~*?:\\]
|
||||
end
|
||||
|
||||
rule space
|
||||
[\s]+
|
||||
end
|
||||
end
|
||||
285
cookbooks/chef-solo-search/libraries/vendor/chef/solr_query/lucene_nodes.rb
vendored
Normal file
285
cookbooks/chef-solo-search/libraries/vendor/chef/solr_query/lucene_nodes.rb
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
#
|
||||
# Author:: Seth Falcon (<seth@opscode.com>)
|
||||
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
||||
# License:: Apache License, Version 2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
require 'treetop'
|
||||
|
||||
module Lucene
|
||||
SEP = "__=__"
|
||||
|
||||
class Term < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"T:#{self.text_value}"
|
||||
end
|
||||
|
||||
def transform
|
||||
self.text_value
|
||||
end
|
||||
end
|
||||
|
||||
class Field < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
field = self.elements[0].text_value
|
||||
term = self.elements[1].to_array
|
||||
"(F:#{field} #{term})"
|
||||
end
|
||||
|
||||
def transform
|
||||
field = self.elements[0].text_value
|
||||
term = self.elements[1]
|
||||
if term.is_a? Phrase
|
||||
str = term.transform
|
||||
# remove quotes
|
||||
str = str[1 ... (str.length - 1)]
|
||||
"content:\"#{field}#{SEP}#{str}\""
|
||||
else
|
||||
"content:#{field}#{SEP}#{term.transform}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class FieldRange < Treetop::Runtime::SyntaxNode
|
||||
|
||||
def to_array
|
||||
field = self.elements[0].text_value
|
||||
range_start = self.elements[1].to_array
|
||||
range_end = self.elements[2].to_array
|
||||
"(FR:#{field} #{left}#{range_start}#{right} #{left}#{range_end}#{right})"
|
||||
end
|
||||
|
||||
def transform
|
||||
field = self.elements[0].text_value
|
||||
range_start = self.elements[1].transform
|
||||
range_end = self.elements[2].transform
|
||||
# FIXME: handle special cases for missing start/end
|
||||
if ("*" == range_start && "*" == range_end)
|
||||
"content:#{field}#{SEP}*"
|
||||
elsif "*" == range_end
|
||||
"content:#{left}#{field}#{SEP}#{range_start} TO #{field}#{SEP}\\ufff0#{right}"
|
||||
elsif "*" == range_start
|
||||
"content:#{left}#{field}#{SEP} TO #{field}#{SEP}#{range_end}#{right}"
|
||||
else
|
||||
"content:#{left}#{field}#{SEP}#{range_start} TO #{field}#{SEP}#{range_end}#{right}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class InclFieldRange < FieldRange
|
||||
def left
|
||||
"["
|
||||
end
|
||||
def right
|
||||
"]"
|
||||
end
|
||||
end
|
||||
|
||||
class ExclFieldRange < FieldRange
|
||||
def left
|
||||
"{"
|
||||
end
|
||||
def right
|
||||
"}"
|
||||
end
|
||||
end
|
||||
|
||||
class RangeValue < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
self.text_value
|
||||
end
|
||||
|
||||
def transform
|
||||
to_array
|
||||
end
|
||||
end
|
||||
|
||||
class FieldName < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
self.text_value
|
||||
end
|
||||
|
||||
def transform
|
||||
to_array
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class Body < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
self.elements.map { |x| x.to_array }.join(" ")
|
||||
end
|
||||
|
||||
def transform
|
||||
self.elements.map { |x| x.transform }.join(" ")
|
||||
end
|
||||
end
|
||||
|
||||
class Group < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"(" + self.elements[0].to_array + ")"
|
||||
end
|
||||
|
||||
def transform
|
||||
"(" + self.elements[0].transform + ")"
|
||||
end
|
||||
end
|
||||
|
||||
class BinaryOp < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
op = self.elements[1].to_array
|
||||
a = self.elements[0].to_array
|
||||
b = self.elements[2].to_array
|
||||
"(#{op} #{a} #{b})"
|
||||
end
|
||||
|
||||
def transform
|
||||
op = self.elements[1].transform
|
||||
a = self.elements[0].transform
|
||||
b = self.elements[2].transform
|
||||
"#{a} #{op} #{b}"
|
||||
end
|
||||
end
|
||||
|
||||
class AndOperator < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"OP:AND"
|
||||
end
|
||||
|
||||
def transform
|
||||
"AND"
|
||||
end
|
||||
end
|
||||
|
||||
class OrOperator < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"OP:OR"
|
||||
end
|
||||
|
||||
def transform
|
||||
"OR"
|
||||
end
|
||||
end
|
||||
|
||||
class FuzzyOp < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
a = self.elements[0].to_array
|
||||
param = self.elements[1]
|
||||
if param
|
||||
"(OP:~ #{a} #{param.to_array})"
|
||||
else
|
||||
"(OP:~ #{a})"
|
||||
end
|
||||
end
|
||||
|
||||
def transform
|
||||
a = self.elements[0].transform
|
||||
param = self.elements[1]
|
||||
if param
|
||||
"#{a}~#{param.transform}"
|
||||
else
|
||||
"#{a}~"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class BoostOp < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
a = self.elements[0].to_array
|
||||
param = self.elements[1]
|
||||
"(OP:^ #{a} #{param.to_array})"
|
||||
end
|
||||
|
||||
def transform
|
||||
a = self.elements[0].transform
|
||||
param = self.elements[1]
|
||||
"#{a}^#{param.transform}"
|
||||
end
|
||||
end
|
||||
|
||||
class FuzzyParam < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
self.text_value
|
||||
end
|
||||
|
||||
def transform
|
||||
self.text_value
|
||||
end
|
||||
end
|
||||
|
||||
class UnaryOp < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
op = self.elements[0].to_array
|
||||
a = self.elements[1].to_array
|
||||
"(#{op} #{a})"
|
||||
end
|
||||
|
||||
def transform
|
||||
op = self.elements[0].transform
|
||||
a = self.elements[1].transform
|
||||
spc = case op
|
||||
when "+", "-"
|
||||
""
|
||||
else
|
||||
" "
|
||||
end
|
||||
"#{op}#{spc}#{a}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class NotOperator < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"OP:NOT"
|
||||
end
|
||||
|
||||
def transform
|
||||
"NOT"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class RequiredOperator < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"OP:+"
|
||||
end
|
||||
|
||||
def transform
|
||||
"+"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class ProhibitedOperator < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"OP:-"
|
||||
end
|
||||
|
||||
def transform
|
||||
"-"
|
||||
end
|
||||
end
|
||||
|
||||
class Phrase < Treetop::Runtime::SyntaxNode
|
||||
def to_array
|
||||
"STR:#{self.text_value}"
|
||||
end
|
||||
|
||||
def transform
|
||||
"#{self.text_value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
65
cookbooks/chef-solo-search/libraries/vendor/chef/solr_query/query_transform.rb
vendored
Normal file
65
cookbooks/chef-solo-search/libraries/vendor/chef/solr_query/query_transform.rb
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
#
|
||||
# Author:: Seth Falcon (<seth@opscode.com>)
|
||||
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
|
||||
# License:: Apache License, Version 2.0
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
require 'treetop'
|
||||
require 'chef/solr_query/lucene_nodes'
|
||||
|
||||
class Chef
|
||||
class Exceptions
|
||||
class QueryParseError < StandardError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Chef
|
||||
class SolrQuery
|
||||
class QueryTransform
|
||||
@@base_path = File.expand_path(File.dirname(__FILE__))
|
||||
Treetop.load(File.join(@@base_path, 'lucene.treetop'))
|
||||
@@parser = LuceneParser.new
|
||||
|
||||
def self.parse(data)
|
||||
tree = @@parser.parse(data)
|
||||
msg = "Parse error at offset: #{@@parser.index}\n"
|
||||
msg += "Reason: #{@@parser.failure_reason}"
|
||||
raise Chef::Exceptions::QueryParseError, msg if tree.nil?
|
||||
self.clean_tree(tree)
|
||||
tree.to_array
|
||||
end
|
||||
|
||||
def self.transform(data)
|
||||
return "*:*" if data == "*:*"
|
||||
tree = @@parser.parse(data)
|
||||
msg = "Parse error at offset: #{@@parser.index}\n"
|
||||
msg += "Reason: #{@@parser.failure_reason}"
|
||||
raise Chef::Exceptions::QueryParseError, msg if tree.nil?
|
||||
self.clean_tree(tree)
|
||||
tree.transform
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.clean_tree(root_node)
|
||||
return if root_node.elements.nil?
|
||||
root_node.elements.delete_if do |node|
|
||||
node.class.name == "Treetop::Runtime::SyntaxNode"
|
||||
end
|
||||
root_node.elements.each { |node| self.clean_tree(node) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user