docker-template 0.1.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 (43) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE +13 -0
  4. data/README.md +20 -0
  5. data/Rakefile +20 -0
  6. data/lib/docker/template.rb +86 -0
  7. data/lib/docker/template/alias.rb +28 -0
  8. data/lib/docker/template/ansi.rb +75 -0
  9. data/lib/docker/template/auth.rb +25 -0
  10. data/lib/docker/template/common.rb +126 -0
  11. data/lib/docker/template/config.rb +84 -0
  12. data/lib/docker/template/error.rb +20 -0
  13. data/lib/docker/template/error/bad_exit_status.rb +17 -0
  14. data/lib/docker/template/error/bad_repo_name.rb +15 -0
  15. data/lib/docker/template/error/invalid_repo_type.rb +16 -0
  16. data/lib/docker/template/error/invalid_targz_file.rb +15 -0
  17. data/lib/docker/template/error/no_rootfs_copy_dir.rb +15 -0
  18. data/lib/docker/template/error/no_rootfs_mkimg.rb +15 -0
  19. data/lib/docker/template/error/no_setup_context_found.rb +15 -0
  20. data/lib/docker/template/error/not_implemented.rb +15 -0
  21. data/lib/docker/template/error/repo_not_found.rb +16 -0
  22. data/lib/docker/template/interface.rb +119 -0
  23. data/lib/docker/template/metadata.rb +160 -0
  24. data/lib/docker/template/parser.rb +66 -0
  25. data/lib/docker/template/patches.rb +9 -0
  26. data/lib/docker/template/patches/array.rb +11 -0
  27. data/lib/docker/template/patches/hash.rb +76 -0
  28. data/lib/docker/template/patches/object.rb +9 -0
  29. data/lib/docker/template/patches/pathname.rb +46 -0
  30. data/lib/docker/template/patches/string.rb +9 -0
  31. data/lib/docker/template/repo.rb +180 -0
  32. data/lib/docker/template/rootfs.rb +75 -0
  33. data/lib/docker/template/routable.rb +28 -0
  34. data/lib/docker/template/scratch.rb +139 -0
  35. data/lib/docker/template/simple.rb +51 -0
  36. data/lib/docker/template/stream.rb +62 -0
  37. data/lib/docker/template/templates/rootfs.erb +8 -0
  38. data/lib/docker/template/templates/scratch.erb +7 -0
  39. data/lib/docker/template/util.rb +39 -0
  40. data/lib/docker/template/util/copy.rb +82 -0
  41. data/lib/docker/template/util/data.rb +26 -0
  42. data/lib/docker/template/version.rb +9 -0
  43. metadata +155 -0
@@ -0,0 +1,66 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ module Docker
6
+ module Template
7
+ class Parser
8
+ SlashRegexp = /\//.freeze
9
+ SplitRegexp = /:|\//.freeze
10
+ ColonRegexp = /:/.freeze
11
+
12
+ def initialize(argv = [].freeze)
13
+ @argv = argv.freeze
14
+ end
15
+
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
+ def all
21
+ return @argv unless @argv.empty?
22
+ Docker::Template.repos_root.children.map do |path|
23
+ path.basename.to_s
24
+ end
25
+ rescue Errno::ENOENT
26
+ raise Error::RepoNotFound
27
+ end
28
+
29
+ #
30
+
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]
36
+ end
37
+ out
38
+ end
39
+
40
+ #
41
+
42
+ private
43
+ def build_repo_hash(val)
44
+ data, hsh = val.split(SplitRegexp), {}
45
+ if data.size == 1
46
+ hsh["repo"] = data[0]
47
+
48
+ elsif val =~ ColonRegexp && data.size == 2
49
+ hsh["repo"] = data[0]
50
+ hsh[ "tag"] = data[1]
51
+
52
+ elsif val =~ SlashRegexp && data.size == 2
53
+ hsh["user"] = data[0]
54
+ hsh["repo"] = data[1]
55
+
56
+ elsif data.size == 3
57
+ hsh["user"] = data[0]
58
+ hsh["repo"] = data[1]
59
+ hsh[ "tag"] = data[2]
60
+ end
61
+
62
+ hsh
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ require "docker/template/patches/object"
6
+ require "docker/template/patches/array"
7
+ require "docker/template/patches/pathname"
8
+ require "docker/template/patches/string"
9
+ require "docker/template/patches/hash"
@@ -0,0 +1,11 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ class Array
6
+ def stringify
7
+ map do |val|
8
+ val.is_a?(Hash) || val.is_a?(Array) ? val.stringify : val.to_s
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,76 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ class Hash
6
+ def to_env
7
+ inject({}) do |hsh, (key, val)|
8
+ val = val.is_a?(Array) ? val.join(" ") : val.to_s
9
+ key = key.to_s.upcase
10
+ hsh[key] = val
11
+ hsh
12
+ end
13
+ end
14
+
15
+ #
16
+
17
+ def any_keys?(*keys)
18
+ keys.map(&method(:has_key?)).any? do |val|
19
+ val == true
20
+ end
21
+ end
22
+
23
+ #
24
+
25
+ def leftover_keys?(*keys)
26
+ return (self.keys - keys).any?
27
+ end
28
+
29
+ #
30
+
31
+ def has_keys?(*keys)
32
+ return false unless rtn = true && any?
33
+ while rtn && key = keys.shift
34
+ rtn = has_key?(key) || false
35
+ end
36
+
37
+ rtn
38
+ end
39
+
40
+ #
41
+
42
+ def to_env_ary
43
+ inject([]) do |array, (key, val)|
44
+ array.push("#{key}=#{val}")
45
+ end
46
+ end
47
+
48
+ #
49
+
50
+ def deep_merge(newh)
51
+ merge(newh) do |key, oval, nval|
52
+ if oval.is_a?(self.class) && nval.is_a?(self.class)
53
+ then oval.deep_merge(nval) else nval
54
+ end
55
+ end
56
+ end
57
+
58
+ #
59
+
60
+ def stringify
61
+ inject({}) do |hsh, (key, val)|
62
+ hsh[key.to_s] = val.is_a?(Array) || val.is_a?(Hash) ? val.stringify : val.to_s
63
+ hsh
64
+ end
65
+ end
66
+
67
+ #
68
+
69
+ def stringify_keys
70
+ inject({}) do |hsh, (key, val)|
71
+ hsh[key.to_s] = val
72
+
73
+ hsh
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,9 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ class Object
6
+ def to_pathname
7
+ Object::Pathname.new(self)
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ class Pathname
6
+ def in_path?(path)
7
+ path_str = path.is_a?(self.class) ? path.expanded_realpath.to_s : path.to_s
8
+ expanded_realpath.to_s.start_with?(path_str)
9
+ end
10
+
11
+ #
12
+
13
+ def write(data)
14
+ File.write(self.to_s, data)
15
+ end
16
+
17
+ #
18
+
19
+ def expanded_path
20
+ @expanded_path ||= begin
21
+ expand_path Dir.pwd
22
+ end
23
+ end
24
+
25
+ #
26
+
27
+ def expanded_realpath
28
+ return @expanded_real_path ||= begin
29
+ expanded_path.realpath
30
+ end
31
+ end
32
+
33
+ #
34
+
35
+ def all_children
36
+ glob "**/*"
37
+ end
38
+
39
+ #
40
+
41
+ def glob(*args)
42
+ Dir.glob(self.join(*args)).map do |path|
43
+ self.class.new(path)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,9 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ class String
6
+ def to_a
7
+ split " "
8
+ end
9
+ end
@@ -0,0 +1,180 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ module Docker
6
+ 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
+ class Repo
13
+ extend Forwardable, Routable
14
+
15
+ route_to_hash :name, :@base_metadata, :repo
16
+ route_to_hash [:tag, :type, :user], :metadata
17
+ def_delegator :@base_metadata, :to_h
18
+ def_delegator :metadata, :aliased
19
+ def_delegator :metadata, :tags
20
+
21
+ def initialize(base_metadata)
22
+ raise ArgumentError, "Metadata not a hash" if !base_metadata.is_a?(Hash)
23
+
24
+ @base_metadata = base_metadata.freeze
25
+ @sync_allowed = type == "simple" ? true : false
26
+ raise Error::InvalidRepoType, type if !Template.config.build_types.include?(type)
27
+ raise Error::RepoNotFound, name if !root.exist?
28
+ end
29
+
30
+ def builder
31
+ const = Template.const_get(type.capitalize)
32
+ const.new(self)
33
+ end
34
+
35
+ # Simply initializes the the builder and passes itself onto
36
+ # it so that it the builder can take over and do it's job cleanly
37
+ # without us needing to care about what's going on.
38
+
39
+ def build
40
+ return builder.build
41
+ end
42
+
43
+ #
44
+
45
+ def disable_sync!
46
+ @sync_allowed = false
47
+ end
48
+
49
+ #
50
+
51
+ def syncable?
52
+ metadata["dockerhub_copy"] && @sync_allowed
53
+ end
54
+
55
+ #
56
+
57
+ def to_s
58
+ "#{user}/#{name}:#{tag}"
59
+ end
60
+
61
+ #
62
+
63
+ def copy_dir(*path)
64
+ dir = metadata["copy_dir"]
65
+ root.join(dir, *path)
66
+ end
67
+
68
+ #
69
+
70
+ def building_all?
71
+ !@base_metadata.has_key?("tag")
72
+ end
73
+
74
+ #
75
+
76
+ def to_rootfs_s
77
+ prefix = metadata["local_prefix"]
78
+ "#{prefix}/rootfs:#{name}"
79
+ end
80
+
81
+ #
82
+
83
+ def root
84
+ return @root ||= begin
85
+ Template.repos_root.join(name)
86
+ end
87
+ end
88
+
89
+ #
90
+
91
+ def to_tag_h
92
+ {
93
+ "force" => true,
94
+ "repo" => "#{user}/#{name}",
95
+ "tag" => tag,
96
+ }
97
+ end
98
+
99
+ #
100
+
101
+ def to_rootfs_h
102
+ prefix = metadata["local_prefix"]
103
+
104
+ {
105
+ "force" => true,
106
+ "repo" => "#{prefix}/rootfs",
107
+ "tag" => name
108
+ }
109
+ end
110
+
111
+ #
112
+
113
+ def tmpdir(*prefixes, root: nil)
114
+ prefixes = [user, name, tag] + prefixes
115
+ args = ["#{prefixes.join("-")}-", root].delete_if(&:nil?)
116
+ Pathname.new(Dir.mktmpdir(*args))
117
+ end
118
+
119
+ #
120
+
121
+ def tmpfile(*prefixes, root: nil)
122
+ prefixes = [user, name, tag] + prefixes
123
+ ext = prefixes.pop if prefixes.last =~ /\A\./
124
+ prefixes = ["#{prefixes.join("-")}-"]
125
+ prefixes = ext ? prefixes.push(ext) : prefixes.first
126
+ args = [prefixes, root].delete_if(&:nil?)
127
+ Pathname.new(Tempfile.new(*args))
128
+ end
129
+
130
+ # If a tag was given then it returns [self] and if a tag was not
131
+ # sent it then goes on to detect the type and split itself accordingly
132
+ # returning multiple AKA all repos to be built.
133
+
134
+ def to_repos
135
+ if building_all?
136
+ base, set = to_h, Set.new
137
+ tags.each do |tag|
138
+ set.add(self.class.new(base.merge({
139
+ "tag" => tag
140
+ })))
141
+ end
142
+
143
+ set
144
+ else
145
+ Set.new([
146
+ self
147
+ ])
148
+ end
149
+ end
150
+
151
+ #
152
+
153
+ def metadata
154
+ return @metadata ||= begin
155
+ metadata = Template.repos_root.join(name)
156
+ metadata = Template.config.read_config_from(metadata)
157
+ Metadata.new(metadata).merge(@base_metadata)
158
+ end
159
+ end
160
+
161
+ #
162
+
163
+ def to_env_hash(tar_gz: nil, copy_dir: nil)
164
+ metadata["env"].as_hash.merge({
165
+ "REPO" => name,
166
+ "NAME" => name,
167
+ "TAR_GZ" => tar_gz,
168
+ "TYPE" => metadata["tags"][tag],
169
+ "VERSION" => metadata["version"].fallback,
170
+ "PKGS" => metadata["pkgs"].as_string_set,
171
+ "RELEASE" => metadata["release"].fallback,
172
+ "BUILD_TYPE" => type,
173
+ "COPY" => copy_dir,
174
+ "TAR" => tar_gz,
175
+ "TAG" => tag,
176
+ }).to_env
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,75 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ module Docker
6
+ module Template
7
+ class Rootfs < Common
8
+ attr_reader :img
9
+ def initialize(repo)
10
+ @repo = repo
11
+ end
12
+
13
+ #
14
+
15
+ def rootfs?
16
+ true
17
+ end
18
+
19
+ #
20
+
21
+ def data
22
+ Template.get(:rootfs, {
23
+ :rootfs_base_img => @repo.metadata["rootfs_base_img"]
24
+ })
25
+ end
26
+
27
+ # In a typical situation we do not remove the rootfs img and don't
28
+ # recommend removing it as it's better cached by Docker, if you wish
29
+ # to delete it we will. Now, here we only remove it if we get told
30
+ # to exit, since we will be in the middle of a build and probably
31
+ # not have tagged yet, unless we are downstream, we will remove
32
+ # it so you have no broken images on your system.
33
+
34
+ def unlink(img: true)
35
+ keep = @repo.metadata["keep_rootfs"]
36
+ @img.delete "force" => true if img && @img && !keep
37
+ @context.rmtree if @context && @context.directory?
38
+ rescue Docker::Error::NotFoundError
39
+ nil
40
+ end
41
+
42
+ #
43
+
44
+ private
45
+ def setup_context
46
+ @context = @repo.tmpdir("rootfs")
47
+ @context.join("Dockerfile").write(data)
48
+ @copy = @context.join(@repo.metadata["copy_dir"])
49
+ @copy.mkdir
50
+ copy_rootfs
51
+ end
52
+
53
+ #
54
+
55
+ private
56
+ def copy_rootfs
57
+ dir = @repo.copy_dir("rootfs")
58
+ Util::Copy.new(dir, @copy).directory
59
+ rescue Errno::ENOENT => error_
60
+ if error_.message !~ /\/(copy|rootfs)\Z/
61
+ raise error_ else raise Error::NoRootfsCopyDir
62
+ end
63
+ end
64
+
65
+ #
66
+
67
+ private
68
+ def verify_context
69
+ unless @copy.join("usr/local/bin/mkimg").file?
70
+ raise Error::NoRootfsMkimg
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end