File: Rakefile

package info (click to toggle)
ruby-compat-resource 12.10.5-1
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 472 kB
  • ctags: 362
  • sloc: ruby: 2,400; makefile: 7
file content (225 lines) | stat: -rw-r--r-- 8,216 bytes parent folder | download
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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/dsl/core
                chef/dsl/declare_resource
                chef/dsl/recipe
                chef/mixin/lazy_module_include
                chef/mixin/notifying_block
                chef/mixin/params_validate
                chef/mixin/powershell_out
                chef/mixin/properties
                chef/property
                chef/provider
                chef/provider/noop
                chef/resource
                chef/resource/action_class
                chef/resource_builder
              )
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
    resource_initializing resource_initializing= to_hash
    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
    compile_and_converge_action
    action
    self.use_inline_resources
    self.include_resource_dsl
    self.include_resource_dsl_module
  ),
  'chef/dsl/recipe' => %w(),
}
KEEP_INCLUDES = {
  'chef/resource' => %w(Chef::Mixin::ParamsValidate Chef::Mixin::Properties),
  'chef/provider' => %w(Chef::DSL::Core),
  'chef/dsl/recipe' => %w(Chef::DSL::Core Chef::DSL::Recipe Chef::Mixin::LazyModuleInclude),
}
KEEP_CLASSES = {
  'chef/provider' => %w(Chef::Provider Chef::Provider::InlineResources Chef::Provider::InlineResources::ClassMethods)
}
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

desc "Pull new files from the chef client this is bundled with and update this cookbook"
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
    # First lets try to load the original file if it exists
    output.puts "begin"
    output.puts "  require '#{file}'"
    output.puts "rescue LoadError; end"
    output.puts ""
    # 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}  CopiedFromChef.extend_chef_module(#{original_class}, self) if defined?(#{original_class})"
        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*['"])([^'"]+)(['"].*)/
        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