hotdog 0.1.18 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +6 -0
- data/README.md +2 -0
- data/hotdog.gemspec +1 -0
- data/lib/hotdog/commands/down.rb +3 -3
- data/lib/hotdog/commands/hosts.rb +3 -11
- data/lib/hotdog/commands/search.rb +146 -92
- data/lib/hotdog/commands/tags.rb +23 -17
- data/lib/hotdog/commands/up.rb +3 -3
- data/lib/hotdog/commands.rb +145 -195
- data/lib/hotdog/formatters/ltsv.rb +9 -4
- data/lib/hotdog/formatters/plain.rb +1 -1
- data/lib/hotdog/version.rb +1 -1
- data/spec/core/application_spec.rb +36 -0
- data/spec/formatter/csv_spec.rb +33 -0
- data/spec/formatter/json_spec.rb +66 -0
- data/spec/formatter/ltsv_spec.rb +32 -0
- data/spec/formatter/plain_spec.rb +76 -0
- data/spec/formatter/text_spec.rb +76 -0
- data/spec/formatter/tsv_spec.rb +33 -0
- data/spec/formatter/yaml_spec.rb +49 -0
- data/spec/parser/parser_spec.rb +300 -0
- data/spec/parser/tag_expression_spec.rb +63 -0
- data/spec/parser/tag_glob_expression_spec.rb +63 -0
- data/spec/parser/tag_regexp_expression_spec.rb +63 -0
- data/spec/spec_helper.rb +1 -0
- metadata +44 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 017715f50e986cf3c0f61cb4834859c296ddf6f7
         | 
| 4 | 
            +
              data.tar.gz: 137f2e8504b9c9908635b8dfe7db6d2b1541be9b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 3b406633a8f174b328dca17c976b4585d6e187f8cefc2dfe7c19ca094f2469faf292a1335d8aaea75f8e440c7d24f1878782710ac9b4c8456cea65466ced87cc
         | 
| 7 | 
            +
              data.tar.gz: a1f2843dd806045110b64c915c8fda049f1a228654e8fc1282f5aa057280e129ecd5da06ca88a80db37b0f35c3c3054ec6e57338fb20d0e9ca176169fb17811c
         | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/README.md
    CHANGED
    
    
    
        data/hotdog.gemspec
    CHANGED
    
    | @@ -20,6 +20,7 @@ Gem::Specification.new do |spec| | |
| 20 20 |  | 
| 21 21 | 
             
              spec.add_development_dependency "bundler", "~> 1.7"
         | 
| 22 22 | 
             
              spec.add_development_dependency "rake", "~> 10.0"
         | 
| 23 | 
            +
              spec.add_development_dependency "rspec", "~> 3.3.0"
         | 
| 23 24 |  | 
| 24 25 | 
             
              spec.add_dependency "dogapi", ">= 1.13.0"
         | 
| 25 26 | 
             
              spec.add_dependency "parslet", "~> 1.6.2"
         | 
    
        data/lib/hotdog/commands/down.rb
    CHANGED
    
    | @@ -29,9 +29,9 @@ module Hotdog | |
| 29 29 | 
             
                    end
         | 
| 30 30 |  | 
| 31 31 | 
             
                    # Remove persistent.db to schedule update on next invocation
         | 
| 32 | 
            -
                    if  | 
| 33 | 
            -
                      @db | 
| 34 | 
            -
                      FileUtils.rm_f(File.join( | 
| 32 | 
            +
                    if @db
         | 
| 33 | 
            +
                      close_db(@db)
         | 
| 34 | 
            +
                      FileUtils.rm_f(File.join(options[:confdir], PERSISTENT_DB))
         | 
| 35 35 | 
             
                    end
         | 
| 36 36 | 
             
                  end
         | 
| 37 37 | 
             
                end
         | 
| @@ -6,21 +6,13 @@ module Hotdog | |
| 6 6 | 
             
                  def run(args=[])
         | 
| 7 7 | 
             
                    args = optparse.parse(args)
         | 
| 8 8 | 
             
                    if args.empty?
         | 
| 9 | 
            -
                      result = execute("SELECT  | 
| 9 | 
            +
                      result = execute("SELECT id FROM hosts").to_a.reduce(:+)
         | 
| 10 10 | 
             
                    else
         | 
| 11 11 | 
             
                      result = args.map { |host_name|
         | 
| 12 12 | 
             
                        if glob?(host_name)
         | 
| 13 | 
            -
                          execute( | 
| 14 | 
            -
                            SELECT DISTINCT hosts_tags.host_id FROM hosts_tags
         | 
| 15 | 
            -
                              INNER JOIN hosts ON hosts_tags.host_id = hosts.id
         | 
| 16 | 
            -
                                WHERE LOWER(hosts.name) GLOB LOWER(?);
         | 
| 17 | 
            -
                          EOS
         | 
| 13 | 
            +
                          execute("SELECT id FROM hosts WHERE name GLOB ?", [host_name]).to_a.reduce(:+)
         | 
| 18 14 | 
             
                        else
         | 
| 19 | 
            -
                          execute( | 
| 20 | 
            -
                            SELECT DISTINCT hosts_tags.host_id FROM hosts_tags
         | 
| 21 | 
            -
                              INNER JOIN hosts ON hosts_tags.host_id = hosts.id
         | 
| 22 | 
            -
                                WHERE LOWER(hosts.name) = LOWER(?);
         | 
| 23 | 
            -
                          EOS
         | 
| 15 | 
            +
                          execute("SELECT id FROM hosts WHERE name = ?", [host_name]).to_a.reduce(:+)
         | 
| 24 16 | 
             
                        end
         | 
| 25 17 | 
             
                      }.reduce(:+)
         | 
| 26 18 | 
             
                    end
         | 
| @@ -15,7 +15,8 @@ module Hotdog | |
| 15 15 | 
             
                    args = optparse.parse(args)
         | 
| 16 16 | 
             
                    expression = args.join(" ").strip
         | 
| 17 17 | 
             
                    if expression.empty?
         | 
| 18 | 
            -
                       | 
| 18 | 
            +
                      # return everything if given expression is empty
         | 
| 19 | 
            +
                      expression = "*"
         | 
| 19 20 | 
             
                    end
         | 
| 20 21 |  | 
| 21 22 | 
             
                    begin
         | 
| @@ -70,9 +71,9 @@ module Hotdog | |
| 70 71 | 
             
                    end
         | 
| 71 72 | 
             
                  end
         | 
| 72 73 |  | 
| 73 | 
            -
                  def evaluate( | 
| 74 | 
            -
                    node = ExpressionTransformer.new.apply( | 
| 75 | 
            -
                    node.evaluate(environment)
         | 
| 74 | 
            +
                  def evaluate(data, environment)
         | 
| 75 | 
            +
                    node = ExpressionTransformer.new.apply(data)
         | 
| 76 | 
            +
                    node.optimize.evaluate(environment)
         | 
| 76 77 | 
             
                  end
         | 
| 77 78 |  | 
| 78 79 | 
             
                  class ExpressionParser < Parslet::Parser
         | 
| @@ -82,18 +83,27 @@ module Hotdog | |
| 82 83 | 
             
                      | term \
         | 
| 83 84 | 
             
                      )
         | 
| 84 85 | 
             
                    }
         | 
| 86 | 
            +
                    rule(:binary_op) {
         | 
| 87 | 
            +
                      ( str('&') >> str('&').maybe \
         | 
| 88 | 
            +
                      | str('|') >> str('|').maybe \
         | 
| 89 | 
            +
                      | match('[Aa]') >> match('[Nn]') >> match('[Dd]') \
         | 
| 90 | 
            +
                      | match('[Oo]') >> match('[Rr]') \
         | 
| 91 | 
            +
                      )
         | 
| 92 | 
            +
                    }
         | 
| 85 93 | 
             
                    rule(:binary_expression) {
         | 
| 86 | 
            -
                      ( term.as(:left) >> spacing.maybe >>  | 
| 87 | 
            -
                      | term.as(:left) >> spacing.maybe >> (str('|') >> str('|').maybe).as(:binary_op) >> spacing.maybe >> expression.as(:right) \
         | 
| 88 | 
            -
                      | term.as(:left) >> spacing.maybe >> (match('[Aa]') >> match('[Nn]') >> match('[Dd]')).as(:binary_op) >> spacing.maybe >> expression.as(:right) \
         | 
| 89 | 
            -
                      | term.as(:left) >> spacing.maybe >> (match('[Oo]') >> match('[Rr]')).as(:binary_op) >> spacing.maybe >> expression.as(:right) \
         | 
| 94 | 
            +
                      ( term.as(:left) >> spacing.maybe >> binary_op.as(:binary_op) >> spacing.maybe >> expression.as(:right) \
         | 
| 90 95 | 
             
                      | term.as(:left) >> spacing.maybe.as(:binary_op) >> expression.as(:right) \
         | 
| 91 96 | 
             
                      )
         | 
| 92 97 | 
             
                    }
         | 
| 98 | 
            +
                    rule(:unary_op) {
         | 
| 99 | 
            +
                      ( str('!') \
         | 
| 100 | 
            +
                      | str('~') \
         | 
| 101 | 
            +
                      | match('[Nn]') >> match('[Oo]') >> match('[Tt]') \
         | 
| 102 | 
            +
                      )
         | 
| 103 | 
            +
                    }
         | 
| 93 104 | 
             
                    rule(:unary_expression) {
         | 
| 94 | 
            -
                      ( spacing.maybe >>  | 
| 95 | 
            -
                      | spacing.maybe >>  | 
| 96 | 
            -
                      | spacing.maybe >> (match('[Nn]') >> match('[Oo]') >> match('[Tt]')).as(:unary_op) >> atom.as(:expression) \
         | 
| 105 | 
            +
                      ( spacing.maybe >> unary_op.as(:unary_op) >> term.as(:expression) \
         | 
| 106 | 
            +
                      | spacing.maybe >> unary_op.as(:unary_op) >> expression.as(:expression) \
         | 
| 97 107 | 
             
                      )
         | 
| 98 108 | 
             
                    }
         | 
| 99 109 | 
             
                    rule(:term) {
         | 
| @@ -114,8 +124,9 @@ module Hotdog | |
| 114 124 | 
             
                      | spacing.maybe >> identifier.as(:identifier) >> separator >> attribute.as(:attribute) >> spacing.maybe \
         | 
| 115 125 | 
             
                      | spacing.maybe >> identifier.as(:identifier) >> separator >> spacing.maybe \
         | 
| 116 126 | 
             
                      | spacing.maybe >> identifier.as(:identifier) >> spacing.maybe \
         | 
| 127 | 
            +
                      | spacing.maybe >> separator >> attribute_regexp.as(:attribute_regexp) >> spacing.maybe \
         | 
| 117 128 | 
             
                      | spacing.maybe >> separator >> attribute_glob.as(:attribute_glob) >> spacing.maybe \
         | 
| 118 | 
            -
                      | spacing.maybe >> separator >> attribute.as(: | 
| 129 | 
            +
                      | spacing.maybe >> separator >> attribute.as(:attribute) >> spacing.maybe \
         | 
| 119 130 | 
             
                      | spacing.maybe >> attribute_regexp.as(:attribute_regexp) >> spacing.maybe \
         | 
| 120 131 | 
             
                      | spacing.maybe >> attribute_glob.as(:attribute_glob) >> spacing.maybe \
         | 
| 121 132 | 
             
                      | spacing.maybe >> attribute.as(:attribute) >> spacing.maybe \
         | 
| @@ -126,11 +137,11 @@ module Hotdog | |
| 126 137 | 
             
                      )
         | 
| 127 138 | 
             
                    }
         | 
| 128 139 | 
             
                    rule(:identifier_glob) {
         | 
| 129 | 
            -
                      ( identifier.repeat(0) >> (glob >> identifier.maybe).repeat(1) \
         | 
| 140 | 
            +
                      ( unary_op.absent? >> binary_op.absent? >> identifier.repeat(0) >> (glob >> identifier.maybe).repeat(1) \
         | 
| 130 141 | 
             
                      )
         | 
| 131 142 | 
             
                    }
         | 
| 132 143 | 
             
                    rule(:identifier) {
         | 
| 133 | 
            -
                      ( match('[A-Za-z]') >> match('[-./0-9A-Z_a-z]').repeat(0) \
         | 
| 144 | 
            +
                      ( unary_op.absent? >> binary_op.absent? >> match('[A-Za-z]') >> match('[-./0-9A-Z_a-z]').repeat(0) \
         | 
| 134 145 | 
             
                      )
         | 
| 135 146 | 
             
                    }
         | 
| 136 147 | 
             
                    rule(:separator) {
         | 
| @@ -143,11 +154,11 @@ module Hotdog | |
| 143 154 | 
             
                      )
         | 
| 144 155 | 
             
                    }
         | 
| 145 156 | 
             
                    rule(:attribute_glob) {
         | 
| 146 | 
            -
                      ( attribute.repeat(0) >> (glob >> attribute.maybe).repeat(1) \
         | 
| 157 | 
            +
                      ( unary_op.absent? >> binary_op.absent? >> attribute.repeat(0) >> (glob >> attribute.maybe).repeat(1) \
         | 
| 147 158 | 
             
                      )
         | 
| 148 159 | 
             
                    }
         | 
| 149 160 | 
             
                    rule(:attribute) {
         | 
| 150 | 
            -
                      ( match('[-./0-9:A-Z_a-z]').repeat(1) \
         | 
| 161 | 
            +
                      ( unary_op.absent? >> binary_op.absent? >> match('[-./0-9:A-Z_a-z]').repeat(1) \
         | 
| 151 162 | 
             
                      )
         | 
| 152 163 | 
             
                    }
         | 
| 153 164 | 
             
                    rule(:glob) {
         | 
| @@ -205,20 +216,31 @@ module Hotdog | |
| 205 216 | 
             
                    def evaluate(environment, options={})
         | 
| 206 217 | 
             
                      raise(NotImplementedError)
         | 
| 207 218 | 
             
                    end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                    def optimize(options={})
         | 
| 221 | 
            +
                      self
         | 
| 222 | 
            +
                    end
         | 
| 208 223 | 
             
                  end
         | 
| 209 224 |  | 
| 210 225 | 
             
                  class BinaryExpressionNode < ExpressionNode
         | 
| 211 | 
            -
                    attr_reader :left, :right
         | 
| 226 | 
            +
                    attr_reader :op, :left, :right
         | 
| 212 227 |  | 
| 213 228 | 
             
                    def initialize(op, left, right)
         | 
| 214 | 
            -
                       | 
| 215 | 
            -
                       | 
| 229 | 
            +
                      case op || "or"
         | 
| 230 | 
            +
                      when "&&", "&", /\Aand\z/i
         | 
| 231 | 
            +
                        @op = :AND
         | 
| 232 | 
            +
                      when "||", "|", /\Aor\z/i
         | 
| 233 | 
            +
                        @op = :OR
         | 
| 234 | 
            +
                      else
         | 
| 235 | 
            +
                        raise(SyntaxError.new("unknown binary operator: #{op.inspect}"))
         | 
| 236 | 
            +
                      end
         | 
| 216 237 | 
             
                      @left = left
         | 
| 217 238 | 
             
                      @right = right
         | 
| 218 239 | 
             
                    end
         | 
| 240 | 
            +
             | 
| 219 241 | 
             
                    def evaluate(environment, options={})
         | 
| 220 242 | 
             
                      case @op
         | 
| 221 | 
            -
                      when  | 
| 243 | 
            +
                      when :AND
         | 
| 222 244 | 
             
                        left_values = @left.evaluate(environment)
         | 
| 223 245 | 
             
                        if left_values.empty?
         | 
| 224 246 | 
             
                          []
         | 
| @@ -226,40 +248,73 @@ module Hotdog | |
| 226 248 | 
             
                          right_values = @right.evaluate(environment)
         | 
| 227 249 | 
             
                          (left_values & right_values)
         | 
| 228 250 | 
             
                        end
         | 
| 229 | 
            -
                      when  | 
| 251 | 
            +
                      when :OR
         | 
| 230 252 | 
             
                        left_values = @left.evaluate(environment)
         | 
| 231 253 | 
             
                        right_values = @right.evaluate(environment)
         | 
| 232 254 | 
             
                        (left_values | right_values).uniq
         | 
| 233 255 | 
             
                      else
         | 
| 234 | 
            -
                         | 
| 256 | 
            +
                        []
         | 
| 235 257 | 
             
                      end
         | 
| 236 258 | 
             
                    end
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                    def optimize(options={})
         | 
| 261 | 
            +
                      @left = @left.optimize(options)
         | 
| 262 | 
            +
                      @right = @right.optimize(options)
         | 
| 263 | 
            +
                      if @left == @right
         | 
| 264 | 
            +
                        @left
         | 
| 265 | 
            +
                      else
         | 
| 266 | 
            +
                        self
         | 
| 267 | 
            +
                      end
         | 
| 268 | 
            +
                    end
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                    def ==(other)
         | 
| 271 | 
            +
                      self.class === other and @op == other.op and @left == other.left and @right == other.right
         | 
| 272 | 
            +
                    end
         | 
| 237 273 | 
             
                  end
         | 
| 238 274 |  | 
| 239 275 | 
             
                  class UnaryExpressionNode < ExpressionNode
         | 
| 240 | 
            -
                    attr_reader :expression
         | 
| 276 | 
            +
                    attr_reader :op, :expression
         | 
| 241 277 |  | 
| 242 278 | 
             
                    def initialize(op, expression)
         | 
| 243 | 
            -
                       | 
| 279 | 
            +
                      case op
         | 
| 280 | 
            +
                      when "!", "~", /\Anot\z/i
         | 
| 281 | 
            +
                        @op = :NOT
         | 
| 282 | 
            +
                      else
         | 
| 283 | 
            +
                        raise(SyntaxError.new("unknown unary operator: #{@op.inspect}"))
         | 
| 284 | 
            +
                      end
         | 
| 244 285 | 
             
                      @expression = expression
         | 
| 245 286 | 
             
                    end
         | 
| 287 | 
            +
             | 
| 246 288 | 
             
                    def evaluate(environment, options={})
         | 
| 247 289 | 
             
                      case @op
         | 
| 248 | 
            -
                      when  | 
| 290 | 
            +
                      when :NOT
         | 
| 249 291 | 
             
                        values = @expression.evaluate(environment)
         | 
| 250 292 | 
             
                        if values.empty?
         | 
| 251 | 
            -
                          environment.execute( | 
| 252 | 
            -
                            SELECT DISTINCT host_id FROM hosts_tags;
         | 
| 253 | 
            -
                          EOS
         | 
| 293 | 
            +
                          environment.execute("SELECT DISTINCT host_id FROM hosts_tags").map { |row| row.first }
         | 
| 254 294 | 
             
                        else
         | 
| 255 | 
            -
                          environment.execute( | 
| 256 | 
            -
                            SELECT DISTINCT host_id FROM hosts_tags WHERE host_id NOT IN (%s);
         | 
| 257 | 
            -
                          EOS
         | 
| 295 | 
            +
                          environment.execute("SELECT DISTINCT host_id FROM hosts_tags WHERE host_id NOT IN (%s)" % values.map { "?" }.join(", "), values).map { |row| row.first }
         | 
| 258 296 | 
             
                        end
         | 
| 259 297 | 
             
                      else
         | 
| 260 | 
            -
                         | 
| 298 | 
            +
                        []
         | 
| 261 299 | 
             
                      end
         | 
| 262 300 | 
             
                    end
         | 
| 301 | 
            +
             | 
| 302 | 
            +
                    def optimize(options={})
         | 
| 303 | 
            +
                      @expression = @expression.optimize(options)
         | 
| 304 | 
            +
                      if UnaryExpressionNode === @expression
         | 
| 305 | 
            +
                        if @op == :NOT and @expression.op == :NOT
         | 
| 306 | 
            +
                          @expression.expression
         | 
| 307 | 
            +
                        else
         | 
| 308 | 
            +
                          self
         | 
| 309 | 
            +
                        end
         | 
| 310 | 
            +
                      else
         | 
| 311 | 
            +
                        self
         | 
| 312 | 
            +
                      end
         | 
| 313 | 
            +
                    end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                    def ==(other)
         | 
| 316 | 
            +
                      self.class === other and @op == other.op and @expression == other.expression
         | 
| 317 | 
            +
                    end
         | 
| 263 318 | 
             
                  end
         | 
| 264 319 |  | 
| 265 320 | 
             
                  class TagExpressionNode < ExpressionNode
         | 
| @@ -269,43 +324,43 @@ module Hotdog | |
| 269 324 | 
             
                    end
         | 
| 270 325 | 
             
                    attr_reader :identifier
         | 
| 271 326 | 
             
                    attr_reader :attribute
         | 
| 327 | 
            +
             | 
| 272 328 | 
             
                    def identifier?
         | 
| 273 329 | 
             
                      !(identifier.nil? or identifier.to_s.empty?)
         | 
| 274 330 | 
             
                    end
         | 
| 331 | 
            +
             | 
| 275 332 | 
             
                    def attribute?
         | 
| 276 333 | 
             
                      !(attribute.nil? or attribute.to_s.empty?)
         | 
| 277 334 | 
             
                    end
         | 
| 335 | 
            +
             | 
| 278 336 | 
             
                    def evaluate(environment, options={})
         | 
| 337 | 
            +
                      q = []
         | 
| 279 338 | 
             
                      if identifier?
         | 
| 280 339 | 
             
                        if attribute?
         | 
| 281 340 | 
             
                          case identifier
         | 
| 282 341 | 
             
                          when /\Ahost\z/i
         | 
| 283 | 
            -
                             | 
| 284 | 
            -
             | 
| 285 | 
            -
             | 
| 286 | 
            -
                            EOS
         | 
| 342 | 
            +
                            q << "SELECT hosts.id FROM hosts"
         | 
| 343 | 
            +
                            q <<   "WHERE hosts.name = ?;"
         | 
| 344 | 
            +
                            values = environment.execute(q.join(" "), [attribute]).map { |row| row.first }
         | 
| 287 345 | 
             
                          else
         | 
| 288 | 
            -
                             | 
| 289 | 
            -
             | 
| 290 | 
            -
             | 
| 291 | 
            -
             | 
| 292 | 
            -
                            EOS
         | 
| 346 | 
            +
                            q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 347 | 
            +
                            q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 348 | 
            +
                            q <<     "WHERE tags.name = ? AND tags.value = ?;"
         | 
| 349 | 
            +
                            values = environment.execute(q.join(" "), [identifier, attribute]).map { |row| row.first }
         | 
| 293 350 | 
             
                          end
         | 
| 294 351 | 
             
                        else
         | 
| 295 | 
            -
                           | 
| 296 | 
            -
             | 
| 297 | 
            -
             | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 300 | 
            -
                          EOS
         | 
| 352 | 
            +
                          q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 353 | 
            +
                          q <<   "INNER JOIN hosts ON hosts_tags.host_id = hosts.id"
         | 
| 354 | 
            +
                          q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 355 | 
            +
                          q <<     "WHERE hosts.name = ? OR tags.name = ? OR tags.value = ?;"
         | 
| 356 | 
            +
                          values = environment.execute(q.join(" "), [identifier, identifier, identifier]).map { |row| row.first }
         | 
| 301 357 | 
             
                        end
         | 
| 302 358 | 
             
                      else
         | 
| 303 359 | 
             
                        if attribute?
         | 
| 304 | 
            -
             | 
| 305 | 
            -
             | 
| 306 | 
            -
             | 
| 307 | 
            -
             | 
| 308 | 
            -
                          EOS
         | 
| 360 | 
            +
                           q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 361 | 
            +
                           q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 362 | 
            +
                           q <<     "WHERE tags.value = ?;"
         | 
| 363 | 
            +
                          values = environment.execute(q.join(" "), [attribute]).map { |row| row.first }
         | 
| 309 364 | 
             
                        else
         | 
| 310 365 | 
             
                          return []
         | 
| 311 366 | 
             
                        end
         | 
| @@ -317,6 +372,10 @@ module Hotdog | |
| 317 372 | 
             
                      end
         | 
| 318 373 | 
             
                    end
         | 
| 319 374 |  | 
| 375 | 
            +
                    def ==(other)
         | 
| 376 | 
            +
                      self.class == other.class and @identifier == other.identifier and @attribute == other.attribute
         | 
| 377 | 
            +
                    end
         | 
| 378 | 
            +
             | 
| 320 379 | 
             
                    def fallback(environment, options={})
         | 
| 321 380 | 
             
                      if environment.fixed_string?
         | 
| 322 381 | 
             
                        []
         | 
| @@ -352,36 +411,33 @@ module Hotdog | |
| 352 411 |  | 
| 353 412 | 
             
                  class TagGlobExpressionNode < TagExpressionNode
         | 
| 354 413 | 
             
                    def evaluate(environment, options={})
         | 
| 414 | 
            +
                      q = []
         | 
| 355 415 | 
             
                      if identifier?
         | 
| 356 416 | 
             
                        if attribute?
         | 
| 357 417 | 
             
                          case identifier
         | 
| 358 418 | 
             
                          when /\Ahost\z/i
         | 
| 359 | 
            -
                             | 
| 360 | 
            -
             | 
| 361 | 
            -
             | 
| 362 | 
            -
                            EOS
         | 
| 419 | 
            +
                            q << "SELECT hosts.id FROM hosts"
         | 
| 420 | 
            +
                            q <<   "WHERE hosts.name GLOB ?;"
         | 
| 421 | 
            +
                            values = environment.execute(q.join(" "), [attribute]).map { |row| row.first }
         | 
| 363 422 | 
             
                          else
         | 
| 364 | 
            -
                             | 
| 365 | 
            -
             | 
| 366 | 
            -
             | 
| 367 | 
            -
             | 
| 368 | 
            -
                            EOS
         | 
| 423 | 
            +
                            q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 424 | 
            +
                            q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 425 | 
            +
                            q <<     "WHERE tags.name GLOB ? AND tags.value GLOB ?;"
         | 
| 426 | 
            +
                            values = environment.execute(q.join(" "), [identifier, attribute]).map { |row| row.first }
         | 
| 369 427 | 
             
                          end
         | 
| 370 428 | 
             
                        else
         | 
| 371 | 
            -
                           | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 374 | 
            -
             | 
| 375 | 
            -
             | 
| 376 | 
            -
                          EOS
         | 
| 429 | 
            +
                          q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 430 | 
            +
                          q <<   "INNER JOIN hosts ON hosts_tags.host_id = hosts.id"
         | 
| 431 | 
            +
                          q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 432 | 
            +
                          q <<     "WHERE hosts.name GLOB ? OR tags.name GLOB ? OR tags.value GLOB ?;"
         | 
| 433 | 
            +
                          values = environment.execute(q.join(" "), [identifier, identifier, identifier]).map { |row| row.first }
         | 
| 377 434 | 
             
                        end
         | 
| 378 435 | 
             
                      else
         | 
| 379 436 | 
             
                        if attribute?
         | 
| 380 | 
            -
                           | 
| 381 | 
            -
             | 
| 382 | 
            -
             | 
| 383 | 
            -
             | 
| 384 | 
            -
                          EOS
         | 
| 437 | 
            +
                          q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 438 | 
            +
                          q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 439 | 
            +
                          q <<     "WHERE tags.value GLOB ?;"
         | 
| 440 | 
            +
                          values = environment.execute(q.join(" "), [attribute]).map { |row| row.first }
         | 
| 385 441 | 
             
                        else
         | 
| 386 442 | 
             
                          return []
         | 
| 387 443 | 
             
                        end
         | 
| @@ -400,37 +456,35 @@ module Hotdog | |
| 400 456 | 
             
                      attribute = attribute.sub(%r{\A/(.*)/\z}) { $1 } if attribute
         | 
| 401 457 | 
             
                      super(identifier, attribute)
         | 
| 402 458 | 
             
                    end
         | 
| 459 | 
            +
             | 
| 403 460 | 
             
                    def evaluate(environment, options={})
         | 
| 461 | 
            +
                      q = []
         | 
| 404 462 | 
             
                      if identifier?
         | 
| 405 463 | 
             
                        if attribute?
         | 
| 406 464 | 
             
                          case identifier
         | 
| 407 465 | 
             
                          when /\Ahost\z/i
         | 
| 408 | 
            -
                             | 
| 409 | 
            -
             | 
| 410 | 
            -
             | 
| 411 | 
            -
                            EOS
         | 
| 466 | 
            +
                            q << "SELECT hosts.id FROM hosts"
         | 
| 467 | 
            +
                            q <<   "WHERE hosts.name REGEXP ?;"
         | 
| 468 | 
            +
                            values = environment.execute(q.join(" "), [attribute]).map { |row| row.first }
         | 
| 412 469 | 
             
                          else
         | 
| 413 | 
            -
                             | 
| 414 | 
            -
             | 
| 415 | 
            -
             | 
| 416 | 
            -
             | 
| 417 | 
            -
                            EOS
         | 
| 470 | 
            +
                            q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 471 | 
            +
                            q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 472 | 
            +
                            q <<     "WHERE tags.name REGEXP ? AND tags.value REGEXP ?;"
         | 
| 473 | 
            +
                            values = environment.execute(q.join(" "), [identifier, attribute]).map { |row| row.first }
         | 
| 418 474 | 
             
                          end
         | 
| 419 475 | 
             
                        else
         | 
| 420 | 
            -
                           | 
| 421 | 
            -
             | 
| 422 | 
            -
             | 
| 423 | 
            -
             | 
| 424 | 
            -
             | 
| 425 | 
            -
                          EOS
         | 
| 476 | 
            +
                          q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 477 | 
            +
                          q <<   "INNER JOIN hosts ON hosts_tags.host_id = hosts.id"
         | 
| 478 | 
            +
                          q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 479 | 
            +
                          q <<     "WHERE hosts.name REGEXP ? OR tags.name REGEXP ? OR tags.value REGEXP ?;"
         | 
| 480 | 
            +
                          values = environment.execute(q.join(" "), [identifier, identifier, identifier]).map { |row| row.first }
         | 
| 426 481 | 
             
                        end
         | 
| 427 482 | 
             
                      else
         | 
| 428 483 | 
             
                        if attribute?
         | 
| 429 | 
            -
                           | 
| 430 | 
            -
             | 
| 431 | 
            -
             | 
| 432 | 
            -
             | 
| 433 | 
            -
                          EOS
         | 
| 484 | 
            +
                          q << "SELECT DISTINCT hosts_tags.host_id FROM hosts_tags"
         | 
| 485 | 
            +
                          q <<   "INNER JOIN tags ON hosts_tags.tag_id = tags.id"
         | 
| 486 | 
            +
                          q <<     "WHERE tags.value REGEXP ?;"
         | 
| 487 | 
            +
                          values = environment.execute(q.join(" "), [attribute]).map { |row| row.first }
         | 
| 434 488 | 
             
                        else
         | 
| 435 489 | 
             
                          return []
         | 
| 436 490 | 
             
                        end
         | 
    
        data/lib/hotdog/commands/tags.rb
    CHANGED
    
    | @@ -7,22 +7,31 @@ module Hotdog | |
| 7 7 | 
             
                    args = optparse.parse(args)
         | 
| 8 8 | 
             
                    if 0 < args.length
         | 
| 9 9 | 
             
                      fields = args.map { |tag|
         | 
| 10 | 
            -
                        tag_name, tag_value = tag | 
| 10 | 
            +
                        tag_name, tag_value = split_tag(tag)
         | 
| 11 11 | 
             
                        tag_name
         | 
| 12 12 | 
             
                      }
         | 
| 13 | 
            -
                      result1 =  | 
| 14 | 
            -
                         | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 13 | 
            +
                      result1 = args.map { |tag|
         | 
| 14 | 
            +
                        tag_name, tag_value = split_tag(tag)
         | 
| 15 | 
            +
                        if glob?(tag_name)
         | 
| 16 | 
            +
                          if tag_value.empty?
         | 
| 17 | 
            +
                            execute("SELECT DISTINCT value FROM tags WHERE name GLOB ?", [tag_name]).map { |row| row.join(",") }
         | 
| 18 | 
            +
                          else
         | 
| 19 | 
            +
                            if glob?(tag_value)
         | 
| 20 | 
            +
                              execute("SELECT DISTINCT value FROM tags WHERE name GLOB ? AND value GLOB ?", [tag_name, tag_value]).map { |row| row.join(",") }
         | 
| 21 | 
            +
                            else
         | 
| 22 | 
            +
                              execute("SELECT DISTINCT value FROM tags WHERE name GLOB ? AND value = ?", [tag_name, tag_value]).map { |row| row.join(",") }
         | 
| 23 | 
            +
                            end
         | 
| 24 | 
            +
                          end
         | 
| 20 25 | 
             
                        else
         | 
| 21 | 
            -
                           | 
| 22 | 
            -
                            SELECT DISTINCT  | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            +
                          if tag_value.empty?
         | 
| 27 | 
            +
                            execute("SELECT DISTINCT value FROM tags WHERE name = ?", [tag_name]).map { |row| row.join(",") }
         | 
| 28 | 
            +
                          else
         | 
| 29 | 
            +
                            if glob?(tag_value)
         | 
| 30 | 
            +
                              execute("SELECT DISTINCT value FROM tags WHERE name = ? AND value GLOB ?", [tag_name, tag_value]).map { |row| row.join(",") }
         | 
| 31 | 
            +
                            else
         | 
| 32 | 
            +
                              execute("SELECT DISTINCT value FROM tags WHERE name = ? AND value = ?", [tag_name, tag_value]).map { |row| row.join(",") }
         | 
| 33 | 
            +
                            end
         | 
| 34 | 
            +
                          end
         | 
| 26 35 | 
             
                        end
         | 
| 27 36 | 
             
                      }
         | 
| 28 37 | 
             
                      result = (0...result1.reduce(0) { |max, values| [max, values.length].max }).map { |field_index|
         | 
| @@ -30,10 +39,7 @@ module Hotdog | |
| 30 39 | 
             
                      }
         | 
| 31 40 | 
             
                    else
         | 
| 32 41 | 
             
                      fields = ["tag"]
         | 
| 33 | 
            -
                      result = execute( | 
| 34 | 
            -
                        SELECT DISTINCT tags.name, tags.value FROM hosts_tags
         | 
| 35 | 
            -
                          INNER JOIN tags ON hosts_tags.tag_id = tags.id;
         | 
| 36 | 
            -
                      EOS
         | 
| 42 | 
            +
                      result = execute("SELECT DISTINCT name, value FROM tags").map { |name, value| [0 < value.length ? "#{name}:#{value}" : name] }
         | 
| 37 43 | 
             
                    end
         | 
| 38 44 | 
             
                    if 0 < result.length
         | 
| 39 45 | 
             
                      STDOUT.print(format(result, fields: fields))
         | 
    
        data/lib/hotdog/commands/up.rb
    CHANGED
    
    | @@ -31,9 +31,9 @@ module Hotdog | |
| 31 31 | 
             
                    end
         | 
| 32 32 |  | 
| 33 33 | 
             
                    # Remove persistent.db to schedule update on next invocation
         | 
| 34 | 
            -
                    if  | 
| 35 | 
            -
                      @db | 
| 36 | 
            -
                      FileUtils.rm_f(File.join( | 
| 34 | 
            +
                    if @db
         | 
| 35 | 
            +
                      close_db(@db)
         | 
| 36 | 
            +
                      FileUtils.rm_f(File.join(options[:confdir], PERSISTENT_DB))
         | 
| 37 37 | 
             
                    end
         | 
| 38 38 | 
             
                  end
         | 
| 39 39 | 
             
                end
         |