module Buildr::DRbApplication

This addon allows you start a DRb server hosting a buildfile, so that you can later invoke tasks on it without having to load the complete buildr runtime again.

Usage:

buildr -r buildr/drb drb:start

Once the server has been started you can invoke tasks using a simple script:

#!/usr/bin/env ruby
require 'rubygems'
require 'buildr/drb'
Buildr::DRbApplication.run

Save this script as 'dbuildr', make it executable and use it to invoke tasks.

dbuildr clean compile

The dbuildr script will run as the server if there isn't one already running. Subsequent calls to dbuildr will act as the client and invoke the tasks you provide in the server. If the buildfile has been modified it will be reloaded on the BuildrServer.

JRuby users can use a nailgun client to invoke tasks as fast as possible without having to incur JVM startup time. See the documentation for buildr/nailgun.

Constants

PORT

Attributes

original[RW]
snapshot[RW]

Public Class Methods

client_uri() click to toggle source
# File addon/buildr/drb.rb, line 116
def client_uri
  "druby://:#{PORT + 1}"
end
remote_run(cfg) click to toggle source
# File addon/buildr/drb.rb, line 120
def remote_run(cfg)
  with_config(cfg) { Buildr.application.remote_run(self) }
rescue => e
  cfg[:err].puts e.message
  e.backtrace.each { |b| cfg[:err].puts "\tfrom #{b}" }
  raise e
end
run() click to toggle source
# File addon/buildr/drb.rb, line 106
def run
  begin
    client = connect
  rescue DRb::DRbConnError => e
    run_server!
  else
    run_client(client)
  end
end
save_snapshot(app) click to toggle source
# File addon/buildr/drb.rb, line 128
def save_snapshot(app)
  if app.instance_eval { @rakefile }
    @snapshot = self::Snapshot.new
    app.buildfile_reloaded!
  end
end

Private Class Methods

connect() click to toggle source
# File addon/buildr/drb.rb, line 141
def connect
  buildr = DRbObject.new(nil, server_uri)
  uri = buildr.client_uri # obtain our uri from the server
  DRb.start_service(uri)
  buildr
end
delegate_stdio() click to toggle source
# File addon/buildr/drb.rb, line 187
def delegate_stdio
  $stdin  = SimpleDelegator.new($stdin)
  $stdout = SimpleDelegator.new($stdout)
  $stderr = SimpleDelegator.new($stderr)
end
run_client(client) click to toggle source
# File addon/buildr/drb.rb, line 148
def run_client(client)
  client.remote_run :dir => Dir.pwd, :argv => ARGV,
                    :in  => $stdin, :out => $stdout, :err => $stderr
end
run_server() click to toggle source
# File addon/buildr/drb.rb, line 170
def run_server
  setup
  DRb.start_service(server_uri, self)
  puts "#{self} waiting on #{server_uri}"
end
run_server!() click to toggle source
# File addon/buildr/drb.rb, line 176
def run_server!
  setup
  if RUBY_PLATFORM[/java/]
    require 'buildr/nailgun'
    Buildr.application['nailgun:drb'].invoke
  else
    run_server
    DRb.thread.join
  end
end
server_uri() click to toggle source
# File addon/buildr/drb.rb, line 137
def server_uri
  "druby://:#{PORT}"
end
setup() click to toggle source
# File addon/buildr/drb.rb, line 153
def setup
  unless original
    # Create the stdio delegator that can be cached (eg by fileutils)
    delegate_stdio

    # Lazily load buildr the first time it's needed
    require 'buildr'

    # Save the tasks,rules,layout defined by buildr
    # before loading any project
    @original = self::Snapshot.new

    Buildr.application.extend self
    save_snapshot(Buildr.application)
  end
end
with_config(remote) { || ... } click to toggle source
# File addon/buildr/drb.rb, line 193
def with_config(remote)
  @invoked = true
  set = lambda do |env|
    ARGV.replace env[:argv]
    $stdin.__setobj__(env[:in])
    $stdout.__setobj__(env[:out])
    $stderr.__setobj__(env[:err])
    Buildr.application.instance_variable_set :@original_dir, env[:dir]
  end
  original = {
    :dir => Buildr.application.instance_variable_get(:@original_dir),
    :argv => ARGV,
    :in => $stdin.__getobj__,
    :out => $stdout.__getobj__,
    :err => $stderr.__getobj__
  }
  begin
    set[remote]
    yield
  ensure
    set[original]
  end
end

Public Instance Methods

buildfile_reloaded!() click to toggle source
# File addon/buildr/drb.rb, line 234
def buildfile_reloaded!
  @last_loaded = buildfile.timestamp if @rakefile
end
remote_run(server) click to toggle source
# File addon/buildr/drb.rb, line 219
def remote_run(server)
  @options = server.original.options.clone
  init 'Distributed Buildr'
  if @rakefile
    if buildfile_needs_reload?
      reload_buildfile(server, server.original)
    else
      clear_invoked_tasks(server.snapshot || server.original)
    end
  else
    reload_buildfile(server, server.original)
  end
  top_level
end

Private Instance Methods

buildfile_needs_reload?() click to toggle source
# File addon/buildr/drb.rb, line 240
def buildfile_needs_reload?
  !@last_loaded || @last_loaded < buildfile.timestamp
end
clear_for_reload(snapshot) click to toggle source
# File addon/buildr/drb.rb, line 250
def clear_for_reload(snapshot)
  Project.clear
  @tasks = {}
  @rules = snapshot.rules.clone
  snapshot.tasks.each_pair { |name, saved| saved.define! }
  Layout.default = snapshot.layout.clone
end
clear_invoked_tasks(snapshot) click to toggle source
# File addon/buildr/drb.rb, line 258
def clear_invoked_tasks(snapshot)
  @rules = snapshot.rules.clone
  (@tasks.keys - snapshot.projects.keys).each do |name|
    if saved = snapshot.tasks[name]
      # reenable this task, restoring its actions/prereqs
      task = @tasks[name]
      task.reenable
      task.prerequisites.replace saved.prerequisites.clone
      task.actions.replace saved.actions.clone
    else
      # tasks generated at runtime, drop it
      @tasks.delete(name)
    end
  end
end
reload_buildfile(server, snapshot) click to toggle source
# File addon/buildr/drb.rb, line 244
def reload_buildfile(server, snapshot)
  clear_for_reload(snapshot)
  load_buildfile
  server.save_snapshot(self)
end