docker-template 0.2.0 → 0.3.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +30 -4
  3. data/LICENSE +1 -1
  4. data/README.md +79 -14
  5. data/Rakefile +115 -38
  6. data/bin/docker-template +24 -10
  7. data/comp/bin +9 -0
  8. data/comp/list +83 -0
  9. data/comp/list.pak +0 -0
  10. data/lib/docker/template.rb +47 -61
  11. data/lib/docker/template/builder.rb +302 -0
  12. data/lib/docker/template/cache.rb +71 -0
  13. data/lib/docker/template/cli.rb +125 -0
  14. data/lib/docker/template/error.rb +120 -11
  15. data/lib/docker/template/logger.rb +128 -0
  16. data/lib/docker/template/metadata.rb +566 -103
  17. data/lib/docker/template/normal.rb +46 -0
  18. data/lib/docker/template/notify.rb +44 -0
  19. data/lib/docker/template/parser.rb +48 -38
  20. data/lib/docker/template/repo.rb +131 -97
  21. data/lib/docker/template/rootfs.rb +51 -41
  22. data/lib/docker/template/scratch.rb +96 -66
  23. data/lib/docker/template/version.rb +4 -2
  24. data/lib/erb/context.rb +29 -0
  25. data/shas.yml +11 -0
  26. data/templates/rootfs.erb +5 -0
  27. data/templates/rootfs/alpine.erb +71 -0
  28. data/templates/rootfs/ubuntu.erb +76 -0
  29. data/{lib/docker/template/templates → templates}/scratch.erb +0 -1
  30. metadata +64 -50
  31. data/lib/docker/template/alias.rb +0 -28
  32. data/lib/docker/template/ansi.rb +0 -85
  33. data/lib/docker/template/auth.rb +0 -25
  34. data/lib/docker/template/common.rb +0 -130
  35. data/lib/docker/template/config.rb +0 -80
  36. data/lib/docker/template/error/bad_exit_status.rb +0 -17
  37. data/lib/docker/template/error/bad_repo_name.rb +0 -15
  38. data/lib/docker/template/error/invalid_repo_type.rb +0 -16
  39. data/lib/docker/template/error/invalid_targz_file.rb +0 -15
  40. data/lib/docker/template/error/no_rootfs_copy_dir.rb +0 -15
  41. data/lib/docker/template/error/no_rootfs_mkimg.rb +0 -15
  42. data/lib/docker/template/error/no_setup_context_found.rb +0 -15
  43. data/lib/docker/template/error/not_implemented.rb +0 -15
  44. data/lib/docker/template/error/repo_not_found.rb +0 -16
  45. data/lib/docker/template/interface.rb +0 -118
  46. data/lib/docker/template/patches.rb +0 -9
  47. data/lib/docker/template/patches/array.rb +0 -11
  48. data/lib/docker/template/patches/hash.rb +0 -71
  49. data/lib/docker/template/patches/object.rb +0 -9
  50. data/lib/docker/template/patches/pathname.rb +0 -46
  51. data/lib/docker/template/patches/string.rb +0 -9
  52. data/lib/docker/template/routable.rb +0 -28
  53. data/lib/docker/template/simple.rb +0 -49
  54. data/lib/docker/template/stream.rb +0 -63
  55. data/lib/docker/template/templates/rootfs.erb +0 -8
  56. data/lib/docker/template/util.rb +0 -54
  57. data/lib/docker/template/util/copy.rb +0 -77
  58. data/lib/docker/template/util/data.rb +0 -26
Binary file
@@ -1,99 +1,85 @@
1
+ # ----------------------------------------------------------------------------
1
2
  # Frozen-string-literal: true
2
- # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
3
4
  # Encoding: utf-8
4
-
5
- require "docker/template/version"
6
- require "docker/template/patches"
5
+ # ----------------------------------------------------------------------------
7
6
 
8
7
  require "docker"
9
- require "forwardable"
10
- require "json"
11
- require "erb"
8
+ require "extras/all"
9
+ require "erb/context"
10
+ require "forwardable/extended"
11
+ require "simple/ansi"
12
+ require "pathutil"
12
13
  require "set"
13
14
 
15
+ # ----------------------------------------------------------------------------
16
+
17
+ Excon.defaults[ :read_timeout] = 1440
18
+ Excon.defaults[:write_timeout] = 1440
19
+
20
+ # ----------------------------------------------------------------------------
21
+
14
22
  module Docker
15
23
  module Template
16
24
  module_function
17
25
 
18
- autoload :Util, "docker/template/util"
19
- autoload :Config, "docker/template/config"
20
- autoload :Ansi, "docker/template/ansi"
21
- autoload :Parser, "docker/template/parser"
22
- autoload :Routable, "docker/template/routable"
23
- autoload :Interface, "docker/template/interface"
24
- autoload :Metadata, "docker/template/metadata"
25
- autoload :Stream, "docker/template/stream"
26
- autoload :Safe, "docker/template/safe"
26
+ # ------------------------------------------------------------------------
27
+
28
+ autoload :Notify, "docker/template/notify"
29
+ autoload :Utils, "docker/template/utils"
27
30
  autoload :Repo, "docker/template/repo"
28
31
  autoload :Error, "docker/template/error"
29
- autoload :Common, "docker/template/common"
30
- autoload :Rootfs, "docker/template/rootfs"
32
+ autoload :Logger, "docker/template/logger"
33
+ autoload :Normal, "docker/template/normal"
34
+ autoload :Parser, "docker/template/parser"
35
+ autoload :Builder, "docker/template/builder"
36
+ autoload :Metadata, "docker/template/metadata"
31
37
  autoload :Scratch, "docker/template/scratch"
32
- autoload :Simple, "docker/template/simple"
38
+ autoload :Rootfs, "docker/template/rootfs"
39
+ autoload :Cache, "docker/template/cache"
33
40
  autoload :Alias, "docker/template/alias"
34
- autoload :Auth, "docker/template/auth"
41
+ autoload :CLI, "docker/template/cli"
35
42
 
36
- def repo_is_root?
37
- root.join("copy").exist? && !root.join("../..", config["repos_dir"]).exist?
38
- end
39
-
40
- def config
41
- @config ||= begin
42
- Config.new
43
- end
44
- end
45
-
46
- #
43
+ # ------------------------------------------------------------------------
47
44
 
48
45
  def root
49
46
  @root ||= begin
50
- Pathname.new(Dir.pwd)
47
+ Pathutil.new(Dir.pwd)
51
48
  end
52
49
  end
53
50
 
54
- # The location of the standard repos/ dir, you can change this by adding
55
- # `repos_dir` into your configuration file. I'm not saying it has to be but
56
- # it should probably be relative rather than absolute, ther are no
57
- # guarantees that an absolute path will work.
58
-
59
- def repos_root
60
- @repos_root ||= begin
61
- root.join(config["repos_dir"])
62
- end
63
- end
64
-
65
- #
66
-
67
- def repo_root_for(name)
68
- repo_is_root?? root : repos_root.join(name)
69
- end
70
-
71
- # Provides the root to Docker template, wherever it is installed so that
72
- # we can do things, mostly ignore files for the profiler. Otherwise it's
73
- # not really used, it's just an encapsulator.
51
+ # ------------------------------------------------------------------------
74
52
 
75
53
  def gem_root
76
54
  @gem_root ||= begin
77
- path = File.expand_path("../../", __dir__)
78
- Pathname.new(path)
55
+ Pathutil.new("../../").expand_path(
56
+ __dir__
57
+ )
79
58
  end
80
59
  end
81
60
 
82
- # Provides the templates directory so you can quickly pull a template
83
- # from our templates and use it if you wish to.
61
+ # ------------------------------------------------------------------------
84
62
 
85
63
  def template_root
86
64
  @template_root ||= begin
87
- gem_root.join("lib/docker/template/templates")
65
+ gem_root.join("templates")
88
66
  end
89
67
  end
90
68
 
91
- #
69
+ # ------------------------------------------------------------------------
70
+ # Pull a `template` from the `template_root` to parse it's data.
71
+ # TODO: Rename this get template!
72
+ # ------------------------------------------------------------------------
92
73
 
93
74
  def get(name, data = {})
94
- data = Util::Data.new(data)
95
- template = template_root.join("#{name}.erb").read
96
- ERB.new(template).result(data._binding)
75
+ data = ERB::Context.new(data)
76
+ template = template_root.join("#{name}.erb").read unless name.is_a?(Pathutil)
77
+ template = name.read if name.is_a?(Pathutil)
78
+ template = ERB.new(template)
79
+
80
+ return template.result(
81
+ data._binding
82
+ )
97
83
  end
98
84
  end
99
85
  end
@@ -0,0 +1,302 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Docker
8
+ module Template
9
+ class Builder
10
+ extend Forwardable::Extended
11
+
12
+ # ----------------------------------------------------------------------
13
+
14
+ attr_reader :repo
15
+ attr_reader :context
16
+ attr_reader :img
17
+
18
+ # ----------------------------------------------------------------------
19
+
20
+ ALIAS_SETUP = [:cache_context]
21
+ SETUP = [:setup_context, :copy_global, :copy_all,
22
+ :copy_group, :copy_tag, :copy_cleanup, :build_context,
23
+ :verify_context, :cache_context].freeze
24
+
25
+ # ----------------------------------------------------------------------
26
+
27
+ def initialize(repo)
28
+ @repo = repo
29
+ end
30
+
31
+ # ----------------------------------------------------------------------
32
+ # Checks to see if this repository is an alias. This happens when the
33
+ # user has alised data inside of their configuration file. At this point
34
+ # we will not only copy the parent's data but the aliased data.
35
+ # ----------------------------------------------------------------------
36
+
37
+ def alias?
38
+ !@repo.complex_alias? && @repo.alias? && !rootfs?
39
+ end
40
+
41
+ # ----------------------------------------------------------------------
42
+
43
+ def rootfs?
44
+ is_a?(
45
+ Rootfs
46
+ )
47
+ end
48
+
49
+ # ----------------------------------------------------------------------
50
+
51
+ def normal?
52
+ @repo.type == "normal" \
53
+ && !rootfs?
54
+ end
55
+
56
+ # ----------------------------------------------------------------------
57
+
58
+ def scratch?
59
+ @repo.type == "scratch" \
60
+ && !rootfs?
61
+ end
62
+
63
+ # ----------------------------------------------------------------------
64
+
65
+ def aliased_img
66
+ return unless alias?
67
+ @aliased_img ||= Docker::Image.get(
68
+ aliased_repo.to_s
69
+ )
70
+
71
+ rescue Docker::Error::NotFoundError
72
+ if alias?
73
+ nil
74
+ end
75
+ end
76
+
77
+ # ----------------------------------------------------------------------
78
+
79
+ def push
80
+ return if rootfs? || !@repo.pushable?
81
+ Notify.push self
82
+ auth!
83
+
84
+ img = @img || Image.get(@repo.to_s)
85
+ img.push nil, :repo_tag => \
86
+ @repo.to_s, &Logger.new.method(:api)
87
+
88
+ rescue Docker::Error::NotFoundError
89
+ $stderr.puts Simple::Ansi.red(
90
+ "Image does not exist, unpushable."
91
+ )
92
+ end
93
+
94
+ # ----------------------------------------------------------------------
95
+
96
+ def build
97
+ Simple::Ansi.clear if @repo.buildable?
98
+ return build_alias if alias?
99
+ setup
100
+
101
+ if @repo.buildable?
102
+ Notify.build(@repo, {
103
+ :rootfs => rootfs?
104
+ })
105
+
106
+ chdir_build
107
+ end
108
+
109
+ push
110
+ rescue SystemExit => exit_
111
+ teardown :img => true
112
+ raise exit_
113
+ ensure
114
+ if !rootfs?
115
+ teardown else teardown({
116
+ :img => false
117
+ })
118
+ end
119
+ end
120
+
121
+ # ----------------------------------------------------------------------
122
+ # This method is a default reference. It is called when the image is
123
+ # done building or when there is an error and we need to clean up some
124
+ # stuff before exiting, use it... please.
125
+ # ----------------------------------------------------------------------
126
+
127
+ def teardown(*_)
128
+ $stderr.puts Ansi.red(
129
+ "#{__method__}: Not Implemented."
130
+ )
131
+ end
132
+
133
+ # ----------------------------------------------------------------------
134
+
135
+ private
136
+ def build_alias
137
+ alias_setup
138
+
139
+ if @repo.buildable?
140
+ aliased = self.class.new(aliased_repo)
141
+ aliased.build unless aliased_img
142
+ Notify.alias(self)
143
+
144
+ aliased_img.tag(
145
+ @repo.to_tag_h
146
+ )
147
+ end
148
+
149
+ push
150
+ end
151
+
152
+ # ----------------------------------------------------------------------
153
+ # The prebuild happens when a user has "setup_context", which typically
154
+ # only happens with scratch, which will prebuild it's rootfs image so
155
+ # it can get to building it's actual image.
156
+ # ----------------------------------------------------------------------
157
+
158
+ private
159
+ def setup
160
+ unless respond_to?(:setup_context, true)
161
+ raise Error::NoSetupContext
162
+ end
163
+
164
+ SETUP.map do |val|
165
+ if respond_to?(val, true)
166
+ send(val)
167
+ end
168
+ end
169
+ end
170
+
171
+ # ----------------------------------------------------------------------
172
+
173
+ private
174
+ def alias_setup
175
+ ALIAS_SETUP.map do |m|
176
+ if respond_to?(m, true)
177
+ send(m)
178
+ end
179
+ end
180
+ end
181
+
182
+ # ----------------------------------------------------------------------
183
+
184
+ private
185
+ def chdir_build
186
+ @context.chdir do
187
+ logger = Logger.new(self).method(:api)
188
+ opts = { :t => @repo.to_s(rootfs: rootfs?) }
189
+ $stderr.puts Simple::Ansi.yellow("TTY not supported: Ignored.") if @repo.metadata["tty"]
190
+ @img = Docker::Image.build_from_dir(".", opts, &logger)
191
+ end
192
+ end
193
+
194
+ # ----------------------------------------------------------------------
195
+
196
+ private
197
+ def cache_context
198
+ if repo.cacheable?
199
+ $stderr.puts Simple::Ansi.red(
200
+ "Context caching not supported"
201
+ )
202
+ end
203
+ end
204
+
205
+ # ----------------------------------------------------------------------
206
+ # The root can have it's own global copy directory shared across all
207
+ # repos in your repo container dir so this encapsulates those.
208
+ # ----------------------------------------------------------------------
209
+
210
+ private
211
+ def copy_global
212
+ unless rootfs?
213
+ dir = Template.root.join(
214
+ @repo.metadata["copy_dir"]
215
+ )
216
+
217
+ if dir.exist?
218
+ then dir.safe_copy(
219
+ @copy, :root => Template.root
220
+ )
221
+ end
222
+ end
223
+ end
224
+
225
+ # ----------------------------------------------------------------------
226
+
227
+ private
228
+ def copy_tag
229
+ unless rootfs?
230
+ dir = @repo.copy_dir("tag", @repo.tag)
231
+
232
+ if dir.exist?
233
+ then dir.safe_copy(
234
+ @copy, :root => Template.root
235
+ )
236
+ end
237
+ end
238
+ end
239
+
240
+ # ----------------------------------------------------------------------
241
+
242
+ private
243
+ def copy_group
244
+ build_group = @repo.metadata["tags"][
245
+ @repo.tag
246
+ ]
247
+
248
+ unless rootfs? || !build_group
249
+ dir = @repo.copy_dir("group", build_group)
250
+
251
+ if dir.exist?
252
+ then dir.safe_copy(
253
+ @copy, :root => Template.root
254
+ )
255
+ end
256
+ end
257
+ end
258
+
259
+ # ----------------------------------------------------------------------
260
+
261
+ private
262
+ def copy_all
263
+ unless rootfs?
264
+ dir = @repo.copy_dir("all")
265
+
266
+ if dir.exist?
267
+ then dir.safe_copy(
268
+ @copy, :root => Template.root
269
+ )
270
+ end
271
+ end
272
+ end
273
+
274
+ # ----------------------------------------------------------------------
275
+
276
+ private
277
+ def auth!
278
+ credentials = Pathutil.new("~/.docker/config.json").expand_path.read_json
279
+ return if credentials.empty?
280
+
281
+ credentials["auths"].each do |server, info|
282
+ user, pass = Base64.decode64(info["auth"]).split(
283
+ ":", 2
284
+ )
285
+
286
+ Docker.authenticate!({
287
+ "username" => user,
288
+ "serveraddress" => server,
289
+ "email" => info["email"],
290
+ "password" => pass
291
+ })
292
+ end
293
+ end
294
+
295
+ # ----------------------------------------------------------------------
296
+
297
+ rb_delegate :aliased_repo, {
298
+ :to => :repo, :alias_of => :aliased
299
+ }
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,71 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ module Docker
8
+ module Template
9
+ module Cache
10
+ module_function
11
+
12
+ # ----------------------------------------------------------------------
13
+ # Cache the context into the cache directory.
14
+ # ----------------------------------------------------------------------
15
+
16
+ def context(builder, context)
17
+ if builder.alias? && builder.aliased_repo.cache_dir.exist?
18
+ parent_cache_dir = builder.aliased_repo.cache_dir
19
+ $stderr.puts Simple::Ansi.yellow("Copying #{builder.aliased_repo} context to #{builder.repo}")
20
+ cache_dir = builder.repo.cache_dir
21
+
22
+ parent_cache_dir.cp_r(cache_dir.tap(
23
+ &:rm_rf
24
+ ))
25
+ elsif context
26
+ builder.repo.cache_dir.rm_rf
27
+ $stderr.puts Simple::Ansi.yellow("Copying context for #{builder.repo}")
28
+ cache_dir = builder.repo.cache_dir
29
+ cache_dir.parent.mkdir_p
30
+
31
+ readme(builder)
32
+ context.cp_r(cache_dir.tap(
33
+ &:rm_rf
34
+ ))
35
+ end
36
+ end
37
+
38
+ # ----------------------------------------------------------------------
39
+ # Cleanup the context caches, removing the caches we no longer need.
40
+ # ----------------------------------------------------------------------
41
+
42
+ def cleanup(repo)
43
+ repo.cache_dir.parent.children.each do |file|
44
+ unless repo.metadata.tags.include?(file.basename)
45
+ $stdout.puts Simple::Ansi.yellow("Removing %s." % [
46
+ file.relative_path_from(Template.root)
47
+ ])
48
+
49
+ file.rm_rf
50
+ end
51
+ end
52
+ end
53
+
54
+ # ----------------------------------------------------------------------
55
+ # Note: We normally expect but do not require you to have a README.
56
+ # Search for and copy the readme if available.
57
+ # ----------------------------------------------------------------------
58
+
59
+ def readme(builder)
60
+ file = builder.repo.root.children.find do |val|
61
+ val =~ /readme/i
62
+ end
63
+
64
+ return unless file
65
+ file.safe_copy(builder.repo.cache_dir, {
66
+ :root => file.parent
67
+ })
68
+ end
69
+ end
70
+ end
71
+ end