nutkins 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/nutkins/docker.rb +17 -3
- data/lib/nutkins/docker_builder.rb +120 -0
- data/lib/nutkins/version.rb +1 -1
- data/lib/nutkins.rb +18 -8
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bfa69ab3c9cd1fa876a151921a9e04f1af3de8d
|
4
|
+
data.tar.gz: 52b50703467b3f9f010733a7681f9739653002c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6ff593c34f989c41d76c1f45395ed35b2a44dd289ae1e1fbe9ced7909467315c15a8a3896b712874d5ab4895748c3ab3d46187a8ec6048c0ef82e341c8dcbca
|
7
|
+
data.tar.gz: 258db6118fb8c67204521773771497b1e6f51a21731feb41ab6a82a1274fb36b43a426f6dce404bd261f29e3dd522d75b86e052d1341fcd36218e1ea751882b5
|
data/lib/nutkins/docker.rb
CHANGED
@@ -5,14 +5,28 @@ module Nutkins::Docker
|
|
5
5
|
self.run_get_stdout 'inspect', '--format="{{.Id}}"', tag
|
6
6
|
end
|
7
7
|
|
8
|
-
def self.
|
9
|
-
|
10
|
-
|
8
|
+
def self.kill_and_remove_container id
|
9
|
+
raise "issue killing existing container" unless Nutkins::Docker.run 'kill', id
|
10
|
+
raise "issue removing existing container" unless Nutkins::Docker.run 'rm', id
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.container_id_for_tag tag, running: false
|
14
|
+
flags = running ? '' : ' -a'
|
15
|
+
regex = /^[0-9a-f]+ +#{Regexp.escape tag} +/
|
16
|
+
`docker ps#{flags}`.each_line do |line|
|
11
17
|
return line.split(' ')[0] if line =~ regex
|
12
18
|
end
|
13
19
|
nil
|
14
20
|
end
|
15
21
|
|
22
|
+
def self.get_short_commit commit
|
23
|
+
if /^sha256:/.match(commit)
|
24
|
+
commit[7...19]
|
25
|
+
else
|
26
|
+
commit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
16
30
|
def self.container_id_for_name name
|
17
31
|
self.run_get_stdout 'inspect', '--format="{{.Id}}"', name
|
18
32
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require_relative "docker"
|
2
|
+
require "json"
|
3
|
+
require "digest"
|
4
|
+
|
5
|
+
module Nutkins::DockerBuilder
|
6
|
+
def self.build cfg
|
7
|
+
base = cfg["base"]
|
8
|
+
raise "to use build commands you must specify the base image" unless base
|
9
|
+
|
10
|
+
# TODO: build cache from this and use to determine restore point
|
11
|
+
# Nutkins::Docker.run 'inspect', tag, stderr: false
|
12
|
+
|
13
|
+
unless Nutkins::Docker.run 'inspect', base, stderr: false
|
14
|
+
puts "getting base image"
|
15
|
+
Docker.run 'pull', base, stdout: true
|
16
|
+
end
|
17
|
+
|
18
|
+
cont_id = Nutkins::Docker.container_id_for_tag base, running: true
|
19
|
+
if cont_id
|
20
|
+
puts "found existing container #{cont_id}"
|
21
|
+
Nutkins::Docker.kill_and_remove_container cont_id
|
22
|
+
puts "killed and removed existing container"
|
23
|
+
end
|
24
|
+
|
25
|
+
# the base image to start rebuilding from
|
26
|
+
parent_img_id = base
|
27
|
+
cont_id = nil
|
28
|
+
pwd = Dir.pwd
|
29
|
+
begin
|
30
|
+
Dir.chdir cfg["directory"]
|
31
|
+
|
32
|
+
cache_is_dirty = false
|
33
|
+
build_commands = cfg["build"]["commands"]
|
34
|
+
build_commands.each do |build_cmd|
|
35
|
+
cmd = /^\w+/.match(build_cmd).to_s.downcase
|
36
|
+
cmd_args = build_cmd[(cmd.length + 1)..-1].strip
|
37
|
+
|
38
|
+
docker_args = []
|
39
|
+
# the commit_msg is used to look up cache entries, it can be
|
40
|
+
# modified if the command uses dynamic data, e.g. to add checksums
|
41
|
+
commit_msg = nil
|
42
|
+
|
43
|
+
case cmd
|
44
|
+
when "run"
|
45
|
+
cmd_args.gsub! /\n+/, ' '
|
46
|
+
docker_args = ['exec', '%CONT_ID%', cfg['shell'], '-c', cmd_args]
|
47
|
+
commit_msg = cmd + ' ' + cmd_args
|
48
|
+
when "add"
|
49
|
+
*srcs, dest = cmd_args.split ' '
|
50
|
+
srcs = srcs.map { |src| Dir.glob src }.flatten
|
51
|
+
|
52
|
+
docker_args = srcs.map { |src| ['cp', src, '%CONT_ID%' + ':' + dest] }
|
53
|
+
# ensure checksum of each file is embedded into commit_msg
|
54
|
+
# if any file changes the cache is dirtied
|
55
|
+
commit_msg = 'add ' + srcs.map do |src|
|
56
|
+
src + ':' + Digest::MD5.file(src).to_s
|
57
|
+
end.push(dest).join(' ')
|
58
|
+
when "cmd", "entrypoint", "env", "expose", "label", "onbuild", "user", "volume", "workdir"
|
59
|
+
commit_msg = commit_change = build_cmd
|
60
|
+
else
|
61
|
+
raise "unsupported command: #{cmd}"
|
62
|
+
# TODO add metadata flags
|
63
|
+
end
|
64
|
+
|
65
|
+
if (commit_change or docker_args) and commit_msg
|
66
|
+
commit_msg = "#{parent_img_id} -> #{commit_msg}"
|
67
|
+
|
68
|
+
unless cache_is_dirty
|
69
|
+
# searches the commit messages of all images for the one matching the expected
|
70
|
+
# cache entry for the given content
|
71
|
+
all_images = Nutkins::Docker.run_get_stdout('images', '-aq').split("\n")
|
72
|
+
images_meta = JSON.parse(Nutkins::Docker.run_get_stdout('inspect', *all_images))
|
73
|
+
cache_entry = images_meta.find do |image_meta|
|
74
|
+
if image_meta['Comment'] == commit_msg
|
75
|
+
parent_img_id = Nutkins::Docker.get_short_commit(image_meta['Id'])
|
76
|
+
true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
if cache_entry
|
81
|
+
puts "cached: #{commit_msg}"
|
82
|
+
next
|
83
|
+
else
|
84
|
+
puts "starting build container from commit #{parent_img_id}"
|
85
|
+
Nutkins::Docker.run 'run', '-d', parent_img_id, 'sleep', '3600'
|
86
|
+
cont_id = Nutkins::Docker.container_id_for_tag parent_img_id, running: true
|
87
|
+
puts "started build container #{cont_id}"
|
88
|
+
cache_is_dirty = true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
puts "#{cmd}: #{cmd_args}"
|
93
|
+
|
94
|
+
unless docker_args.empty?
|
95
|
+
# docker can be an array of one set of args, or an array of arrays of args
|
96
|
+
docker_args = [ docker_args ] unless docker_args[0].kind_of? Array
|
97
|
+
docker_args.each do |one_docker_args|
|
98
|
+
run_args = one_docker_args.map { |arg| arg.gsub '%CONT_ID%', cont_id }
|
99
|
+
puts "run #{run_args.join ' '}"
|
100
|
+
unless Nutkins::Docker.run *run_args, stdout: true
|
101
|
+
raise "build failed: #{one_docker_args.join ' '}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
commit_args = commit_change ? ['-c', commit_change] : []
|
107
|
+
parent_img_id = Nutkins::Docker.run_get_stdout 'commit', '-m', commit_msg, *commit_args, cont_id
|
108
|
+
raise "could not commit docker image" if parent_img_id.nil?
|
109
|
+
parent_img_id = Nutkins::Docker.get_short_commit parent_img_id
|
110
|
+
else
|
111
|
+
puts "TODO: support cmd #{build_cmd}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
ensure
|
115
|
+
Dir.chdir pwd
|
116
|
+
Nutkins::Docker.kill_and_remove_container cont_id if cont_id
|
117
|
+
puts "killed and removed build container"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/nutkins/version.rb
CHANGED
data/lib/nutkins.rb
CHANGED
@@ -9,6 +9,7 @@ require "net/http"
|
|
9
9
|
module Nutkins ; end
|
10
10
|
|
11
11
|
require "nutkins/docker"
|
12
|
+
require "nutkins/docker_builder"
|
12
13
|
require "nutkins/download"
|
13
14
|
require "nutkins/version"
|
14
15
|
|
@@ -36,6 +37,8 @@ module Nutkins
|
|
36
37
|
raise "directory `#{img_dir}' does not exist" unless Dir.exists? img_dir
|
37
38
|
tag = cfg['tag']
|
38
39
|
|
40
|
+
prev_image_id = Docker.image_id_for_tag tag
|
41
|
+
|
39
42
|
build_cfg = cfg["build"]
|
40
43
|
if build_cfg
|
41
44
|
# download each of the files in the resources section if it doesn't exist
|
@@ -43,16 +46,22 @@ module Nutkins
|
|
43
46
|
Download.download_resources img_dir, resources if resources
|
44
47
|
end
|
45
48
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
if cfg.dig "build", "commands"
|
50
|
+
# if build commands are available use nutkins built-in builder
|
51
|
+
DockerBuilder::build cfg
|
52
|
+
else
|
53
|
+
# fallback to `docker build` which is less good
|
54
|
+
if not Docker.run 'build', '-t', cfg['latest_tag'], '-t', tag, img_dir, stdout: true
|
55
|
+
raise "issue building docker image for #{img_name}"
|
53
56
|
end
|
57
|
+
end
|
58
|
+
|
59
|
+
image_id = Docker.image_id_for_tag tag
|
60
|
+
if prev_image_id and image_id != prev_image_id
|
61
|
+
puts "deleting previous image #{prev_image_id}"
|
62
|
+
Docker.run "rmi", prev_image_id
|
54
63
|
else
|
55
|
-
|
64
|
+
puts "image is identical to cached version"
|
56
65
|
end
|
57
66
|
end
|
58
67
|
|
@@ -286,6 +295,7 @@ module Nutkins
|
|
286
295
|
img_cfg_path = File.join directory, IMG_CONFIG_FILE_NAME
|
287
296
|
img_cfg = File.exists?(img_cfg_path) ? YAML.load_file(img_cfg_path) : {}
|
288
297
|
img_cfg['image'] ||= path if path != '.'
|
298
|
+
img_cfg['shell'] ||= 'sh'
|
289
299
|
img_cfg['directory'] = directory
|
290
300
|
img_cfg["version"] ||= @config.version if @config.version
|
291
301
|
img_cfg['version'] = img_cfg['version'].to_s
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nutkins
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Pike
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- circle.yml
|
87
87
|
- lib/nutkins.rb
|
88
88
|
- lib/nutkins/docker.rb
|
89
|
+
- lib/nutkins/docker_builder.rb
|
89
90
|
- lib/nutkins/download.rb
|
90
91
|
- lib/nutkins/version.rb
|
91
92
|
- nutkins.gemspec
|