Class: Ridley::Chef::Cookbook::SyntaxCheck

Inherits:
Object
  • Object
show all
Includes:
Logging, Mixin::Checksum
Defined in:
lib/ridley/chef/cookbook/syntax_check.rb

Overview

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

Borrowed and modified from: https://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.

Defined Under Namespace

Classes: PersistentSet

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Mixin::Checksum

#checksum

Methods included from Logging

logger, #logger, set_logger

Constructor Details

#initialize(cookbook_path, chefignore = nil) ⇒ SyntaxCheck

Create a new SyntaxCheck object

Parameters:

  • cookbook_path (String)

    the (on disk) path to the cookbook

  • chefignore (Ridley::Chef::Chefignore) (defaults to: nil)

    the instance of R::C::Chefignore to filter out



85
86
87
88
89
# 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

Instance Attribute Details

#cookbook_pathObject (readonly)

Returns the value of attribute cookbook_path.



73
74
75
# File 'lib/ridley/chef/cookbook/syntax_check.rb', line 73

def cookbook_path
  @cookbook_path
end

#validated_filesObject (readonly)

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



77
78
79
# File 'lib/ridley/chef/cookbook/syntax_check.rb', line 77

def validated_files
  @validated_files
end

Instance Method Details

#ruby_filesObject



92
93
94
# 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_filesObject



100
101
102
# 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_filesObject



96
97
98
# File 'lib/ridley/chef/cookbook/syntax_check.rb', line 96

def untested_ruby_files
  ruby_files.reject { |file| validated?(file) }
end

#untested_template_filesObject



104
105
106
# 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) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# 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_filesObject



116
117
118
119
120
121
122
# 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) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# 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_templatesObject



124
125
126
127
128
129
130
# 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) ⇒ Object



112
113
114
# File 'lib/ridley/chef/cookbook/syntax_check.rb', line 112

def validated(file)
  validated_files.add(checksum(file))
end

#validated?(file) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/ridley/chef/cookbook/syntax_check.rb', line 108

def validated?(file)
  validated_files.include?(checksum(file))
end