Class: Rubber::Configuration::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/rubber/generator.rb

Overview

Handles selection and transformation of a set of config files based on the host/role they belong to

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_dir, roles, host, options = {}) ⇒ Generator

Returns a new instance of Generator.



17
18
19
20
21
22
# File 'lib/rubber/generator.rb', line 17

def initialize(config_dir, roles, host, options={})
  @config_dir = config_dir
  @roles = roles.to_a.reverse #First roles take precedence
  @host = host || 'no_host'
  @options=options
end

Instance Attribute Details

#fake_rootObject

Returns the value of attribute fake_root.



14
15
16
# File 'lib/rubber/generator.rb', line 14

def fake_root
  @fake_root
end

#file_patternObject

Returns the value of attribute file_pattern.



11
12
13
# File 'lib/rubber/generator.rb', line 11

def file_pattern
  @file_pattern
end

#forceObject

Returns the value of attribute force.



13
14
15
# File 'lib/rubber/generator.rb', line 13

def force
  @force
end

#no_postObject

Returns the value of attribute no_post.



12
13
14
# File 'lib/rubber/generator.rb', line 12

def no_post
  @no_post
end

#stop_on_error_cmdObject

Returns the value of attribute stop_on_error_cmd.



15
16
17
# File 'lib/rubber/generator.rb', line 15

def stop_on_error_cmd
  @stop_on_error_cmd
end

Instance Method Details

#runObject



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
# File 'lib/rubber/generator.rb', line 24

def run
  config_dirs = []
  config_dirs << "#{@config_dir}/common/**/**"
  @roles.sort.each {|role| config_dirs <<  "#{@config_dir}/role/#{role}/**/**" }
  config_dirs << "#{@config_dir}/host/#{@host}/**/**"

  pat = Regexp.new(file_pattern) if file_pattern
  
  config_dirs.each do |dir|
    Dir[dir].sort.each do |f|
      next if f =~ /\/(CVS|\.svn)\//
      if File.file?(f) && (! pat || pat.match(f))
        Rubber.logger.info{"Transforming #{f}"}
        begin
          transform(IO.read(f), @options)
        rescue Exception => e
          lines = e.backtrace.grep(/^\(erb\):([0-9]+)/) {|b| Regexp.last_match(1) }
          Rubber.logger.error{"Transformation failed for #{f}#{':' + lines.first if lines.first}"}
          Rubber.logger.error e.message
          exit 1
        end
      end
    end
  end
end

#transform(src_data, options = {}) ⇒ Object

Transforms the ERB template given in srcfile and writes the result to dest_file (if not nil) before returning it



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
# File 'lib/rubber/generator.rb', line 52

def transform(src_data, options={})
  config = ConfigDescriptor.new
  config.generator = self

  # for development/test, if we have a fake root, echo any
  # calls to system
  if fake_root
    class << config
      def system(*args)
        puts ("Not running system command during a fake_root transformation: #{args.inspect}")
      end
      def open(*args)
        if args.first && args.first =~ /^|/
          puts ("Not running open/pipe command during a fake_root transformation: #{args.inspect}")
        else
          super
        end
      end
      alias ` system
      alias exec system
      alias fork system
    end
  end

  config.options = options
  template = ERB.new(src_data, nil, "-")
  result = template.result(config.get_binding())
  
  return if config.skip

  config_path = config.path

  # for development/test, if we have a fake root, then send config
  # output there, and also put write_cmd output there
  if fake_root
    config_path = "write_cmd_" + config.write_cmd.gsub(/[^a-z0-9_-]/i, '') if config.write_cmd
    config_path = "#{fake_root}/#{config_path}" if config_path
  end

  if ! config_path && ! (config.read_cmd && config.write_cmd)
    raise "Transformation requires either a output filename or command"
  end

  reader = config_path || "|#{config.read_cmd}"
  orig = IO.read(reader) rescue ""

  # When additive is set we need to only replace between our delimiters
  if config.additive
    additive = ["# start rubber #{@host}", "# end rubber #{@host}"] unless additive.is_a? Array
    pat = /#{config.additive[0]}.*#{config.additive[1]}/m
    new = "#{config.additive[0]}#{result}#{config.additive[1]}"
    if orig =~ pat
      result = orig.gsub(pat, new)
    else
      result = orig + new + "\n"
    end
  end

  # Only do something if the transformed result is different than what
  # is currently in the destination file
  if orig != result || force
    # create dirs as needed
    FileUtils.mkdir_p(File.dirname(config_path)) if config_path

    # Write a backup of original
    open("#{config_path}.bak", 'w') { |f| f.write(orig) } if config_path && config.backup

    # Write out transformed file
    writer = config_path || "|#{config.write_cmd}"
    open(writer, 'w') do |pipe|
      pipe.write(result)
    end
    if config.write_cmd && ! fake_root && $?.exitstatus != 0
      raise "Config command failed execution:  #{config.write_cmd}"
    end

    # Set file permissions and owner if needed
    FileUtils.chmod(config.perms, config_path) if config.perms && config_path
    FileUtils.chown(config.owner, config.group, config_path) if config_path && (config.owner || config.group)

    # Run post transform command if needed
    if config.post
      if fake_root
        Rubber.logger.info("Not running post command as a fake root was given: #{config.post}")
      elsif no_post
        Rubber.logger.info("Not running post command as no post specified")
      else
        if orig != result || force
          # this lets us abort a script if a command in the middle of it errors out
          # stop_on_error_cmd = "function error_exit { exit 99; }; trap error_exit ERR"
          config.post = "#{stop_on_error_cmd}\n#{config.post}" if stop_on_error_cmd

          Rubber.logger.info{"Transformation executing post config command: #{config.post}"}
          Rubber.logger.info `#{config.post}`
          if $?.exitstatus != 0
            raise "Post command failed execution:  #{config.post}"
          end
        else
          Rubber.logger.info("Nothing to do, not running post command")
        end
      end
    end
  end
end