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