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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f3b7843f510727766a84aa47a990fa24e1d75db
4
+ data.tar.gz: 385b436c17f1ac1c3dcf71236f0d80c833945384
5
+ SHA512:
6
+ metadata.gz: 4d0e8cb2c9bb3f852be270b072abf34b7cbc8b895d5e3e61c4191af9f21e6e7dacda55e2970b93722add97f0c41e5621d1d5f4a37239274b2ccfb106ced82dcf
7
+ data.tar.gz: f7615f982ea856ee912d46fe5e2973c0a6932f34d61b0f47c176928b01fb07a7ae928b6c2fdfaff116f25e80c1acb431fc96381ee98666ce0d33e28b41d20732
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ source "https://rubygems.org"
6
+ gem "rake", :require => false
7
+ gemspec
8
+
9
+ group :development do
10
+ gem "guard-rspec", :require => false
11
+ gem "benchmark-ips", :require => false
12
+ gem "pry", :require => false
13
+ end
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015 Jordon Bedwell
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ [![Build Status](https://travis-ci.org/envygeeks/docker-template.svg?branch=master)][travis]
2
+ [![Coverage Status](https://coveralls.io/repos/envygeeks/docker-template/badge.svg?branch=master&service=github)][coveralls]
3
+ [![Code Climate](https://codeclimate.com/github/envygeeks/docker-template/badges/gpa.svg)][codeclimate]
4
+
5
+ [codeclimate]: https://codeclimate.com/github/envygeeks/docker-template
6
+ [coveralls]: https://coveralls.io/github/envygeeks/docker-template?branch=master
7
+ [travis]: https://travis-ci.org/envygeeks/docker-template
8
+
9
+ # Docker Template
10
+
11
+ Docker template is a way to organize your Docker repos into multiple types with
12
+ multiple templates for multiple tags but those templates aren't actually templates,
13
+ they are JSON or YAML files and copy folders with tons of shared or split data.
14
+ The idea is that you can have many tags for a single repo and that each tag
15
+ can have many different things going on.
16
+
17
+ Docker template makes it so that you can facilitate and organize those things in
18
+ a clean way and just get work done. It also makes building "scratch" images 100%
19
+ easier for anybody by doing most of the work for you and just asking that you
20
+ build the file system script that pumps out a tar.gz file.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ $:.unshift(File.expand_path("../lib", __FILE__))
6
+ require "rspec/core/rake_task"
7
+ task :default => [:spec]
8
+ RSpec::Core::RakeTask.new :spec
9
+ task :test => :spec
10
+
11
+ task :build do
12
+ exec "bundle", "exec", "bin/docker-template", *ARGV[
13
+ 1..-1
14
+ ]
15
+ end
16
+
17
+ task :pry do
18
+ exec "bundle", "exec", "pry", "-Ilib/", \
19
+ "-rdocker/template"
20
+ end
@@ -0,0 +1,86 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ require "docker/template/version"
6
+ require "docker/template/patches"
7
+
8
+ require "docker"
9
+ require "forwardable"
10
+ require "json"
11
+ require "erb"
12
+
13
+ module Docker
14
+ module Template module_function
15
+ autoload :Util, "docker/template/util"
16
+ autoload :Config, "docker/template/config"
17
+ autoload :Ansi, "docker/template/ansi"
18
+ autoload :Parser, "docker/template/parser"
19
+ autoload :Routable, "docker/template/routable"
20
+ autoload :Interface, "docker/template/interface"
21
+ autoload :Metadata, "docker/template/metadata"
22
+ autoload :Stream, "docker/template/stream"
23
+ autoload :Safe, "docker/template/safe"
24
+ autoload :Repo, "docker/template/repo"
25
+ autoload :Error, "docker/template/error"
26
+ autoload :Common, "docker/template/common"
27
+ autoload :Rootfs, "docker/template/rootfs"
28
+ autoload :Scratch, "docker/template/scratch"
29
+ autoload :Simple, "docker/template/simple"
30
+ autoload :Alias, "docker/template/alias"
31
+ autoload :Auth, "docker/template/auth"
32
+
33
+ def config
34
+ return @config ||= begin
35
+ Config.new
36
+ end
37
+ end
38
+
39
+ #
40
+
41
+ def root
42
+ return @root ||= begin
43
+ Pathname.new(Dir.pwd)
44
+ end
45
+ end
46
+
47
+ # The location of the standard repos/ dir, you can change this by adding
48
+ # `repos_dir` into your configuration file. I'm not saying it has to be but
49
+ # it should probably be relative rather than absolute, ther are no
50
+ # guarantees that an absolute path will work.
51
+
52
+ def repos_root
53
+ return @repos_root ||= begin
54
+ root.join(config["repos_dir"])
55
+ end
56
+ end
57
+
58
+ # Provides the root to Docker template, wherever it is installed so that
59
+ # we can do things, mostly ignore files for the profiler. Otherwise it's
60
+ # not really used, it's just an encapsulator.
61
+
62
+ def gem_root
63
+ return @gem_root ||= begin
64
+ path = File.expand_path("../../", __dir__)
65
+ Pathname.new(path)
66
+ end
67
+ end
68
+
69
+ # Provides the templates directory so you can quickly pull a template
70
+ # from our templates and use it if you wish to.
71
+
72
+ def template_root
73
+ return @template_root ||= begin
74
+ gem_root.join("lib/docker/template/templates")
75
+ end
76
+ end
77
+
78
+ #
79
+
80
+ def get(name, data = {})
81
+ data = Util::Data.new(data)
82
+ template = template_root.join("#{name}.erb").read
83
+ ERB.new(template).result(data._binding)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,28 @@
1
+ module Docker
2
+ module Template
3
+ class Alias
4
+ def initialize(aliased)
5
+ @aliased = aliased
6
+ end
7
+
8
+ #
9
+
10
+ def build
11
+ Util.notify_alias(@aliased)
12
+ prebuild unless @aliased.parent_img
13
+ @aliased.parent_img.tag(@aliased.repo.to_tag_h)
14
+ @aliased.push
15
+ end
16
+
17
+ #
18
+
19
+ private
20
+ def prebuild
21
+ repo = @aliased.parent_repo
22
+ simple = @aliased.repo.type == "simple"
23
+ @aliased.class.new(repo, @aliased.rootfs_img) unless simple
24
+ @aliased.class.new(repo).build if simple
25
+ end
26
+ end
27
+ end
28
+ 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
+ module Ansi module_function
8
+ Escape = "%c" % 27
9
+ Match = /#{Escape}\[(?:\d+)(?:;\d+)?(j|k|m|s|u|A|B)|\e\(B\e\[m/ix.freeze
10
+ Colors = { :red => 31, :green => 32, :black => 30, :magenta => 35,
11
+ :yellow => 33, :white => 37, :blue => 34, :cyan => 36 }
12
+
13
+ # Strip ANSI from the current string. It also strips cursor stuff,
14
+ # well some of it, and it also strips some other stuff that a lot of
15
+ # the other ANSI strippers don't.
16
+
17
+ def strip(str)
18
+ str.gsub Match, ""
19
+ end
20
+
21
+ # Reset the vterm view if it's supported. Depending on how badly
22
+ # your vterm is implemented it might reset rather than clear scrollback
23
+ # with a few empty lines added on the top.
24
+
25
+ def clear
26
+ $stdout.print("%c[H%c[2J" % [27, 27])
27
+ end
28
+
29
+ #
30
+
31
+ def has?(str)
32
+ !!(str =~ Match)
33
+ end
34
+
35
+ # Jump the cursor up and then back down or just up and down. This is
36
+ # useful when streaming async downloads from something like Docker. It
37
+ # also works better than using `tput`
38
+
39
+ def jump(str = "", up: nil, down: nil, both: nil, clear: true)
40
+ str = clear_line(str) if clear
41
+
42
+ return "%c[%dA%s%c[%dB" % [27, up || both, str, 27, down || both] if (up && down) || both
43
+ up ? "%c[%dA%s" % [27, up, str] : "%s%c[%dB" % [str, 27, down]
44
+ end
45
+
46
+ # Reset the color back to the default color so that you do not leak any
47
+ # colors when you move onto the next line. This is probably normally
48
+ # used as part of a wrapper so that we don't leak colors.
49
+
50
+ def reset(str = "")
51
+ @ansi_reset ||= "%c[0m" % 27
52
+ "#{@ansi_reset}#{str}"
53
+ end
54
+
55
+ #
56
+
57
+ def clear_line(str = "")
58
+ @ansi_clear_line ||= "%c[2K\r" % 27
59
+ "#{@ansi_clear_line}#{str}\r"
60
+ end
61
+
62
+ # SEE: `self::Colors` for a list of methods. They are mostly
63
+ # standard base colors supported by pretty much any xterm-color, we do
64
+ # not need more than the base colors so we do not include them.
65
+ # Actually... if I'm honest we don't even need most of the
66
+ # base colors.
67
+
68
+ Colors.each do |color, num|
69
+ define_method color do |str|
70
+ "#{"%c" % 27}[#{num}m#{str}#{reset}"
71
+ end; module_function color
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,25 @@
1
+ module Docker
2
+ module Template
3
+ module Auth
4
+ module_function
5
+
6
+ def auth!
7
+ return unless login = get_info
8
+ login["auths"].each do |server, auth|
9
+ username, password = Base64.decode64(auth["auth"]).split(":", 2)
10
+ Docker.authenticate!({
11
+ "username" => username,
12
+ "serveraddress" => server,
13
+ "email" => auth["email"],
14
+ "password" => password
15
+ })
16
+ end
17
+ end
18
+
19
+ def get_info
20
+ path = Pathname.new("~/.docker/config.json").expand_path
21
+ return JSON.parse(path.read) if path.exist?
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,126 @@
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 Common
8
+ CopyMethods = [
9
+ :setup_context, :copy_global,
10
+ :copy_all, :copy_type, :copy_tag, :build_context,
11
+ :verify_context].freeze
12
+
13
+ def push
14
+ return if rootfs? || !Interface.push?
15
+
16
+ Auth.auth!
17
+ img = @img || Docker::Image.get(@repo.to_s)
18
+ logger = Stream.new.method(:log)
19
+ img.push(&logger)
20
+ end
21
+
22
+ #
23
+
24
+ def aliased?
25
+ @repo.tag != @repo.aliased && !rootfs?
26
+ end
27
+
28
+ #
29
+
30
+ def rootfs?
31
+ false
32
+ end
33
+
34
+ #
35
+
36
+ def parent_repo
37
+ return false unless aliased?
38
+ @parent_repo ||= Repo.new(@repo.to_h.merge({
39
+ "tag" => @repo.aliased
40
+ }))
41
+ end
42
+
43
+ #
44
+
45
+ def parent_img
46
+ return false unless aliased?
47
+ @parent_img ||= Docker::Image.get(parent_repo.to_s)
48
+ rescue Docker::Error::NotFoundError
49
+ if aliased?
50
+ nil
51
+ end
52
+ end
53
+
54
+ #
55
+
56
+ def build
57
+ return Alias.new(self).build if aliased?
58
+
59
+ Ansi.clear
60
+ Util.notify_build(@repo, rootfs: rootfs?)
61
+ logger = Stream.new.method(:log)
62
+ copy_build_and_verify
63
+
64
+ Dir.chdir(@context) do
65
+ @img = Docker::Image.build_from_dir(".", &logger)
66
+ @img.tag rootfs?? @repo.to_rootfs_h : @repo.to_tag_h
67
+ push
68
+ end
69
+ rescue SystemExit => exit_
70
+ unlink img: true
71
+ raise exit_
72
+ ensure
73
+ if rootfs?
74
+ unlink img: false else unlink
75
+ end
76
+ end
77
+
78
+ #
79
+
80
+ private
81
+ def copy_build_and_verify
82
+ unless respond_to?(:setup_context, true)
83
+ raise Error::NoSetupContextFound
84
+ end
85
+
86
+ CopyMethods.each do |val|
87
+ send(val) if respond_to?(val, true)
88
+ end
89
+ end
90
+
91
+ private
92
+ def copy_tag
93
+ return if rootfs?
94
+ dir = @repo.copy_dir("tag", @repo.tag)
95
+ Util::Copy.directory(dir, @copy)
96
+ end
97
+
98
+ #
99
+
100
+ private
101
+ def copy_global
102
+ return if rootfs?
103
+ dir = Template.root.join(@repo.metadata["copy_dir"])
104
+ Util::Copy.directory(dir, @copy)
105
+ end
106
+
107
+ #
108
+
109
+ private
110
+ def copy_type
111
+ return unless !rootfs? && build_type = @repo.metadata["tags"][@repo.tag]
112
+ dir = @repo.copy_dir("type", build_type)
113
+ Util::Copy.directory(dir, @copy)
114
+ end
115
+
116
+ #
117
+
118
+ private
119
+ def copy_all
120
+ return if rootfs?
121
+ dir = @repo.copy_dir("all")
122
+ Util::Copy.directory(dir, @copy)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,84 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Encoding: utf-8
4
+
5
+ require "json"
6
+ require "yaml"
7
+
8
+ module Docker
9
+ module Template
10
+
11
+ # Configuration is a global version of meatadata, where anything
12
+ # that can be set on configuration can be optimized and stored globally
13
+ # in a opts.{json,yml} file in the current working directory.
14
+
15
+ class Config
16
+ extend Forwardable
17
+
18
+ def_delegator :@config, :keys
19
+ def_delegator :@config, :to_h
20
+ def_delegator :@config, :to_enum
21
+ def_delegator :@config, :has_key?
22
+ def_delegator :@config, :each
23
+ def_delegator :@config, :[]
24
+
25
+ Defaults = {
26
+ "type" => "simple",
27
+ "user" => "envygeeks",
28
+ "local_prefix" => "local",
29
+ "rootfs_base_img" => "envygeeks/ubuntu:tiny",
30
+ "maintainer" => "Jordon Bedwell <jordon@envygeeks.io>",
31
+ "dockerhub_copy" => false,
32
+ "repos_dir" => "repos",
33
+ "copy_dir" => "copy",
34
+ "tag" => "latest",
35
+
36
+ "aliases" => {},
37
+ "pkgs" => { "tag" => {}, "type" => {}, "all" => nil },
38
+ "entries" => { "tag" => {}, "type" => {}, "all" => nil },
39
+ "releases" => { "tag" => {}, "type" => {}, "all" => nil },
40
+ "versions" => { "tag" => {}, "type" => {}, "all" => nil },
41
+ "env" => { "tag" => {}, "type" => {}, "all" => nil },
42
+ "tags" => {}
43
+ }.freeze
44
+
45
+ EmptyDefaults = {
46
+ "tags" => { "latest" => "normal" }
47
+ }
48
+
49
+ #
50
+
51
+ def initialize
52
+ @config = Defaults.deep_merge(read_config_from)
53
+ @config = @config.merge(EmptyDefaults) do |key, oval, nval|
54
+ oval.nil? || oval.empty?? nval : oval
55
+ end
56
+
57
+ @config.freeze
58
+ end
59
+
60
+ # Allows you to read a configuration file from a root and get back
61
+ # either the parsed data or a blank hash that can be merged the way you
62
+ # wish to merge it (if you even care to merge it.)
63
+
64
+ def read_config_from(dir = Docker::Template.root)
65
+ file = Dir[dir.join("*.{json,yml}")].first
66
+ return {} unless file && (file = Pathname.new(file)).file?
67
+ return JSON.parse(file.read).stringify if file.extname == ".json"
68
+ YAML.load_file(file).stringify
69
+ end
70
+
71
+ #
72
+
73
+ def has_default?(key)
74
+ return @config.has_key?(key)
75
+ end
76
+
77
+ #
78
+
79
+ def build_types
80
+ return @build_types ||= %W(simple scratch).freeze
81
+ end
82
+ end
83
+ end
84
+ end