dapp 0.2.8 → 0.3.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 (49) hide show
  1. checksums.yaml +8 -8
  2. data/config/en/common.yml +3 -1
  3. data/config/en/net_status.yml +5 -2
  4. data/lib/dapp.rb +9 -6
  5. data/lib/dapp/application.rb +30 -5
  6. data/lib/dapp/application/logging.rb +2 -2
  7. data/lib/dapp/application/path.rb +10 -6
  8. data/lib/dapp/build/stage/base.rb +77 -9
  9. data/lib/dapp/build/stage/chef_cookbooks.rb +1 -1
  10. data/lib/dapp/build/stage/from.rb +2 -1
  11. data/lib/dapp/build/stage/infra_install.rb +1 -1
  12. data/lib/dapp/build/stage/source_1.rb +1 -1
  13. data/lib/dapp/build/stage/source_1_archive.rb +0 -4
  14. data/lib/dapp/build/stage/source_2.rb +1 -1
  15. data/lib/dapp/build/stage/source_3.rb +1 -1
  16. data/lib/dapp/build/stage/source_base.rb +3 -3
  17. data/lib/dapp/builder/chef.rb +160 -140
  18. data/lib/dapp/cli.rb +2 -1
  19. data/lib/dapp/cli/base.rb +1 -1
  20. data/lib/dapp/cli/build.rb +7 -7
  21. data/lib/dapp/cli/flush.rb +3 -3
  22. data/lib/dapp/cli/flush/{build_cache.rb → metadata.rb} +7 -7
  23. data/lib/dapp/cli/flush/{stage_cache.rb → stages.rb} +4 -4
  24. data/lib/dapp/cli/push.rb +3 -3
  25. data/lib/dapp/cli/run.rb +59 -0
  26. data/lib/dapp/config/application.rb +20 -2
  27. data/lib/dapp/config/artifact.rb +69 -0
  28. data/lib/dapp/config/chef.rb +27 -0
  29. data/lib/dapp/config/docker.rb +1 -1
  30. data/lib/dapp/config/git_artifact.rb +3 -29
  31. data/lib/dapp/config/shell.rb +20 -0
  32. data/lib/dapp/controller.rb +21 -22
  33. data/lib/dapp/exception/base.rb +1 -5
  34. data/lib/dapp/filelock.rb +1 -1
  35. data/lib/dapp/git_artifact.rb +2 -2
  36. data/lib/dapp/git_repo/base.rb +5 -5
  37. data/lib/dapp/git_repo/own.rb +6 -2
  38. data/lib/dapp/git_repo/remote.rb +5 -3
  39. data/lib/dapp/helper/cli.rb +7 -1
  40. data/lib/dapp/helper/log.rb +2 -2
  41. data/lib/dapp/helper/shellout.rb +1 -1
  42. data/lib/dapp/helper/trivia.rb +0 -4
  43. data/lib/dapp/image/arguments.rb +115 -0
  44. data/lib/dapp/image/docker.rb +76 -0
  45. data/lib/dapp/image/stage.rb +74 -0
  46. data/lib/dapp/version.rb +1 -1
  47. metadata +9 -6
  48. data/lib/dapp/docker_image.rb +0 -51
  49. data/lib/dapp/stage_image.rb +0 -160
@@ -15,52 +15,51 @@ module Dapp
15
15
 
16
16
  paint_initialize
17
17
  Helper::I18n.initialize
18
- build_confs
18
+ end
19
+
20
+ def run(docker_options, command)
21
+ raise Error::Controller, code: :run_command_unexpected_apps_number unless build_configs.one?
22
+ Application.new(config: build_configs.first, cli_options: cli_options, ignore_git_fetch: true).run(docker_options, command)
19
23
  end
20
24
 
21
25
  def build
22
- build_confs.each do |build_conf|
23
- log_step(build_conf._name)
24
- with_log_indent { Application.new(config: build_conf, cli_options: cli_options).build! }
25
- end
26
+ build_configs.each { |config| Application.new(config: config, cli_options: cli_options).build! }
26
27
  end
27
28
 
28
29
  def list
29
- build_confs.each do |build_conf|
30
- log(build_conf._name)
31
- end
30
+ build_configs.each { |config| log(config._name) }
32
31
  end
33
32
 
34
33
  def push(repo)
35
- raise Error::Controller, code: :push_command_unexpected_apps unless @build_confs.one?
36
- Application.new(config: @build_confs.first, cli_options: cli_options, ignore_git_fetch: true).export!(repo)
34
+ raise Error::Controller, code: :push_command_unexpected_apps_number unless build_configs.one?
35
+ Application.new(config: build_configs.first, cli_options: cli_options, ignore_git_fetch: true).export!(repo)
37
36
  end
38
37
 
39
38
  def smartpush(repo_prefix)
40
- build_confs.each do |build_conf|
41
- log_step(build_conf._name)
42
- repo = File.join(repo_prefix, build_conf._name)
43
- with_log_indent { Application.new(config: build_conf, cli_options: cli_options, ignore_git_fetch: true).export!(repo) }
39
+ build_configs.each do |config|
40
+ log_step(config._name)
41
+ repo = File.join(repo_prefix, config._name)
42
+ with_log_indent { Application.new(config: config, cli_options: cli_options, ignore_git_fetch: true).export!(repo) }
44
43
  end
45
44
  end
46
45
 
47
- def flush_build_cache
48
- build_confs.each do |build_conf|
49
- log(build_conf._name)
50
- app = Application.new(config: build_conf, cli_options: cli_options, ignore_git_fetch: true)
51
- FileUtils.rm_rf app.build_cache_path
46
+ def flush_metadata
47
+ build_configs.each do |config|
48
+ log(config._name)
49
+ app = Application.new(config: config, cli_options: cli_options, ignore_git_fetch: true)
50
+ FileUtils.rm_rf app.metadata_path
52
51
  end
53
52
  end
54
53
 
55
- def self.flush_stage_cache
54
+ def self.flush_stages
56
55
  shellout('docker rmi $(docker images --format="{{.Repository}}:{{.Tag}}" dapp)')
57
56
  shellout('docker rmi $(docker images -f "dangling=true" -q)')
58
57
  end
59
58
 
60
59
  private
61
60
 
62
- def build_confs
63
- @build_confs ||= begin
61
+ def build_configs
62
+ @configs ||= begin
64
63
  if File.exist? dappfile_path
65
64
  dappfiles = dappfile_path
66
65
  elsif (dappfiles = dapps_dappfiles_pathes).empty? && (dappfiles = search_dappfile_up).nil?
@@ -1,10 +1,6 @@
1
1
  module Dapp
2
2
  module Exception
3
3
  # Base
4
- class Base < NetStatus::Exception
5
- def initialize(net_status = {})
6
- super(net_status.merge(context: self.class.to_s.split('::').last.downcase))
7
- end
8
- end
4
+ class Base < Error::Base; end
9
5
  end
10
6
  end
@@ -28,7 +28,7 @@ module Dapp
28
28
  protected
29
29
 
30
30
  def filelock_lockfile(filelock, error_message: 'Already in use!', timeout: 10)
31
- File.open(build_path(filelock), File::RDWR | File::CREAT, 0o644) do |file|
31
+ File.open(home_path(filelock), File::RDWR | File::CREAT, 0o644) do |file|
32
32
  Timeout.timeout(timeout) do
33
33
  file.flock(File::LOCK_EX)
34
34
  end
@@ -26,7 +26,7 @@ module Dapp
26
26
  credentials = [:owner, :group].map { |attr| "--#{attr}=#{send(attr)}" unless send(attr).nil? }.compact
27
27
 
28
28
  ["install #{credentials.join(' ')} -d #{where_to_add}",
29
- ["git --git-dir=#{repo.container_build_dir_path} archive #{stage.layer_commit(self)}:#{cwd} #{paths}",
29
+ ["git --git-dir=#{repo.container_path} archive #{stage.layer_commit(self)}:#{cwd} #{paths}",
30
30
  "#{sudo}tar -x -C #{where_to_add}"].join(' | ')]
31
31
  end
32
32
 
@@ -35,7 +35,7 @@ module Dapp
35
35
  prev_commit = stage.prev_source_stage.layer_commit(self)
36
36
 
37
37
  if prev_commit != current_commit || any_changes?(prev_commit, current_commit)
38
- [["git --git-dir=#{repo.container_build_dir_path} #{diff_command(prev_commit, current_commit)}",
38
+ [["git --git-dir=#{repo.container_path} #{diff_command(prev_commit, current_commit)}",
39
39
  "#{sudo}git apply --whitespace=nowarn --directory=#{where_to_add} " \
40
40
  '$(if [[ "$(git --version)" != "git version 1."* ]]; then echo "--unsafe-paths"; fi)'].join(' | ')] # FIXME
41
41
  else
@@ -10,16 +10,16 @@ module Dapp
10
10
  @name = name
11
11
  end
12
12
 
13
- def container_build_dir_path
14
- application.container_build_path "#{name}.git"
13
+ def container_path
14
+ application.container_tmp_path "#{name}.git"
15
15
  end
16
16
 
17
- def dir_path
18
- application.build_path "#{name}.git"
17
+ def path
18
+ application.tmp_path "#{name}.git"
19
19
  end
20
20
 
21
21
  def git_bare(command, **kwargs)
22
- git "--git-dir=#{dir_path} #{command}", **kwargs
22
+ git "--git-dir=#{path} #{command}", **kwargs
23
23
  end
24
24
 
25
25
  def commit_at(commit)
@@ -6,8 +6,12 @@ module Dapp
6
6
  super(application, 'own')
7
7
  end
8
8
 
9
- def dir_path
10
- @dir_path ||= Pathname(git("-C #{application.home_path} rev-parse --git-dir").stdout.strip).expand_path
9
+ def container_path
10
+ application.container_dapp_path('own', "#{name}.git")
11
+ end
12
+
13
+ def path
14
+ @path ||= Pathname(git("-C #{application.home_path} rev-parse --git-dir").stdout.strip).expand_path
11
15
  end
12
16
 
13
17
  def latest_commit(branch = nil)
@@ -12,8 +12,10 @@ module Dapp
12
12
  File.chmod(0o600, @ssh_key_path) if @ssh_key_path
13
13
 
14
14
  with_ssh_key do
15
- git "clone --bare --depth 1 #{url} #{dir_path}"
16
- end unless File.directory? dir_path
15
+ application.log_secondary_process(application.t(code: 'process.git_artifact_clone', data: { name: name }), short: true) do
16
+ git "clone --bare --depth 1 #{url} #{path}"
17
+ end
18
+ end unless File.directory?(path)
17
19
  end
18
20
 
19
21
  def fetch!(branch = 'master')
@@ -26,7 +28,7 @@ module Dapp
26
28
 
27
29
  def cleanup!
28
30
  super
29
- FileUtils.rm_rf dir_path
31
+ FileUtils.rm_rf path
30
32
  end
31
33
 
32
34
  protected
@@ -3,7 +3,13 @@ module Dapp
3
3
  # Cli
4
4
  module Cli
5
5
  def parse_options(cli, argv)
6
- cli.parse_options(argv)
6
+ cli_wrapper(cli) do
7
+ cli.parse_options(argv)
8
+ end
9
+ end
10
+
11
+ def cli_wrapper(cli)
12
+ yield
7
13
  rescue OptionParser::MissingArgument, OptionParser::InvalidOption, OptionParser::InvalidArgument => e
8
14
  STDERR.puts "Error: #{e.message}"
9
15
  puts cli.opt_parser
@@ -34,9 +34,9 @@ module Dapp
34
34
  end.join
35
35
  end
36
36
 
37
- def log_with_indent(message = '', **kvargs)
37
+ def log_with_indent(message = '', **kwargs)
38
38
  with_log_indent do
39
- log(message, **kvargs)
39
+ log(message, **kwargs)
40
40
  end
41
41
  end
42
42
 
@@ -34,7 +34,7 @@ module Dapp
34
34
  end
35
35
 
36
36
  def shellout_pack(command)
37
- "bash -ec 'eval $(echo #{Base64.strict_encode64(command)} | base64 --decode)'"
37
+ "-ec 'eval $(echo #{Base64.strict_encode64(command)} | base64 --decode)'"
38
38
  end
39
39
 
40
40
  def self.included(base)
@@ -15,10 +15,6 @@ module Dapp
15
15
  path.delete if path.exist?
16
16
  end
17
17
 
18
- def to_mb(bytes)
19
- (bytes / 1024.0 / 1024.0).round(2)
20
- end
21
-
22
18
  def self.class_to_lowercase(class_name = self.class)
23
19
  class_name.to_s.split('::').last.split(/(?=[[:upper:]]|[0-9])/).join('_').downcase.to_s
24
20
  end
@@ -0,0 +1,115 @@
1
+ module Dapp
2
+ module Image
3
+ # Arguments
4
+ module Arguments
5
+ def add_change_volume(value)
6
+ add_change_option(:volume, value)
7
+ end
8
+
9
+ def add_change_expose(value)
10
+ add_change_option(:expose, value)
11
+ end
12
+
13
+ def add_change_env(value)
14
+ add_change_option(:env, value)
15
+ end
16
+
17
+ def add_change_label(value)
18
+ add_change_option(:label, value)
19
+ end
20
+
21
+ def add_change_cmd(value)
22
+ add_change_option(:cmd, value)
23
+ end
24
+
25
+ def add_change_entrypoint(value)
26
+ add_change_option(:entrypoint, value)
27
+ end
28
+
29
+ def add_change_onbuild(value)
30
+ add_change_option(:onbuild, value)
31
+ end
32
+
33
+ def add_change_workdir(value)
34
+ add_change_option(:workdir, value)
35
+ end
36
+
37
+ def add_change_user(value)
38
+ add_change_option(:user, value)
39
+ end
40
+
41
+ def add_cmd(value)
42
+ add_option(:cmd, value)
43
+ end
44
+
45
+ def add_volume(value)
46
+ add_option(:volume, value)
47
+ end
48
+
49
+ def add_volumes_from(value)
50
+ add_option(:'volumes-from', value)
51
+ end
52
+
53
+ def add_entrypoint(value)
54
+ add_option(:entrypoint, value)
55
+ end
56
+
57
+ def add_commands(*commands)
58
+ @bash_commands.concat(commands.flatten)
59
+ end
60
+
61
+ protected
62
+
63
+ attr_reader :bash_commands
64
+ attr_reader :options, :change_options
65
+
66
+ def add_option(key, value)
67
+ add_option_default(options, key, value)
68
+ end
69
+
70
+ def add_change_option(key, value)
71
+ add_option_default(change_options, key, value)
72
+ end
73
+
74
+ def add_option_default(hash, key, value)
75
+ hash[key] = (hash[key].nil? ? value : (Array(hash[key]) << value).flatten)
76
+ end
77
+
78
+ def from_options
79
+ return {} if from.nil?
80
+ [:entrypoint, :cmd].each_with_object({}) do |option, options|
81
+ output = shellout!("docker inspect --format='{{json .Config.#{option.to_s.capitalize}}}' #{from.built_id}").stdout.strip
82
+ options[option] = output == 'null' ? [] : JSON.parse(output)
83
+ options
84
+ end
85
+ end
86
+
87
+ def prepared_options
88
+ prepared_options_default(options) { |k, vals| Array(vals).map { |v| "--#{k}=#{v}" }.join(' ') }
89
+ end
90
+
91
+ def prepared_change
92
+ prepared_options_default(from_options.merge(change_options)) do |k, vals|
93
+ if [:cmd, :entrypoint].include? k
94
+ %(-c '#{k.to_s.upcase} #{Array(vals)}')
95
+ else
96
+ Array(vals).map { |v| %(-c "#{k.to_s.upcase} #{v}") }.join(' ')
97
+ end
98
+ end
99
+ end
100
+
101
+ def prepared_options_default(hash)
102
+ hash.map { |k, vals| yield(k, vals) }.join(' ')
103
+ end
104
+
105
+ def prepared_bash_command
106
+ shellout_pack prepared_commands.join(' && ')
107
+ end
108
+
109
+ def prepared_commands
110
+ return ['true'] if bash_commands.empty?
111
+ bash_commands
112
+ end
113
+ end
114
+ end # Image
115
+ end # Dapp
@@ -0,0 +1,76 @@
1
+ module Dapp
2
+ # Image
3
+ module Image
4
+ # Docker
5
+ class Docker
6
+ include Helper::Shellout
7
+
8
+ attr_reader :from
9
+ attr_reader :name
10
+
11
+ def initialize(name:, from: nil)
12
+ @from = from
13
+ @name = name
14
+ end
15
+
16
+ def id
17
+ @id || cache[:id]
18
+ end
19
+
20
+ def untag!
21
+ raise Error::Build, code: :image_already_untagged, data: { name: name } unless tagged?
22
+ shellout!("docker rmi #{name}")
23
+ cache_reset
24
+ end
25
+
26
+ def push!(log_verbose: false, log_time: false)
27
+ raise Error::Build, code: :image_not_exist, data: { name: name } unless tagged?
28
+ shellout!("docker push #{name}", log_verbose: log_verbose, log_time: log_time)
29
+ end
30
+
31
+ def pull!(log_verbose: false, log_time: false)
32
+ return if tagged?
33
+ shellout!("docker pull #{name}", log_verbose: log_verbose, log_time: log_time)
34
+ @pulled = true
35
+ cache_reset
36
+ end
37
+
38
+ def tagged?
39
+ !!id
40
+ end
41
+
42
+ def pulled?
43
+ !!@pulled
44
+ end
45
+
46
+ def info
47
+ raise Error::Build, code: :image_not_exist, data: { name: name } unless tagged?
48
+ [cache[:created_at], cache[:size]]
49
+ end
50
+
51
+ protected
52
+
53
+ def cache
54
+ self.class.cache[name.to_s] || {}
55
+ end
56
+
57
+ def cache_reset
58
+ self.class.cache.delete(name)
59
+ self.class.cache_reset(name)
60
+ end
61
+
62
+ class << self
63
+ def cache
64
+ @cache ||= (@cache = {}).tap { cache_reset }
65
+ end
66
+
67
+ def cache_reset(name = '')
68
+ shellout!("docker images --format='{{.Repository}}:{{.Tag}};{{.ID}};{{.CreatedAt}};{{.Size}}' #{name}").stdout.lines.each do |line|
69
+ name, id, created_at, size = line.split(';')
70
+ cache[name] = { id: id, created_at: created_at, size: size }
71
+ end
72
+ end
73
+ end
74
+ end # Docker
75
+ end # Image
76
+ end # Dapp
@@ -0,0 +1,74 @@
1
+ module Dapp
2
+ # Image
3
+ module Image
4
+ # Stage
5
+ class Stage < Docker
6
+ include Arguments
7
+
8
+ def initialize(name:, built_id: nil, from: nil)
9
+ @bash_commands = []
10
+ @options = {}
11
+ @change_options = {}
12
+ @container_name = SecureRandom.hex
13
+ @built_id = built_id
14
+ super(name: name, from: from)
15
+ end
16
+
17
+ def built_id
18
+ @built_id ||= id
19
+ end
20
+
21
+ def build!(**kwargs)
22
+ @built_id = if should_be_built?
23
+ begin
24
+ run!(**kwargs)
25
+ commit!
26
+ ensure
27
+ shellout("docker rm #{container_name}")
28
+ end
29
+ else
30
+ from.built_id
31
+ end
32
+ end
33
+
34
+ def export!(name, log_verbose: false, log_time: false, force: false)
35
+ image = self.class.new(built_id: built_id, name: name)
36
+ image.tag!(log_verbose: log_verbose, log_time: log_time, force: force)
37
+ image.push!(log_verbose: log_verbose, log_time: log_time)
38
+ image.untag!
39
+ end
40
+
41
+ def tag!(log_verbose: false, log_time: false, force: false)
42
+ if !(existed_id = id).nil? && !force
43
+ raise Error::Build, code: :another_image_already_tagged if built_id != existed_id
44
+ return
45
+ end
46
+ shellout!("docker tag #{built_id} #{name}", log_verbose: log_verbose, log_time: log_time)
47
+ cache_reset
48
+ end
49
+
50
+ protected
51
+
52
+ attr_reader :container_name
53
+
54
+ def run!(log_verbose: false, log_time: false, introspect_error: false, introspect_before_error: false)
55
+ raise Error::Build, code: :built_id_not_defined if from.built_id.nil?
56
+ shellout!("docker run #{prepared_options} --entrypoint /bin/sh --name=#{container_name} #{from.built_id} #{prepared_bash_command}",
57
+ log_verbose: log_verbose, log_time: log_time)
58
+ rescue Error::Shellout => e
59
+ raise unless introspect_error || introspect_before_error
60
+ built_id = introspect_error ? commit! : from.built_id
61
+ raise Exception::IntrospectImage, message: Dapp::Helper::NetStatus.message(e),
62
+ data: { built_id: built_id, options: prepared_options, rmi: introspect_error }
63
+ end
64
+
65
+ def commit!
66
+ shellout!("docker commit #{prepared_change} #{container_name}").stdout.strip
67
+ end
68
+
69
+ def should_be_built?
70
+ !(bash_commands.empty? && change_options.empty?)
71
+ end
72
+ end # Stage
73
+ end # Image
74
+ end # Dapp