diff --git a/data/export/launchd/launchd.plist.erb b/data/export/launchd/launchd.plist.erb
new file mode 100644
index 0000000..6b57fa9
--- /dev/null
+++ b/data/export/launchd/launchd.plist.erb
@@ -0,0 +1,22 @@
+
+
+
+
+ Label
+ <%= "#{app}-#{process.name}-#{num}" %>
+ ProgramArguments
+
+ <%= process.command %>
+
+ KeepAlive
+
+ RunAtLoad
+
+ StandardErrorPath
+ <%= log_root %>/<%= app %>-<%= process.name %>-<%=num%>.log
+ UserName
+ <%= user %>
+ WorkingDirectory
+ <%= engine.directory %>
+
+
diff --git a/lib/foreman/export.rb b/lib/foreman/export.rb
index 7cd80f3..97f7188 100644
--- a/lib/foreman/export.rb
+++ b/lib/foreman/export.rb
@@ -31,4 +31,5 @@ require "foreman/export/upstart"
require "foreman/export/bluepill"
require "foreman/export/runit"
require "foreman/export/supervisord"
+require "foreman/export/launchd"
diff --git a/lib/foreman/export/launchd.rb b/lib/foreman/export/launchd.rb
new file mode 100644
index 0000000..003a075
--- /dev/null
+++ b/lib/foreman/export/launchd.rb
@@ -0,0 +1,27 @@
+require "erb"
+require "foreman/export"
+
+class Foreman::Export::Launchd < Foreman::Export::Base
+
+ def export
+ error("Must specify a location") unless location
+
+ app = self.app || File.basename(engine.directory)
+ user = self.user || app
+ log_root = self.log || "/var/log/#{app}"
+ template_root = self.template
+
+ FileUtils.mkdir_p(location)
+
+ engine.procfile.entries.each do |process|
+ 1.upto(self.concurrency[process.name]) do |num|
+
+ master_template = export_template("launchd", "launchd.plist.erb", template_root)
+ master_config = ERB.new(master_template).result(binding)
+ write_file "#{location}/#{app}-#{process.name}-#{num}.plist", master_config
+ end
+ end
+
+ end
+
+end
diff --git a/spec/foreman/export/launchd_spec.rb b/spec/foreman/export/launchd_spec.rb
new file mode 100644
index 0000000..674c516
--- /dev/null
+++ b/spec/foreman/export/launchd_spec.rb
@@ -0,0 +1,24 @@
+require "spec_helper"
+require "foreman/engine"
+require "foreman/export/launchd"
+require "tmpdir"
+
+describe Foreman::Export::Launchd, :fakefs do
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
+ let(:engine) { Foreman::Engine.new(procfile) }
+ let(:options) { Hash.new }
+ let(:launchd) { Foreman::Export::Launchd.new("/tmp/init", engine, options) }
+
+ before(:each) { load_export_templates_into_fakefs("launchd") }
+ before(:each) { stub(launchd).say }
+
+ it "exports to the filesystem" do
+ launchd.export
+
+ normalize_space(File.read("/tmp/init/app-alpha-1.plist")).should == normalize_space(example_export_file("launchd/launchd-a.default"))
+
+ normalize_space(File.read("/tmp/init/app-bravo-1.plist")).should == normalize_space(example_export_file("launchd/launchd-b.default"))
+
+ end
+
+end
diff --git a/spec/resources/export/launchd/launchd-a.default b/spec/resources/export/launchd/launchd-a.default
new file mode 100644
index 0000000..05675ea
--- /dev/null
+++ b/spec/resources/export/launchd/launchd-a.default
@@ -0,0 +1,22 @@
+
+
+
+
+ Label
+ app-alpha-1
+ ProgramArguments
+
+ ./alpha
+
+ KeepAlive
+
+ RunAtLoad
+
+ StandardErrorPath
+ /var/log/app/app-alpha-1.log
+ UserName
+ app
+ WorkingDirectory
+ /tmp/app
+
+
diff --git a/spec/resources/export/launchd/launchd-b.default b/spec/resources/export/launchd/launchd-b.default
new file mode 100644
index 0000000..99d5a04
--- /dev/null
+++ b/spec/resources/export/launchd/launchd-b.default
@@ -0,0 +1,22 @@
+
+
+
+
+ Label
+ app-bravo-1
+ ProgramArguments
+
+ ./bravo
+
+ KeepAlive
+
+ RunAtLoad
+
+ StandardErrorPath
+ /var/log/app/app-bravo-1.log
+ UserName
+ app
+ WorkingDirectory
+ /tmp/app
+
+