Class: Chef::Cookbook::SyntaxCheck

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

Overview

Chef::Cookbook::SyntaxCheck

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

Defined Under Namespace

Classes: PersistentSet

Constant Summary

Constants included from Mixin::ShellOut

Mixin::ShellOut::DEPRECATED_OPTIONS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixin::Checksum

#checksum

Methods included from Mixin::ShellOut

#run_command_compatible_options, #shell_out, #shell_out!

Constructor Details

#initialize(cookbook_path) ⇒ SyntaxCheck

Create a new SyntaxCheck object

Arguments

cookbook_path:

the (on disk) path to the cookbook



101
102
103
104
# File 'lib/chef/cookbook/syntax_check.rb', line 101

def initialize(cookbook_path)
  @cookbook_path = cookbook_path
  @validated_files = PersistentSet.new
end

Instance Attribute Details

#cookbook_pathObject (readonly)

Returns the value of attribute cookbook_path.



82
83
84
# File 'lib/chef/cookbook/syntax_check.rb', line 82

def cookbook_path
  @cookbook_path
end

#validated_filesObject (readonly)

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



86
87
88
# File 'lib/chef/cookbook/syntax_check.rb', line 86

def validated_files
  @validated_files
end

Class Method Details

.for_cookbook(cookbook_name, cookbook_path = nil) ⇒ Object

Creates a new SyntaxCheck given the cookbook_name and a cookbook_path. If no cookbook_path is given, Chef::Config.cookbook_path is used.



90
91
92
93
94
95
96
# File 'lib/chef/cookbook/syntax_check.rb', line 90

def self.for_cookbook(cookbook_name, cookbook_path=nil)
  cookbook_path ||= Chef::Config.cookbook_path
  unless cookbook_path
    raise ArgumentError, "Cannot find cookbook #{cookbook_name} unless Chef::Config.cookbook_path is set or an explicit cookbook path is given"
  end
  new(File.join(cookbook_path, cookbook_name.to_s))
end

Instance Method Details

#chefignoreObject



106
107
108
# File 'lib/chef/cookbook/syntax_check.rb', line 106

def chefignore
  @chefignore ||= Chefignore.new(File.dirname(cookbook_path))
end

#remove_ignored_files(file_list) ⇒ Object



110
111
112
113
114
115
116
117
118
# File 'lib/chef/cookbook/syntax_check.rb', line 110

def remove_ignored_files(file_list)
  return file_list unless chefignore.ignores.length > 0
  file_list.reject do |full_path|
    cookbook_pn = Pathname.new cookbook_path
    full_pn = Pathname.new full_path
    relative_pn = full_pn.relative_path_from cookbook_pn
    chefignore.ignored? relative_pn.to_s
  end
end

#ruby_filesObject



120
121
122
# File 'lib/chef/cookbook/syntax_check.rb', line 120

def ruby_files
  remove_ignored_files Dir[File.join(cookbook_path, '**', '*.rb')]
end

#template_filesObject



135
136
137
# File 'lib/chef/cookbook/syntax_check.rb', line 135

def template_files
  remove_ignored_files Dir[File.join(cookbook_path, '**', '*.erb')]
end

#untested_ruby_filesObject



124
125
126
127
128
129
130
131
132
133
# File 'lib/chef/cookbook/syntax_check.rb', line 124

def untested_ruby_files
  ruby_files.reject do |file|
    if validated?(file)
      Chef::Log.debug("Ruby file #{file} is unchanged, skipping syntax check")
      true
    else
      false
    end
  end
end

#untested_template_filesObject



139
140
141
142
143
144
145
146
147
148
# File 'lib/chef/cookbook/syntax_check.rb', line 139

def untested_template_files
  template_files.reject do |file| 
    if validated?(file)
      Chef::Log.debug("Template #{file} is unchanged, skipping syntax check")
      true
    else
      false
    end
  end
end

#validate_ruby_file(ruby_file) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/chef/cookbook/syntax_check.rb', line 184

def validate_ruby_file(ruby_file)
  Chef::Log.debug("Testing #{ruby_file} for syntax errors...")
  result = shell_out("ruby -c #{ruby_file}")
  result.error!
  true
rescue Mixlib::ShellOut::ShellCommandFailed
  file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
  Chef::Log.fatal("Cookbook file #{file_relative_path} has a ruby syntax error:")
  result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) }
  false
end

#validate_ruby_filesObject



158
159
160
161
162
163
# File 'lib/chef/cookbook/syntax_check.rb', line 158

def validate_ruby_files
  untested_ruby_files.each do |ruby_file|
    return false unless validate_ruby_file(ruby_file)
    validated(ruby_file)
  end
end

#validate_template(erb_file) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
# File 'lib/chef/cookbook/syntax_check.rb', line 172

def validate_template(erb_file)
  Chef::Log.debug("Testing template #{erb_file} for syntax errors...")
  result = shell_out("erubis -x #{erb_file} | ruby -c")
  result.error!
  true
rescue Mixlib::ShellOut::ShellCommandFailed
  file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
  Chef::Log.fatal("Erb template #{file_relative_path} has a syntax error:")
  result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) }
  false
end

#validate_templatesObject



165
166
167
168
169
170
# File 'lib/chef/cookbook/syntax_check.rb', line 165

def validate_templates
  untested_template_files.each do |template|
    return false unless validate_template(template)
    validated(template)
  end
end

#validated(file) ⇒ Object



154
155
156
# File 'lib/chef/cookbook/syntax_check.rb', line 154

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

#validated?(file) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/chef/cookbook/syntax_check.rb', line 150

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