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,241 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class Binary < Luban::Deployment::Command
|
5
|
+
using Luban::CLI::CoreRefinements
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def inherited(subclass)
|
9
|
+
super
|
10
|
+
# Ensure package dependencies from base class
|
11
|
+
# got inherited to its subclasses
|
12
|
+
|
13
|
+
subclass.instance_variable_set(
|
14
|
+
'@dependencies',
|
15
|
+
Marshal.load(Marshal.dump(dependencies))
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def dependencies
|
20
|
+
@dependencies ||= DependencySet.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def apply_to(version, &blk)
|
24
|
+
dependencies.apply_to(version, &blk)
|
25
|
+
end
|
26
|
+
|
27
|
+
def required_packages_for(version)
|
28
|
+
dependencies.dependencies_for(version)
|
29
|
+
end
|
30
|
+
|
31
|
+
def package_class(package)
|
32
|
+
require_path = package_require_path(package)
|
33
|
+
require require_path
|
34
|
+
package_base_class(require_path)
|
35
|
+
rescue LoadError => e
|
36
|
+
abort "Aborted! Failed to load package #{require_path}: #{e.message}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def worker_class(worker, package: self)
|
40
|
+
if package.is_a?(Class)
|
41
|
+
if package == self
|
42
|
+
super(worker)
|
43
|
+
else
|
44
|
+
package.worker_class(worker)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
package_class(package).worker_class(worker)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def package_require_path(package_name)
|
54
|
+
package_require_root.join(package_name.to_s.gsub(':', '/'))
|
55
|
+
end
|
56
|
+
|
57
|
+
def package_require_root
|
58
|
+
@default_package_root ||= Pathname.new("luban/deployment/packages")
|
59
|
+
end
|
60
|
+
|
61
|
+
def package_base_class(path)
|
62
|
+
Object.const_get(path.to_s.camelcase, false)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
include Luban::Deployment::Parameters::Project
|
67
|
+
include Luban::Deployment::Parameters::Application
|
68
|
+
include Luban::Deployment::Command::Tasks::Install
|
69
|
+
|
70
|
+
attr_reader :current_version
|
71
|
+
|
72
|
+
def package_options; @package_options ||= {}; end
|
73
|
+
|
74
|
+
def update_package_options(version, **opts)
|
75
|
+
unless package_options.has_key?(version)
|
76
|
+
package_options[version] =
|
77
|
+
{ name: name.to_s }.merge!(decompose_version(version))
|
78
|
+
end
|
79
|
+
@current_version = version if opts[:current]
|
80
|
+
package_options[version].merge!(opts)
|
81
|
+
end
|
82
|
+
|
83
|
+
def has_version?(version)
|
84
|
+
package_options.has_key?(version)
|
85
|
+
end
|
86
|
+
|
87
|
+
def decompose_version(version)
|
88
|
+
{ major_version: version, patch_level: '' }
|
89
|
+
end
|
90
|
+
|
91
|
+
def versions; package_options.keys; end
|
92
|
+
|
93
|
+
%i(install uninstall cleanup_all update_binstubs
|
94
|
+
get_summary which_current whence_origin).each do |m|
|
95
|
+
define_task_method(m, worker: :installer)
|
96
|
+
end
|
97
|
+
|
98
|
+
def install_all(args:, opts:)
|
99
|
+
versions.each do |v|
|
100
|
+
install(args: args, opts: opts.merge(version: v))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def uninstall_all(args:, opts:)
|
105
|
+
versions.each do |v|
|
106
|
+
uninstall(args: args, opts: opts.merge(version: v))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
alias_method :uninstall!, :uninstall
|
111
|
+
def uninstall(args:, opts:)
|
112
|
+
servers = select_servers(opts[:roles], opts[:hosts])
|
113
|
+
apps = parent.other_package_users_for(name, opts[:version], servers: servers)
|
114
|
+
if apps.empty? or opts[:force]
|
115
|
+
uninstall!(args: args, opts: opts)
|
116
|
+
else
|
117
|
+
puts "Skipped. #{name}-#{opts[:version]} is being referenced by #{apps.join(', ')}. " +
|
118
|
+
"use -f to force uninstalling if necessary."
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def cleanup(args:, opts:)
|
123
|
+
versions.each do |v|
|
124
|
+
cleanup_all(args: args, opts: opts.merge(version: v))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def binstubs(args:, opts:)
|
129
|
+
if current_version
|
130
|
+
update_binstubs(args: args, opts: opts.merge(version: current_version))
|
131
|
+
else
|
132
|
+
versions.each do |v|
|
133
|
+
update_binstubs(args: args, opts: opts.merge(version: v))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def show_current(args:, opts:)
|
139
|
+
if current_version
|
140
|
+
print_summary(get_summary(args: args, opts: opts.merge(version: current_version)))
|
141
|
+
else
|
142
|
+
puts " Warning! No current version of #{display_name} is specified."
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def show_summary(args:, opts:)
|
147
|
+
versions.each do |v|
|
148
|
+
print_summary(get_summary(args: args, opts: opts.merge(version: v)))
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def which(args:, opts:)
|
153
|
+
if current_version
|
154
|
+
print_summary(which_current(args: args, opts: opts.merge(version: current_version)))
|
155
|
+
else
|
156
|
+
puts " Warning! No current version of #{display_name} is specified."
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def whence(args:, opts:)
|
161
|
+
versions.each do |v|
|
162
|
+
print_summary(whence_origin(args: args, opts: opts.merge(version: v)))
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
protected
|
167
|
+
|
168
|
+
def set_parameters
|
169
|
+
self.config = parent.config
|
170
|
+
end
|
171
|
+
|
172
|
+
def setup_tasks
|
173
|
+
super
|
174
|
+
setup_install_tasks
|
175
|
+
end
|
176
|
+
|
177
|
+
def compose_task_options(opts)
|
178
|
+
opts = super
|
179
|
+
version = opts[:version]
|
180
|
+
unless version.nil?
|
181
|
+
# Merge package options into task options without nil ones
|
182
|
+
opts = package_options[version].merge(opts.reject { |_, v| v.nil? })
|
183
|
+
end
|
184
|
+
opts
|
185
|
+
end
|
186
|
+
|
187
|
+
def setup_descriptions
|
188
|
+
desc "Manage package #{display_name}"
|
189
|
+
long_desc "Manage the deployment of package #{display_name} in #{parent.class.name}"
|
190
|
+
end
|
191
|
+
|
192
|
+
def setup_install_tasks
|
193
|
+
super
|
194
|
+
|
195
|
+
undef_task :build
|
196
|
+
undef_task :destroy
|
197
|
+
|
198
|
+
_package = self
|
199
|
+
task :install do
|
200
|
+
desc "Install a given version"
|
201
|
+
option :version, "Version to install", short: :v, required: true,
|
202
|
+
assure: ->(v){ _package.versions.include?(v) }
|
203
|
+
switch :force, "Force to install", short: :f
|
204
|
+
action! :install
|
205
|
+
end
|
206
|
+
|
207
|
+
task :install_all do
|
208
|
+
desc "Install all versions"
|
209
|
+
switch :force, "Force to install", short: :f
|
210
|
+
action! :install_all
|
211
|
+
end
|
212
|
+
|
213
|
+
task :uninstall do
|
214
|
+
desc "Uninstall a given version"
|
215
|
+
option :version, "Version to uninstall", short: :v, required: true,
|
216
|
+
assure: ->(v){ _package.versions.include?(v) }
|
217
|
+
switch :force, "Force to uninstall", short: :f
|
218
|
+
action! :uninstall
|
219
|
+
end
|
220
|
+
|
221
|
+
task :uninstall_all do
|
222
|
+
desc "Uninstall all versions"
|
223
|
+
switch :force, "Force to uninstall", short: :f, required: true
|
224
|
+
action! :uninstall_all
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def print_summary(result)
|
229
|
+
result.each do |entry|
|
230
|
+
s = entry[:summary]
|
231
|
+
puts " [#{entry[:hostname]}] #{s[:status]} #{s[:name]} #{s[:installed]}"
|
232
|
+
puts " [#{entry[:hostname]}] #{s[:executable]}" unless s[:executable].nil?
|
233
|
+
puts " [#{entry[:hostname]}] #{s[:alert]}" unless s[:alert].nil?
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
Base = Binary
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
DependencyTypes = %i(before_install after_install)
|
5
|
+
|
6
|
+
class Dependency
|
7
|
+
attr_reader :apply_to
|
8
|
+
attr_reader :type
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :version
|
11
|
+
attr_reader :options
|
12
|
+
|
13
|
+
def initialize(apply_to, type, name, version, **opts)
|
14
|
+
@apply_to = apply_to
|
15
|
+
@type = type
|
16
|
+
@name = name
|
17
|
+
@version = version
|
18
|
+
@options = opts
|
19
|
+
validate
|
20
|
+
end
|
21
|
+
|
22
|
+
def applicable_to?(version)
|
23
|
+
if @apply_to == :all
|
24
|
+
true
|
25
|
+
else
|
26
|
+
Gem::Requirement.new(@apply_to).satisfied_by?(Gem::Version.new(version))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def validate
|
33
|
+
if @apply_to.nil?
|
34
|
+
raise ArgumentError, 'The version requirement that the dependency applies to is NOT provided.'
|
35
|
+
end
|
36
|
+
unless DependencyTypes.include?(@type)
|
37
|
+
raise ArgumentError, "Invalid dependency type: #{type.inspect}"
|
38
|
+
end
|
39
|
+
if @name.nil?
|
40
|
+
raise ArgumentError, 'Dependency name is NOT provided.'
|
41
|
+
end
|
42
|
+
if @version.nil?
|
43
|
+
raise ArgumentError, 'Dependency version is NOT provided.'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class DependencySet
|
5
|
+
def initialize
|
6
|
+
@dependencies = {}
|
7
|
+
@ctx = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply_to(version_requirement, &blk)
|
11
|
+
@ctx = { version_requirement: version_requirement }
|
12
|
+
instance_eval(&blk) if block_given?
|
13
|
+
ensure
|
14
|
+
@ctx = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_install(&blk)
|
18
|
+
if @ctx[:version_requirement].nil?
|
19
|
+
raise RuntimeError, 'Please call #apply_to prior to #before_install.'
|
20
|
+
end
|
21
|
+
@ctx[:type] = :before_install
|
22
|
+
instance_eval(&blk) if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
def after_install(&blk)
|
26
|
+
if @ctx[:version_requirement].nil?
|
27
|
+
raise RuntimeError, 'Please call #apply_to prior to #after_install.'
|
28
|
+
end
|
29
|
+
@ctx[:type] = :after_install
|
30
|
+
instance_eval(&blk) if block_given?
|
31
|
+
end
|
32
|
+
|
33
|
+
def depend_on(name, version:, **opts)
|
34
|
+
if @ctx[:type].nil?
|
35
|
+
raise RuntimeError, 'Please call #before_install or #after_install prior to #depend_on.'
|
36
|
+
end
|
37
|
+
requirement = @ctx[:version_requirement]
|
38
|
+
type = @ctx[:type]
|
39
|
+
dependency = Dependency.new(requirement, type, name, version, **opts)
|
40
|
+
unless @dependencies.has_key?(requirement)
|
41
|
+
@dependencies[requirement] = { before_install: [],
|
42
|
+
after_install: [] }
|
43
|
+
end
|
44
|
+
@dependencies[requirement][type] << dependency
|
45
|
+
end
|
46
|
+
|
47
|
+
def dependencies_for(version, type: nil)
|
48
|
+
types = *type
|
49
|
+
types = DependencyTypes if types.empty?
|
50
|
+
deps = { before_install: [],
|
51
|
+
after_install: [] }
|
52
|
+
@dependencies.each_pair do |r, d|
|
53
|
+
types.each do |t|
|
54
|
+
next if d[t].empty?
|
55
|
+
deps[t] |= d[t] if d[t].first.applicable_to?(version)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
deps
|
59
|
+
end
|
60
|
+
|
61
|
+
def before_install_dependencies_for(version)
|
62
|
+
dependencies_for(version, type: :before_install)
|
63
|
+
end
|
64
|
+
|
65
|
+
def after_install_dependencies_for(version)
|
66
|
+
dependencies_for(version, type: :after_install)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Luban
|
2
|
+
module Deployment
|
3
|
+
module Package
|
4
|
+
class Installer < Worker
|
5
|
+
# Shared library file extension name based on OS
|
6
|
+
LibExtensions = {
|
7
|
+
Linux: 'so', # Linux
|
8
|
+
Darwin: 'dylib' # OSX
|
9
|
+
}
|
10
|
+
DefaultLibExtension = 'so'
|
11
|
+
|
12
|
+
attr_reader :configure_opts
|
13
|
+
attr_reader :build_env_vars
|
14
|
+
|
15
|
+
def currently_used_by
|
16
|
+
parent.currently_used_by
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_symlinked?
|
20
|
+
current_package_version == package_version
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_configured?; task.opts.current; end
|
24
|
+
alias_method :current?, :current_configured?
|
25
|
+
|
26
|
+
def current_package_version
|
27
|
+
if symlink?(current_path)
|
28
|
+
File.basename(readlink(current_path))
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def default_configure_opts
|
35
|
+
@default_configure_opts ||= []
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def init
|
41
|
+
super
|
42
|
+
configure_build_env_variables
|
43
|
+
configure_build_options
|
44
|
+
end
|
45
|
+
|
46
|
+
def configure_build_env_variables
|
47
|
+
@build_env_vars = {
|
48
|
+
ldflags: [ENV['LDFLAGS'].to_s],
|
49
|
+
cflags: [ENV['CFLAGS'].to_s],
|
50
|
+
cppflags: [ENV['CPPFLAGS'].to_s]
|
51
|
+
}
|
52
|
+
if child?
|
53
|
+
configure_parent_build_env_variables
|
54
|
+
configure_parent_build_options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def configure_parent_build_env_variables
|
59
|
+
parent.build_env_vars[:ldflags] << "-L#{lib_path}"
|
60
|
+
parent.build_env_vars[:cflags] << "-I#{include_path}"
|
61
|
+
parent.build_env_vars[:cppflags] << "-I#{include_path}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def configure_parent_build_options
|
65
|
+
if parent.respond_to?("with_#{package_name}_dir")
|
66
|
+
parent.send("with_#{package_name}_dir", install_path)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def compose_build_env_variables
|
71
|
+
build_env_vars.inject({}) do |vars, (k, v)|
|
72
|
+
vars[k] = "'#{v.join(' ').strip}'" unless v.all?(&:empty?)
|
73
|
+
vars
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def configure_build_options
|
78
|
+
@configure_opts = default_configure_opts | (task.opts.__remaining__ || [])
|
79
|
+
@configure_opts.unshift(install_prefix)
|
80
|
+
end
|
81
|
+
|
82
|
+
def compose_build_options
|
83
|
+
@configure_opts.reject(&:empty?).join(' ')
|
84
|
+
end
|
85
|
+
|
86
|
+
def install_prefix
|
87
|
+
"--prefix=#{install_path}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate; end
|
91
|
+
|
92
|
+
def lib_extension
|
93
|
+
@lib_extension ||= LibExtensions.fetch(os_name.to_sym, DefaultLibExtension)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|