buildizer 0.1.0 → 0.1.1

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.
@@ -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