buildizer 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,46 +16,6 @@ module Buildizer
16
16
  def buildizer_conf_setup!
17
17
  write_yaml(buildizer_conf_path, buildizer_conf)
18
18
  end
19
-
20
- def package_name
21
- buildizer_conf['package_name']
22
- end
23
-
24
- def package_version
25
- buildizer_conf['package_version']
26
- end
27
-
28
- def before_prepare
29
- Array(buildizer_conf['before_prepare'])
30
- end
31
-
32
- def after_prepare
33
- Array(buildizer_conf['after_prepare'])
34
- end
35
-
36
- def targets
37
- targets = Array(buildizer_conf['target'])
38
- restrict_targets = ENV['BUILDIZER_TARGET']
39
- restrict_targets = restrict_targets.split(',').map(&:strip) if restrict_targets
40
- targets = targets & restrict_targets if restrict_targets
41
- targets
42
- end
43
-
44
- def prepare
45
- Array(buildizer_conf['prepare'])
46
- end
47
-
48
- def build_dep
49
- Array(buildizer_conf['build_dep']).to_set
50
- end
51
-
52
- def before_build
53
- Array(buildizer_conf['before_build'])
54
- end
55
-
56
- def maintainer
57
- buildizer_conf['maintainer']
58
- end
59
19
  end # BuildizerConfMod
60
20
  end # Buildizer
61
21
  end # Buildizer
@@ -45,7 +45,7 @@ module Overcommit::Hook::PreCommit
45
45
  def run
46
46
  #{overcommit_buildizer_require}
47
47
 
48
- ::Buildizer::Buildizer.new.verify!
48
+ ::Buildizer::Buildizer.new.verify
49
49
  :pass
50
50
  rescue ::Buildizer::Error => e
51
51
  $stderr.puts e.net_status.net_status_message
@@ -51,24 +51,31 @@ module Buildizer
51
51
  'sudo apt-get update',
52
52
 
53
53
  # FIXME [https://github.com/docker/docker/issues/20316]:
54
- 'sudo apt-get -o dpkg::options::="--force-confnew" install -y docker-engine=1.9.1-0~trusty',
54
+ 'sudo apt-get -o dpkg::options::="--force-confnew" install -y --force-yes docker-engine=1.9.1-0~trusty',
55
55
 
56
56
  'echo "docker-engine hold" | sudo dpkg --set-selections',
57
57
  ]
58
58
  install.push(*Array(buildizer_install_instructions(master: buildizer.project_settings['master'])))
59
59
 
60
- env = buildizer.targets.map {|t| "BUILDIZER_TARGET=#{t}"}
61
- conf.merge(
60
+ if buildizer.project_settings['master']
61
+ buildizer_bin = 'bundle exec buildizer'
62
+ else
63
+ buildizer_bin = 'buildizer'
64
+ end
65
+
66
+ env = buildizer.builder.target_names.map {|t| "BUILDIZER_TARGET=#{t}"}
67
+
68
+ conf.merge!(
62
69
  'dist' => 'trusty',
63
70
  'sudo' => 'required',
64
71
  'cache' => 'apt',
65
72
  'language' => 'ruby',
66
73
  'rvm' => '2.2.1',
67
74
  'install' => install,
68
- 'before_script' => 'buildizer prepare',
69
- 'script' => 'buildizer build',
75
+ 'before_script' => "#{buildizer_bin} prepare",
76
+ 'script' => "#{buildizer_bin} build && #{buildizer_bin} test",
70
77
  'env' => env,
71
- 'after_success' => 'buildizer deploy',
78
+ 'after_success' => "#{buildizer_bin} deploy",
72
79
  )
73
80
  end
74
81
 
@@ -51,34 +51,36 @@ module Buildizer
51
51
  end
52
52
  end
53
53
 
54
- desc "deinit", "Deinitialize settings (.buildizer.yml, git pre-commit hook)"
55
- shared_options
56
- def deinit
57
- buildizer.deinit!
58
- end
59
-
60
54
  desc "prepare", "Prepare images for building packages"
61
55
  shared_options
62
56
  def prepare
63
- buildizer.prepare!
57
+ buildizer.prepare
64
58
  end
65
59
 
66
60
  desc "build", "Build packages"
67
61
  shared_options
68
62
  def build
69
- buildizer.build!
63
+ buildizer.build
64
+ end
65
+
66
+ desc "test", "Run integration tests for packages"
67
+ shared_options
68
+ method_option :shell, type: :boolean, default: false,
69
+ desc: "drop into test shell for each target + env"
70
+ def test
71
+ buildizer.test
70
72
  end
71
73
 
72
74
  desc "deploy", "Deploy packages"
73
75
  shared_options
74
76
  def deploy
75
- buildizer.deploy!
77
+ buildizer.deploy
76
78
  end
77
79
 
78
80
  desc "verify", "Verify targets params"
79
81
  shared_options
80
82
  def verify
81
- buildizer.verify!
83
+ buildizer.verify
82
84
  end
83
85
  end # Main
84
86
  end # Cli
@@ -1,20 +1,20 @@
1
1
  class Hash
2
2
  def zymbolize_keys
3
3
  map do |key, value|
4
- [_symbolize(key), value]
4
+ [_zymbolize(key), value]
5
5
  end.to_h
6
6
  end
7
7
 
8
8
  def zymbolize_keys!
9
9
  keys.each do |key|
10
- self[_symbolize(key)] = delete(key)
10
+ self[_zymbolize(key)] = delete(key)
11
11
  end
12
12
  self
13
13
  end
14
14
 
15
15
  def zymbolize_keys_deep
16
16
  map do |key, value|
17
- [_symbolize(key), if value.is_a? Hash
17
+ [_zymbolize(key), if value.is_a? Hash
18
18
  value.zymbolize_keys_deep
19
19
  else
20
20
  value
@@ -29,7 +29,7 @@ class Hash
29
29
  visited.add hash
30
30
  hash.keys.each do |key|
31
31
  value = hash.delete(key)
32
- hash[_symbolize(key)] = value
32
+ hash[_zymbolize(key)] = value
33
33
  queue << value if value.is_a? Hash and not visited.include? hash
34
34
  end
35
35
  end
@@ -42,7 +42,7 @@ class Hash
42
42
 
43
43
  private
44
44
 
45
- def _symbolize(value)
45
+ def _zymbolize(value)
46
46
  value.respond_to?(:to_sym) ? value.to_sym : value
47
47
  end
48
48
  end # Hash
@@ -1,9 +1,9 @@
1
1
  class Pathname
2
2
  def load_yaml
3
- exist? ? YAML.load(read) : {}
3
+ exist? ? YAML.load(read) || {} : {}
4
4
  rescue Psych::Exception => err
5
- raise Error, error: :input_error,
6
- message: "bad yaml config file #{self}: #{err.message}"
5
+ raise Buildizer::Error, error: :input_error,
6
+ message: "bad yaml config file #{self}: #{err.message}"
7
7
  end
8
8
 
9
9
  def dump_yaml(cfg)
@@ -8,25 +8,25 @@ module Buildizer
8
8
  @cache = cache
9
9
  end
10
10
 
11
- def image_klass(os_name, os_version)
11
+ def os_klass(name, version)
12
12
  ({
13
13
  'ubuntu' => {
14
- '12.04' => Image::Ubuntu1204,
15
- '14.04' => Image::Ubuntu1404,
16
- '16.04' => Image::Ubuntu1604,
17
- nil => Image::Ubuntu1404,
14
+ '12.04' => Os::Ubuntu1204,
15
+ '14.04' => Os::Ubuntu1404,
16
+ '16.04' => Os::Ubuntu1604,
17
+ nil => Os::Ubuntu1404,
18
18
  },
19
19
  'centos' => {
20
- 'centos6' => Image::Centos6,
21
- 'centos7' => Image::Centos7,
22
- nil => Image::Centos7,
20
+ 'centos6' => Os::Centos6,
21
+ 'centos7' => Os::Centos7,
22
+ nil => Os::Centos7,
23
23
  },
24
- }[os_name] || {})[os_version]
24
+ }[name] || {})[version]
25
25
  end
26
26
 
27
- def new_image(os_name, os_version, **kwargs)
28
- klass = image_klass(os_name, os_version)
29
- raise Error, message: "unknown os '#{[os_name, os_version].compact.join('-')}'" unless klass
27
+ def new_os(name, version, **kwargs)
28
+ klass = os_klass(name, version)
29
+ raise Error, message: "unknown os '#{[name, version].compact.join('-')}'" unless klass
30
30
  klass.new(self, **kwargs)
31
31
  end
32
32
 
@@ -60,41 +60,40 @@ module Buildizer
60
60
  builder.buildizer.command! 'docker logout', desc: "Docker cache account logout"
61
61
  end
62
62
 
63
- def pull_image(image)
64
- builder.buildizer.command! "docker pull #{image.base_image}", desc: "Pull docker base image #{image.base_image}"
65
- if cache
66
- pull_cache_res = builder.buildizer.command(
67
- "docker pull #{image.cache_name}",
68
- desc: "Try to pull docker cache image #{image.cache_name}"
69
- )
70
- if pull_cache_res.status.success?
71
- builder.buildizer.command! "docker tag -f #{image.cache_name} #{image.name}",
72
- desc: "Tag cache image #{image.cache_name}" +
73
- " as prepared build image #{image.name}"
74
- builder.buildizer.command! "docker rmi #{image.cache_name}",
75
- desc: "Remove cache image #{image.cache_name}"
76
- end
63
+ def pull_cache_image(build_image, cache_image)
64
+ pull_cache_res = builder.buildizer.command(
65
+ "docker pull #{cache_image.name}",
66
+ desc: "Try to pull docker cache image #{cache_image.name}"
67
+ )
68
+ if pull_cache_res.status.success?
69
+ builder.buildizer.command! "docker tag -f #{cache_image.name} #{build_image.name}",
70
+ desc: "Tag cache image #{cache_image.name}" +
71
+ " as prepared build image #{build_image.name}"
72
+ builder.buildizer.command! "docker rmi #{cache_image.name}",
73
+ desc: "Remove cache image #{cache_image.name}"
77
74
  end
78
75
  end
79
76
 
80
- def push_image(image)
81
- if cache
82
- builder.buildizer.command! "docker tag -f #{image.name} #{image.cache_name}",
83
- desc: "Tag prepared build image #{image.name}" +
84
- " as cache image #{image.cache_name}"
85
- builder.buildizer.command! "docker push #{image.cache_name}",
86
- desc: "Push cache image #{image.cache_name}"
87
- end
77
+ def cache_build_image(build_image, cache_image)
78
+ builder.buildizer.command! "docker tag -f #{build_image.name} #{cache_image.name}",
79
+ desc: "Tag prepared build image #{build_image.name}" +
80
+ " as cache image #{cache_image.name}"
81
+ builder.buildizer.command! "docker push #{cache_image.name}",
82
+ desc: "Push cache image #{cache_image.name}"
88
83
  end
89
84
 
90
- def build_image!(target)
91
- pull_image target.image
85
+ def make_build_image(target)
86
+ pull_cache_image(target.build_image, target.cache_image) if target.cache_image
87
+
88
+ target.build_image.dockerfile_write!
92
89
 
93
- target.image_work_path.join('Dockerfile').write! [*target.image.instructions, nil].join("\n")
94
- builder.buildizer.command! "docker build -t #{target.image.name} #{target.image_work_path}",
95
- desc: "Build docker image #{target.image.name}"
90
+ builder.buildizer.command! "docker build " +
91
+ "-t #{target.build_image.name} " +
92
+ "-f #{target.build_image.dockerfile_path} " +
93
+ "#{target.build_image.dockerfile_path.dirname}",
94
+ desc: "Build docker image #{target.build_image.name}"
96
95
 
97
- push_image target.image
96
+ cache_build_image(target.build_image, target.cache_image) if target.cache_image
98
97
  end
99
98
 
100
99
  def container_package_path
@@ -117,14 +116,15 @@ module Buildizer
117
116
  Pathname.new('/extra')
118
117
  end
119
118
 
120
- def run_target_container!(target:, env: {})
121
- container = SecureRandom.uuid
122
- builder.buildizer.command! [
123
- "docker run --detach --name #{container}",
124
- *Array(_prepare_docker_params(target, env)),
125
- _wrap_docker_run("while true ; do sleep 1 ; done"),
126
- ].join(' '), desc: "Run container '#{container}' from docker image '#{target.image.name}'"
127
- container
119
+ def run_container!(name: nil, image:, env: {}, desc: nil, docker_opts: {})
120
+ (name || SecureRandom.uuid).tap do |name|
121
+ builder.buildizer.command! [
122
+ "docker run --detach --name #{name}",
123
+ *Array(_prepare_docker_opts(docker_opts)),
124
+ *Array(_prepare_container_params(image, env: env)),
125
+ _wrap_docker_command("while true ; do sleep 1 ; done"),
126
+ ].join(' '), desc: desc
127
+ end
128
128
  end
129
129
 
130
130
  def shutdown_container!(container:)
@@ -132,38 +132,74 @@ module Buildizer
132
132
  builder.buildizer.command! "docker rm #{container}", desc: "Remove container '#{container}'"
133
133
  end
134
134
 
135
- def run_in_container!(container:, cmd:, desc: nil)
136
- builder.buildizer.command! [
137
- "docker exec #{container}",
138
- _wrap_docker_exec(cmd),
139
- ].join(' '), timeout: 24*60*60, desc: desc
135
+ def with_container(**kwargs, &blk)
136
+ container = run_container!(**kwargs)
137
+ begin
138
+ yield container if block_given?
139
+ ensure
140
+ shutdown_container!(container: container)
141
+ end
142
+ end
143
+
144
+ def shell_in_container(container:)
145
+ system "docker exec -ti #{container} bash -lec 'cd #{container_package_mount_path}; bash'"
140
146
  end
141
147
 
142
- def run_in_image!(target:, cmd:, env: {}, desc: nil)
143
- builder.buildizer.command! [
148
+ def run_in_container(container:, cmd:, desc: nil, cmd_opts: {}, docker_opts: {})
149
+ builder.buildizer.command [
150
+ "docker exec",
151
+ *Array(_prepare_docker_opts(docker_opts)),
152
+ container,
153
+ _wrap_docker_command(cmd),
154
+ ].join(' '), timeout: 24*60*60, desc: desc, **cmd_opts
155
+ end
156
+
157
+ def run_in_container!(cmd_opts: {}, **kwargs)
158
+ cmd_opts[:do_raise] = true
159
+ cmd_opts[:log_failure] = true
160
+ run_in_container(cmd_opts: cmd_opts, **kwargs)
161
+ end
162
+
163
+ def run_in_image(image:, cmd:, env: {}, desc: nil, cmd_opts: {}, docker_opts: {})
164
+ builder.buildizer.command [
144
165
  "docker run --rm",
145
- *Array(_prepare_docker_params(target, env)),
146
- _wrap_docker_run(cmd),
147
- ].join(' '), timeout: 24*60*60, desc: desc
166
+ *Array(_prepare_docker_opts(docker_opts)),
167
+ *Array(_prepare_container_params(image, env: env)),
168
+ _wrap_docker_command(cmd),
169
+ ].join(' '), timeout: 24*60*60, desc: desc, **cmd_opts
170
+ end
171
+
172
+ def run_in_image!(cmd_opts: {}, **kwargs)
173
+ cmd_opts[:do_raise] = true
174
+ run_in_image(cmd_opts: cmd_opts, **kwargs)
148
175
  end
149
176
 
150
- def _prepare_docker_params(target, env)
151
- target.image_extra_path.mkpath
152
- target.image_build_path.mkpath
177
+ def _prepare_container_params(image, env: {})
178
+ image.extra_path.mkpath
179
+ image.build_path.mkpath
153
180
 
154
181
  [*env.map {|k,v| "-e #{k}=#{v}"},
155
182
  "-v #{builder.buildizer.package_path}:#{container_package_mount_path}:ro",
156
- "-v #{target.image_extra_path}:#{container_extra_path}:ro",
157
- "-v #{target.image_build_path}:#{container_build_path}",
158
- target.image.name]
183
+ "-v #{image.extra_path}:#{container_extra_path}:ro",
184
+ "-v #{image.build_path}:#{container_build_path}",
185
+ image.name].compact
159
186
  end
160
187
 
161
- def _wrap_docker_exec(cmd)
162
- "/bin/bash -lec '#{_make_cmd(cmd)}'"
188
+ def _prepare_docker_opts(docker_opts)
189
+ docker_opts.map do |k, v|
190
+ next if v.nil?
191
+
192
+ to_opt = ->(value) {"--#{k}=#{value}"}
193
+ if v.is_a? Array
194
+ v.map(&to_opt)
195
+ else
196
+ to_opt[v]
197
+ end
198
+ end.flatten.compact
163
199
  end
164
200
 
165
- def _wrap_docker_run(cmd)
166
- "'#{['set -e', _make_cmd(cmd)].join('; ')}'"
201
+ def _wrap_docker_command(cmd)
202
+ "/bin/bash -lec '#{_make_cmd(cmd)}'"
167
203
  end
168
204
 
169
205
  def _make_cmd(cmd)
@@ -1,4 +1,47 @@
1
1
  module Buildizer
2
- module Image
2
+ class Image
3
+ attr_reader :name
4
+ attr_reader :target
5
+
6
+ attr_reader :instructions
7
+ attr_reader :from
8
+
9
+ def initialize(name, target, from: nil)
10
+ @name = name
11
+ @target = target
12
+
13
+ @instructions = []
14
+ @from = from
15
+
16
+ instruction :FROM, from if from
17
+ end
18
+
19
+ def instruction(instruction, cmd)
20
+ instructions << [instruction.to_s.upcase, cmd].join(' ')
21
+ end
22
+
23
+ def build_path
24
+ target.image_build_path
25
+ end
26
+
27
+ def extra_path
28
+ target.image_extra_path
29
+ end
30
+
31
+ def dockerfile_name
32
+ "#{name}.dockerfile"
33
+ end
34
+
35
+ def dockerfile_path
36
+ target.image_work_path.join(dockerfile_name)
37
+ end
38
+
39
+ def dockerfile_dump
40
+ [instructions, nil].join("\n")
41
+ end
42
+
43
+ def dockerfile_write!
44
+ dockerfile_path.write! dockerfile_dump
45
+ end
3
46
  end # Image
4
47
  end # Buildizer