docker-template 0.1.0

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