forked from chef-boneyard/compat_resource
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRakefile
202 lines (172 loc) · 7.2 KB
/
Rakefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'stove/rake_task'
require 'fileutils'
RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = FileList['files/spec/**/*_spec.rb']
end
Stove::RakeTask.new
task default: :spec
#
# "rake update" updates the copied_from_chef files so we can grab bugfixes or new features
#
CHEF_FILES = %w(chef/constants chef/delayed_evaluator chef/property
chef/resource chef/resource/action_class chef/provider
chef/mixin/params_validate chef/mixin/properties)
SPEC_FILES = %w(unit/mixin/properties_spec.rb
unit/property_spec.rb
unit/property/state_spec.rb
unit/property/validation_spec.rb
integration/recipes/resource_action_spec.rb
integration/recipes/resource_converge_if_changed_spec.rb
integration/recipes/resource_load_spec.rb
)
KEEP_FUNCTIONS = {
'chef/resource' => %w(
initialize
name
resource_name self.use_automatic_resource_name
identity state state_for_resource_reporter property_is_set reset_property
self.properties self.state_properties self.state_attr
self.identity_properties self.identity_property self.identity_attrs
self.property self.property_type
self.lazy
action allowed_actions self.allowed_actions self.default_action
self.action self.declare_action_class self.action_class
load_current_value current_value_does_not_exist
self.load_current_value
),
'chef/provider' => %w(
initialize
converge_if_changed
self.use_inline_resources
self.include_resource_dsl
self.include_resource_dsl_module
),
}
KEEP_INCLUDES = {
'chef/resource' => %w(Chef::Mixin::ParamsValidate Chef::Mixin::Properties),
'chef/provider' => [],
}
KEEP_CLASSES = {
'chef/provider' => %w(Chef::Provider)
}
SKIP_LINES = {
'chef/dsl/recipe' => [ /include Chef::Mixin::PowershellOut/ ]
}
PROCESS_LINES = {
}
# See chef_compat/resource for def. of resource_name and provider
# See chef_compat/monkeypatches/chef/resource for def. of current_value
task :update do
# Copy files from chef to chef_compat/chef, with a few changes
target_path = File.expand_path("../files/lib/chef_compat/copied_from_chef", __FILE__)
chef_gem_path = Bundler.environment.specs['chef'].first.full_gem_path
CHEF_FILES.each do |file|
output = StringIO.new
# Wrap the whole thing in a ChefCompat module
output.puts "require 'chef_compat/copied_from_chef'"
output.puts "class Chef"
output.puts "module ::ChefCompat"
output.puts "module CopiedFromChef"
# Bring over the Chef file
chef_contents = IO.read(File.join(chef_gem_path, 'lib', "#{file}.rb"))
skip_until = nil
keep_until = nil
in_class = []
chef_contents.lines.each do |line|
if keep_until
keep_until = nil if keep_until === line
else
if skip_until
skip_until = nil if skip_until === line
next
end
# If this file only keeps certain functions, detect which function we are
# in and only keep those. Also strip comments outside functions
case line
# Skip modules and classes that aren't part of our list
when /\A(\s*)def\s+([A-Za-z0-9_.]+)/
if KEEP_FUNCTIONS[file] && !KEEP_FUNCTIONS[file].include?($2)
skip_until = /\A#{$1}end\s*$/
next
else
function = $2
# Keep everything inside a function no matter what it is
keep_until = /\A#{$1}end\s*$/
end
# Skip comments and whitespace if we're narrowing the file (otherwise it
# looks super weird)
when /\A\s*#/, /\A\s*$/
next if KEEP_CLASSES[file] || KEEP_FUNCTIONS[file]
# Skip aliases/attrs/properties that we're not keeping
when /\A\s*(attr_reader|attr_writer|attr_accessor|property|alias)\s*:(\w+)/
next if KEEP_FUNCTIONS[file] && !KEEP_FUNCTIONS[file].include?($2)
# Skip includes and extends that we're not keeping
when /\A\s*(include|extend)\s*([A-Za-z0-9_:]+)/
next if KEEP_INCLUDES[file] && !KEEP_INCLUDES[file].include?($2)
end
next if SKIP_LINES[file] && SKIP_LINES[file].any? { |skip| skip === line }
end
# If we are at the end of a class, pop in_class
if in_class[-1] && in_class[-1][:until].match(line)
class_name = in_class.pop[:name]
# Don't bother printing classes/modules that we're not going to print anything under
next if KEEP_CLASSES[file] && !KEEP_CLASSES[file].any? { |c| c.start_with?(class_name) }
# Detect class open
elsif line =~ /\A(\s*)(class|module)(\s+)([A-Za-z0-9_:]+)(\s*<\s*([A-Za-z0-9_:]+))?.*$/
indent, type, space, class_name, _, superclass_name = $1, $2, $3, $4, $5, $6
full_class_name = in_class[-1] ? "#{in_class[-1][:name]}::#{class_name}" : class_name
in_class << { name: full_class_name, until: /\A#{indent}end\s*$/ }
superclass_name ||= "Object"
# Don't print the class open unless it contains stuff we'll keep
next if KEEP_CLASSES[file] && !KEEP_CLASSES[file].any? { |c| c.start_with?(full_class_name) }
# Fix the class to extend from its parent
original_class = "::#{full_class_name}"
if type == 'class'
line = "#{indent}#{type}#{space}#{class_name} < (defined?(#{original_class}) ? #{original_class} : #{superclass_name})"
else
# Modules have a harder time of it because of self methods
line += "#{indent} if defined?(#{original_class})\n"
line += "#{indent} require 'chef_compat/delegating_class'\n"
line += "#{indent} extend DelegatingClass\n"
line += "#{indent} @delegates_to = #{original_class}\n"
line += "#{indent} end"
end
# If we're not in a class we care about, don't print stuff
elsif KEEP_CLASSES[file] && in_class[-1] && !KEEP_CLASSES[file].any? { |c| c == in_class[-1][:name] }
next
end
# Modify requires to overridden files to bring in the local version
if line =~ /\A(\s*require\s*['"])(.+)(['"]\s*)$/
if CHEF_FILES.include?($2)
line = "#{$1}chef_compat/copied_from_chef/#{$2}#{$3}"
else
next
end
end
line = PROCESS_LINES[file].call(line) if PROCESS_LINES[file]
output.puts line
# If this was the header for an initialize function, write out "super"
if function == 'initialize'
output.puts "super if defined?(::#{in_class[-1][:name]})"
end
end
# Close the ChefCompat module declaration from the top
output.puts "end"
output.puts "end"
output.puts "end"
# Write out the file in chef_compat
target_file = File.join(target_path, "#{file}.rb")
if !File.exist?(target_file) || IO.read(target_file) != output.string
puts "Writing #{target_file} ..."
FileUtils.mkdir_p(File.dirname(target_file))
File.open(target_file, "w") { |f| f.write(output.string) }
end
end
# SPEC_FILES.each do |file|
# target_path = File.expand_path("../files/spec/copied_from_chef", __FILE__)
# source_file = File.join(chef_gem_path, 'lib', "#{file}.rb")
# target_file = File.join(target_path, "#{file}")
# end
end