buildizer 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -1
- data/{Packagefile.example.1 → Buildizer.example.1} +1 -1
- data/{Packagefile.example.2 → Buildizer.example.2} +0 -0
- data/{Packagefile.example.3 → Buildizer.example.3} +0 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +12 -4
- data/bin/buildizer +1 -941
- data/buildizer.gemspec +2 -2
- data/lib/buildizer/builder/base.rb +173 -0
- data/lib/buildizer/builder/fpm.rb +129 -0
- data/lib/buildizer/builder.rb +4 -0
- data/lib/buildizer/cli.rb +58 -0
- data/lib/buildizer/docker.rb +95 -0
- data/lib/buildizer/error.rb +4 -0
- data/lib/buildizer/image/base.rb +56 -0
- data/lib/buildizer/image/centos.rb +52 -0
- data/lib/buildizer/image/centos6.rb +9 -0
- data/lib/buildizer/image/centos7.rb +9 -0
- data/lib/buildizer/image/ubuntu.rb +39 -0
- data/lib/buildizer/image/ubuntu1204.rb +13 -0
- data/lib/buildizer/image/ubuntu1404.rb +13 -0
- data/lib/buildizer/image.rb +4 -0
- data/lib/buildizer/packager.rb +260 -0
- data/lib/buildizer/refine.rb +11 -0
- data/lib/buildizer/target/base.rb +39 -0
- data/lib/buildizer/target/fpm.rb +17 -0
- data/lib/buildizer/target.rb +4 -0
- data/lib/buildizer/version.rb +1 -1
- data/lib/buildizer.rb +26 -0
- metadata +49 -30
data/bin/buildizer
CHANGED
@@ -2,947 +2,7 @@
|
|
2
2
|
# vi: set ft=ruby :
|
3
3
|
# vi: set sts=2 ts=2 sw=2 :
|
4
4
|
|
5
|
-
require '
|
6
|
-
require 'yaml'
|
7
|
-
require 'net_status'
|
8
|
-
require 'pathname'
|
9
|
-
require 'mixlib/shellout'
|
10
|
-
require 'net_status'
|
11
|
-
require 'pry'
|
12
|
-
|
13
|
-
module Buildizer
|
14
|
-
module Refine
|
15
|
-
refine String do
|
16
|
-
def underscore
|
17
|
-
self.gsub(/(.)([A-Z])/,'\1_\2').downcase
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end # Refine
|
21
|
-
|
22
|
-
using Refine
|
23
|
-
|
24
|
-
module Concern
|
25
|
-
def self.included(base)
|
26
|
-
base.send(:extend, ClassMethods) if defined? ClassMethods
|
27
|
-
end
|
28
|
-
|
29
|
-
def command(*command_args, do_raise: nil)
|
30
|
-
p command_args
|
31
|
-
Mixlib::ShellOut.new(*command_args).tap do |cmd|
|
32
|
-
cmd.live_stdout = $stdout
|
33
|
-
cmd.run_command
|
34
|
-
if not cmd.status.success? and do_raise
|
35
|
-
raise Error.new(error: :error, message: [cmd.stdout, cmd.stderr].join("\n"))
|
36
|
-
end
|
37
|
-
cmd
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def command!(*command_args)
|
42
|
-
command(*command_args, do_raise: true)
|
43
|
-
end
|
44
|
-
end # Concern
|
45
|
-
|
46
|
-
class Error < NetStatus::Exception
|
47
|
-
end # Error
|
48
|
-
|
49
|
-
module Target
|
50
|
-
class Base
|
51
|
-
attr_reader :builder
|
52
|
-
attr_reader :image
|
53
|
-
|
54
|
-
attr_reader :name
|
55
|
-
attr_reader :package_name
|
56
|
-
attr_reader :package_version
|
57
|
-
attr_reader :package_cloud
|
58
|
-
attr_reader :prepare
|
59
|
-
attr_reader :build_dep
|
60
|
-
attr_reader :before_build
|
61
|
-
|
62
|
-
def initialize(builder, image,
|
63
|
-
name:, package_name:, package_version:, package_cloud:,
|
64
|
-
prepare: [], build_dep: [], before_build: [])
|
65
|
-
@builder = builder
|
66
|
-
@image = image
|
67
|
-
|
68
|
-
@name = name
|
69
|
-
@package_name = package_name
|
70
|
-
@package_version = package_version
|
71
|
-
@package_cloud = package_cloud
|
72
|
-
@prepare = prepare
|
73
|
-
@build_dep = build_dep
|
74
|
-
@before_build = before_build
|
75
|
-
end
|
76
|
-
|
77
|
-
def docker_image
|
78
|
-
"#{builder.packager.docker_image || "buildizer/#{package_name}"}:#{name}"
|
79
|
-
end
|
80
|
-
|
81
|
-
def package_cloud_path
|
82
|
-
"#{package_cloud}/#{image.os_package_cloud_name}/#{image.os_package_cloud_version}"
|
83
|
-
end
|
84
|
-
end # Base
|
85
|
-
|
86
|
-
class Fpm < Base
|
87
|
-
attr_reader :fpm_script
|
88
|
-
attr_reader :fpm_config_files
|
89
|
-
attr_reader :fpm_files
|
90
|
-
|
91
|
-
def initialize(builder, image, fpm_script: [], fpm_config_files: {}, fpm_files: {}, **kwargs)
|
92
|
-
super(builder, image, **kwargs)
|
93
|
-
|
94
|
-
@fpm_script = fpm_script
|
95
|
-
@fpm_config_files = fpm_config_files
|
96
|
-
@fpm_files = fpm_files
|
97
|
-
end
|
98
|
-
end # Fpm
|
99
|
-
end # Target
|
100
|
-
|
101
|
-
module Image
|
102
|
-
class Base
|
103
|
-
include Concern
|
104
|
-
|
105
|
-
attr_reader :instructions
|
106
|
-
attr_reader :docker
|
107
|
-
|
108
|
-
attr_accessor :target
|
109
|
-
|
110
|
-
def initialize(docker, **kwargs)
|
111
|
-
@instructions = []
|
112
|
-
@docker = docker
|
113
|
-
|
114
|
-
instruction :FROM, base_image
|
115
|
-
end
|
116
|
-
|
117
|
-
def os_name
|
118
|
-
raise
|
119
|
-
end
|
120
|
-
|
121
|
-
def os_package_cloud_name
|
122
|
-
os_name
|
123
|
-
end
|
124
|
-
|
125
|
-
def os_package_cloud_version
|
126
|
-
os_version
|
127
|
-
end
|
128
|
-
|
129
|
-
def os_version
|
130
|
-
raise
|
131
|
-
end
|
132
|
-
|
133
|
-
def fpm_output_type
|
134
|
-
raise
|
135
|
-
end
|
136
|
-
|
137
|
-
def fpm_extra_params
|
138
|
-
end
|
139
|
-
|
140
|
-
def build_dep(build_dep)
|
141
|
-
raise
|
142
|
-
end
|
143
|
-
|
144
|
-
def base_image
|
145
|
-
"buildizer/#{os_name}:#{os_version}"
|
146
|
-
end
|
147
|
-
|
148
|
-
def name
|
149
|
-
target.docker_image
|
150
|
-
end
|
151
|
-
|
152
|
-
def instruction(instruction, cmd)
|
153
|
-
instructions << [instruction.to_s.upcase, cmd].join(' ')
|
154
|
-
end
|
155
|
-
end # Base
|
156
|
-
|
157
|
-
class Ubuntu < Base
|
158
|
-
attr_reader :os_version
|
159
|
-
|
160
|
-
def initialize(docker, os_version, **kwargs)
|
161
|
-
@os_version = os_version
|
162
|
-
super(docker, **kwargs)
|
163
|
-
end
|
164
|
-
|
165
|
-
def os_name
|
166
|
-
'ubuntu'
|
167
|
-
end
|
168
|
-
|
169
|
-
def os_codename
|
170
|
-
raise
|
171
|
-
end
|
172
|
-
|
173
|
-
def os_package_cloud_version
|
174
|
-
os_codename
|
175
|
-
end
|
176
|
-
|
177
|
-
def fpm_output_type
|
178
|
-
'deb'
|
179
|
-
end
|
180
|
-
|
181
|
-
def fpm_extra_params
|
182
|
-
Array(super).tap do |res|
|
183
|
-
res << '--deb-use-file-permissions'
|
184
|
-
res << '--deb-no-default-config-files'
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def build_dep(build_dep)
|
189
|
-
instruction :RUN, "apt-get build-dep -y #{build_dep.to_a.join(' ')}" if build_dep.any?
|
190
|
-
end
|
191
|
-
end # Ubuntu
|
192
|
-
|
193
|
-
class Ubuntu1204 < Ubuntu
|
194
|
-
def initialize(docker, **kwargs)
|
195
|
-
super(docker, '12.04', **kwargs)
|
196
|
-
end
|
197
|
-
|
198
|
-
def os_codename
|
199
|
-
'precise'
|
200
|
-
end
|
201
|
-
end # Ubuntu1204
|
202
|
-
|
203
|
-
class Ubuntu1404 < Ubuntu
|
204
|
-
def initialize(docker, **kwargs)
|
205
|
-
super(docker, '14.04', **kwargs)
|
206
|
-
end
|
207
|
-
|
208
|
-
def os_codename
|
209
|
-
'trusty'
|
210
|
-
end
|
211
|
-
end # Ubuntu1404
|
212
|
-
|
213
|
-
class Centos < Base
|
214
|
-
attr_reader :os_version
|
215
|
-
|
216
|
-
def initialize(docker, os_version, **kwargs)
|
217
|
-
@os_version = os_version
|
218
|
-
super(docker, **kwargs)
|
219
|
-
end
|
220
|
-
|
221
|
-
def os_name
|
222
|
-
'centos'
|
223
|
-
end
|
224
|
-
|
225
|
-
def os_package_cloud_name
|
226
|
-
'el'
|
227
|
-
end
|
228
|
-
|
229
|
-
def os_package_cloud_version
|
230
|
-
os_version.match(/\d+$/).to_s.to_i
|
231
|
-
end
|
232
|
-
|
233
|
-
def fpm_output_type
|
234
|
-
'rpm'
|
235
|
-
end
|
236
|
-
|
237
|
-
def fpm_extra_params
|
238
|
-
Array(super).tap do |res|
|
239
|
-
res << '--rpm-use-file-permissions'
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
def build_dep(build_dep)
|
244
|
-
instruction :RUN, "yum-builddep -y #{build_dep.to_a.join(' ')}" if build_dep.any?
|
245
|
-
end
|
246
|
-
|
247
|
-
def add_repo(id:, name:, baseurl: nil, enabled: 1, gpgcheck: nil, gpgkey: nil, exclude: nil, includepkgs: nil, mirrorlist: nil)
|
248
|
-
repo = "[#{id}]\
|
249
|
-
\\nname=#{name}\
|
250
|
-
\\nenabled=#{enabled}\
|
251
|
-
#{baseurl ? "\\nbaseurl=#{baseurl}" : nil}\
|
252
|
-
#{mirrorlist ? "\\nmirrorlist=#{mirrorlist}" : nil}\
|
253
|
-
#{gpgcheck ? "\\ngpgcheck=#{gpgcheck}" : nil}\
|
254
|
-
#{gpgkey ? "\\ngpgkey=#{gpgkey}" : nil}\
|
255
|
-
#{exclude ? "\\nexclude=#{exclude}" : nil}\
|
256
|
-
#{includepkgs ? "\\nincludepkgs=#{includepkgs}" : nil}"
|
257
|
-
|
258
|
-
instruction :RUN, "bash -lec \"echo -e '#{repo}' >> /etc/yum.repos.d/CentOS-Extra-Buildizer.repo\""
|
259
|
-
end
|
260
|
-
end # Centos
|
261
|
-
|
262
|
-
class Centos6 < Centos
|
263
|
-
def initialize(docker, **kwargs)
|
264
|
-
super(docker, 'centos6', **kwargs)
|
265
|
-
end
|
266
|
-
end # Centos6
|
267
|
-
|
268
|
-
class Centos7 < Centos
|
269
|
-
def initialize(docker, **kwargs)
|
270
|
-
super(docker, 'centos7', **kwargs)
|
271
|
-
end
|
272
|
-
end # Centos7
|
273
|
-
end # Image
|
274
|
-
|
275
|
-
class Docker
|
276
|
-
include Concern
|
277
|
-
|
278
|
-
attr_reader :builder
|
279
|
-
attr_reader :username
|
280
|
-
attr_reader :password
|
281
|
-
attr_reader :email
|
282
|
-
attr_reader :server
|
283
|
-
|
284
|
-
def initialize(builder, username:, password:, email:, server: nil)
|
285
|
-
@builder = builder
|
286
|
-
@username = username
|
287
|
-
@password = password
|
288
|
-
@email = email
|
289
|
-
@server = server
|
290
|
-
end
|
291
|
-
|
292
|
-
def image_klass(os_name, os_version)
|
293
|
-
({
|
294
|
-
'ubuntu' => {
|
295
|
-
'12.04' => Image::Ubuntu1204,
|
296
|
-
'14.04' => Image::Ubuntu1404,
|
297
|
-
nil => Image::Ubuntu1404,
|
298
|
-
},
|
299
|
-
'centos' => {
|
300
|
-
'centos6' => Image::Centos6,
|
301
|
-
'centos7' => Image::Centos7,
|
302
|
-
nil => Image::Centos7,
|
303
|
-
},
|
304
|
-
}[os_name] || {})[os_version]
|
305
|
-
end
|
306
|
-
|
307
|
-
def new_image(os_name, os_version, **kwargs)
|
308
|
-
klass = image_klass(os_name, os_version)
|
309
|
-
raise Error, message: "unknown os '#{[os_name, os_version].compact.join('-')}'" unless klass
|
310
|
-
klass.new(self, **kwargs)
|
311
|
-
end
|
312
|
-
|
313
|
-
def login!
|
314
|
-
docker_login = ["docker login --email=#{email} --username=#{username} --password=#{password}"]
|
315
|
-
docker_login << "--server=#{server}" if server
|
316
|
-
command! docker_login.join(' ')
|
317
|
-
end
|
318
|
-
|
319
|
-
def logout!
|
320
|
-
command! 'docker logout'
|
321
|
-
end
|
322
|
-
|
323
|
-
def pull_image!(image)
|
324
|
-
command "docker pull #{image.base_image}"
|
325
|
-
command "docker pull #{image.name}"
|
326
|
-
end
|
327
|
-
|
328
|
-
def push_image!(image)
|
329
|
-
command! "docker push #{image.name}"
|
330
|
-
end
|
331
|
-
|
332
|
-
def build_image!(image)
|
333
|
-
pull_image! image
|
334
|
-
|
335
|
-
image_build_path(image).join('Dockerfile').write [*image.instructions, nil].join("\n")
|
336
|
-
command! "docker build -t #{image.name} #{image_build_path(image)}"
|
337
|
-
|
338
|
-
push_image! image
|
339
|
-
end
|
340
|
-
|
341
|
-
def image_build_path(image)
|
342
|
-
builder.build_path.join(image.os_name).join(image.os_version)
|
343
|
-
end
|
344
|
-
|
345
|
-
def image_runtime_build_path(image)
|
346
|
-
image_build_path(image).join('build')
|
347
|
-
end
|
348
|
-
|
349
|
-
def container_package_path
|
350
|
-
Pathname.new('/package')
|
351
|
-
end
|
352
|
-
|
353
|
-
def container_build_path
|
354
|
-
container_package_path.join('build')
|
355
|
-
end
|
356
|
-
|
357
|
-
def run!(image, cmd:, env: {})
|
358
|
-
cmd = Array(cmd)
|
359
|
-
|
360
|
-
command! p [
|
361
|
-
"docker run --rm",
|
362
|
-
*env.map {|k,v| "-e #{k}=#{v}"},
|
363
|
-
"-v #{builder.packager.package_path}:#{container_package_path}",
|
364
|
-
"-v #{image_runtime_build_path(image)}:#{container_build_path}",
|
365
|
-
image.name,
|
366
|
-
"'#{cmd.join('; ')}'"
|
367
|
-
].join(' ')
|
368
|
-
end
|
369
|
-
end # Docker
|
370
|
-
|
371
|
-
module Builder
|
372
|
-
class Base
|
373
|
-
include Concern
|
374
|
-
|
375
|
-
attr_reader :packager
|
376
|
-
attr_reader :build_path
|
377
|
-
attr_reader :docker
|
378
|
-
|
379
|
-
def initialize(packager)
|
380
|
-
@packager = packager
|
381
|
-
|
382
|
-
@build_path = Pathname.new(ENV['PREFIX'] || packager.package_path.join('build')).expand_path
|
383
|
-
raise Error, message: "bad build prefix: '#{build_path}' is a file" if build_path.file?
|
384
|
-
build_path.mkdir rescue nil
|
385
|
-
|
386
|
-
@docker = Docker.new(self,
|
387
|
-
username: packager.docker_username,
|
388
|
-
password: packager.docker_password,
|
389
|
-
email: packager.docker_email,
|
390
|
-
server: packager.docker_server,
|
391
|
-
)
|
392
|
-
end
|
393
|
-
|
394
|
-
def build_type
|
395
|
-
raise
|
396
|
-
end
|
397
|
-
|
398
|
-
def target_klass
|
399
|
-
raise
|
400
|
-
end
|
401
|
-
|
402
|
-
def prepare_image_instructions(target)
|
403
|
-
end
|
404
|
-
|
405
|
-
def build_instructions(target)
|
406
|
-
end
|
407
|
-
|
408
|
-
def build_dep
|
409
|
-
end
|
410
|
-
|
411
|
-
def new_target(target_name)
|
412
|
-
os_name, os_version, target_package_name, target_package_version = target_name.split('-', 4)
|
413
|
-
|
414
|
-
image = docker.new_image(os_name, os_version)
|
415
|
-
|
416
|
-
params = merge_os_params(image.os_name)
|
417
|
-
params = merge_os_version_params(image.os_name, image.os_version, into: params)
|
418
|
-
params = merge_base_target_params(target_name, target_package_name, target_package_version,
|
419
|
-
into: params) if target_package_name
|
420
|
-
check_params! params
|
421
|
-
|
422
|
-
target_klass.new(self, image, name: target_name, **params).tap do |target|
|
423
|
-
image.target = target
|
424
|
-
end
|
425
|
-
end
|
426
|
-
|
427
|
-
def targets
|
428
|
-
@targets ||= packager.targets.map {|target_name| new_target(target_name)}
|
429
|
-
end
|
430
|
-
|
431
|
-
def initial_target_params
|
432
|
-
{}.tap do |params|
|
433
|
-
params[:package_name] = packager.package_name
|
434
|
-
params[:package_version] = packager.package_version
|
435
|
-
params[:package_cloud] = packager.package_cloud
|
436
|
-
params[:prepare] = packager.prepare
|
437
|
-
params[:build_dep] = packager.build_dep
|
438
|
-
params[:before_build] = packager.before_build
|
439
|
-
end
|
440
|
-
end
|
441
|
-
|
442
|
-
def merge_params(into: nil, params:, &blk)
|
443
|
-
into ||= initial_target_params
|
444
|
-
params ||= {}
|
445
|
-
yield into, params if block_given?
|
446
|
-
do_merge_params into, params
|
447
|
-
end
|
448
|
-
|
449
|
-
def do_merge_params(into, params)
|
450
|
-
{}.tap do |res|
|
451
|
-
res[:package_name] = into[:package_name] || params['package_name']
|
452
|
-
res[:package_version] = into[:package_version] || params['package_version']
|
453
|
-
res[:package_cloud] = into[:package_cloud]
|
454
|
-
res[:prepare] = into[:prepare] + Array(params['prepare'])
|
455
|
-
res[:build_dep] = into[:build_dep] | Array(params['build_dep']).to_set
|
456
|
-
res[:before_build] = into[:before_build] + Array(params['before_build'])
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
def merge_os_params(os_name, into: nil, &blk)
|
461
|
-
merge_params(into: into, params: packager.os_params(os_name), &blk)
|
462
|
-
end
|
463
|
-
|
464
|
-
def merge_os_version_params(os_name, os_version, into: nil, &blk)
|
465
|
-
merge_params(into: into,
|
466
|
-
params: packager.os_params([os_name, os_version].join('-')), &blk)
|
467
|
-
end
|
468
|
-
|
469
|
-
def merge_base_target_params(target, target_package_name, target_package_version,
|
470
|
-
into: nil, &blk)
|
471
|
-
merge_params(into: into,
|
472
|
-
params: {'package_name' => target_package_name,
|
473
|
-
'package_version' => target_package_version}, &blk)
|
474
|
-
end
|
475
|
-
|
476
|
-
def check_params!(params)
|
477
|
-
[:package_name, :package_version, :package_cloud].each do |param|
|
478
|
-
raise(Error,
|
479
|
-
error: :input_error,
|
480
|
-
message: "#{param} is not defined") unless params[param] and not params[param].empty?
|
481
|
-
end
|
482
|
-
end
|
483
|
-
|
484
|
-
def prepare
|
485
|
-
return unless packager.enabled?
|
486
|
-
|
487
|
-
docker.login!
|
488
|
-
|
489
|
-
begin
|
490
|
-
packager.before_prepare.each {|cmd| command! cmd}
|
491
|
-
targets.each {|target| prepare_target_image(target)}
|
492
|
-
packager.after_prepare.each {|cmd| command! cmd}
|
493
|
-
ensure
|
494
|
-
docker.logout!
|
495
|
-
end
|
496
|
-
end
|
497
|
-
|
498
|
-
def prepare_target_image(target)
|
499
|
-
docker.image_build_path(target.image).mkpath
|
500
|
-
|
501
|
-
(Array(prepare_image_instructions(target)) + target.prepare).each do |cmd|
|
502
|
-
target.image.instruction(:RUN, "bash -lec \"#{cmd}\"")
|
503
|
-
end
|
504
|
-
target.image.build_dep(Array(build_dep).to_set + target.build_dep)
|
505
|
-
docker.build_image! target.image
|
506
|
-
end
|
507
|
-
|
508
|
-
def build
|
509
|
-
return unless packager.enabled?
|
510
|
-
targets.each {|target| build_target(target)}
|
511
|
-
end
|
512
|
-
|
513
|
-
def build_target(target)
|
514
|
-
docker.image_runtime_build_path(target.image).mkpath
|
515
|
-
|
516
|
-
cmd = [
|
517
|
-
"cd /package",
|
518
|
-
*target.before_build,
|
519
|
-
*Array(build_instructions(target)),
|
520
|
-
]
|
521
|
-
|
522
|
-
docker.run! target.image, cmd: cmd
|
523
|
-
end
|
524
|
-
|
525
|
-
def deploy
|
526
|
-
return unless packager.enabled?
|
527
|
-
targets.each {|target| deploy_target(target)}
|
528
|
-
end
|
529
|
-
|
530
|
-
def deploy_target(target)
|
531
|
-
cmd = Dir[docker.image_runtime_build_path(target.image)
|
532
|
-
.join("*.#{target.image.fpm_output_type}")]
|
533
|
-
.map {|p| Pathname.new(p)}
|
534
|
-
.map {|p| ["package_cloud yank #{target.package_cloud_path} #{p.basename}",
|
535
|
-
"package_cloud push #{target.package_cloud_path} #{p}"]}
|
536
|
-
.each {|yank, push|
|
537
|
-
command yank
|
538
|
-
command! push
|
539
|
-
}
|
540
|
-
end
|
541
|
-
end # Base
|
542
|
-
|
543
|
-
class Fpm < Base
|
544
|
-
FPM_SCRIPT_EVENTS = [:before, :after].map {|at|
|
545
|
-
[:install, :upgrade, :remove].map {|event|
|
546
|
-
"#{at}_#{event}"}}.flatten
|
547
|
-
|
548
|
-
def build_type
|
549
|
-
'fpm'
|
550
|
-
end
|
551
|
-
|
552
|
-
def target_klass
|
553
|
-
Target::Fpm
|
554
|
-
end
|
555
|
-
|
556
|
-
def initial_target_params
|
557
|
-
super.tap do |params|
|
558
|
-
raise(Error,
|
559
|
-
error: :input_error,
|
560
|
-
message: [
|
561
|
-
"explicit definition of package_version in #{build_type} ",
|
562
|
-
"build type is forbidden ",
|
563
|
-
"(use TRAVIS_TAG, CI_BUILD_TAG env variables)",
|
564
|
-
].join) if params[:package_version]
|
565
|
-
params[:package_version] = ENV['TRAVIS_TAG'] || ENV['CI_BUILD_TAG']
|
566
|
-
params[:fpm_script] = Array(packager.packagefile['fpm_script'])
|
567
|
-
params[:fpm_config_files] = packager.packagefile['fpm_config_files'].to_h
|
568
|
-
params[:fpm_files] = packager.packagefile['fpm_files'].to_h
|
569
|
-
end
|
570
|
-
end
|
571
|
-
|
572
|
-
def cannot_redefine_package_params!(params, redefine_for: nil)
|
573
|
-
[:package_name, :package_version].each do |param|
|
574
|
-
raise(Error,
|
575
|
-
error: :input_error,
|
576
|
-
message: [
|
577
|
-
"cannot redefine #{param}",
|
578
|
-
redefine_for ? "for #{redefine_for}" : nil,
|
579
|
-
"in #{build_type} build_type",
|
580
|
-
].compact.join(' ')
|
581
|
-
) if params.key? param.to_s
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
def do_merge_params(into, params)
|
586
|
-
super.tap do |res|
|
587
|
-
res[:fpm_script] = into[:fpm_script] + Array(params['fpm_script'])
|
588
|
-
res[:fpm_config_files] = into[:fpm_config_files].merge params['fpm_config_files'].to_h
|
589
|
-
res[:fpm_files] = into[:fpm_files].merge params['fpm_files'].to_h
|
590
|
-
end
|
591
|
-
end
|
592
|
-
|
593
|
-
def merge_os_params(os_name, **kwargs, &blk)
|
594
|
-
super(os_name, **kwargs) do |into, params|
|
595
|
-
yield into, params if block_given?
|
596
|
-
cannot_redefine_package_params!(params, redefine_for: "os '#{os_name}'")
|
597
|
-
end
|
598
|
-
end
|
599
|
-
|
600
|
-
def merge_os_version_params(os_name, os_version, **kwargs, &blk)
|
601
|
-
super(os_name, os_version, **kwargs) do |into, params|
|
602
|
-
yield into, params if block_given?
|
603
|
-
cannot_redefine_package_params!(params,
|
604
|
-
redefine_for: "os version '#{os_name}-#{os_version}'")
|
605
|
-
end
|
606
|
-
end
|
607
|
-
|
608
|
-
def merge_base_target_params(target, target_package_name, target_package_version, **kwargs, &blk)
|
609
|
-
super(target, target_package_name, target_package_version, **kwargs) do |into, params|
|
610
|
-
yield into, params if block_given?
|
611
|
-
cannot_redefine_package_params!(params, redefine_for: "target '#{target}'")
|
612
|
-
end
|
613
|
-
end
|
614
|
-
|
615
|
-
def check_params!(params)
|
616
|
-
super
|
617
|
-
if [:fpm_files, :fpm_config_files].all? {|param| params[param].empty?}
|
618
|
-
raise Error, error: :input_error,
|
619
|
-
message: ["either of fpm_files or fpm_config_files ",
|
620
|
-
"required in #{build_type} build_type"].join
|
621
|
-
end
|
622
|
-
end
|
623
|
-
|
624
|
-
def build_instructions(target)
|
625
|
-
fpm_script = target.fpm_script.reduce({}) do |res, spec|
|
626
|
-
conditions = Array(spec['when'])
|
627
|
-
raise Error, message: ["no when conditions given ",
|
628
|
-
"for fpm_script of target ",
|
629
|
-
"'#{target.name}'"].join unless conditions.any?
|
630
|
-
|
631
|
-
cmd = Array(spec['do'])
|
632
|
-
next res unless cmd.any?
|
633
|
-
conditions.each do |_when|
|
634
|
-
raise(
|
635
|
-
Error,
|
636
|
-
message: "unknown fpm_script event #{_when.inspect}"
|
637
|
-
) unless FPM_SCRIPT_EVENTS.include? _when
|
638
|
-
res[_when] ||= {fpm_option: "--#{_when.split('_').join('-')}",
|
639
|
-
file: docker.image_runtime_build_path(target.image)
|
640
|
-
.join("fpm_#{_when}.sh"),
|
641
|
-
container_file: Pathname.new('/package/build').join("fpm_#{_when}.sh"),
|
642
|
-
cmd: []}
|
643
|
-
res[_when][:cmd] += cmd
|
644
|
-
end
|
645
|
-
res
|
646
|
-
end
|
647
|
-
|
648
|
-
fpm_script.values.map do |desc|
|
649
|
-
desc[:file].write ["#!/bin/bash", *desc[:cmd], nil].join("\n")
|
650
|
-
desc[:file].chmod 0755
|
651
|
-
end
|
652
|
-
|
653
|
-
version, release = target.package_version.split('-')
|
654
|
-
|
655
|
-
["fpm -s dir",
|
656
|
-
"--force",
|
657
|
-
"-p #{docker.container_build_path}",
|
658
|
-
"-t #{target.image.fpm_output_type}",
|
659
|
-
"-n #{target.package_name}",
|
660
|
-
"--version=#{version}",
|
661
|
-
"--iteration=#{release}",
|
662
|
-
*fpm_script.values.map {|desc| "#{desc[:fpm_option]}=#{desc[:container_file]}"},
|
663
|
-
*Array(target.image.fpm_extra_params),
|
664
|
-
*target.fpm_config_files.values.map {|p| "--config-files=#{p}"},
|
665
|
-
*target.fpm_files.merge(target.fpm_config_files).map {|p1, p2| "#{p1}=#{p2}"}].join(' ')
|
666
|
-
end
|
667
|
-
end # Fpm
|
668
|
-
end # Builder
|
669
|
-
|
670
|
-
class Packager
|
671
|
-
attr_reader :package_path
|
672
|
-
attr_reader :packagefile_path
|
673
|
-
attr_reader :options_path
|
674
|
-
attr_reader :travis_path
|
675
|
-
|
676
|
-
def initialize(options: {})
|
677
|
-
@package_path = Pathname.new(ENV['BUILDIZER_PATH'] || '.').expand_path
|
678
|
-
@packagefile_path = package_path.join('Packagefile')
|
679
|
-
@options_path = package_path.join('.buildizer.yml')
|
680
|
-
@travis_path = package_path.join('.travis.yml')
|
681
|
-
@_options = options
|
682
|
-
end
|
683
|
-
|
684
|
-
def initialized?
|
685
|
-
options_path.exist?
|
686
|
-
end
|
687
|
-
|
688
|
-
def enabled?
|
689
|
-
not (ENV['TRAVIS_TAG'] || ENV['CI_BUILD_TAG']).empty?
|
690
|
-
end
|
691
|
-
|
692
|
-
def init!
|
693
|
-
raise Error, error: :logical_error, message: "already initialized" if initialized?
|
694
|
-
|
695
|
-
git_precommit_init!
|
696
|
-
options_setup!
|
697
|
-
travis_setup!
|
698
|
-
end
|
699
|
-
|
700
|
-
def deinit!
|
701
|
-
raise Error, error: :logical_error, message: "not initialized" unless initialized?
|
702
|
-
options_path.delete
|
703
|
-
git_precommit_deinit!
|
704
|
-
end
|
705
|
-
|
706
|
-
def update!
|
707
|
-
travis_setup!
|
708
|
-
end
|
709
|
-
|
710
|
-
def prepare!
|
711
|
-
builder.prepare
|
712
|
-
end
|
713
|
-
|
714
|
-
def build!
|
715
|
-
builder.build
|
716
|
-
end
|
717
|
-
|
718
|
-
def deploy!
|
719
|
-
builder.deploy
|
720
|
-
end
|
721
|
-
|
722
|
-
def packagefile
|
723
|
-
@packagefile ||= YAML.load(packagefile_path.read)
|
724
|
-
end
|
725
|
-
|
726
|
-
def options
|
727
|
-
@options ||= (YAML.load(options_path.read) rescue {}).merge(@_options)
|
728
|
-
end
|
729
|
-
|
730
|
-
def options_setup!
|
731
|
-
options_path.write YAML.dump(options)
|
732
|
-
@options = nil
|
733
|
-
end
|
734
|
-
|
735
|
-
def travis
|
736
|
-
@travis ||= (travis_path.exist? ? YAML.load(travis_path.read) : {})
|
737
|
-
rescue Psych::Exception => err
|
738
|
-
raise Error, error: :input_error, message: "bad travis config file #{file}: #{err.message}"
|
739
|
-
end
|
740
|
-
|
741
|
-
def travis_setup!
|
742
|
-
install = [
|
743
|
-
'sudo apt-get update',
|
744
|
-
'sudo apt-get install -y apt-transport-https ca-certificates',
|
745
|
-
'sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D',
|
746
|
-
'echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo tee /etc/apt/sources.list.d/docker.list',
|
747
|
-
'sudo apt-get update',
|
748
|
-
'sudo apt-get -o dpkg::options::="--force-confnew" install -y docker-engine=1.9.1-0~trusty', # FIXME [https://github.com/docker/docker/issues/20316]
|
749
|
-
'echo "docker-engine hold" | sudo dpkg --set-selections',
|
750
|
-
]
|
751
|
-
install.push(*Array(buildizer_install_instructions(latest: options['latest'])))
|
752
|
-
|
753
|
-
env = targets.map {|t| "BUILDIZER_TARGET=#{t}"}
|
754
|
-
|
755
|
-
travis_path.write YAML.dump(travis.merge(
|
756
|
-
'dist' => 'trusty',
|
757
|
-
'sudo' => 'required',
|
758
|
-
'cache' => 'apt',
|
759
|
-
'language' => 'ruby',
|
760
|
-
'rvm' => '2.2.1',
|
761
|
-
'install' => install,
|
762
|
-
'before_script' => 'buildizer prepare',
|
763
|
-
'script' => 'buildizer build',
|
764
|
-
'env' => env,
|
765
|
-
'after_success' => 'buildizer deploy',
|
766
|
-
))
|
767
|
-
@travis = nil
|
768
|
-
end
|
769
|
-
|
770
|
-
def git_hooks_path
|
771
|
-
package_path.join('.git').join('hooks')
|
772
|
-
end
|
773
|
-
|
774
|
-
def git_old_hooks_path
|
775
|
-
git_hooks_path.join('old-hooks')
|
776
|
-
end
|
777
|
-
|
778
|
-
def git_precommit_path
|
779
|
-
git_hooks_path.join('pre-commit')
|
780
|
-
end
|
781
|
-
|
782
|
-
def git_old_precommit_path
|
783
|
-
git_old_hooks_path.join('pre-commit')
|
784
|
-
end
|
785
|
-
|
786
|
-
def git_precommit_init!
|
787
|
-
if git_precommit_path.exist?
|
788
|
-
raise(Error,
|
789
|
-
error: :logical_error,
|
790
|
-
message: [
|
791
|
-
"unable to backup existing precommit script: ",
|
792
|
-
"file already exists: #{git_old_precommit_path}",
|
793
|
-
].join) if git_old_precommit_path.exist?
|
794
|
-
git_old_hooks_path.mkpath
|
795
|
-
FileUtils.cp git_precommit_path, git_old_precommit_path
|
796
|
-
end
|
797
|
-
|
798
|
-
git_precommit_path.write <<-EOF
|
799
|
-
#!/bin/bash
|
800
|
-
buildizer update
|
801
|
-
git add -v .travis.yml
|
802
|
-
EOF
|
803
|
-
git_precommit_path.chmod 0755
|
804
|
-
end
|
805
|
-
|
806
|
-
def git_precommit_deinit!
|
807
|
-
git_precommit_path.delete if git_precommit_path.exist?
|
808
|
-
FileUtils.cp git_old_precommit_path, git_precommit_path if git_old_precommit_path.exist?
|
809
|
-
git_old_hooks_path.rmtree if git_old_hooks_path.exist?
|
810
|
-
end
|
811
|
-
|
812
|
-
def package_name
|
813
|
-
packagefile['package_name']
|
814
|
-
end
|
815
|
-
|
816
|
-
def package_version
|
817
|
-
packagefile['package_version']
|
818
|
-
end
|
819
|
-
|
820
|
-
def os_params(os)
|
821
|
-
packagefile['os'].to_h[os.to_s].to_h
|
822
|
-
end
|
823
|
-
|
824
|
-
def before_prepare
|
825
|
-
Array(packagefile['before_prepare'])
|
826
|
-
end
|
827
|
-
|
828
|
-
def after_prepare
|
829
|
-
Array(packagefile['after_prepare'])
|
830
|
-
end
|
831
|
-
|
832
|
-
def targets
|
833
|
-
targets = Array(packagefile['target'])
|
834
|
-
restrict_targets = ENV['BUILDIZER_TARGET']
|
835
|
-
restrict_targets = restrict_targets.split(',').map(&:strip) if restrict_targets
|
836
|
-
targets = targets & restrict_targets if restrict_targets
|
837
|
-
targets
|
838
|
-
end
|
839
|
-
|
840
|
-
def prepare
|
841
|
-
Array(packagefile['prepare'])
|
842
|
-
end
|
843
|
-
|
844
|
-
def build_dep
|
845
|
-
Array(packagefile['build_dep']).to_set
|
846
|
-
end
|
847
|
-
|
848
|
-
def before_build
|
849
|
-
Array(packagefile['before_build'])
|
850
|
-
end
|
851
|
-
|
852
|
-
def docker_server
|
853
|
-
packagefile['docker_server']
|
854
|
-
end
|
855
|
-
|
856
|
-
def docker_image
|
857
|
-
packagefile['image']
|
858
|
-
end
|
859
|
-
|
860
|
-
def package_cloud
|
861
|
-
packagefile['package_cloud']
|
862
|
-
end
|
863
|
-
|
864
|
-
def package_cloud_token
|
865
|
-
ENV['PACKAGECLOUD_TOKEN'] || begin
|
866
|
-
raise Error, error: :input_error, message: "PACKAGECLOUD_TOKEN env variable required"
|
867
|
-
end
|
868
|
-
end
|
869
|
-
|
870
|
-
def docker_username
|
871
|
-
ENV['BUILDIZER_DOCKER_USERNAME'] || begin
|
872
|
-
raise Error, error: :input_error, message: "BUILDIZER_DOCKER_USERNAME env variable required"
|
873
|
-
end
|
874
|
-
end
|
875
|
-
|
876
|
-
def docker_password
|
877
|
-
ENV['BUILDIZER_DOCKER_PASSWORD'] || begin
|
878
|
-
raise Error, error: :input_error, message: "BUILDIZER_DOCKER_PASSWORD env variable required"
|
879
|
-
end
|
880
|
-
end
|
881
|
-
|
882
|
-
def docker_email
|
883
|
-
ENV['BUILDIZER_DOCKER_EMAIL'] || begin
|
884
|
-
raise Error, error: :input_error, message: "BUILDIZER_DOCKER_EMAIL env variable required"
|
885
|
-
end
|
886
|
-
end
|
887
|
-
|
888
|
-
def builder
|
889
|
-
@builder ||= begin
|
890
|
-
build_type = packagefile['build_type']
|
891
|
-
klass = {'fpm' => Builder::Fpm}[build_type]
|
892
|
-
raise Error, error: :input_error, message: "unknown build_type '#{build_type}'" unless klass
|
893
|
-
klass.new(self)
|
894
|
-
end
|
895
|
-
end
|
896
|
-
|
897
|
-
def buildizer_install_instructions(latest: nil)
|
898
|
-
if latest
|
899
|
-
['git clone https://github.com/flant/buildizer ~/buildizer',
|
900
|
-
'echo "export BUNDLE_GEMFILE=~/buildizer/Gemfile" | tee -a ~/.bashrc',
|
901
|
-
'export BUNDLE_GEMFILE=~/buildizer/Gemfile',
|
902
|
-
'gem install bundler',
|
903
|
-
'bundle install',
|
904
|
-
]
|
905
|
-
else
|
906
|
-
'gem install buildizer'
|
907
|
-
end
|
908
|
-
end
|
909
|
-
end # Packager
|
910
|
-
|
911
|
-
class Cli < Thor
|
912
|
-
desc "init", "Initialize settings (.travis.yml, .buildizer.yml, git pre-commit hook)"
|
913
|
-
method_option :latest,
|
914
|
-
type: :boolean,
|
915
|
-
desc: "use buildizer github master branch"
|
916
|
-
def init
|
917
|
-
Packager.new(options: options).init!
|
918
|
-
end
|
919
|
-
|
920
|
-
desc "update", "Regenerate .travis.yml"
|
921
|
-
def update
|
922
|
-
Packager.new(options: options).update!
|
923
|
-
end
|
924
|
-
|
925
|
-
desc "deinit", "Deinitialize settings (.buildizer.yml, git pre-commit hook)"
|
926
|
-
def deinit
|
927
|
-
Packager.new(options: options).deinit!
|
928
|
-
end
|
929
|
-
|
930
|
-
desc "prepare", "Prepare images for building packages"
|
931
|
-
def prepare
|
932
|
-
Packager.new(options: options).prepare!
|
933
|
-
end
|
934
|
-
|
935
|
-
desc "build", "Build packages"
|
936
|
-
def build
|
937
|
-
Packager.new(options: options).build!
|
938
|
-
end
|
939
|
-
|
940
|
-
desc "deploy", "Deploy packages"
|
941
|
-
def deploy
|
942
|
-
Packager.new(options: options).deploy!
|
943
|
-
end
|
944
|
-
end # Cli
|
945
|
-
end # Buildizer
|
5
|
+
require 'buildizer'
|
946
6
|
|
947
7
|
begin
|
948
8
|
Buildizer::Cli.start
|