How do I implement a custom buildr task defined externally?

90 Views Asked by At

I have a task which I'm trying to refactor into an external module so that I can later separate it from this project and use it for other projects.

When I try to run my task, I get an error:

Buildr aborted!
NoMethodError : undefined method `path_to' for nil:NilClass

Essentially it seems like the code for the project.task block is never called.

The code is as follows. Some of the code comes from the working code for the compile task, so I know that those bits are probably correct. Other parts come from documented examples for buildr, which from experience earlier today can be taken with a grain (or sometimes an entire lake) of salt. I can't figure out what I've done wrong, though.

module MacAppBundle
  include Buildr::Extension

  class MacAppBundleTask < Rake::Task
    attr_accessor :app_name

    def initialize(*args)
      super

      enhance do |task|
        #TODO: @project is always nil here because associate_with is never called
        app = @project.path_to("target/#{app_name}.app")
        if File.exists?(app)
          FileUtils.rm_rf(app)
        end
        Dir.mkdir(app)
        #... omitting copying the rest of the stuff into the bundle ...
      end
    end

  protected

    def associate_with(project)
      @project = project
    end
  end

  before_define do |project|
    mac_app_bundle = MacAppBundleTask.define_task('mac_app_bundle')

    project.task 'mac_app_bundle' do |task|
      #TODO: This code never executes. Why?
      mac_app_bundle.send :associate_with, project
      project.local_task('mac_app_bundle')
    end
  end

  after_define do |project|
    #TODO: This bit is definitely questionable because I can't find any documentation
    # or working examples of similar code.
    task('mac_app_bundle' => project.package(:jar))
  end

  def mac_app_bundle
    task('mac_app_bundle')
  end
end

class Buildr::Project
  include MacAppBundle
end

#TODO: Find a place to move this. Seems weird to have to call it in global scope.
Project.local_task('mac_app_bundle') do |name|
  puts "Creating Mac OS X app bundle for #{name}"
end
1

There are 1 best solutions below

0
On

The correct way appears to be:

  before_define do |project|
    mac_app_bundle = MacAppBundleTask.define_task('mac_app_bundle')
    mac_app_bundle.send :associate_with, project
    project.task('mac_app_bundle')
  end