class Ridley::Chef::Cookbook::SyntaxCheck

Encapsulates the process of validating the ruby syntax of files in Chef cookbooks.

Borrowed and modified from: {github.com/opscode/chef/blob/11.4.0/lib/chef/cookbook/syntax_check.rb}

Copyright

Copyright © 2010 Opscode, Inc.

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.

Attributes

chefignore[R]

@return [Ridley::Chef::Chefignore, nil]

cookbook_path[R]
validated_files[R]

A PersistentSet object that tracks which files have already been validated.

Public Class Methods

new(cookbook_path, chefignore = nil) click to toggle source

Create a new SyntaxCheck object

@param [String] cookbook_path

the (on disk) path to the cookbook

@param [Ridley::Chef::Chefignore] chefignore

the instance of R::C::Chefignore to filter out
# File lib/ridley/chef/cookbook/syntax_check.rb, line 85
def initialize(cookbook_path, chefignore = nil)
  @cookbook_path   = cookbook_path
  @validated_files = PersistentSet.new
  @chefignore      = chefignore
end

Public Instance Methods

ruby_files() click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 92
def ruby_files
  Dir[File.join(cookbook_path, '**', '*.rb')].reject { |f| ignored?(f) }
end
template_files() click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 100
def template_files
  Dir[File.join(cookbook_path, '**', '*.erb')].reject { |f| ignored?(f) }
end
untested_ruby_files() click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 96
def untested_ruby_files
  ruby_files.reject { |file| validated?(file) }
end
untested_template_files() click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 104
def untested_template_files
  template_files.reject { |file| validated?(file) }
end
validate_ruby_file(ruby_file) click to toggle source

Borrowed from: github.com/opscode/chef/blob/d111e82/lib/chef/cookbook/syntax_check.rb#L242-L264

# File lib/ridley/chef/cookbook/syntax_check.rb, line 159
def validate_ruby_file(ruby_file)
  # Even when we're compiling the code w/ RubyVM, syntax errors just
  # print to $stderr. We want to capture this and handle the printing
  # ourselves, so we must temporarily swap $stderr to capture the output.
  old_stderr = $stderr
  tmp_stderr = $stderr = StringIO.new
  abs_path = File.expand_path(ruby_file)
  file_content = IO.read(abs_path)

  # We have to wrap this in a block so the user code evaluates in a
  # similar context as what Chef does normally. Otherwise RubyVM
  # will reject some common idioms, like using `return` to end evaluation
  # of a recipe. See also CHEF-5199
  wrapped_content = "Object.new.instance_eval do\n#{file_content}\nend\n"
  RubyVM::InstructionSequence.new(wrapped_content, ruby_file, abs_path, 0)
  true
rescue SyntaxError
  $stderr = old_stderr
  invalid_ruby_file(ruby_file, tmp_stderr.string)
  false
ensure
  $stderr = old_stderr if defined?(old_stderr) && old_stderr
end
validate_ruby_files() click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 116
def validate_ruby_files
  untested_ruby_files.each do |ruby_file|
    return false unless validate_ruby_file(ruby_file)
    validated(ruby_file)
  end
  true
end
validate_template(erb_file) click to toggle source

Borrowed from: github.com/opscode/chef/blob/d111e82/lib/chef/cookbook/syntax_check.rb#L191-L215

# File lib/ridley/chef/cookbook/syntax_check.rb, line 133
def validate_template(erb_file)
  old_stderr = $stderr

  engine = Erubis::Eruby.new
  engine.convert!(IO.read(erb_file))

  ruby_code = engine.src

  # Even when we're compiling the code w/ RubyVM, syntax errors just
  # print to $stderr. We want to capture this and handle the printing
  # ourselves, so we must temporarily swap $stderr to capture the output.
  tmp_stderr = $stderr = StringIO.new

  abs_path = File.expand_path(erb_file)
  RubyVM::InstructionSequence.new(ruby_code, erb_file, abs_path, 0)

  true
rescue SyntaxError
  $stderr = old_stderr
  invalid_erb_file(erb_file, tmp_stderr.string)
  false
ensure
  $stderr = old_stderr if defined?(old_stderr) && old_stderr
end
validate_templates() click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 124
def validate_templates
  untested_template_files.each do |template|
    return false unless validate_template(template)
    validated(template)
  end
  true
end
validated(file) click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 112
def validated(file)
  validated_files.add(checksum(file))
end
validated?(file) click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 108
def validated?(file)
  validated_files.include?(checksum(file))
end

Private Instance Methods

ignored?(file) click to toggle source
# File lib/ridley/chef/cookbook/syntax_check.rb, line 188
def ignored?(file)
  !!chefignore && chefignore.ignored?(file)
end
invalid_erb_file(erb_file, error_message) click to toggle source

Debug a syntax error in a template.

# File lib/ridley/chef/cookbook/syntax_check.rb, line 193
def invalid_erb_file(erb_file, error_message)
  log.error("Erb template #{erb_file} has a syntax error:")
  error_message.each_line { |l| log.error(l.chomp) }
  nil
end
invalid_ruby_file(ruby_file, error_message) click to toggle source

Debugs ruby syntax errors by printing the path to the file and any diagnostic info given in error_message

# File lib/ridley/chef/cookbook/syntax_check.rb, line 201
def invalid_ruby_file(ruby_file, error_message)
  log.error("Cookbook file #{ruby_file} has a ruby syntax error:")
  error_message.each_line { |l| log.error(l.chomp) }
  false
end