dapp 0.1.5 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NTQ5NzZmNDM5NTE5OWU5ZDcyMmRkZWE4YzU1MDZhNDVkYzI0ZmFlNA==
4
+ NWVjYjY0MmM4ZDBlYzIyMDJmNWM0YjkxNDY0ZmUxN2VhZDZhNzZjMw==
5
5
  data.tar.gz: !binary |-
6
- ZjFlYjI4ZTNmZWY4ODU1ZTcxZTYxYWRlNDhjNTc5ZGQzMzk2NGE1Yw==
6
+ MjBiNDMyMmQ1NmY5MTQxMTU0YWQ3NWI5OWEyNjNlMDM2OTc4YzhlYw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MDEzNmU1NDY0MmIyZGVkYzViNjg5ZGM0YzYyYTU0N2U3NGNiYjA1NmQyNzIy
10
- Zjg0NGQyN2Y3ODdlY2RjNTdmNDA4ODdiMDUzZmJkMzEyMTM0MjQ0ZDY4N2Q0
11
- MTZmOTkzMDQxMTA5OWQ1ZWNlOWFhY2Y1MjI1MWE5N2VlNDA5ZTI=
9
+ ZjE4Y2ZlNDI1ZjU3MzczMTQ0NzJlNjI1NWYzMGNlZjI1ZTMyYTBlNjk0NDAw
10
+ OWE5OTExYjIxODU3Y2Q3YzMzMjRmN2FlYzJmMTYwMzcyYzdlMDc1NWQzNDcx
11
+ YWZmN2E4MTgwZjIxOTllYTU1Nzk5MDk4OWRhZTY0M2Y4YzYxZTI=
12
12
  data.tar.gz: !binary |-
13
- Yjc0ZDI5NDhmNDRlMTU2ZjMwZmFiODYzZDk3NjBjYzRkYjMwNTQ0MGRiYTIx
14
- MDZlZTcwZDYxMDZmMGI0ZjEzMzQzZTNlM2IwOTFmNWIwNmEyOTE2MzI3YWQ3
15
- Y2VhMmI5NzdmN2JkZDA2MjczYjQ4NTJkY2JjNDE5NWRjZmZhNmI=
13
+ NzVmY2ZlNjdmMzVjZmI0Y2FhNzdhZTY2OGM5NDljOGQ1NDZlMmFiYzNiYzk5
14
+ NWIyMWI1MWU3MDllMjY2YjUyOTRlZjAyM2JhZmMxZWI1YmQ2NWY2NmU5MjNi
15
+ ZjI4ZTNkYjE1ZTdkNWMzMzU5ODA2MTE4YmE0MjhmZTgzYTJlYzg=
data/bin/dapp CHANGED
@@ -5,18 +5,13 @@
5
5
  require 'rubygems'
6
6
  require 'dapp'
7
7
 
8
- def net_status_message(exception)
9
- net_status = exception.net_status.net_status_normalize(context: exception.net_status.delete(:context))
10
- net_status[:message] || [net_status[:error], net_status[:code]].compact.join(': ')
11
- end
12
-
13
8
  begin
14
9
  Dapp::CLI.new.run
15
10
  rescue Dapp::Error::Shellout => e
16
- $stderr.puts(net_status_message(e))
11
+ $stderr.puts(Dapp::Helper::NetStatus.message(e))
17
12
  exit 1
18
13
  rescue Dapp::Error::Base => e
19
- $stderr.puts(Dapp::Helper::Paint.paint_string(net_status_message(e), :warning))
14
+ $stderr.puts(Dapp::Helper::Paint.paint_string(Dapp::Helper::NetStatus.message(e), :warning))
20
15
  exit 1
21
16
  rescue Interrupt => _e
22
17
  $stderr.puts(Dapp::Helper::Paint.paint_string('Interrupted', :warning))
@@ -21,3 +21,6 @@ en:
21
21
  state:
22
22
  using_cache: '[USING CACHE]'
23
23
  build: '[BUILD]'
24
+ push: '[PUSH]'
25
+ introspect:
26
+ stage: "Introspect stage '%{name}'"
@@ -11,7 +11,7 @@ en:
11
11
  from_image_required: 'Missing from_image!'
12
12
  image_already_untagged: "Image `%{name}` already untagged!"
13
13
  image_not_exist: "Image `%{name}` not exist!"
14
- image_already_tagged: 'Image with other id already tagged!'
14
+ another_image_already_tagged: 'Image with other id already tagged!'
15
15
  built_id_not_defined: '`from.built_id` not defined!'
16
16
  controller:
17
17
  push_command_unexpected_apps: "Push command can process only one application!"
@@ -24,6 +24,7 @@ require 'dapp/helper/log'
24
24
  require 'dapp/helper/paint'
25
25
  require 'dapp/helper/streaming'
26
26
  require 'dapp/helper/shellout'
27
+ require 'dapp/helper/net_status'
27
28
  require 'dapp/cli'
28
29
  require 'dapp/cli/base'
29
30
  require 'dapp/cli/build'
@@ -71,6 +72,8 @@ require 'dapp/git_repo/base'
71
72
  require 'dapp/git_repo/own'
72
73
  require 'dapp/git_repo/remote'
73
74
  require 'dapp/git_artifact'
75
+ require 'dapp/exception/base'
76
+ require 'dapp/exception/introspect_image'
74
77
  require 'dapp/error/base'
75
78
  require 'dapp/error/application'
76
79
  require 'dapp/error/build'
@@ -32,15 +32,15 @@ module Dapp
32
32
  end
33
33
 
34
34
  def export!(repo)
35
- fail Error::Application, code: :application_not_built unless last_stage.image.tagged? || dry_run?
35
+ raise Error::Application, code: :application_not_built unless last_stage.image.tagged? || dry_run?
36
36
 
37
37
  tags.each do |tag|
38
38
  image_name = [repo, tag].join(':')
39
39
  if dry_run?
40
- log_state(image_name, state: 'PUSH', styles: { status: :success })
40
+ log_state(image_name, state: t(code: 'state.push'), styles: { status: :success })
41
41
  else
42
42
  log_process(image_name, process: t(code: 'status.process.pushing')) do
43
- last_stage.image.export!(image_name, log_verbose: log_verbose?, log_time: log_time?)
43
+ last_stage.image.export!(image_name, log_verbose: log_verbose?, log_time: log_time?, force: cli_options[:force])
44
44
  end
45
45
  end
46
46
  end
@@ -66,7 +66,7 @@ module Dapp
66
66
  process = paint_string(rjust(process, message), style[:process])
67
67
  info = paint_string(message, style[:message]) + process
68
68
  success_message = paint_string(slice(message), style[:message]) +
69
- paint_string(rjust(t(code: 'status.success.default'), message), style[:success])
69
+ paint_string(rjust(t(code: 'status.success.default'), message), style[:success])
70
70
  failed_message = paint_string(slice(message) +
71
71
  rjust(t(code: 'status.failed.default'), message), style[:failed])
72
72
  log_process_default(info, success_message, failed_message, &blk)
@@ -84,7 +84,7 @@ module Dapp
84
84
  message = success_message
85
85
  start = Time.now
86
86
  yield
87
- rescue Error::Base, SignalException, StandardError => _e
87
+ rescue Exception::Base, Error::Base, SignalException, StandardError => _e
88
88
  message = failed_message
89
89
  raise
90
90
  ensure
@@ -3,12 +3,6 @@ module Dapp
3
3
  class Application
4
4
  # Path
5
5
  module Path
6
- def build_cache_path(*path)
7
- make_path(@build_cache_path, *path).expand_path.tap do |p|
8
- FileUtils.mkdir_p p.parent
9
- end
10
- end
11
-
12
6
  def home_path(*path)
13
7
  make_path(config._home_path, *path).expand_path
14
8
  end
@@ -17,6 +11,10 @@ module Dapp
17
11
  make_path(@build_path, *path).expand_path.tap { |p| FileUtils.mkdir_p p.parent }
18
12
  end
19
13
 
14
+ def build_cache_path(*path)
15
+ make_path(@build_cache_path, *path).expand_path.tap { |p| FileUtils.mkdir_p p.parent }
16
+ end
17
+
20
18
  def container_build_path(*path)
21
19
  make_path('/.build', *path)
22
20
  end
@@ -21,7 +21,7 @@ module Dapp
21
21
 
22
22
  def branch_tags
23
23
  return [] unless cli_options[:tag_branch]
24
- fail Error::Application, code: :git_branch_without_name if (branch = git_repo.branch) == 'HEAD'
24
+ raise Error::Application, code: :git_branch_without_name if (branch = git_repo.branch) == 'HEAD'
25
25
  [branch]
26
26
  end
27
27
 
@@ -39,7 +39,7 @@ module Dapp
39
39
  elsif ENV['TRAVIS']
40
40
  build_id = ENV['TRAVIS_BUILD_NUMBER']
41
41
  else
42
- fail Error::Application, code: :ci_environment_required
42
+ raise Error::Application, code: :ci_environment_required
43
43
  end
44
44
 
45
45
  [build_id]
@@ -55,7 +55,7 @@ module Dapp
55
55
  branch = ENV['TRAVIS_BRANCH']
56
56
  tag = ENV['TRAVIS_TAG']
57
57
  else
58
- fail Error::Application, code: :ci_environment_required
58
+ raise Error::Application, code: :ci_environment_required
59
59
  end
60
60
 
61
61
  [branch, tag].compact
@@ -16,9 +16,9 @@ module Dapp
16
16
  @next_stage.prev_stage = self
17
17
  end
18
18
 
19
- # rubocop:disable Metrics/AbcSize
19
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
20
20
  def build!
21
- return if image.tagged? && !application.log_verbose?
21
+ return if should_be_skipped?
22
22
  prev_stage.build! if prev_stage
23
23
  begin
24
24
  if image.tagged?
@@ -33,8 +33,11 @@ module Dapp
33
33
  ensure
34
34
  log_build
35
35
  end
36
+ raise Exception::IntrospectImage,
37
+ message: application.t(code: 'introspect.stage', data: { name: name }),
38
+ data: { built_id: image.built_id, options: image.send(:prepared_options) } if should_be_introspected?
36
39
  end
37
- # rubocop:enable Metrics/AbcSize
40
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
38
41
 
39
42
  def save_in_cache!
40
43
  return if image.tagged?
@@ -65,13 +68,24 @@ module Dapp
65
68
  image.send(:bash_commands).empty?
66
69
  end
67
70
 
71
+ def should_be_skipped?
72
+ image.tagged? && !application.log_verbose? && application.cli_options[:introspect_stage].nil?
73
+ end
74
+
75
+ def should_be_introspected?
76
+ application.cli_options[:introspect_stage] == name && !application.dry_run?
77
+ end
78
+
68
79
  def image_build!
69
- image.build!(log_verbose: application.log_verbose?, log_time: application.log_time?)
80
+ image.build!(log_verbose: application.log_verbose?,
81
+ log_time: application.log_time?,
82
+ introspect_error: application.cli_options[:introspect_error],
83
+ introspect_before_error: application.cli_options[:introspect_before_error])
70
84
  end
71
85
 
72
86
  def from_image
73
87
  prev_stage.image if prev_stage || begin
74
- fail Error::Build, code: :from_image_required
88
+ raise Error::Build, code: :from_image_required
75
89
  end
76
90
  end
77
91
 
@@ -87,12 +101,13 @@ module Dapp
87
101
 
88
102
  def format_image_info
89
103
  date, bytesize = image_info
90
- application.t(code: 'image.info', data: { date: Time.parse(date).localtime, size: to_mb(bytesize.to_i)})
104
+ application.t(code: 'image.info', data: { date: Time.parse(date).localtime, size: to_mb(bytesize.to_i) })
91
105
  end
92
106
 
107
+ # rubocop:disable Metrics/AbcSize
93
108
  def log_build
94
109
  application.with_log_indent do
95
- application.log_info application.t(code: 'image.signature', data: { signature: image_name})
110
+ application.log_info application.t(code: 'image.signature', data: { signature: image_name })
96
111
  application.log_info format_image_info if image.tagged?
97
112
  unless (bash_commands = image.send(:bash_commands)).empty?
98
113
  application.log_info application.t(code: 'image.commands')
@@ -17,7 +17,7 @@ module Dapp
17
17
  protected
18
18
 
19
19
  def image_build!
20
- from_image.pull!(log_verbose: application.log_verbose?, log_time: application.log_time?)
20
+ from_image.pull!(log_time: application.log_time?)
21
21
  super
22
22
  end
23
23
 
@@ -28,7 +28,7 @@ module Dapp
28
28
  end
29
29
 
30
30
  def from_image
31
- StageImage.new(name: from_image_name)
31
+ @from_image ||= StageImage.new(name: from_image_name)
32
32
  end
33
33
 
34
34
  def image_info
@@ -17,29 +17,22 @@ module Dapp
17
17
  end
18
18
 
19
19
  def signature
20
- hashsum [super, *exposes]
20
+ hashsum [super, change_options]
21
21
  end
22
22
 
23
23
  def image
24
24
  super do |image|
25
- image.add_expose(exposes) unless exposes.empty?
26
- image.add_env(envs) unless envs.empty?
27
- image.add_workdir(workdir) unless workdir.nil?
25
+ change_options.each do |k, v|
26
+ next if v.nil? || v.empty?
27
+ image.public_send("add_change_#{k}", v)
28
+ end
28
29
  end
29
30
  end
30
31
 
31
32
  protected
32
33
 
33
- def exposes
34
- application.config._docker._expose
35
- end
36
-
37
- def envs
38
- application.config._docker._env
39
- end
40
-
41
- def workdir
42
- application.config._docker._workdir
34
+ def change_options
35
+ application.config._docker._change_options
43
36
  end
44
37
 
45
38
  def layers_commits_write!
@@ -26,14 +26,17 @@ module Dapp
26
26
 
27
27
  def image
28
28
  super do |image|
29
- if application.git_artifacts.any?
30
- image.add_volumes_from(gitartifact_container)
31
- image.add_commands 'export PATH=/.dapp/deps/gitartifact/bin:$PATH'
29
+ bash_commands = []
30
+ volumes = []
31
+ application.git_artifacts.each do |git_artifact|
32
+ volumes << "#{git_artifact.repo.dir_path}:#{git_artifact.repo.container_build_dir_path}"
33
+ bash_commands.concat(git_artifact.send(apply_command_method, self))
32
34
  end
33
35
 
34
- application.git_artifacts.each do |git_artifact|
35
- image.add_volume "#{git_artifact.repo.dir_path}:#{git_artifact.repo.container_build_dir_path}"
36
- image.add_commands git_artifact.send(apply_command_method, self)
36
+ unless bash_commands.empty?
37
+ image.add_volumes_from(gitartifact_container)
38
+ image.add_volume(volumes)
39
+ image.add_commands 'export PATH=/.dapp/deps/gitartifact/bin:$PATH', *bash_commands
37
40
  end
38
41
  yield image if block_given?
39
42
  end
@@ -61,7 +64,7 @@ module Dapp
61
64
 
62
65
  def gitartifact_container
63
66
  @gitartifact_container ||= begin
64
- if application.shellout("docker inspect #{gitartifact_container_name}").exitstatus != 0
67
+ if application.shellout("docker inspect #{gitartifact_container_name}").exitstatus.nonzero?
65
68
  application.log_secondary_process(application.t(code: 'process.git_artifact_loading'), short: true) do
66
69
  application.shellout ['docker run',
67
70
  '--restart=no',
@@ -9,35 +9,35 @@ module Dapp
9
9
  end
10
10
 
11
11
  def infra_install(_image)
12
- fail
12
+ raise
13
13
  end
14
14
 
15
15
  def infra_install_checksum
16
- fail
16
+ raise
17
17
  end
18
18
 
19
19
  def infra_setup(_image)
20
- fail
20
+ raise
21
21
  end
22
22
 
23
23
  def infra_setup_checksum
24
- fail
24
+ raise
25
25
  end
26
26
 
27
27
  def app_install(_image)
28
- fail
28
+ raise
29
29
  end
30
30
 
31
31
  def app_install_checksum
32
- fail
32
+ raise
33
33
  end
34
34
 
35
35
  def app_setup(_image)
36
- fail
36
+ raise
37
37
  end
38
38
 
39
39
  def app_setup_checksum
40
- fail
40
+ raise
41
41
  end
42
42
  end # Base
43
43
  end # Builder
@@ -4,6 +4,8 @@ module Dapp
4
4
  class CLI
5
5
  # CLI build subcommand
6
6
  class Build < Base
7
+ include Dapp::Helper::Shellout
8
+
7
9
  banner <<BANNER.freeze
8
10
  Version: #{Dapp::VERSION}
9
11
 
@@ -26,6 +28,31 @@ BANNER
26
28
  option :git_artifact_branch,
27
29
  long: '--git-artifact-branch BRANCH',
28
30
  description: 'Default branch to archive artifacts from'
31
+
32
+ option :introspect_error,
33
+ long: '--introspect-error',
34
+ boolean: true,
35
+ default: false
36
+
37
+ option :introspect_before_error,
38
+ long: '--introspect-before-error',
39
+ boolean: true,
40
+ default: false
41
+
42
+ option :introspect_stage,
43
+ long: '--introspect-stage STAGE',
44
+ proc: proc { |v| v.to_sym },
45
+ in: [nil, :from, :infra_install, :source_1_archive, :source_1, :app_install,
46
+ :source_2, :infra_setup, :source_3, :app_setup, :source_4, :source_5]
47
+
48
+ def run(*args)
49
+ super
50
+ rescue Exception::IntrospectImage => e
51
+ $stderr.puts(e.net_status[:message])
52
+ data = e.net_status[:data]
53
+ system("docker run -ti --rm #{data[:options]} #{data[:built_id]} bash")
54
+ shellout("docker rmi #{data[:built_id]}") if data[:rmi]
55
+ end
29
56
  end
30
57
  end
31
58
  end
@@ -49,6 +49,12 @@ BANNER
49
49
  description: 'Tag by git commit',
50
50
  boolean: true
51
51
 
52
+ option :force,
53
+ long: '--force',
54
+ description: 'Override existing image',
55
+ default: false,
56
+ boolean: true
57
+
52
58
  def run(argv = ARGV)
53
59
  self.class.parse_options(self, argv)
54
60
  repo = self.class.required_argument(self)
@@ -33,12 +33,12 @@ module Dapp
33
33
  end
34
34
 
35
35
  def chef
36
- fail Error::Config, code: :builder_type_conflict unless _builder == :chef
36
+ raise Error::Config, code: :builder_type_conflict unless _builder == :chef
37
37
  @_chef ||= Chef.new
38
38
  end
39
39
 
40
40
  def shell
41
- fail Error::Config, code: :builder_type_conflict unless _builder == :shell
41
+ raise Error::Config, code: :builder_type_conflict unless _builder == :shell
42
42
  @_shell ||= Shell.new
43
43
  end
44
44
 
@@ -51,7 +51,7 @@ module Dapp
51
51
  end
52
52
 
53
53
  def builder(type)
54
- fail Error::Config, code: :builder_type_unsupported, data: { type: type } unless [:chef, :shell].include?((type = type.to_sym))
54
+ raise Error::Config, code: :builder_type_unsupported, data: { type: type } unless [:chef, :shell].include?((type = type.to_sym))
55
55
  another_builder = [:chef, :shell].find { |t| t != type }
56
56
  instance_variable_set(:"@_#{another_builder}", Config.const_get(another_builder.capitalize).new)
57
57
  @_builder = type
@@ -2,12 +2,16 @@ module Dapp
2
2
  module Config
3
3
  # Docker
4
4
  class Docker
5
- attr_reader :_expose, :_workdir, :_env
5
+ attr_reader :_volume, :_expose, :_env, :_label, :_cmd, :_onbuild, :_workdir, :_user, :_entrypoint
6
6
  attr_reader :_from_cache_version
7
7
 
8
8
  def initialize
9
+ @_volume = []
9
10
  @_expose = []
10
11
  @_env = []
12
+ @_label = []
13
+ @_cmd = []
14
+ @_onbuild = []
11
15
  end
12
16
 
13
17
  def from(image_name, cache_version: nil)
@@ -15,20 +19,58 @@ module Dapp
15
19
  @_from_cache_version = cache_version
16
20
  end
17
21
 
18
- def expose(*args)
19
- @_expose.concat(args)
22
+ def volume(*args)
23
+ @_volume.concat(args)
20
24
  end
21
25
 
22
- def workdir(path)
23
- @_workdir = path
26
+ def expose(*args)
27
+ @_expose.concat(args)
24
28
  end
25
29
 
26
30
  def env(*args)
27
31
  @_env.concat(args)
28
32
  end
29
33
 
34
+ def label(*args)
35
+ @_label.concat(args)
36
+ end
37
+
38
+ def cmd(*args)
39
+ @_cmd.concat(args)
40
+ end
41
+
42
+ def onbuild(*args)
43
+ @_onbuild.concat(args)
44
+ end
45
+
46
+ def workdir(val)
47
+ @_workdir = val
48
+ end
49
+
50
+ def user(val)
51
+ @_user = val
52
+ end
53
+
54
+ def entrypoint(*cmd_with_args)
55
+ @_entrypoint = cmd_with_args.flatten
56
+ end
57
+
30
58
  def _from
31
- @_from || fail(Error::Config, code: :docker_from_not_defined)
59
+ @_from || raise(Error::Config, code: :docker_from_not_defined)
60
+ end
61
+
62
+ def _change_options
63
+ {
64
+ volume: _volume,
65
+ expose: _expose,
66
+ env: _env,
67
+ label: _label,
68
+ cmd: _cmd,
69
+ onbuild: _onbuild,
70
+ workdir: _workdir,
71
+ user: _user,
72
+ entrypoint: _entrypoint
73
+ }
32
74
  end
33
75
 
34
76
  def clone
@@ -31,8 +31,8 @@ module Dapp
31
31
  @_where_to_add = where_to_add
32
32
 
33
33
  options.each do |k, v|
34
- respond_to?("_#{k}=") ? send(:"_#{k}=", v) : fail(Error::Config, code: :git_artifact_unexpected_attribute,
35
- data: { type: object_name, attr: k })
34
+ respond_to?("_#{k}=") ? send(:"_#{k}=", v) : raise(Error::Config, code: :git_artifact_unexpected_attribute,
35
+ data: { type: object_name, attr: k })
36
36
  end
37
37
  end
38
38
 
@@ -6,7 +6,7 @@ module Dapp
6
6
 
7
7
  attr_reader :cli_options, :patterns
8
8
 
9
- def initialize(cli_options:, patterns: nil)
9
+ def initialize(cli_options: {}, patterns: nil)
10
10
  @cli_options = cli_options
11
11
  @cli_options[:log_indent] = 0
12
12
 
@@ -19,25 +19,25 @@ module Dapp
19
19
  end
20
20
 
21
21
  def build
22
- @build_confs.each do |build_conf|
22
+ build_confs.each do |build_conf|
23
23
  log_step(build_conf._name)
24
24
  with_log_indent { Application.new(config: build_conf, cli_options: cli_options).build! }
25
25
  end
26
26
  end
27
27
 
28
28
  def list
29
- @build_confs.each do |build_conf|
29
+ build_confs.each do |build_conf|
30
30
  log(build_conf._name)
31
31
  end
32
32
  end
33
33
 
34
34
  def push(repo)
35
- fail Error::Controller, code: :push_command_unexpected_apps unless @build_confs.one?
35
+ raise Error::Controller, code: :push_command_unexpected_apps unless @build_confs.one?
36
36
  Application.new(config: @build_confs.first, cli_options: cli_options, ignore_git_fetch: true).export!(repo)
37
37
  end
38
38
 
39
39
  def smartpush(repo_prefix)
40
- @build_confs.each do |build_conf|
40
+ build_confs.each do |build_conf|
41
41
  log_step(build_conf._name)
42
42
  repo = File.join(repo_prefix, build_conf._name)
43
43
  with_log_indent { Application.new(config: build_conf, cli_options: cli_options, ignore_git_fetch: true).export!(repo) }
@@ -45,7 +45,7 @@ module Dapp
45
45
  end
46
46
 
47
47
  def flush_build_cache
48
- @build_confs.each do |build_conf|
48
+ build_confs.each do |build_conf|
49
49
  log(build_conf._name)
50
50
  app = Application.new(config: build_conf, cli_options: cli_options, ignore_git_fetch: true)
51
51
  FileUtils.rm_rf app.build_cache_path
@@ -61,17 +61,13 @@ module Dapp
61
61
 
62
62
  def build_confs
63
63
  @build_confs ||= begin
64
- dappfiles = []
65
64
  if File.exist? dappfile_path
66
- dappfiles << dappfile_path
67
- elsif File.exist? dapps_path
68
- dappfiles += Dir.glob(File.join([dapps_path, '*', 'Dappfile'].compact))
69
- else
70
- fail Error::Controller, code: :dappfile_not_found
65
+ dappfiles = dappfile_path
66
+ elsif (dappfiles = dapps_dappfiles_pathes).empty? && (dappfiles = search_dappfile_up).nil?
67
+ raise Error::Controller, code: :dappfile_not_found
71
68
  end
72
- dappfiles.flatten.uniq!
73
- dappfiles.map { |dappfile| apps(dappfile, app_filters: patterns) }.flatten.tap do |apps|
74
- fail Error::Controller, code: :no_such_app, data: { path: dappfile_path, patterns: patterns.join(', ') } if apps.empty?
69
+ Array(dappfiles).map { |dappfile| apps(dappfile, app_filters: patterns) }.flatten.tap do |apps|
70
+ raise Error::Controller, code: :no_such_app, data: { path: dappfile_path, patterns: patterns.join(', ') } if apps.empty?
75
71
  end
76
72
  end
77
73
  end
@@ -84,11 +80,19 @@ module Dapp
84
80
  end
85
81
 
86
82
  def dappfile_path
87
- @dappfile_path ||= File.join [cli_options[:dir], 'Dappfile'].compact
83
+ File.join [cli_options[:dir], 'Dappfile'].compact
88
84
  end
89
85
 
90
- def dapps_path
91
- @dapps_path ||= File.join [cli_options[:dir], '.dapps'].compact
86
+ def dapps_dappfiles_pathes
87
+ Dir.glob(File.join([cli_options[:dir], '.dapps', '*', 'Dappfile'].compact))
88
+ end
89
+
90
+ def search_dappfile_up
91
+ cdir = Pathname(File.expand_path(cli_options[:dir] || Dir.pwd))
92
+ until (cdir = cdir.parent).root?
93
+ next unless (path = cdir.join('Dappfile')).exist?
94
+ return path.to_s
95
+ end
92
96
  end
93
97
 
94
98
  def paint_initialize
@@ -96,7 +100,7 @@ module Dapp
96
100
  when 'auto' then STDOUT.tty? ? 8 : 0
97
101
  when 'on' then 8
98
102
  when 'off' then 0
99
- else fail
103
+ else raise
100
104
  end
101
105
  end
102
106
  end # Controller
@@ -20,12 +20,12 @@ module Dapp
20
20
  end
21
21
 
22
22
  def untag!
23
- fail Error::Build, code: :image_already_untagged, data: { name: name } unless tagged?
23
+ raise Error::Build, code: :image_already_untagged, data: { name: name } unless tagged?
24
24
  shellout!("docker rmi #{name}")
25
25
  end
26
26
 
27
27
  def push!(log_verbose: false, log_time: false)
28
- fail Error::Build, code: :image_not_exist, data: { name: name } unless tagged?
28
+ raise Error::Build, code: :image_not_exist, data: { name: name } unless tagged?
29
29
  shellout!("docker push #{name}", log_verbose: log_verbose, log_time: log_time)
30
30
  end
31
31
 
@@ -44,7 +44,7 @@ module Dapp
44
44
  end
45
45
 
46
46
  def info
47
- fail Error::Build, code: :image_not_exist, data: { name: name } unless tagged?
47
+ raise Error::Build, code: :image_not_exist, data: { name: name } unless tagged?
48
48
  shellout!("docker inspect --format='{{.Created}} {{.Size}}' #{name}").stdout.strip.split
49
49
  end
50
50
  end # DockerImage
@@ -0,0 +1,10 @@
1
+ module Dapp
2
+ module Exception
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
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module Dapp
2
+ module Exception
3
+ # IntrospectImage
4
+ class IntrospectImage < Base; end
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module Dapp
2
+ module Helper
3
+ # NetStatus
4
+ module NetStatus
5
+ def self.message(exception)
6
+ net_status = exception.net_status.net_status_normalize(context: exception.net_status.delete(:context))
7
+ net_status[:message] || [net_status[:error], net_status[:code]].compact.join(': ')
8
+ end
9
+ end
10
+ end # Helper
11
+ end # Dapp
@@ -13,7 +13,7 @@ module Dapp
13
13
 
14
14
  def paint_style(name)
15
15
  FORMAT[name].tap do |format|
16
- fail if format.nil?
16
+ raise if format.nil?
17
17
  end
18
18
  end
19
19
 
@@ -4,56 +4,87 @@ module Dapp
4
4
  def initialize(name:, built_id: nil, from: nil)
5
5
  @bash_commands = []
6
6
  @options = {}
7
+ @change_options = {}
7
8
  @container_name = SecureRandom.hex
8
9
  @built_id = built_id
9
10
  super(name: name, from: from)
10
11
  end
11
12
 
12
- def add_expose(value)
13
- add_option(:expose, value)
13
+ def add_change_volume(value)
14
+ add_change_option(:volume, value)
14
15
  end
15
16
 
16
- def add_volume(value)
17
- add_option(:volume, value)
17
+ def add_change_expose(value)
18
+ add_change_option(:expose, value)
18
19
  end
19
20
 
20
- def add_volumes_from(value)
21
- add_option(:'volumes-from', value)
21
+ def add_change_env(value)
22
+ add_change_option(:env, value)
23
+ end
24
+
25
+ def add_change_label(value)
26
+ add_change_option(:label, value)
27
+ end
28
+
29
+ def add_change_cmd(value)
30
+ add_change_option(:cmd, value)
31
+ end
32
+
33
+ def add_change_onbuild(value)
34
+ add_change_option(:onbuild, value)
35
+ end
36
+
37
+ def add_change_workdir(value)
38
+ add_change_option(:workdir, value)
39
+ end
40
+
41
+ def add_change_entrypoint(value)
42
+ add_change_option(:entrypoint, value)
43
+ end
44
+
45
+ def add_change_user(value)
46
+ add_change_option(:user, value)
22
47
  end
23
48
 
24
- def add_env(value)
25
- add_option(:env, value)
49
+ def add_volume(value)
50
+ add_option(:volume, value)
26
51
  end
27
52
 
28
- def add_workdir(value)
29
- add_option(:workdir, value)
53
+ def add_volumes_from(value)
54
+ add_option(:'volumes-from', value)
30
55
  end
31
56
 
32
57
  def add_commands(*commands)
33
- @bash_commands += commands.flatten
58
+ @bash_commands.concat(commands.flatten)
34
59
  end
35
60
 
36
61
  def built_id
37
62
  @built_id ||= id
38
63
  end
39
64
 
40
- def build!(log_verbose: false, log_time: false)
41
- run!(log_verbose: log_verbose, log_time: log_time)
42
- @built_id = commit!
43
- ensure
44
- shellout("docker rm #{container_name}")
65
+ def build!(**kvargs)
66
+ @built_id = if should_be_built?
67
+ begin
68
+ run!(**kvargs)
69
+ commit!
70
+ ensure
71
+ shellout("docker rm #{container_name}")
72
+ end
73
+ else
74
+ from.built_id
75
+ end
45
76
  end
46
77
 
47
- def export!(name, log_verbose: false, log_time: false)
78
+ def export!(name, log_verbose: false, log_time: false, force: false)
48
79
  image = self.class.new(built_id: built_id, name: name)
49
- image.tag!(log_verbose: log_verbose, log_time: log_time)
80
+ image.tag!(log_verbose: log_verbose, log_time: log_time, force: force)
50
81
  image.push!(log_verbose: log_verbose, log_time: log_time)
51
82
  image.untag!
52
83
  end
53
84
 
54
- def tag!(log_verbose: false, log_time: false)
55
- unless (existed_id = id).nil?
56
- fail Error::Build, code: :image_already_tagged if built_id != existed_id
85
+ def tag!(log_verbose: false, log_time: false, force: false)
86
+ if !(existed_id = id).nil? && !force
87
+ raise Error::Build, code: :another_image_already_tagged if built_id != existed_id
57
88
  return
58
89
  end
59
90
  shellout!("docker tag #{built_id} #{name}", log_verbose: log_verbose, log_time: log_time)
@@ -63,34 +94,61 @@ module Dapp
63
94
 
64
95
  attr_reader :container_name
65
96
  attr_reader :bash_commands
66
- attr_reader :options
97
+ attr_reader :options, :change_options
67
98
 
68
99
  def add_option(key, value)
69
- options[key] = (options[key].nil? ? value : (Array(options[key]) << value).flatten)
100
+ add_option_default(options, key, value)
101
+ end
102
+
103
+ def add_change_option(key, value)
104
+ add_option_default(change_options, key, value)
105
+ end
106
+
107
+ def add_option_default(hash, key, value)
108
+ hash[key] = (hash[key].nil? ? value : (Array(hash[key]) << value).flatten)
70
109
  end
71
110
 
72
- def run!(log_verbose: false, log_time: false)
73
- fail Error::Build, code: :built_id_not_defined if from.built_id.nil?
111
+ def run!(log_verbose: false, log_time: false, introspect_error: false, introspect_before_error: false)
112
+ raise Error::Build, code: :built_id_not_defined if from.built_id.nil?
74
113
  shellout!("docker run #{prepared_options} --name=#{container_name} #{from.built_id} #{prepared_bash_command}",
75
114
  log_verbose: log_verbose, log_time: log_time)
115
+ rescue Error::Shellout => e
116
+ raise unless introspect_error || introspect_before_error
117
+ built_id = introspect_error ? commit! : from.built_id
118
+ raise Exception::IntrospectImage, message: Dapp::Helper::NetStatus.message(e),
119
+ data: { built_id: built_id, options: prepared_options, rmi: introspect_error }
76
120
  end
77
121
 
78
122
  def commit!
79
- shellout!("docker commit #{container_name}").stdout.strip
123
+ shellout!("docker commit #{prepared_change} #{container_name}").stdout.strip
124
+ end
125
+
126
+ def should_be_built?
127
+ !(bash_commands.empty? && change_options.empty?)
80
128
  end
81
129
 
82
130
  def prepared_options
83
- options.map { |k, vals| Array(vals).map { |v| "--#{k}=#{v}" }.join(' ') }.join(' ')
131
+ prepared_options_default(options) { |k, vals| Array(vals).map { |v| "--#{k}=#{v}" }.join(' ') }
84
132
  end
85
133
 
86
- def prepared_bash_command
87
- if bash_commands.empty?
88
- 'true'
89
- else
90
- "bash -ec 'eval $(echo #{Base64.strict_encode64(prepared_commands.join(' && '))} | base64 --decode)'"
134
+ def prepared_change
135
+ prepared_options_default(change_options) do |k, vals|
136
+ if [:cmd, :entrypoint].include? k
137
+ %(-c '#{k.to_s.upcase} #{Array(vals)}')
138
+ else
139
+ Array(vals).map { |v| %(-c "#{k.to_s.upcase} #{v}") }.join(' ')
140
+ end
91
141
  end
92
142
  end
93
143
 
144
+ def prepared_options_default(hash)
145
+ hash.map { |k, vals| yield(k, vals) }.join(' ')
146
+ end
147
+
148
+ def prepared_bash_command
149
+ "bash -ec 'eval $(echo #{Base64.strict_encode64(prepared_commands.join(' && '))} | base64 --decode)'"
150
+ end
151
+
94
152
  def prepared_commands
95
153
  bash_commands.map { |command| command.gsub(/^[\ |;]*|[\ |;]*$/, '') } # strip [' ', ';']
96
154
  end
@@ -1,5 +1,5 @@
1
1
  # Version
2
2
  module Dapp
3
- VERSION = '0.1.5'.freeze
3
+ VERSION = '0.2.4'.freeze
4
4
  BUILD_CACHE_VERSION = 1
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dapp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Stolyarov
@@ -373,6 +373,8 @@ files:
373
373
  - lib/dapp/error/config.rb
374
374
  - lib/dapp/error/controller.rb
375
375
  - lib/dapp/error/shellout.rb
376
+ - lib/dapp/exception/base.rb
377
+ - lib/dapp/exception/introspect_image.rb
376
378
  - lib/dapp/filelock.rb
377
379
  - lib/dapp/git_artifact.rb
378
380
  - lib/dapp/git_repo/base.rb
@@ -381,6 +383,7 @@ files:
381
383
  - lib/dapp/helper/cli.rb
382
384
  - lib/dapp/helper/i18n.rb
383
385
  - lib/dapp/helper/log.rb
386
+ - lib/dapp/helper/net_status.rb
384
387
  - lib/dapp/helper/paint.rb
385
388
  - lib/dapp/helper/sha256.rb
386
389
  - lib/dapp/helper/shellout.rb