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
@@ -0,0 +1,46 @@
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 Normal < Builder
10
+ def teardown(img: false)
11
+ @img.delete "force" => true if @img && img
12
+ @context.rmtree if @context && \
13
+ @context.directory?
14
+ end
15
+
16
+ # ----------------------------------------------------------------------
17
+
18
+ def setup_context
19
+ @context = @repo.tmpdir
20
+ @copy = @context.join("copy")
21
+ copy_dockerfile
22
+ @copy.mkdir
23
+ end
24
+
25
+ # ----------------------------------------------------------------------
26
+
27
+ private
28
+ def copy_dockerfile
29
+ dockerfile = @repo.root.join("Dockerfile").read
30
+ data = ERB::Context.new(:metadata => @repo.metadata)
31
+ data = ERB.new(dockerfile).result(data._binding)
32
+ context = @context.join("Dockerfile")
33
+ context.write(data)
34
+ end
35
+
36
+ # ----------------------------------------------------------------------
37
+
38
+ private
39
+ def cache_context
40
+ if @repo.cacheable?
41
+ Cache.context self, @context
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,44 @@
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 Notify
10
+ module_function
11
+
12
+ # ----------------------------------------------------------------------
13
+ # Notify the user of a push that is happening.
14
+ # ----------------------------------------------------------------------
15
+
16
+ def push(builder)
17
+ $stderr.puts Simple::Ansi.green(
18
+ "Pushing: #{builder.repo}"
19
+ )
20
+ end
21
+
22
+ # ----------------------------------------------------------------------
23
+ # Notify the user that we are tag aliasing.
24
+ # ----------------------------------------------------------------------
25
+
26
+ def alias(builder)
27
+ repo = builder.repo
28
+ aliased_repo = builder.aliased_repo
29
+ msg = Simple::Ansi.green("Aliasing #{repo} -> #{aliased_repo}")
30
+ $stderr.puts msg
31
+ end
32
+
33
+ # ----------------------------------------------------------------------
34
+ # Notify the user that we are building their repository.
35
+ # ----------------------------------------------------------------------
36
+
37
+ def build(repo, **kwd)
38
+ img = repo.to_s(**kwd)
39
+ msg = Simple::Ansi.green("Building: #{img}")
40
+ $stderr.puts msg
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,66 +1,76 @@
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
5
+ # ----------------------------------------------------------------------------
4
6
 
5
7
  module Docker
6
8
  module Template
7
9
  class Parser
8
- SLASH_REGEXP = /\//.freeze
9
- SPLIT_REGEXP = /:|\//.freeze
10
- COLON_REGEXP = /:/.freeze
10
+ SLASH_REGEXP = /\//
11
+ SPLIT_REGEXP = /:|\//
12
+ COLON_REGEXP = /:/
11
13
 
12
- def initialize(argv = [].freeze)
13
- @argv = argv.freeze
14
+ def initialize(raw_repos = [], argv = {})
15
+ @raw_repos = raw_repos
16
+ @argv = argv
14
17
  end
15
18
 
16
- # Return ARGV if you send us a list of repos you wish to build,
17
- # otherwise we get the children of the repo folder and ship that off
18
- # so you can build *every* repo, I don't know if you want that.
19
+ # ----------------------------------------------------------------------
20
+ # Return `raw_repos` if you send us a list of repos you wish to build,
21
+ # otherwise we get the children of the repo folder and ship that off so
22
+ # you can build *every* repo, I don't know if you want that.
23
+ # ----------------------------------------------------------------------
19
24
 
20
25
  def all
21
- return @argv unless @argv.empty?
22
- Template.repos_root.children.map do |path|
26
+ return @raw_repos unless @raw_repos.empty?
27
+ Template.root.join(Metadata.new({}).repos_dir).children.map do |path|
23
28
  path.basename.to_s
24
29
  end
30
+
25
31
  rescue Errno::ENOENT
26
- raise Error::RepoNotFound
32
+ then raise Error::RepoNotFound
27
33
  end
28
34
 
29
- #
35
+ # ----------------------------------------------------------------------
36
+
37
+ def parse
38
+ repos = {
39
+ :scratch => [],
40
+ :simple => [],
41
+ :aliases => []
42
+ }
30
43
 
31
- def parse(as: :repos, out: Set.new)
32
- all.each do |val|
33
- hash = build_repo_hash(val)
34
- raise Docker::Template::Error::BadRepoName, val if hash.empty?
35
- out += as == :repos ? Repo.new(hash).to_repos : [hash]
44
+ all.each do |v|
45
+ hash = to_repo_hash(v)
46
+ if hash.empty?
47
+ raise Docker::Template::Error::BadRepoName, v
48
+
49
+ else
50
+ Repo.new(hash, @argv).to_repos.each do |r|
51
+ r.alias?? repos[:aliases] << r : r.builder.scratch?? \
52
+ repos[:scratch] << r : repos[:simple] << r
53
+ end
54
+ end
36
55
  end
37
- out
56
+
57
+ repos.values.reduce(
58
+ :|
59
+ )
38
60
  end
39
61
 
40
- #
62
+ # ----------------------------------------------------------------------
41
63
 
42
64
  private
43
- def build_repo_hash(val)
65
+ def to_repo_hash(val)
44
66
  data = val.split(SPLIT_REGEXP)
45
- hsh = {}
46
67
 
47
- if data.size == 1
48
- hsh["repo"] = data[0]
68
+ return "name" => data[0] if data.one?
69
+ return "name" => data[0], "tag" => data[1] if val =~ COLON_REGEXP && data.size == 2
70
+ return "user" => data[0], "name" => data[1] if val =~ SLASH_REGEXP && data.size == 2
71
+ return "user" => data[0], "name" => data[1], "tag" => data[2] if data.size == 3
49
72
 
50
- elsif val =~ COLON_REGEXP && data.size == 2
51
- hsh["repo"] = data[0]
52
- hsh[ "tag"] = data[1]
53
-
54
- elsif val =~ SLASH_REGEXP && data.size == 2
55
- hsh["user"] = data[0]
56
- hsh["repo"] = data[1]
57
-
58
- elsif data.size == 3
59
- hsh["user"] = data[0]
60
- hsh["repo"] = data[1]
61
- hsh[ "tag"] = data[2]
62
- end
63
- hsh
73
+ {}
64
74
  end
65
75
  end
66
76
  end
@@ -1,85 +1,109 @@
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
5
+ # ----------------------------------------------------------------------------
4
6
 
5
7
  module Docker
6
8
  module Template
7
-
8
- # * A repo is not an image but a parent name w/ a tag.
9
- # * An image is the final result of a build on a repo, and is associated.
10
- # * Think of an image as the binary of the source in the repo.
11
-
12
9
  class Repo
13
- extend Forwardable, Routable
10
+ extend Forwardable::Extended
14
11
 
15
- def_delegator :builder, :build
16
- route_to_hash :name, :@base_metadata, :repo
17
- route_to_hash [:tag, :type, :user], :metadata
18
- def_delegator :@base_metadata, :to_h
19
- def_delegator :metadata, :aliased
20
- def_delegator :metadata, :tags
12
+ # ----------------------------------------------------------------------
21
13
 
22
- def initialize(base_metadata)
23
- raise ArgumentError, "Metadata not a hash" unless base_metadata.is_a?(Hash)
24
-
25
- @base_metadata = base_metadata.freeze
26
- @sync_allowed = type == "simple" ? true : false
27
- raise Error::InvalidRepoType, type unless Template.config.build_types.include?(type)
14
+ def initialize(*hashes)
15
+ @base_meta = hashes.compact.reduce(:deep_merge).freeze
28
16
  raise Error::RepoNotFound, name unless root.exist?
29
17
  end
30
18
 
31
- def builder
32
- const = Template.const_get(type.capitalize)
33
- const.new(self)
34
- end
35
-
36
- #
19
+ # ----------------------------------------------------------------------
20
+ # Determines whether or not we should (or you should) push the repo.
21
+ # ----------------------------------------------------------------------
37
22
 
38
- def disable_sync!
39
- @sync_allowed = false
23
+ def pushable?
24
+ (metadata["push"] || metadata["push_only"]) && !metadata[
25
+ "cache_only"
26
+ ]
40
27
  end
41
28
 
42
- #
29
+ # ----------------------------------------------------------------------
30
+ # Determines whether or not we should (or you should) cache the repo.
31
+ # ----------------------------------------------------------------------
43
32
 
44
- def syncable?
45
- metadata["dockerhub_copy"] && @sync_allowed
33
+ def cacheable?
34
+ (metadata["cache"] || metadata["cache_only"]) && !metadata[
35
+ "push_only"
36
+ ]
46
37
  end
47
38
 
48
- #
39
+ # ----------------------------------------------------------------------
40
+ # Determines whether or not we should (or you should) build the repo.
41
+ # ----------------------------------------------------------------------
49
42
 
50
- def to_s
51
- "#{user}/#{name}:#{tag}"
43
+ def buildable?
44
+ !metadata["push_only"] && !metadata["cache_only"] && !metadata[
45
+ "clean_only"
46
+ ]
52
47
  end
53
48
 
54
- #
49
+ # ----------------------------------------------------------------------
50
+ # Pulls out the repo this repo is aliasing it, this happens when you
51
+ # when you set the tag in the "alias" section of your `opts.yml`.
52
+ # ----------------------------------------------------------------------
55
53
 
56
- def copy_dir(*path)
57
- dir = metadata["copy_dir"]
58
- root.join(dir, *path)
54
+ def aliased
55
+ if alias?
56
+ self.class.new(to_h.merge({
57
+ "tag" => metadata.aliased_tag
58
+ }))
59
+ end
59
60
  end
60
61
 
61
- #
62
+ # ----------------------------------------------------------------------
63
+ # Initializes and returns the builder so that you can build the repo.
64
+ # ----------------------------------------------------------------------
62
65
 
63
- def building_all?
64
- !@base_metadata.key?("tag")
66
+ def builder
67
+ return @builder ||= begin
68
+ Template.const_get(type.capitalize).new(
69
+ self
70
+ )
71
+ end
65
72
  end
66
73
 
67
- #
74
+ # ----------------------------------------------------------------------
75
+ # Convert the repo into it's final image name, however if you tell, us
76
+ # this is a rootfs build we will convert it into the rootfs name.
77
+ # ----------------------------------------------------------------------
68
78
 
69
- def to_rootfs_s
79
+ def to_s(rootfs: false)
70
80
  prefix = metadata["local_prefix"]
81
+ return "#{user}/#{name}:#{tag}" unless rootfs
71
82
  "#{prefix}/rootfs:#{name}"
72
83
  end
73
84
 
74
- #
85
+ # ----------------------------------------------------------------------
86
+ # The directory you wish to cache to (like `cache/`) or other.
87
+ # ----------------------------------------------------------------------
75
88
 
76
- def root
77
- @root ||= begin
78
- Template.repo_root_for(name)
79
- end
89
+ def cache_dir
90
+ return root.join(
91
+ metadata["cache_dir"], tag
92
+ )
80
93
  end
81
94
 
82
- #
95
+ # ----------------------------------------------------------------------
96
+ # The directory you store your image data in (by default `copy/`.)
97
+ # ----------------------------------------------------------------------
98
+
99
+ def copy_dir(*path)
100
+ dir = metadata["copy_dir"]
101
+ root.join(dir,
102
+ *path
103
+ )
104
+ end
105
+
106
+ # ----------------------------------------------------------------------
83
107
 
84
108
  def to_tag_h
85
109
  {
@@ -89,86 +113,96 @@ module Docker
89
113
  }
90
114
  end
91
115
 
92
- #
116
+ # ----------------------------------------------------------------------
93
117
 
94
118
  def to_rootfs_h
95
- prefix = metadata["local_prefix"]
96
-
97
119
  {
98
120
  "tag" => name,
99
- "repo" => "#{prefix}/rootfs",
121
+ "repo" => "#{metadata["local_prefix"]}/rootfs",
100
122
  "force" => true
101
123
  }
102
124
  end
103
125
 
104
- #
126
+ # ----------------------------------------------------------------------
105
127
 
106
- def tmpdir(*prefixes, root: nil)
107
- prefixes = [user, name, tag] + prefixes
108
- args = ["#{prefixes.join("-")}-", root].delete_if(&:nil?)
109
- Pathname.new(Dir.mktmpdir(*args))
128
+ def tmpdir(*args, root: nil)
129
+ args.unshift(user, name, tag)
130
+ Pathutil.tmpdir(args,
131
+ nil, root
132
+ )
110
133
  end
111
134
 
112
- #
135
+ # ----------------------------------------------------------------------
113
136
 
114
- def tmpfile(*prefixes, root: nil)
115
- prefixes = [user, name, tag] + prefixes
116
- ext = prefixes.pop if prefixes.last =~ /\A\./
117
- prefixes = ["#{prefixes.join("-")}-"]
118
- prefixes = ext ? prefixes.push(ext) : prefixes.first
119
- args = [prefixes, root].delete_if(&:nil?)
120
- Pathname.new(Tempfile.new(*args))
137
+ def tmpfile(*args, root: nil)
138
+ args.unshift(user, name, tag)
139
+ Pathutil.tmpfile(args,
140
+ nil, root
141
+ )
121
142
  end
122
143
 
123
- # If a tag was given then it returns [self] and if a tag was not
124
- # sent it then goes on to detect the type and split itself accordingly
125
- # returning multiple AKA all repos to be built.
144
+ # ----------------------------------------------------------------------
145
+ # If a tag was given then it returns [self] and if a tag was not sent
146
+ # it then goes on to detect the type and split itself accordingly
147
+ # returning multiple, AKA all repos that should be built.
148
+ # ----------------------------------------------------------------------
126
149
 
127
150
  def to_repos
128
- if building_all?
129
- set = Set.new
130
- base = to_h
131
-
151
+ set = Set.new
152
+ if @base_meta.key?("tag")
153
+ set << self
154
+ else
132
155
  tags.each do |tag|
133
- base = base.merge("tag" => tag)
134
- set << self.class.new(base)
156
+ hash = to_h.merge("tag" => tag)
157
+ set << self.class.new(
158
+ hash, @cli_opts
159
+ )
135
160
  end
136
-
137
- set
138
- else
139
- Set.new([
140
- self
141
- ])
142
161
  end
162
+ set
143
163
  end
144
164
 
145
- #
165
+ # ----------------------------------------------------------------------
146
166
 
147
167
  def metadata
148
- @metadata ||= begin
149
- metadata = Template.repo_root_for(name)
150
- metadata = Template.config.read_config_from(metadata)
151
- Metadata.new(metadata).merge(@base_metadata)
168
+ return @metadata ||= begin
169
+ Metadata.new(
170
+ @base_meta
171
+ )
152
172
  end
153
173
  end
154
174
 
155
- #
175
+ # ----------------------------------------------------------------------
156
176
 
157
- def to_env_hash(tar_gz: nil, copy_dir: nil)
158
- metadata["env"].as_hash.merge({
177
+ def to_env(tar_gz: nil, copy_dir: nil)
178
+ hash = metadata["env"] || { "all" => {}}
179
+ Metadata.new(hash, :root => metadata).merge({
159
180
  "REPO" => name,
160
- "NAME" => name,
161
181
  "TAR_GZ" => tar_gz,
162
- "TYPE" => metadata["tags"][tag],
163
- "VERSION" => metadata["version"].fallback,
164
- "PKGS" => metadata["pkgs"].as_string_set,
165
- "RELEASE" => metadata["release"].fallback,
182
+ "GROUP" => metadata.group,
183
+ "COPY_DIR" => copy_dir,
166
184
  "BUILD_TYPE" => type,
167
- "COPY" => copy_dir,
168
- "TAR" => tar_gz,
169
185
  "TAG" => tag
170
- }).to_env
171
- end
186
+ })
187
+ end
188
+
189
+ # ----------------------------------------------------------------------
190
+
191
+ rb_delegate :build, :to => :builder
192
+ rb_delegate :alias?, :to => :metadata
193
+ rb_delegate :complex_alias?, :to => :metadata
194
+ rb_delegate :type, :to => :metadata, :type => :hash
195
+ rb_delegate :user, :to => :metadata, :type => :hash
196
+ rb_delegate :name, :to => :metadata, :type => :hash
197
+ rb_delegate :tag, :to => :metadata, :type => :hash
198
+ rb_delegate :to_h, :to => :@base_meta
199
+ rb_delegate :root, :to => :metadata
200
+ rb_delegate :tags, :to => :metadata
201
+ rb_delegate :clean, {
202
+ :to => Cache, :alias_of => :cleanup, :args => %w(
203
+ self
204
+ )
205
+ }
172
206
  end
173
207
  end
174
208
  end