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.
- 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
|