capistrano-sbt 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -26,29 +26,29 @@ This recipes will try to do following things during Capistrano `deploy:setup` an
26
26
 
27
27
  To build you sbt projects during Capistrano `deploy` tasks, add following in you `config/deploy.rb`. By default, sbt build will run after the Capistrano's `deploy:finalize_update`.
28
28
 
29
- # in "config/deploy.rb"
30
- require 'capistrano-sbt'
31
- set(:sbt_version, '0.11.2') # sbt version to build project
29
+ # config/deploy.rb
30
+ require "capistrano-sbt"
32
31
 
33
32
  Following options are available to manage your sbt build.
34
33
 
35
- * `:sbt_use_extras` - Use [sbt-extras](https://github.com/paulp/sbt-extras) to manage sbt. `false` by default.
36
- * `:sbt_version` - Project sbt version. This value may be discarded if `sbt_use_extras` is turned `true`.
37
- * `:sbt_archive_url` - Download URL for specified sbt version. This value may be discarded if `sbt_use_extras` is turned `true`.
38
- * `:sbt_compile_locally` - compile project on localhost. false by default.
39
- * `:sbt_goals` - sbt commands and tasks to execute. default is "reload clean package".
40
- * `:sbt_update_settings` - update `*.sbt` or not. false by default.
41
- * `:sbt_update_settings_locally` - udate `*.sbt` or not on local compilation. false by default.
42
- * `:sbt_settings` - list of your optional `*.sbt` files
43
- * `:sbt_settings_local` - list of your optional `*.sbt` files in on local compilation.
44
- * `:sbt_settings_path` - the destination path of the optional `*.sbt` files.
45
- * `:sbt_settings_path_local` - the destination path of the optional `*.sbt` files.
46
- * `:sbt_template_path` - specify ERB template path for `*.sbt`.
47
- * `:sbt_java_home` - optional `JAVA_HOME` settings for sbt commands.
48
- * `:sbt_java_home_local` - optional `JAVA_HOME` settings for sbt commands in localhost.
49
- * `:sbt_extras_url` - Download URL of `sbt` script of sbt-extras.
50
- * `:sbt_extras_check_interval` - Check updates of sbt-extras every specified seconds. `86400` by default.
51
- * `:sbt_log_noformat` - Do not colorize sbt outputs. `true` by default.
34
+ * `:sbt_use_extras` - Use [sbt-extras](https://github.com/paulp/sbt-extras) to manage sbt. `true` by default.
35
+ * `:sbt_extras_url` - The download url of sbt-extras.
36
+ * `:sbt_version` - If `:sbt_use_extras` was set as `false`, download specified version of `sbt-launch.jar` and set it up as `sbt`. If no version was given, try loading version from `project/build.properties`.
37
+ * `:sbt_setup_remotely` - Setup `sbt` on remote servers. As same value as `:sbt_update_remotely` by default.
38
+ * `:sbt_setup_locally` - Setup `sbt` on local server. Asa same value as `:sbt_update_locally` by default.
39
+ * `:sbt_update_remotely` - Run `sbt` on remote servers. `true` by default.
40
+ * `:sbt_update_locally` - Run `sbt` on local server. `false` by default.
41
+ * `:sbt_goals` - The `sbt` commands and tasks to be be executed. Run `reload clean package` by default.
42
+ * `:sbt_project_path` - The project path to be built on remote servers.
43
+ * `:sbt_project_path_local` - The project path to be built on local server.
44
+ * `:sbt_settings` - List of optional `*.sbt` files for remote servers.
45
+ * `:sbt_settings_local` - List of optional `*.sbt` files for local server.
46
+ * `:sbt_template_path` - The local path where the templates of `*.sbt` are in. By default, searches from `config/templates`.
47
+ * `:sbt_settings_path` - The destination path of the optional `*.sbt` files.
48
+ * `:sbt_settings_path_local` - The destination path of the optional `*.sbt` files.
49
+ * `:sbt_java_home` - Optional `JAVA_HOME` settings for `sbt` on remote servers.
50
+ * `:sbt_java_home_local` - Optional `JAVA_HOME` settings for `sbt` on local server.
51
+ * `:sbt_log_noformat` - Do not colorize `sbt` outputs. `true` by default.
52
52
  * `:sbt_release_build` - Skip building on SNAPSHOT version. `false` by default.
53
53
 
54
54
  ## Contributing
@@ -13,9 +13,13 @@ Gem::Specification.new do |gem|
13
13
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
14
  gem.name = "capistrano-sbt"
15
15
  gem.require_paths = ["lib"]
16
- gem.version = Capistrano::Sbt::VERSION
16
+ gem.version = Capistrano::SBT::VERSION
17
17
 
18
18
  gem.add_dependency("capistrano")
19
- gem.add_dependency("capistrano-file-resources", "~> 0.0.1")
20
- gem.add_dependency("capistrano-file-transfer-ext", "~> 0.0.3")
19
+ gem.add_dependency("capistrano-file-resources", "~> 0.1.0")
20
+ gem.add_dependency("capistrano-file-transfer-ext", "~> 0.1.0")
21
+ gem.add_development_dependency("capistrano-jdk-installer", "~> 0.1.0")
22
+ gem.add_development_dependency("net-scp", "~> 1.0.4")
23
+ gem.add_development_dependency("net-ssh", "~> 2.2.2")
24
+ gem.add_development_dependency("vagrant", "~> 1.0.6")
21
25
  end
@@ -2,267 +2,480 @@ require "capistrano-sbt/version"
2
2
  require "capistrano"
3
3
  require "capistrano/configuration/actions/file_transfer_ext"
4
4
  require "capistrano/configuration/resources/file_resources"
5
+ require "tempfile"
5
6
  require "uri"
6
7
 
7
8
  module Capistrano
8
- module Sbt
9
+ module SBT
9
10
  def self.extended(configuration)
10
11
  configuration.load {
11
12
  namespace(:sbt) {
12
- _cset(:sbt_version, '0.12.2')
13
- _cset(:sbt_group_id) {
14
- case sbt_version
15
- when /^0\.(?:7|10)\.\d+$/, /^0\.11\.[0-2]$/
16
- 'org.scala-tools.sbt'
13
+ _cset(:sbt_roles, [:app])
14
+ _cset(:sbt_tools_path) { File.join(shared_path, "tools", "sbt") }
15
+ _cset(:sbt_tools_path_local) { File.expand_path("tools/sbt") }
16
+ _cset(:sbt_archive_path) { sbt_tools_path }
17
+ _cset(:sbt_archive_path_local) { sbt_tools_path_local }
18
+ _cset(:sbt_path) {
19
+ if sbt_use_extras
20
+ File.join(sbt_tools_path, "sbt-extras")
17
21
  else
18
- 'org.scala-sbt'
22
+ File.join(sbt_tools_path, "sbt-#{sbt_version}")
19
23
  end
20
24
  }
21
- _cset(:sbt_jar_url) {
22
- "http://typesafe.artifactoryonline.com/typesafe/ivy-releases/#{sbt_group_id}/sbt-launch/#{sbt_version}/sbt-launch.jar"
23
- }
24
- _cset(:sbt_jar_file) {
25
- File.join(shared_path, 'tools', 'sbt', "sbt-#{sbt_version}", File.basename(URI.parse(sbt_jar_url).path))
26
- }
27
- _cset(:sbt_jar_file_local) {
28
- File.join(File.expand_path('.'), 'tools', 'sbt', "sbt-#{sbt_version}", File.basename(URI.parse(sbt_jar_url).path))
25
+ _cset(:sbt_path_local) {
26
+ if sbt_use_extras
27
+ File.join(sbt_tools_path_local, "sbt-extras")
28
+ else
29
+ File.join(sbt_tools_path_local, "sbt-#{sbt_version}")
30
+ end
29
31
  }
30
- _cset(:sbt_use_extras, false)
32
+ _cset(:sbt_bin_path) { sbt_path }
33
+ _cset(:sbt_bin_path_local) { sbt_path_local }
34
+ _cset(:sbt_bin) { File.join(sbt_bin_path, "sbt") }
35
+ _cset(:sbt_bin_local) { File.join(sbt_bin_path_local, "sbt") }
36
+ _cset(:sbt_project_path) { release_path }
37
+ _cset(:sbt_project_path_local) { File.expand_path(".") }
38
+ _cset(:sbt_target_path) { File.join(sbt_project_path, "target") }
39
+ _cset(:sbt_target_path_local) { File.join(sbt_project_path_local, "target") }
40
+ _cset(:sbt_template_path) { File.expand_path("config/templates") }
41
+
42
+ ## sbt-extras
43
+ _cset(:sbt_use_extras, true)
31
44
  _cset(:sbt_extras_url, "https://raw.github.com/paulp/sbt-extras/master/sbt")
32
- _cset(:sbt_extras_file) { File.join(shared_path, 'tools', 'sbt', 'sbt') }
33
- _cset(:sbt_extras_file_local) { File.join(File.expand_path('.'), 'tools', 'sbt', 'sbt') }
34
- _cset(:sbt_extras_check_interval, 86400)
35
- _cset(:sbt_extras_check_timestamp) { (Time.now - sbt_extras_check_interval).strftime('%Y%m%d%H%M') }
36
- _cset(:sbt_cmd) {
37
- if fetch(:sbt_java_home, nil)
38
- env = "env JAVA_HOME=#{sbt_java_home.dump}"
39
- java = "#{sbt_java_home}/bin/java"
45
+ _cset(:sbt_extras_file) { File.join(sbt_tools_path, "sbt") }
46
+ _cset(:sbt_extras_file_local) { File.join(sbt_tools_path_local, "sbt") }
47
+ _cset(:sbt_extras_update_interval) {
48
+ if exists?(:sbt_extras_check_interval)
49
+ logger.info(":sbt_extras_check_interval has been deprecated. use :sbt_extras_update_interval instead.")
50
+ fetch(:sbt_extras_check_interval)
40
51
  else
41
- env = ""
42
- java = "java"
52
+ 86400
43
53
  end
44
- if sbt_use_extras
45
- "#{env} #{sbt_extras_file} #{sbt_options.join(' ')}".strip
54
+ }
55
+ _cset(:sbt_extras_update_timestamp) { (Time.now - sbt_extras_update_interval).strftime("%Y%m%d%H%M") }
56
+
57
+ ## sbt-launch.jar
58
+ _cset(:sbt_project_sbt_version) {
59
+ begin
60
+ tempfile = Tempfile.new("capistrano-sbt")
61
+ download(File.join(sbt_project_path, "project", "build.properties"), tempfile.path)
62
+ tempfile.rewind()
63
+ tempfile.read().scan(/^sbt\.version=(.*)$/).map { |x| x.last }.last
64
+ rescue
65
+ nil
66
+ ensure
67
+ tempfile.close()
68
+ end
69
+ }
70
+ _cset(:sbt_project_sbt_version_local) {
71
+ begin
72
+ properties = File.read(File.join(sbt_project_path_local, "project", "build.properties"))
73
+ properties.scan(/^sbt\.version=(.*)$/).map { |x| x.last }.last
74
+ rescue
75
+ nil
76
+ end
77
+ }
78
+ _cset(:sbt_version) {
79
+ version ||= sbt_project_sbt_version if sbt_update_remotely
80
+ version ||= sbt_project_sbt_version_local if sbt_update_locally
81
+ version ||= "0.12.2"
82
+ logger.debug("Detected sbt version #{version}")
83
+ version
84
+ }
85
+ _cset(:sbt_group_id) {
86
+ case sbt_version
87
+ when /^0\.(?:7|10)\.\d+$/, /^0\.11\.[0-2]$/
88
+ "org.scala-tools.sbt"
46
89
  else
47
- "#{env} #{java} -jar #{sbt_jar_file} #{sbt_options.join(' ')}".strip
90
+ "org.scala-sbt"
48
91
  end
49
92
  }
50
- _cset(:sbt_cmd_local) {
51
- if fetch(:sbt_java_home_local, nil)
52
- env = "env JAVA_HOME=#{sbt_java_home_local.dump}"
53
- java = "#{sbt_java_home_local}/bin/java"
93
+ _cset(:sbt_launch_jar_url) {
94
+ if exists?(:sbt_jar_url)
95
+ logger.info(":sbt_jar_url has been deprecated. use :sbt_launch_jar_url instead.")
96
+ fetch(:sbt_jar_url)
97
+ else
98
+ "http://typesafe.artifactoryonline.com/typesafe/ivy-releases/#{sbt_group_id}/sbt-launch/#{sbt_version}/sbt-launch.jar"
54
99
  end
55
- if sbt_use_extras
56
- "#{env} #{sbt_extras_file_local} #{sbt_options_local.join(' ')}".strip
100
+ }
101
+ _cset(:sbt_launch_jar) {
102
+ if exists?(:sbt_jar_file)
103
+ logger.info(":sbt_jar_file has been deprecated. use :sbt_launch_jar instead.")
104
+ fetch(:sbt_jar_file)
57
105
  else
58
- "#{env} #{java} -jar #{sbt_jar_file_local} #{sbt_options_local.join(' ')}".strip
106
+ File.join(sbt_path, "sbt-launch.jar")
59
107
  end
60
108
  }
61
- _cset(:sbt_project_path) {
62
- release_path
109
+ _cset(:sbt_launch_jar_local) {
110
+ if exists?(:sbt_jar_file_local)
111
+ logger.info(":sbt_jar_file_local has been deprecated. use :sbt_launch_jar_local instead.")
112
+ fetch(:sbt_jar_file_local)
113
+ else
114
+ File.join(sbt_path_local, "sbt-launch.jar")
115
+ end
63
116
  }
64
- _cset(:sbt_project_path_local) {
65
- Dir.pwd
117
+ _cset(:sbt_launch_jar_script) {
118
+ (<<-EOS).gsub(/^\s*/, "")
119
+ #!/bin/sh -e
120
+ java -Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=384M -jar `dirname $0`/sbt-launch.jar "$@"
121
+ EOS
66
122
  }
67
- _cset(:sbt_target_path) {
68
- File.join(sbt_project_path, 'target')
123
+
124
+ ## SBT environment
125
+ _cset(:sbt_common_environment, {})
126
+ _cset(:sbt_default_environment) {
127
+ environment = {}
128
+ environment["JAVA_HOME"] = fetch(:sbt_java_home) if exists?(:sbt_java_home)
129
+ environment["PATH"] = [ sbt_bin_path, "$PATH" ].join(":") if sbt_setup_remotely
130
+ _merge_environment(sbt_common_environment, environment)
69
131
  }
70
- _cset(:sbt_target_path_local) {
71
- File.join(sbt_project_path_local, File.basename(sbt_target_path))
132
+ _cset(:sbt_default_environment_local) {
133
+ environment = {}
134
+ environment["JAVA_HOME"] = fetch(:sbt_java_home_local) if exists?(:sbt_java_home_local)
135
+ environment["PATH"] = [ sbt_bin_path, "$PATH" ].join(":") if sbt_setup_locally
136
+ _merge_environment(sbt_common_environment, environment)
72
137
  }
73
- _cset(:sbt_template_path, File.join(File.dirname(__FILE__), 'templates'))
74
- _cset(:sbt_update_settings, false)
75
- _cset(:sbt_update_settings_locally, false)
76
- _cset(:sbt_settings_path) { File.join(sbt_project_path, 'sbt') }
77
- _cset(:sbt_settings_path_local) { File.join(sbt_project_path_local, 'sbt') }
78
- _cset(:sbt_settings, [])
79
- _cset(:sbt_settings_local, [])
80
- _cset(:sbt_cleanup_settings, [])
81
- _cset(:sbt_cleanup_settings_local, [])
82
- _cset(:sbt_compile_locally, false) # perform precompilation on localhost
138
+ _cset(:sbt_environment) { _merge_environment(sbt_default_environment, fetch(:sbt_extra_environment, {})) }
139
+ _cset(:sbt_environment_local) { _merge_environment(sbt_default_environment_local, fetch(:sbt_extra_environment_local, {})) }
140
+ def _command(cmdline, options={})
141
+ environment = options.fetch(:env, {})
142
+ if environment.empty?
143
+ cmdline
144
+ else
145
+ env = (["env"] + environment.map { |k, v| "#{k}=#{v.dump}" }).join(" ")
146
+ "#{env} #{cmdline}"
147
+ end
148
+ end
149
+ def command(cmdline, options={})
150
+ _command(cmdline, :env => sbt_environment.merge(options.fetch(:env, {})))
151
+ end
152
+ def command_local(cmdline, options={})
153
+ _command(cmdline, :env => sbt_environment_local.merge(options.fetch(:env, {})))
154
+ end
155
+ _cset(:sbt_cmd) { command("#{sbt_bin.dump} #{sbt_options.map { |x| x.dump }.join(" ")}") }
156
+ _cset(:sbt_cmd_local) { command_local("#{sbt_bin_local.dump} #{sbt_options_local.map { |x| x.dump }.join(" ")}") }
83
157
  _cset(:sbt_goals, %w(reload clean package))
84
158
  _cset(:sbt_common_options) {
85
159
  options = []
86
160
  if fetch(:sbt_log_noformat, true)
87
- options << if sbt_use_extras
88
- "-no-colors"
89
- else
90
- "-Dsbt.log.noformat=true"
91
- end
161
+ if sbt_use_extras
162
+ options << "-no-colors"
163
+ else
164
+ options << "-Dsbt.log.noformat=true"
165
+ end
92
166
  end
93
167
  options
94
168
  }
95
- _cset(:sbt_options) {
96
- options = sbt_common_options + fetch(:sbt_extra_options, [])
169
+ _cset(:sbt_default_options) {
170
+ options = sbt_common_options.dup
97
171
  if sbt_update_settings
98
- options << if sbt_use_extras
99
- "-sbt-dir #{sbt_settings_path}"
100
- else
101
- "-Dsbt.global.base=#{sbt_settings_path}"
102
- end
172
+ if sbt_use_extras
173
+ options += ["-sbt-dir", sbt_settings_path]
174
+ else
175
+ options << "-Dsbt.global.base=#{sbt_settings_path}"
176
+ end
103
177
  end
104
178
  options
105
179
  }
106
- _cset(:sbt_options_local) {
107
- options = sbt_common_options + fetch(:sbt_extra_options_local, [])
180
+ _cset(:sbt_default_options_local) {
181
+ options = sbt_common_options.dup
108
182
  if sbt_update_settings_locally
109
- options << if sbt_use_extras
110
- "-sbt-dir #{sbt_settings_path_local}"
111
- else
112
- "-Dsbt.global.base=#{sbt_settings_path_local}"
113
- end
183
+ if sbt_use_extras
184
+ options += ["-sbt-dir", sbt_settings_path_local]
185
+ else
186
+ options << "-Dsbt.global.base=#{sbt_settings_path_local}"
187
+ end
114
188
  end
115
189
  options
116
190
  }
191
+ _cset(:sbt_options) { sbt_default_options + fetch(:sbt_extra_options, []) }
192
+ _cset(:sbt_options_local) { sbt_default_options_local + fetch(:sbt_extra_options_local, []) }
117
193
 
118
- desc("Setup sbt.")
119
- task(:setup, :roles => :app, :except => { :no_release => true }) {
120
- transaction {
121
- install
122
- update_settings if sbt_update_settings
123
- setup_locally if sbt_compile_locally
124
- }
194
+ _cset(:sbt_setup_remotely) { sbt_update_remotely }
195
+ _cset(:sbt_setup_locally) { sbt_update_locally }
196
+ _cset(:sbt_update_remotely) { not(sbt_update_locally) }
197
+ _cset(:sbt_update_locally) { # perform update on localhost
198
+ if exists?(:sbt_compile_locally)
199
+ logger.info(":sbt_compile_locally has been deprecated. use :sbt_update_locally instead.")
200
+ fetch(:sbt_compile_locally, false)
201
+ else
202
+ false
203
+ end
125
204
  }
126
- after 'deploy:setup', 'sbt:setup'
127
205
 
128
- desc("Setup sbt locally.")
129
- task(:setup_locally, :except => { :no_release => true }) {
130
- transaction {
131
- install_locally
132
- update_settings_locally if sbt_update_settings_locally
206
+ if top.namespaces.key?(:multistage)
207
+ after "multistage:ensure", "sbt:setup_default_environment"
208
+ else
209
+ on :start do
210
+ if top.namespaces.key?(:multistage)
211
+ after "multistage:ensure", "sbt:setup_default_environment"
212
+ else
213
+ setup_default_environment
214
+ end
215
+ end
216
+ end
217
+
218
+ _cset(:sbt_environment_join_keys, %w(DYLD_LIBRARY_PATH LD_LIBRARY_PATH MANPATH PATH))
219
+ def _merge_environment(x, y)
220
+ x.merge(y) { |key, x_val, y_val|
221
+ if sbt_environment_join_keys.include?(key)
222
+ ( y_val.split(":") + x_val.split(":") ).uniq.join(":")
223
+ else
224
+ y_val
225
+ end
133
226
  }
227
+ end
228
+
229
+ task(:setup_default_environment, :roles => sbt_roles, :except => { :no_release => true }) {
230
+ if fetch(:sbt_setup_default_environment, true)
231
+ set(:default_environment, _merge_environment(default_environment, sbt_environment))
232
+ end
134
233
  }
135
234
 
136
- def _install(options={})
235
+ def _invoke_command(cmdline, options={})
236
+ if options[:via] == :run_locally
237
+ run_locally(cmdline)
238
+ else
239
+ invoke_command(cmdline, options)
240
+ end
241
+ end
242
+
243
+ def _download_extras(uri, filename, options={})
137
244
  execute = []
138
- if sbt_use_extras
139
- extras_file = options.delete(:extras_file)
140
- execute << "mkdir -p #{File.dirname(extras_file)}"
141
- x = "/tmp/sbt-extras.#{$$}"
142
- execute << "touch -t #{sbt_extras_check_timestamp} #{x}"
143
- execute << "( test #{extras_file} -nt #{x} || wget --no-verbose -O #{extras_file} #{sbt_extras_url} )"
144
- execute << "touch #{extras_file}"
145
- execute << "rm -f #{x}"
146
- execute << "( test -x #{extras_file} || chmod a+x #{extras_file} )"
245
+ execute << "mkdir -p #{File.dirname(filename).dump}"
246
+ if fetch(:sbt_update_extras, true)
247
+ execute << %{t=$(mktemp /tmp/sbt.XXXXXXXXXX)}
248
+ execute << %{touch -t #{sbt_extras_update_timestamp.dump} "$t"}
249
+ execute << %{( test #{filename.dump} -nt "$t" || wget --no-verbose -O #{filename.dump} #{uri.dump}; rm -f "$t" )}
250
+ else
251
+ execute << %{( test -f #{filename.dump} || wget --no-verbose -O #{filename.dump} #{uri.dump} )}
252
+ end
253
+ execute << %{( test -x #{filename.dump} || chmod 755 #{filename.dump} )}
254
+ _invoke_command(execute.join(" && "), options)
255
+ end
256
+
257
+ def _download_launch_jar(uri, filename, options={})
258
+ execute = []
259
+ execute << "mkdir -p #{File.dirname(filename).dump}"
260
+ execute << "( test -f #{filename.dump} || wget --no-verbose -O #{filename.dump} #{uri.dump} )"
261
+ _invoke_command(execute.join(" && "), options)
262
+ end
263
+
264
+ def _upload(filename, remote_filename, options={})
265
+ mode = options.delete(:mode)
266
+ _invoke_command("mkdir -p #{File.dirname(remote_filename).dump}", options)
267
+ transfer_if_modified(:up, filename, remote_filename, fetch(:sbt_upload_options, {}).merge(options))
268
+ if mode
269
+ mode = mode.is_a?(Numeric) ? mode.to_s(8) : mode.to_s
270
+ _invoke_command("chmod #{mode.dump} #{remote_filename.dump}", options)
271
+ end
272
+ end
273
+
274
+ def _install_extras(filename, options={})
275
+ # nop
276
+ end
277
+
278
+ def _install_launch_jar(jar, sbt, options={})
279
+ via = options.delete(:via)
280
+ if via == :run_locally
281
+ run_locally("mkdir -p #{File.dirname(sbt).dump}")
282
+ File.write(sbt, sbt_launch_jar_script)
283
+ run_locally("( test -x #{sbt.dump} || chmod 755 #{sbt.dump} )")
147
284
  else
148
- jar_file = options.delete(:jar_file)
149
- execute << "mkdir -p #{File.dirname(jar_file)}"
150
- execute << "( test -f #{jar_file} || wget --no-verbose -O #{jar_file} #{sbt_jar_url} )"
151
- execute << "test -f #{jar_file}"
285
+ safe_put(sbt_launch_jar_script, sbt, {:mode => "755", :run_method => via}.merge(options))
152
286
  end
153
- execute.join(' && ')
154
287
  end
155
288
 
156
- task(:install, :roles => :app, :except => { :no_release => true }) {
157
- run(_install(:jar_file => sbt_jar_file, :extras_file => sbt_extras_file))
289
+ def _installed?(destination, options={})
290
+ sbt = File.join(destination, "sbt")
291
+ cmdline = "test -d #{destination.dump} && test -x #{sbt.dump}"
292
+ _invoke_command(cmdline, options)
293
+ true
294
+ rescue
295
+ false
296
+ end
297
+
298
+ ## setup
299
+ desc("Setup sbt.")
300
+ task(:setup, :roles => sbt_roles, :except => { :no_release => true }) {
301
+ transaction {
302
+ setup_remotely if sbt_setup_remotely
303
+ setup_locally if sbt_setup_locally
304
+ }
158
305
  }
306
+ after "deploy:setup", "sbt:setup"
159
307
 
160
- task(:install_locally, :except => { :no_release => true }) {
161
- run_locally(_install(:jar_file => sbt_jar_file_local, :extras_file => sbt_extras_file_local))
308
+ task(:setup_remotely, :roles => sbt_roles, :except => { :no_release => true }) {
309
+ if sbt_use_extras
310
+ _download_extras(sbt_extras_url, sbt_bin_local, :via => :run_locally)
311
+ _upload(sbt_bin_local, sbt_bin, :mode => "755")
312
+ unless _installed?(sbt_path)
313
+ _install_extras(sbt_bin)
314
+ end
315
+ else
316
+ _download_launch_jar(sbt_launch_jar_url, sbt_launch_jar_local, :via => :run_locally)
317
+ _upload(sbt_launch_jar_local, sbt_launch_jar, :mode => "644")
318
+ unless _installed?(sbt_path)
319
+ _install_launch_jar(sbt_launch_jar, sbt_bin)
320
+ end
321
+ end
322
+ _installed?(sbt_path)
323
+ update_settings if sbt_update_settings
324
+ }
325
+
326
+ desc("Setup sbt locally.")
327
+ task(:setup_locally, :roles => sbt_roles, :except => { :no_release => true }) {
328
+ if sbt_use_extras
329
+ _download_extras(sbt_extras_url, sbt_bin_local, :via => :run_locally)
330
+ unless _installed?(sbt_path_local, :via => :run_locally)
331
+ _install_extras(sbt_bin_local, :via => :run_locally)
332
+ end
333
+ else
334
+ _download_launch_jar(sbt_launch_jar_url, sbt_launch_jar_local, :via => :run_locally)
335
+ unless _installed?(sbt_path_local, :via => :run_locally)
336
+ _install_launch_jar(sbt_launch_jar_local, sbt_bin_local, :via => :run_locally)
337
+ end
338
+ end
339
+ _installed?(sbt_path_local, :via => :run_locally)
340
+ update_settings_locally if sbt_update_settings_locally
162
341
  }
163
342
 
164
- task(:update_settings, :roles => :app, :except => { :no_release => true }) {
165
- sbt_settings.each do |f|
166
- safe_put(template(f, :path => sbt_template_path), File.join(sbt_settings_path, f))
343
+ _cset(:sbt_update_settings) { sbt_setup_remotely and not(sbt_settings.empty?) }
344
+ _cset(:sbt_update_settings_locally) { sbt_setup_locally and not(sbt_settings_local.empty?) }
345
+ _cset(:sbt_settings_path) { File.join(sbt_project_path, "sbt") } # sbt.global.base
346
+ _cset(:sbt_settings_path_local) { File.join(sbt_project_path_local, "sbt") } # sbt.global.base
347
+ _cset(:sbt_settings, [])
348
+ _cset(:sbt_settings_local) { sbt_settings }
349
+ task(:update_settings, :roles => sbt_roles, :except => { :no_release => true }) {
350
+ sbt_settings.each do |file|
351
+ safe_put(template(file, :path => sbt_template_path), File.join(sbt_settings_path, file))
167
352
  end
168
- run("rm -f #{sbt_cleanup_settings.map { |x| x.dump }.join(' ')}") unless sbt_cleanup_settings.empty?
169
353
  }
170
354
 
171
- task(:update_settings_locally, :except => { :no_release => true }) {
172
- sbt_settings_local.each do |f|
173
- File.write(File.join(sbt_settings_path_local, f), template(f, :path => sbt_template_path))
355
+ task(:update_settings_locally, :rols => sbt_roles, :except => { :no_release => true }) {
356
+ sbt_settings_local.each do |file|
357
+ destination = File.join(sbt_settings_path_local, file)
358
+ run_locally("mkdir -p #{File.dirname(destination).dump}")
359
+ File.write(destination, template(file, :path => sbt_template_path))
174
360
  end
175
- run_locally("rm -f #{sbt_cleanup_settings_local.map { |x| x.dump }.join(' ')}") unless sbt_cleanup_settings_local.empty?
176
361
  }
177
362
 
363
+ ## update
178
364
  desc("Update sbt build.")
179
- task(:update, :roles => :app, :except => { :no_release => true }) {
365
+ task(:update, :roles => sbt_roles, :except => { :no_release => true }) {
180
366
  transaction {
181
- if sbt_compile_locally
182
- update_locally
183
- else
184
- execute
185
- end
367
+ update_remotely if sbt_update_remotely
368
+ update_locally if sbt_update_locally
186
369
  }
187
370
  }
188
- after 'deploy:finalize_update', 'sbt:update'
371
+ _cset(:sbt_update_hook_type, :after)
372
+ _cset(:sbt_update_hook, "deploy:finalize_update")
373
+ on(:start) do
374
+ [ sbt_update_hook ].flatten.each do |hook|
375
+ send(sbt_update_hook_type, hook, "sbt:update") if hook
376
+ end
377
+ end
189
378
 
190
- desc("Update sbt build locally.")
191
- task(:update_locally, :except => { :no_release => true }) {
192
- transaction {
193
- execute_locally
194
- upload_locally
195
- }
379
+ task(:update_remotely, :roles => sbt_roles, :except => { :no_release => true }) {
380
+ execute_remotely
196
381
  }
197
382
 
198
- def _sbt(cmd, path, goals=[])
199
- "cd #{path.dump} && #{cmd} #{goals.map { |s| s.dump }.join(' ')}"
200
- end
383
+ desc("Update sbt build locally.")
384
+ task(:update_locally, :roles => sbt_roles, :except => { :no_release => true }) {
385
+ execute_locally
386
+ upload_locally
387
+ }
201
388
 
202
- def _sbt_parse_version(s)
389
+ def _parse_project_version(s)
203
390
  # FIXME: is there any better way to get project version?
204
391
  lastline = s.split(/(?:\r?\n)+/)[-1]
205
392
  lastline.split[-1]
206
393
  end
207
394
 
208
- _cset(:sbt_release_build, false)
209
- _cset(:sbt_snapshot_pattern, /-SNAPSHOT$/i)
210
395
  _cset(:sbt_project_version) {
211
- _sbt_parse_version(capture(_sbt(sbt_cmd, sbt_project_path, ["show version"])))
396
+ _parse_project_version(sbt.exec(["show version"], :via => :capture))
212
397
  }
213
398
  _cset(:sbt_project_version_local) {
214
- _sbt_parse_version(run_locally(_sbt(sbt_cmd_local, sbt_project_path_local, ["show version"])))
399
+ _parse_project_version(sbt.exec_locally(["show version"], :via => :capture_locally))
215
400
  }
216
-
217
- def _validate_project_version(version_key)
218
- if sbt_release_build
219
- version = fetch(version_key)
220
- if sbt_snapshot_pattern === version
221
- abort("Skip to build project since \`#{version}' is a SNAPSHOT version.")
222
- end
401
+ _cset(:sbt_snapshot_pattern, /-SNAPSHOT$/i)
402
+ def _validate_project_version(key)
403
+ if fetch(:sbt_release_build, false)
404
+ version = fetch(key)
405
+ abort("Skip to build project since \`#{version}' is a SNAPSHOT version.") if sbt_snapshot_pattern === version
223
406
  end
224
407
  end
225
408
 
226
409
  desc("Perform sbt build.")
227
- task(:execute, :roles => :app, :except => { :no_release => true }) {
228
- on_rollback {
229
- run(_sbt(sbt_cmd, sbt_project_path, %w(clean)))
230
- }
410
+ task(:execute, :roles => sbt_roles, :except => { :no_release => true }) {
411
+ execute_remotely
412
+ }
413
+
414
+ task(:execute_remotely, :roles => sbt_roles, :except => { :no_release => true }) {
415
+ on_rollback do
416
+ sbt.exec("clean")
417
+ end
231
418
  _validate_project_version(:sbt_project_version)
232
- run(_sbt(sbt_cmd, sbt_project_path, sbt_goals))
419
+ sbt.exec(sbt_goals)
233
420
  }
234
421
 
235
422
  desc("Perform sbt build locally.")
236
- task(:execute_locally, :roles => :app, :except => { :no_release => true }) {
423
+ task(:execute_locally, :roles => sbt_roles, :except => { :no_release => true }) {
237
424
  on_rollback {
238
- run_locally(_sbt(sbt_cmd_local, sbt_project_path_local, %w(clean)))
425
+ sbt.exec_locally("clean")
239
426
  }
240
427
  _validate_project_version(:sbt_project_version_local)
241
- cmdline = _sbt(sbt_cmd_local, sbt_project_path_local, sbt_goals)
242
- logger.info(cmdline)
243
- abort("execution failure") unless system(cmdline)
428
+ sbt.exec_locally(sbt_goals)
244
429
  }
245
430
 
246
- _cset(:sbt_tar, 'tar')
247
- _cset(:sbt_tar_local, 'tar')
248
- _cset(:sbt_target_archive) {
249
- "#{sbt_target_path}.tar.gz"
250
- }
251
- _cset(:sbt_target_archive_local) {
252
- "#{sbt_target_path_local}.tar.gz"
253
- }
254
- task(:upload_locally, :roles => :app, :except => { :no_release => true }) {
255
- on_rollback {
256
- run("rm -rf #{sbt_target_path} #{sbt_target_archive}")
257
- }
431
+ task(:upload_locally, :rolse => sbt_roles, :except => { :no_release => true }) {
432
+ on_rollback do
433
+ run("rm -rf #{sbt_target_path.dump}")
434
+ end
435
+ filename = "#{sbt_target_path_local}.tar.gz"
436
+ remote_filename = "#{sbt_target_path}.tar.gz"
258
437
  begin
259
- run_locally("cd #{File.dirname(sbt_target_path_local)} && #{sbt_tar_local} chzf #{sbt_target_archive_local} #{File.basename(sbt_target_path_local)}")
260
- upload(sbt_target_archive_local, sbt_target_archive)
261
- run("cd #{File.dirname(sbt_target_path)} && #{sbt_tar} xzf #{sbt_target_archive} && rm -f #{sbt_target_archive}")
438
+ run_locally("cd #{File.dirname(sbt_target_path_local).dump} && tar chzf #{filename.dump} #{File.basename(sbt_target_path_local).dump}")
439
+ run("mkdir -p #{File.dirname(sbt_target_path).dump}")
440
+ top.upload(filename, remote_filename)
441
+ run("cd #{File.dirname(sbt_target_path).dump} && tar xzf #{remote_filename.dump}")
262
442
  ensure
263
- run_locally("rm -f #{sbt_target_archive_local}")
443
+ run("rm -f #{remote_filename.dump}") rescue nil
444
+ run_locally("rm -f #{filename.dump}") rescue nil
264
445
  end
265
446
  }
447
+
448
+ def _exec_command(args=[], options={})
449
+ args = [ args ].flatten
450
+ sbt = options.fetch(:sbt, "sbt")
451
+ execute = []
452
+ execute << "cd #{options[:path].dump}" if options.key?(:path)
453
+ execute << "#{sbt} #{args.map { |x| x.dump }.join(" ")}"
454
+ execute.join(" && ")
455
+ end
456
+
457
+ ## public methods
458
+ def exec(args=[], options={})
459
+ cmdline = _exec_command(args, { :path => sbt_project_path, :sbt => sbt_cmd, :via => :run }.merge(options))
460
+ _invoke_command(cmdline, options)
461
+ end
462
+
463
+ def exec_locally(args=[], options={})
464
+ via = options.delete(:via)
465
+ cmdline = _exec_command(args, { :path => sbt_project_path_local, :sbt => sbt_cmd_local, :via => :run_locally }.merge(options))
466
+ if via == :capture_locally
467
+ _invoke_command(cmdline, options.merge(:via => :run_locally))
468
+ else
469
+ logger.trace("executing locally: #{cmdline.dump}")
470
+ elapsed = Benchmark.realtime do
471
+ system(cmdline)
472
+ end
473
+ if $?.to_i > 0 # $? is command exit code (posix style)
474
+ raise Capistrano::LocalArgumentError, "Command #{cmd} returned status code #{$?}"
475
+ end
476
+ logger.trace "command finished in #{(elapsed * 1000).round}ms"
477
+ end
478
+ end
266
479
  }
267
480
  }
268
481
  end
@@ -270,7 +483,7 @@ module Capistrano
270
483
  end
271
484
 
272
485
  if Capistrano::Configuration.instance
273
- Capistrano::Configuration.instance.extend(Capistrano::Sbt)
486
+ Capistrano::Configuration.instance.extend(Capistrano::SBT)
274
487
  end
275
488
 
276
489
  # vim:set ft=ruby :