docker-template 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +13 -0
- data/LICENSE +13 -0
- data/README.md +20 -0
- data/Rakefile +20 -0
- data/lib/docker/template.rb +86 -0
- data/lib/docker/template/alias.rb +28 -0
- data/lib/docker/template/ansi.rb +75 -0
- data/lib/docker/template/auth.rb +25 -0
- data/lib/docker/template/common.rb +126 -0
- data/lib/docker/template/config.rb +84 -0
- data/lib/docker/template/error.rb +20 -0
- data/lib/docker/template/error/bad_exit_status.rb +17 -0
- data/lib/docker/template/error/bad_repo_name.rb +15 -0
- data/lib/docker/template/error/invalid_repo_type.rb +16 -0
- data/lib/docker/template/error/invalid_targz_file.rb +15 -0
- data/lib/docker/template/error/no_rootfs_copy_dir.rb +15 -0
- data/lib/docker/template/error/no_rootfs_mkimg.rb +15 -0
- data/lib/docker/template/error/no_setup_context_found.rb +15 -0
- data/lib/docker/template/error/not_implemented.rb +15 -0
- data/lib/docker/template/error/repo_not_found.rb +16 -0
- data/lib/docker/template/interface.rb +119 -0
- data/lib/docker/template/metadata.rb +160 -0
- data/lib/docker/template/parser.rb +66 -0
- data/lib/docker/template/patches.rb +9 -0
- data/lib/docker/template/patches/array.rb +11 -0
- data/lib/docker/template/patches/hash.rb +76 -0
- data/lib/docker/template/patches/object.rb +9 -0
- data/lib/docker/template/patches/pathname.rb +46 -0
- data/lib/docker/template/patches/string.rb +9 -0
- data/lib/docker/template/repo.rb +180 -0
- data/lib/docker/template/rootfs.rb +75 -0
- data/lib/docker/template/routable.rb +28 -0
- data/lib/docker/template/scratch.rb +139 -0
- data/lib/docker/template/simple.rb +51 -0
- data/lib/docker/template/stream.rb +62 -0
- data/lib/docker/template/templates/rootfs.erb +8 -0
- data/lib/docker/template/templates/scratch.erb +7 -0
- data/lib/docker/template/util.rb +39 -0
- data/lib/docker/template/util/copy.rb +82 -0
- data/lib/docker/template/util/data.rb +26 -0
- data/lib/docker/template/version.rb +9 -0
- metadata +155 -0
@@ -0,0 +1,20 @@
|
|
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
|
+
module Error
|
8
|
+
const_set :StandardError, Class.new(StandardError)
|
9
|
+
autoload :BadRepoName, "docker/template/error/bad_repo_name"
|
10
|
+
autoload :BadExitStatus, "docker/template/error/bad_exit_status"
|
11
|
+
autoload :InvalidTargzFile, "docker/template/error/invalid_targz_file"
|
12
|
+
autoload :NoSetupContextFound, "docker/template/error/no_setup_context_found"
|
13
|
+
autoload :NoRootfsCopyDir, "docker/template/error/no_rootfs_copy_dir"
|
14
|
+
autoload :InvalidRepoType, "docker/template/error/invalid_repo_type"
|
15
|
+
autoload :NoRootfsMkimg, "docker/template/error/no_rootfs_mkimg"
|
16
|
+
autoload :NotImplemented, "docker/template/error/not_implemented"
|
17
|
+
autoload :RepoNotFound, "docker/template/error/repo_not_found"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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
|
+
module Error
|
8
|
+
class BadExitStatus < StandardError
|
9
|
+
attr_reader :status
|
10
|
+
|
11
|
+
def initialize(status)
|
12
|
+
super "Got bad exit status #{@status = status}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module Error
|
8
|
+
class BadRepoName < StandardError
|
9
|
+
def initialize(name)
|
10
|
+
super "Only a-z0-9_- are allowed. Invalid repo name: #{name}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
+
module Error
|
8
|
+
class InvalidRepoType < StandardError
|
9
|
+
def initialize(type)
|
10
|
+
build_types = Template.config.build_types.join(", ")
|
11
|
+
super "Uknown repo type given '#{type}' not in '#{build_types}'"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module Error
|
8
|
+
class InvalidTargzFile < StandardError
|
9
|
+
def initialize(tar_gz)
|
10
|
+
super "No data was given to the tar.gz file '#{tar_gz.basename}'"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module Error
|
8
|
+
class NoRootfsCopyDir < StandardError
|
9
|
+
def initialize
|
10
|
+
super "Unable to find your rootfs copy folder."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module Error
|
8
|
+
class NoRootfsMkimg < StandardError
|
9
|
+
def initialize
|
10
|
+
super "Unable to find a mkimg in your rootfs folder."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module Error
|
8
|
+
class NoSetupContextFound < StandardError
|
9
|
+
def initialize
|
10
|
+
super "No #setup_context found."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module Error
|
8
|
+
class NotImplemented < StandardError
|
9
|
+
def initialize
|
10
|
+
super "The feature is not implemented yet, sorry about that."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
+
module Error
|
8
|
+
class RepoNotFound < StandardError
|
9
|
+
def initialize(repo = nil)
|
10
|
+
ending = repo ? "the repo '#{repo}'" : "your repo folder"
|
11
|
+
super "Unable to find #{ending}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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 Interface
|
8
|
+
def initialize(argv = [])
|
9
|
+
@argv = argv
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
|
14
|
+
def self.push?
|
15
|
+
ARGV.include?("--push")
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
|
20
|
+
def run
|
21
|
+
unless only_sync?
|
22
|
+
Parser.new(argv_without_flags).parse.map do |repo|
|
23
|
+
repo.disable_sync! if wants_sync?
|
24
|
+
repo.build
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
sync
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
|
33
|
+
private
|
34
|
+
def sync
|
35
|
+
if wants_sync?
|
36
|
+
Parser.new.parse.each do |repo|
|
37
|
+
next unless repo.syncable?
|
38
|
+
repo.builder.tap(&:sync). \
|
39
|
+
unlink(sync: false)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
|
46
|
+
private
|
47
|
+
def argv_without_flags
|
48
|
+
return @argv.select do |val|
|
49
|
+
!["--sync", "--push"].include?(val)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
|
55
|
+
private
|
56
|
+
def only_sync?
|
57
|
+
@argv == [
|
58
|
+
"--sync"
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
|
64
|
+
private
|
65
|
+
def wants_sync?
|
66
|
+
@argv.include?("--sync")
|
67
|
+
end
|
68
|
+
|
69
|
+
# Determine whether we are the Docker bin so that we can transform
|
70
|
+
# based on that... for example we will pass on commands to `docker` if
|
71
|
+
# we are running as the `docker` binary in place of `docker`.
|
72
|
+
|
73
|
+
private
|
74
|
+
def self.bin?(bin)
|
75
|
+
!bin ? false : File.basename(bin.to_s) == "docker"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Discover the Docker bin using Ruby. This is a highly unoptimized
|
79
|
+
# method and needs to be reworked because it's pretty trashy shit and
|
80
|
+
# it's just flat out ugly to look at, make it better than it is.
|
81
|
+
|
82
|
+
private
|
83
|
+
def self.discover
|
84
|
+
rtn = bins.select do |path|
|
85
|
+
path.basename.fnmatch?("docker") && path.executable_real?
|
86
|
+
end.first
|
87
|
+
|
88
|
+
if rtn
|
89
|
+
rtn.to_s
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
|
95
|
+
private
|
96
|
+
def self.start(zero)
|
97
|
+
return new(ARGV[1..-1]).run if ARGV[0] == "template" && bin?(zero)
|
98
|
+
return new(ARGV).run unless bin?(zero)
|
99
|
+
|
100
|
+
exe = discover
|
101
|
+
exec exe.to_s, *ARGV if exe
|
102
|
+
abort "No Docker."
|
103
|
+
rescue Error::StandardError => error_
|
104
|
+
$stderr.puts Ansi.red(error_.message)
|
105
|
+
$stderr.puts Ansi.red("Aborting your build. Bye and good luck.")
|
106
|
+
exit error_.respond_to?(:status) ? error_.status.to_i : 1
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
|
111
|
+
private
|
112
|
+
def self.bins
|
113
|
+
ENV["PATH"].split(":").each_with_object(Set.new) do |val, array|
|
114
|
+
array.merge(Pathname.new(val).children) rescue next
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,160 @@
|
|
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 Metadata
|
8
|
+
extend Forwardable, Routable
|
9
|
+
|
10
|
+
# Provides aliases for the root element so you can do something like:
|
11
|
+
# * data["release"].fallback
|
12
|
+
|
13
|
+
Aliases = {
|
14
|
+
"entry" => "entries",
|
15
|
+
"release" => "releases",
|
16
|
+
"version" => "versions",
|
17
|
+
"script" => "scripts",
|
18
|
+
"image" => "images"
|
19
|
+
}
|
20
|
+
|
21
|
+
def_delegator :@metadata, :keys
|
22
|
+
def_delegator :@metadata, :size
|
23
|
+
def_delegator :@metadata, :to_enum
|
24
|
+
def_delegator :@metadata, :has_key?
|
25
|
+
def_delegator :@metadata, :inspect
|
26
|
+
def_delegator :@metadata, :delete
|
27
|
+
def_delegator :@metadata, :each
|
28
|
+
def_delegator :@metadata, :to_h
|
29
|
+
route_to_ivar :is_root, :@is_root, bool: true
|
30
|
+
route_to_hash :for_all, :self, :all
|
31
|
+
|
32
|
+
def initialize(metadata, root_metadata = metadata)
|
33
|
+
@is_root = metadata == root_metadata
|
34
|
+
@root_metadata = root_metadata || {}
|
35
|
+
@metadata = metadata || {}
|
36
|
+
|
37
|
+
if is_root?
|
38
|
+
@base = Template.config
|
39
|
+
@root_metadata = @metadata
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
|
45
|
+
def aliased
|
46
|
+
aliases = from_root("aliases")
|
47
|
+
tag = from_root("tag")
|
48
|
+
|
49
|
+
if aliases.has_key?(tag)
|
50
|
+
return aliases[tag]
|
51
|
+
end
|
52
|
+
tag
|
53
|
+
end
|
54
|
+
|
55
|
+
# Queries providing a default value if on the root repo hash otherwise
|
56
|
+
# returning the returned value, as a `self.class` if it's a Hash.
|
57
|
+
|
58
|
+
def [](key)
|
59
|
+
key = determine_key(key)
|
60
|
+
val = @metadata[key]
|
61
|
+
|
62
|
+
return try_default(key) if !val && is_root?
|
63
|
+
return self.class.new(val, @root_metadata) if val.is_a?(Hash)
|
64
|
+
val
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
|
69
|
+
def tags
|
70
|
+
self["tags"].keys + self["aliases"].keys
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
|
75
|
+
def merge(_new)
|
76
|
+
@metadata.merge!(_new)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
|
82
|
+
def as_string_set
|
83
|
+
as_set.to_a.join(" ")
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
|
88
|
+
def as_hash
|
89
|
+
{}.merge(for_all.to_h). \
|
90
|
+
merge(by_type.to_h). \
|
91
|
+
merge(by_tag. to_h)
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
|
96
|
+
def as_set
|
97
|
+
Set.new. \
|
98
|
+
merge(for_all.to_a). \
|
99
|
+
merge(by_type.to_a). \
|
100
|
+
merge(by_tag .to_a)
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
|
105
|
+
def from_root(key)
|
106
|
+
root = self.class.new(@root_metadata)
|
107
|
+
root[key]
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
|
112
|
+
def fallback
|
113
|
+
by_tag || by_type || for_all
|
114
|
+
end
|
115
|
+
|
116
|
+
# Pulls data based on the given tag through anything that provides a
|
117
|
+
# "tag" key with the given tags. ("tags" is a `Hash`)
|
118
|
+
|
119
|
+
def by_tag
|
120
|
+
return unless tag = aliased
|
121
|
+
return unless has_key?("tag")
|
122
|
+
hash = self["tag"]
|
123
|
+
hash[tag]
|
124
|
+
end
|
125
|
+
|
126
|
+
# Pull data based on the type given in { "tags" => { tag => type }}
|
127
|
+
# through anything that provides a "type" key with the type as a
|
128
|
+
# sub-key and the values.
|
129
|
+
|
130
|
+
def by_type
|
131
|
+
return unless tag = aliased
|
132
|
+
type = @root_metadata["tags"][tag]
|
133
|
+
return unless has_key?("type")
|
134
|
+
return unless type
|
135
|
+
|
136
|
+
hash = self["type"]
|
137
|
+
hash[type]
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
|
142
|
+
private
|
143
|
+
def determine_key(key)
|
144
|
+
if is_root? && !has_key?(key) && Aliases.has_key?(key)
|
145
|
+
key = Aliases[key]
|
146
|
+
end
|
147
|
+
key
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
|
152
|
+
private
|
153
|
+
def try_default(key)
|
154
|
+
val = @base[key]
|
155
|
+
return self.class.new(val, @root_metadata) if val.is_a?(Hash)
|
156
|
+
val
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|