luban 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +37 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/luban +3 -0
- data/lib/luban/deployment/cli/application/authenticator.rb +106 -0
- data/lib/luban/deployment/cli/application/base.rb +179 -0
- data/lib/luban/deployment/cli/application/builder.rb +67 -0
- data/lib/luban/deployment/cli/application/publisher.rb +215 -0
- data/lib/luban/deployment/cli/application/repository.rb +175 -0
- data/lib/luban/deployment/cli/application/scm/git.rb +49 -0
- data/lib/luban/deployment/cli/application/scm/rsync.rb +47 -0
- data/lib/luban/deployment/cli/application.rb +5 -0
- data/lib/luban/deployment/cli/command.rb +360 -0
- data/lib/luban/deployment/cli/package/binary.rb +241 -0
- data/lib/luban/deployment/cli/package/dependency.rb +49 -0
- data/lib/luban/deployment/cli/package/dependency_set.rb +71 -0
- data/lib/luban/deployment/cli/package/installer/core.rb +98 -0
- data/lib/luban/deployment/cli/package/installer/install.rb +330 -0
- data/lib/luban/deployment/cli/package/installer/paths.rb +81 -0
- data/lib/luban/deployment/cli/package/installer.rb +3 -0
- data/lib/luban/deployment/cli/package/service.rb +17 -0
- data/lib/luban/deployment/cli/package/worker.rb +43 -0
- data/lib/luban/deployment/cli/package.rb +6 -0
- data/lib/luban/deployment/cli/project.rb +94 -0
- data/lib/luban/deployment/cli.rb +4 -0
- data/lib/luban/deployment/configuration/core.rb +67 -0
- data/lib/luban/deployment/configuration/filter.rb +54 -0
- data/lib/luban/deployment/configuration/question.rb +38 -0
- data/lib/luban/deployment/configuration/server.rb +70 -0
- data/lib/luban/deployment/configuration/server_set.rb +86 -0
- data/lib/luban/deployment/configuration.rb +5 -0
- data/lib/luban/deployment/error.rb +5 -0
- data/lib/luban/deployment/helpers/configuration.rb +159 -0
- data/lib/luban/deployment/helpers/utils.rb +180 -0
- data/lib/luban/deployment/helpers.rb +2 -0
- data/lib/luban/deployment/packages/bundler.rb +81 -0
- data/lib/luban/deployment/packages/git.rb +37 -0
- data/lib/luban/deployment/packages/openssl.rb +59 -0
- data/lib/luban/deployment/packages/ruby.rb +125 -0
- data/lib/luban/deployment/packages/rubygems.rb +89 -0
- data/lib/luban/deployment/packages/yaml.rb +33 -0
- data/lib/luban/deployment/parameters.rb +160 -0
- data/lib/luban/deployment/runner.rb +99 -0
- data/lib/luban/deployment/templates/envrc.erb +30 -0
- data/lib/luban/deployment/templates/unset_envrc.erb +28 -0
- data/lib/luban/deployment/version.rb +5 -0
- data/lib/luban/deployment/worker/base.rb +71 -0
- data/lib/luban/deployment/worker/controller.rb +11 -0
- data/lib/luban/deployment/worker/local.rb +19 -0
- data/lib/luban/deployment/worker/remote.rb +55 -0
- data/lib/luban/deployment/worker/task.rb +25 -0
- data/lib/luban/deployment/worker.rb +4 -0
- data/lib/luban/deployment.rb +8 -0
- data/lib/luban.rb +4 -0
- data/luban.gemspec +29 -0
- metadata +174 -0
@@ -0,0 +1,330 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class Installer
|
5
|
+
class InstallFailure < Luban::Deployment::Error; end
|
6
|
+
|
7
|
+
def required_packages
|
8
|
+
@required_packages ||=
|
9
|
+
self.class.package_class(package_name).
|
10
|
+
required_packages_for(package_major_version)
|
11
|
+
end
|
12
|
+
|
13
|
+
def configure_executable
|
14
|
+
@configure_executable ||= './configure'
|
15
|
+
end
|
16
|
+
|
17
|
+
def installed?
|
18
|
+
raise NotImplementedError, "#{self.class.name}#installed? is an abstract method."
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate_download_url
|
22
|
+
info "Validating download URL for #{package_full_name}"
|
23
|
+
validate_download_url!
|
24
|
+
end
|
25
|
+
|
26
|
+
def install
|
27
|
+
info "Installing #{package_full_name}"
|
28
|
+
if installed?
|
29
|
+
if force?
|
30
|
+
install!
|
31
|
+
else
|
32
|
+
update_result "Skipped! #{package_full_name} has been installed ALREADY.",
|
33
|
+
status: :skipped
|
34
|
+
return
|
35
|
+
end
|
36
|
+
else
|
37
|
+
install!
|
38
|
+
end
|
39
|
+
|
40
|
+
if installed?
|
41
|
+
update_result "Successfully installed #{package_full_name}."
|
42
|
+
else
|
43
|
+
update_result "Failed to install #{package_full_name}. " +
|
44
|
+
"Please check install log for details: #{install_log_file_path}",
|
45
|
+
status: :failed, level: :error
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def uninstall
|
50
|
+
info "Uninstalling #{package_full_name}"
|
51
|
+
if installed?
|
52
|
+
if current? and !force?
|
53
|
+
update_result "Skippped! #{package_full_name} is the current version in use. " +
|
54
|
+
"Please switch to other version before uninstalling this version or " +
|
55
|
+
"use -f to force uninstalling.",
|
56
|
+
status: :skipped, level: :warn
|
57
|
+
else
|
58
|
+
uninstall!
|
59
|
+
update_result "#{package_full_name} is uninstalled. "
|
60
|
+
end
|
61
|
+
else
|
62
|
+
message = "#{package_full_name} is NOT installed.",
|
63
|
+
if directory?(install_path) or directory?(build_path)
|
64
|
+
if force?
|
65
|
+
uninstall!
|
66
|
+
update_result message +
|
67
|
+
"Cleaned up leftover of #{package_full_name} from last installation."
|
68
|
+
else
|
69
|
+
update_result message +
|
70
|
+
"But leftover from last installation is found. " +
|
71
|
+
"Use -f to force clean it up."
|
72
|
+
end
|
73
|
+
else
|
74
|
+
update_result "Skipped! #{message}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def cleanup_all
|
80
|
+
cleanup_temp!
|
81
|
+
cleanup_logs!
|
82
|
+
update_result "Cleaned up temporary files in #{package_full_name} installation"
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_summary
|
86
|
+
status = if current_symlinked?
|
87
|
+
current? ? " *" : "s*"
|
88
|
+
else
|
89
|
+
current? ? "c*" : " "
|
90
|
+
end
|
91
|
+
|
92
|
+
if installed?
|
93
|
+
installed = '(installed)'
|
94
|
+
alert = case status
|
95
|
+
when "s*"
|
96
|
+
"Alert! #{package_full_name} is not the current version but symlinked IMPROPERLY. " +
|
97
|
+
"Run \"binstubs\" to fix it."
|
98
|
+
when "c*"
|
99
|
+
"Alert! #{package_full_name} is set as current version but NOT symlinked properly. " +
|
100
|
+
"Run \"binstubs\" to fix it."
|
101
|
+
end
|
102
|
+
else
|
103
|
+
installed = '(NOT installed)'
|
104
|
+
alert = nil
|
105
|
+
end
|
106
|
+
update_result summary: { name: package_full_name, installed: installed,
|
107
|
+
status: status, alert: alert }
|
108
|
+
end
|
109
|
+
|
110
|
+
def update_binstubs
|
111
|
+
if current?
|
112
|
+
if installed?
|
113
|
+
update_binstubs!
|
114
|
+
update_result "Updated #{package_name} binstubs with current version #{package_version}"
|
115
|
+
else
|
116
|
+
update_result "Skipped! #{package_full_name} is NOT installed yet. Please install it first.",
|
117
|
+
status: :failed, level: :error
|
118
|
+
end
|
119
|
+
else
|
120
|
+
if current_symlinked?
|
121
|
+
remove_binstubs!
|
122
|
+
remove_symlinks!
|
123
|
+
update_result "Removed #{package_name} binstubs with version #{package_version}. " +
|
124
|
+
"Current version of #{package_name} is NOT specified.",
|
125
|
+
level: :warn
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def which_current
|
131
|
+
get_summary
|
132
|
+
task.result.summary[:executable] = "Not found"
|
133
|
+
if current? and current_symlinked? and
|
134
|
+
file?(executable = File.join(readlink(current_path), 'bin', task.args.executable))
|
135
|
+
task.result.summary[:executable] = executable
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def whence_origin
|
140
|
+
get_summary
|
141
|
+
task.result.summary[:executable] = "Not found"
|
142
|
+
if file?(executable = bin_path.join(task.args.executable))
|
143
|
+
task.result.summary[:executable] = executable
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
def before_install
|
150
|
+
bootstrap
|
151
|
+
unless installed? or file?(src_file_path)
|
152
|
+
validate_download_url
|
153
|
+
end
|
154
|
+
install_required_packages(:before_install)
|
155
|
+
end
|
156
|
+
|
157
|
+
def after_install
|
158
|
+
install_required_packages(:after_install)
|
159
|
+
update_binstubs!
|
160
|
+
end
|
161
|
+
|
162
|
+
def install_required_packages(type)
|
163
|
+
required_packages[type].each do |d|
|
164
|
+
self.class.worker_class(:installer, package: d.name).new(
|
165
|
+
config: config, backend: backend,
|
166
|
+
cmd: :install, args: {},
|
167
|
+
opts: d.options.merge(name: d.name, version: d.version, parent: self)
|
168
|
+
).run
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def validate_download_url!
|
173
|
+
unless url_exists?(download_url)
|
174
|
+
raise InstallFailure,
|
175
|
+
"Package #{package_full_name} is NOT found from url: #{download_url}."
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def install!
|
180
|
+
download_package
|
181
|
+
uncompress_package
|
182
|
+
assure_dirs(build_path)
|
183
|
+
within build_path do
|
184
|
+
with compose_build_env_variables do
|
185
|
+
build_package
|
186
|
+
end
|
187
|
+
end
|
188
|
+
cleanup_build!
|
189
|
+
end
|
190
|
+
|
191
|
+
def uninstall!
|
192
|
+
if current?
|
193
|
+
remove_binstubs!
|
194
|
+
remove_symlinks!
|
195
|
+
end
|
196
|
+
rmdir(install_path)
|
197
|
+
cleanup_temp!
|
198
|
+
cleanup_logs!
|
199
|
+
end
|
200
|
+
|
201
|
+
def cleanup_temp!
|
202
|
+
Luban::Deployment::Package::DependencyTypes.each do |type|
|
203
|
+
required_packages[type].each do |d|
|
204
|
+
self.class.worker_class(:installer, package: d.name).new(
|
205
|
+
config: config, backend: backend,
|
206
|
+
cmd: :cleanup_all, args: {},
|
207
|
+
opts: d.options.merge(name: d.name, version: d.version, parent: self)
|
208
|
+
).run
|
209
|
+
end
|
210
|
+
end
|
211
|
+
cleanup_build!
|
212
|
+
end
|
213
|
+
|
214
|
+
def cleanup_build!
|
215
|
+
rmdir(build_path)
|
216
|
+
end
|
217
|
+
|
218
|
+
def cleanup_logs!
|
219
|
+
rmdir(install_log_path)
|
220
|
+
end
|
221
|
+
|
222
|
+
def update_binstubs!
|
223
|
+
remove_binstubs!
|
224
|
+
remove_symlinks!
|
225
|
+
create_symlinks!
|
226
|
+
create_binstubs!
|
227
|
+
end
|
228
|
+
|
229
|
+
def create_symlinks!
|
230
|
+
ln(install_path, current_path)
|
231
|
+
end
|
232
|
+
|
233
|
+
def create_binstubs!
|
234
|
+
return unless directory?(bin_path)
|
235
|
+
find_cmd = "find #{bin_path}/* -type f -print && find #{bin_path}/* -type l -print"
|
236
|
+
capture(find_cmd).split("\n").each do |bin|
|
237
|
+
ln(bin, app_bin_path.join(File.basename(bin)))
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def remove_symlinks!
|
242
|
+
return unless symlink?(current_path)
|
243
|
+
execute "[ -h #{current_path} ] && rm -f #{current_path}; true"
|
244
|
+
end
|
245
|
+
|
246
|
+
def remove_binstubs!
|
247
|
+
return unless directory?(current_bin_path)
|
248
|
+
find_cmd = "find #{current_bin_path}/* -type f -print && find #{current_bin_path}/* -type l -print"
|
249
|
+
capture(find_cmd).split("\n").each do |bin|
|
250
|
+
bin_symlink = app_bin_path.join(File.basename(bin))
|
251
|
+
execute "[ -h #{bin_symlink} ] && rm -f #{bin_symlink}; true"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def bootstrap
|
256
|
+
assure_dirs(etc_path, tmp_path, app_bin_path, install_path, install_log_path)
|
257
|
+
end
|
258
|
+
|
259
|
+
def download_package
|
260
|
+
info "Downloading #{package_full_name} source package"
|
261
|
+
if file?(src_file_path)
|
262
|
+
info "#{package_full_name} is downloaded ALREADY"
|
263
|
+
else
|
264
|
+
download_package!
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def download_package!
|
269
|
+
unless test("curl -L -o #{src_file_path} #{download_url} >> #{install_log_file_path} 2>&1")
|
270
|
+
rm(src_file_path)
|
271
|
+
abort_action('download')
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def uncompress_package
|
276
|
+
info "Uncompressing #{package_full_name} source package"
|
277
|
+
uncompress_package!
|
278
|
+
end
|
279
|
+
|
280
|
+
def uncompress_package!
|
281
|
+
unless test("tar -xzf #{src_file_path} -C #{package_tmp_path} >> #{install_log_file_path} 2>&1")
|
282
|
+
abort_action('uncompress')
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def build_package
|
287
|
+
configure_package
|
288
|
+
make_package
|
289
|
+
install_package
|
290
|
+
end
|
291
|
+
|
292
|
+
def configure_package
|
293
|
+
info "Configuring #{package_full_name}"
|
294
|
+
abort_action('configure') unless configure_package!
|
295
|
+
end
|
296
|
+
|
297
|
+
def configure_package!
|
298
|
+
test(configure_executable,
|
299
|
+
"#{compose_build_options} >> #{install_log_file_path} 2>&1")
|
300
|
+
end
|
301
|
+
|
302
|
+
def make_package
|
303
|
+
info "Making #{package_full_name}"
|
304
|
+
abort_action('make') unless make_package!
|
305
|
+
end
|
306
|
+
|
307
|
+
def make_package!
|
308
|
+
test(:make, ">> #{install_log_file_path} 2>&1")
|
309
|
+
end
|
310
|
+
|
311
|
+
def install_package
|
312
|
+
info "Installing #{package_full_name}"
|
313
|
+
abort_action('install') unless install_package!
|
314
|
+
end
|
315
|
+
|
316
|
+
def install_package!
|
317
|
+
test(:make, "install >> #{install_log_file_path} 2>&1")
|
318
|
+
end
|
319
|
+
|
320
|
+
def abort_action(action)
|
321
|
+
cleanup_temp!
|
322
|
+
task.result.status = :failed
|
323
|
+
task.result.message = "Failed to #{action} package #{package_full_name}." +
|
324
|
+
"Please check install log for details: #{install_log_file_path}"
|
325
|
+
raise InstallFailure, task.result.message
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class Installer
|
5
|
+
DefaultSrcFileExtName = 'tar.gz'
|
6
|
+
|
7
|
+
def src_file_name
|
8
|
+
@src_file_name ||= "#{package_full_name}.#{src_file_extname}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def src_file_extname
|
12
|
+
@src_file_extname ||= DefaultSrcFileExtName
|
13
|
+
end
|
14
|
+
|
15
|
+
def src_file_path
|
16
|
+
@src_file_path ||= tmp_path.join(src_file_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def source_repo
|
20
|
+
raise NotImplementedError, "#{self.class.name}#source_repo is an abstract method."
|
21
|
+
end
|
22
|
+
|
23
|
+
def download_from_source?
|
24
|
+
lubhub_repo.nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def download_from_lubhub?
|
28
|
+
!lubhub_repo.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def download_repo
|
32
|
+
@download_repo ||= download_from_source? ? source_repo : lubhub_repo
|
33
|
+
end
|
34
|
+
|
35
|
+
def source_url_root
|
36
|
+
raise NotImplementedError, "#{self.class.name}#source_url_root is an abstract method."
|
37
|
+
end
|
38
|
+
|
39
|
+
def download_url_root
|
40
|
+
@download_url_root ||= download_from_source? ? source_url_root : package_name
|
41
|
+
end
|
42
|
+
|
43
|
+
def download_url
|
44
|
+
@download_url ||= File.join(download_repo, download_url_root, src_file_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def install_path
|
48
|
+
@install_path ||= package_path.join('versions', package_version)
|
49
|
+
end
|
50
|
+
|
51
|
+
def bin_path
|
52
|
+
@bin_path ||= install_path.join('bin')
|
53
|
+
end
|
54
|
+
|
55
|
+
def lib_path
|
56
|
+
@lib_path ||= install_path.join('lib')
|
57
|
+
end
|
58
|
+
|
59
|
+
def include_path
|
60
|
+
@include_path ||= install_path.join('include')
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_path
|
64
|
+
@build_path ||= package_tmp_path.join(package_full_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def install_log_path
|
68
|
+
@install_log_path ||= package_path.join('log').join(package_full_name)
|
69
|
+
end
|
70
|
+
|
71
|
+
def install_log_file_path
|
72
|
+
@install_log_file_path ||= install_log_path.join(install_log_file_name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def install_log_file_name
|
76
|
+
@install_log_file_name ||= "#{package_full_name}-install-#{Time.now.strftime("%Y%m%d-%H%M%S")}.log"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class Service < Binary
|
5
|
+
include Luban::Deployment::Command::Tasks::Deploy
|
6
|
+
include Luban::Deployment::Command::Tasks::Control
|
7
|
+
|
8
|
+
%i(deploy).each do |m|
|
9
|
+
define_task_method(m, worker: :deployer)
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class Worker < Luban::Deployment::Worker::Remote
|
5
|
+
class << self
|
6
|
+
def package_class(package)
|
7
|
+
Luban::Deployment::Package::Base.package_class(package)
|
8
|
+
end
|
9
|
+
|
10
|
+
def worker_class(worker, **opts)
|
11
|
+
Luban::Deployment::Package::Base.worker_class(worker, **opts)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def package_name; task.opts.name; end
|
16
|
+
def package_full_name; "#{package_name}-#{package_version}"; end
|
17
|
+
|
18
|
+
def package_version; task.opts.version; end
|
19
|
+
def package_major_version; task.opts.major_version; end
|
20
|
+
def package_patch_level; task.opts.patch_level; end
|
21
|
+
|
22
|
+
def child?; !task.opts.parent.nil?; end
|
23
|
+
def parent; task.opts.parent; end
|
24
|
+
|
25
|
+
def current_path
|
26
|
+
@current_path ||= app_path.join(package_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def current_bin_path
|
30
|
+
@current_bin_path ||= current_path.join('bin')
|
31
|
+
end
|
32
|
+
|
33
|
+
def package_path
|
34
|
+
@package_path ||= luban_install_path.join('pkg', package_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def package_tmp_path
|
38
|
+
@package_tmp_path ||= package_path.join('tmp')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
class Project < Luban::Deployment::Command
|
4
|
+
using Luban::CLI::CoreRefinements
|
5
|
+
include Luban::Deployment::Parameters::Project
|
6
|
+
include Luban::Deployment::Command::Tasks::Install
|
7
|
+
include Luban::Deployment::Command::Tasks::Deploy
|
8
|
+
include Luban::Deployment::Command::Tasks::Control
|
9
|
+
|
10
|
+
attr_reader :apps
|
11
|
+
|
12
|
+
def display_name; @display_name ||= "#{stage} #{project.camelcase}"; end
|
13
|
+
|
14
|
+
def package_users_for(package_name, package_version, exclude: [], servers: [])
|
15
|
+
apps.values.inject([]) do |package_users, app|
|
16
|
+
if !exclude.include?(app.name) and
|
17
|
+
app.use_package?(package_name, package_version, servers: servers)
|
18
|
+
package_users << app.display_name
|
19
|
+
end
|
20
|
+
package_users
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def password_for(user)
|
25
|
+
@passwords_mutex.synchronize do
|
26
|
+
if @passwords[user].nil?
|
27
|
+
@passwords[user] = ask(prompt: "Password for #{user}", echo: false)
|
28
|
+
end
|
29
|
+
@passwords[user]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
%i(installable? deployable? controllable?).each do |method|
|
34
|
+
define_method(method) do
|
35
|
+
apps.values.any? { |app| app.send(__method__) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
%i(build destroy_project cleanup binstubs
|
40
|
+
show_current show_summary which whence
|
41
|
+
).each do |action|
|
42
|
+
define_method(action) do |args:, opts:|
|
43
|
+
apps.each_value do |app|
|
44
|
+
app.send(__method__, args: args, opts: opts) if app.installable?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
alias_method :destroy, :destroy_project
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def validate_parameters
|
54
|
+
super
|
55
|
+
validate_project_parameters
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_default_parameters
|
59
|
+
super
|
60
|
+
set_default :stage, self.class.name.split('::').first.snakecase
|
61
|
+
set_default :project, self.class.name.split('::').last.snakecase
|
62
|
+
set_default_project_parameters
|
63
|
+
@passwords = {}
|
64
|
+
@passwords_mutex = Mutex.new
|
65
|
+
end
|
66
|
+
|
67
|
+
def load_libraries
|
68
|
+
applications.each do |app|
|
69
|
+
require "#{work_dir}/apps/#{app}/lib/application"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def application_base_class(app)
|
74
|
+
Object.const_get("#{project}:#{app}".camelcase)
|
75
|
+
end
|
76
|
+
|
77
|
+
def setup_cli
|
78
|
+
setup_applications
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def setup_descriptions
|
83
|
+
desc "Manage apps in #{display_name}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def setup_applications
|
87
|
+
@apps = {}
|
88
|
+
applications.map(&:to_sym).each do |app|
|
89
|
+
@apps[app] = command(app, base: application_base_class(app))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
class Configuration
|
4
|
+
attr_reader :variables
|
5
|
+
attr_reader :servers
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@variables = {}
|
9
|
+
@servers = ServerSet.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def set(key, value)
|
13
|
+
@variables[key] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_default(key, value)
|
17
|
+
set(key, value) unless @variables.has_key?(key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def delete(key)
|
21
|
+
@variables[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def fetch(key, default = nil, &blk)
|
25
|
+
value = if block_given?
|
26
|
+
@variables.fetch(key, &blk)
|
27
|
+
else
|
28
|
+
@variables.fetch(key, default)
|
29
|
+
end
|
30
|
+
while callable_without_parameters?(value)
|
31
|
+
value = set(key, value.call)
|
32
|
+
end
|
33
|
+
return value
|
34
|
+
end
|
35
|
+
|
36
|
+
def keys
|
37
|
+
@variables.keys
|
38
|
+
end
|
39
|
+
|
40
|
+
def role(name, hosts, **properties)
|
41
|
+
if name == :all
|
42
|
+
raise ArgumentError, 'Reserved role name, :all, is NOT allowed to use.'
|
43
|
+
end
|
44
|
+
@servers.add_hosts_for_role(name, hosts, properties)
|
45
|
+
end
|
46
|
+
|
47
|
+
def server(name, **properties)
|
48
|
+
new_server = servers.add_host(name, properties)
|
49
|
+
if new_server
|
50
|
+
new_server.ssh_options = fetch(:ssh_options) || {}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def ask(key=nil, default:, prompt: nil, echo: true)
|
55
|
+
Question.new(default: default, prompt: prompt, echo: echo).call.tap do |answer|
|
56
|
+
set(key, answer) unless key.nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def callable_without_parameters?(x)
|
63
|
+
x.respond_to?(:call) && (!x.respond_to?(:arity) || x.arity == 0)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
class Configuration
|
4
|
+
def roles(*names)
|
5
|
+
opts = names.last.is_a?(::Hash) ? names.pop : {}
|
6
|
+
filter_servers(servers.find_by_roles(filter_roles(names), opts))
|
7
|
+
end
|
8
|
+
|
9
|
+
def release_roles(*names)
|
10
|
+
if names.last.is_a?(Hash)
|
11
|
+
names.last.merge(:exclude => :no_release)
|
12
|
+
else
|
13
|
+
names << { :exclude => :no_release }
|
14
|
+
end
|
15
|
+
roles(*names)
|
16
|
+
end
|
17
|
+
|
18
|
+
def primary(role)
|
19
|
+
servers.find_primary(role)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def filter_roles(_roles)
|
25
|
+
available_roles = (env_filter(:roles) | config_filter(:roles)).map(&:to_sym)
|
26
|
+
available_roles = servers.available_roles if available_roles.empty?
|
27
|
+
if _roles.include?(:all)
|
28
|
+
available_roles
|
29
|
+
else
|
30
|
+
_roles.select { |name| available_roles.include?(name) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def filter_servers(_servers)
|
35
|
+
filter_hosts = env_filter(:hosts) | config_filter(:hosts)
|
36
|
+
if filter_hosts.empty?
|
37
|
+
_servers
|
38
|
+
else
|
39
|
+
_servers.select { |server| filter_hosts.include?(server.hostname) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def env_filter(type)
|
44
|
+
type = type.to_s.upcase
|
45
|
+
ENV[type].nil? ? [] : ENV[type].split(',')
|
46
|
+
end
|
47
|
+
|
48
|
+
def config_filter(type)
|
49
|
+
filter = fetch(:filter) || fetch(:select)
|
50
|
+
filter.nil? ? [] : filter.fetch(type, [])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|