docker-template 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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