class Omnibus::Builder

Constants

BUNDLER_BUSTER

@todo Look at using Bundler.with_clean_env{ … } instead

Attributes

build_commands[R]

Public Class Methods

new(software, &block) click to toggle source
# File lib/omnibus/builder.rb, line 108
def initialize(software, &block)
  @software = software
  @build_commands = []
  @dsl_proxy = DSLProxy.new(self, software)
  @dsl_proxy.eval_block(&block) if block_given?
end

Public Instance Methods

block(&rb_block) click to toggle source
# File lib/omnibus/builder.rb, line 171
def block(&rb_block)
  @build_commands << rb_block
end
build() click to toggle source
# File lib/omnibus/builder.rb, line 187
def build
  log "building #{name}"
  time_it("#{name} build") do
    @build_commands.each do |cmd|
      execute(cmd)
    end
  end
end
bundle(*args) click to toggle source
# File lib/omnibus/builder.rb, line 163
def bundle(*args)
  @build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/bundle", *args))
end
command(*args) click to toggle source
# File lib/omnibus/builder.rb, line 119
def command(*args)
  @build_commands << args
end
execute(cmd) click to toggle source
# File lib/omnibus/builder.rb, line 196
def execute(cmd)
  case cmd
  when Proc
    execute_proc(cmd)
  else
    execute_sh(cmd)
  end
end
gem(*args) click to toggle source
# File lib/omnibus/builder.rb, line 159
def gem(*args)
  @build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/gem", *args))
end
install_dir() click to toggle source
# File lib/omnibus/builder.rb, line 179
def install_dir
  @software.install_dir
end
log(message) click to toggle source
# File lib/omnibus/builder.rb, line 183
def log(message)
  puts "[builder:#{name}] #{message}"
end
name() click to toggle source
# File lib/omnibus/builder.rb, line 115
def name
  @software.name
end
patch(*args) click to toggle source
# File lib/omnibus/builder.rb, line 123
def patch(*args)
  args = args.dup.pop

  # we'll search for a patch file in the project root AND
  # the omnibus-software gem
  candidate_roots = [Omnibus.project_root]
  candidate_roots << Omnibus.omnibus_software_root if Omnibus.omnibus_software_root

  candidate_paths = candidate_roots.map do |root|
    File.expand_path("#{root}/config/patches/#{name}/#{args[:source]}")
  end

  source = candidate_paths.find{|path| File.exists?(path) }

  unless source
    raise MissingPatch.new(args[:source], candidate_paths)
  end

  plevel = args[:plevel] || 1
  if args[:target] 
    target = File.expand_path("#{project_dir}/#{args[:target]}")
    @build_commands << 
     "cat #{source} | patch -p#{plevel} #{target}"
  else
    @build_commands << 
     "patch -d #{project_dir} -p#{plevel} -i #{source}"
  end
end
project_dir() click to toggle source
# File lib/omnibus/builder.rb, line 175
def project_dir
  @software.project_dir
end
rake(*args) click to toggle source
# File lib/omnibus/builder.rb, line 167
def rake(*args)
  @build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/rake", *args))
end
ruby(*args) click to toggle source

@todo all these ruby commands (ruby, gem, bundle, rake) could

all be collapsed into a single underlying implementation, since
they all just differ on the executable being called
# File lib/omnibus/builder.rb, line 155
def ruby(*args)
  @build_commands << bundle_bust(*prepend_cmd("#{install_dir}/embedded/bin/ruby", *args))
end

Private Instance Methods

bundle_bust(*cmd_args) click to toggle source
# File lib/omnibus/builder.rb, line 276
def bundle_bust(*cmd_args)
  if cmd_args.last.is_a?(Hash)
    cmd_args = cmd_args.dup
    cmd_opts = cmd_args.pop.dup
    cmd_opts[:env] = cmd_opts[:env] ? BUNDLER_BUSTER.merge(cmd_opts[:env]) : BUNDLER_BUSTER
    cmd_args << cmd_opts
  else
    cmd_args << {:env => BUNDLER_BUSTER}
  end
end
execute_proc(cmd) click to toggle source
# File lib/omnibus/builder.rb, line 207
def execute_proc(cmd)
  cmd.call
rescue Exception => e
  # In Ruby 1.9, Procs have a #source_location method with file/line info.
  # Too bad we can't use it :(
  ErrorReporter.new(e, self).explain("Failed to build #{name} while running ruby block build step")
  raise
end
execute_sh(cmd) click to toggle source
# File lib/omnibus/builder.rb, line 216
def execute_sh(cmd)
  retries ||= 0
  shell = nil
  cmd_args = Array(cmd)
  options = {
    :cwd => project_dir,
    :timeout => 5400
  }
  options[:live_stream] = STDOUT if ENV['DEBUG']
  if cmd_args.last.is_a? Hash
    cmd_options = cmd_args.last
    cmd_args[cmd_args.size - 1] = options.merge(cmd_options)
  else
    cmd_args << options
  end

  cmd_string = cmd_args[0..-2].join(' ')
  cmd_opts_for_display = to_kv_str(cmd_args.last)

  log "Executing: `#{cmd_string}` with #{cmd_opts_for_display}"

  shell = Mixlib::ShellOut.new(*cmd)
  shell.environment["HOME"] = "/tmp" unless ENV["HOME"]

  cmd_name = cmd_string.split(/\s+/).first
  time_it("#{cmd_name} command") do
    shell.run_command
    shell.error!
  end
rescue Exception => e
  # Getting lots of errors from github, particularly with erlang/rebar
  # projects fetching tons of deps via git all the time. This isn't a
  # particularly elegant way to solve that problem. But it should work.
  if retries >= 3
    ErrorReporter.new(e, self).explain("Failed to build #{name} while running `#{cmd_string}` with #{cmd_opts_for_display}")
    raise
  else
    time_to_sleep = 5 * (2 ** retries)
    retries +=1
    log "Failed to execute cmd #{cmd} #{retries} time(s). Retrying in #{time_to_sleep}s."
    sleep(time_to_sleep)
    retry
  end
end
prepend_cmd(str, *cmd_args) click to toggle source
# File lib/omnibus/builder.rb, line 261
def prepend_cmd(str, *cmd_args)
  if cmd_args.size == 1
    # command as a string, no opts
    "#{str} #{cmd_args.first}"
  elsif cmd_args.size == 2 && cmd_args.last.is_a?(Hash)
    # command as a string w/ opts
    ["#{str} #{cmd_args.first}", cmd_args.last]
  elsif cmd_args.size == 0
    raise ArgumentError, "I don't even"
  else
    # cmd given as argv array
    cmd_args.dup.unshift(str)
  end
end
time_it(what) { || ... } click to toggle source
# File lib/omnibus/builder.rb, line 288
def time_it(what)
  start = Time.now
  yield
rescue Exception
  elapsed = Time.now - start
  log "#{what} failed, #{elapsed.to_f}s"
  raise
else
  elapsed = Time.now - start
  log "#{what} succeeded, #{elapsed.to_f}s"
end
to_kv_str(hash, join_str=",") click to toggle source

Convert a hash to a string in the form ‘key=value`. It should work with whatever input is given but is designed to make the options to ShellOut look nice.

# File lib/omnibus/builder.rb, line 303
def to_kv_str(hash, join_str=",")
  hash.inject([]) do |kv_pair_strs, (k,v)|
    val_str = case v
    when Hash
      %Q["#{to_kv_str(v, " ")}"]
    else
      v.to_s
    end
    kv_pair_strs << "#{k}=#{val_str}"
  end.join(join_str)
end