buildizer 0.0.1 → 0.0.5
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 +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
|