devkitkat 0.1.21 → 0.1.22

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +13 -11
  3. data/README.md +2 -2
  4. data/bin/devkitkat +1 -1
  5. data/devkitkat.gemspec +2 -1
  6. data/lib/devkitkat/command.rb +6 -8
  7. data/lib/devkitkat/config.rb +33 -20
  8. data/lib/devkitkat/processor.rb +48 -0
  9. data/lib/devkitkat/service/concerns/service_initializer.rb +17 -0
  10. data/lib/devkitkat/service/driver/base.rb +23 -0
  11. data/lib/devkitkat/service/driver/docker/container.rb +163 -0
  12. data/lib/devkitkat/service/driver/docker/image.rb +33 -0
  13. data/lib/devkitkat/service/driver/docker.rb +45 -0
  14. data/lib/devkitkat/service/driver/none.rb +19 -0
  15. data/lib/devkitkat/service/executor/logger.rb +22 -0
  16. data/lib/devkitkat/service/executor/scripter.rb +48 -0
  17. data/lib/devkitkat/service/executor/variables.rb +82 -0
  18. data/lib/devkitkat/service/executor.rb +102 -0
  19. data/lib/devkitkat/service/predefined_command/add_example.rb +33 -0
  20. data/lib/devkitkat/service/predefined_command/add_git_ignore.rb +29 -0
  21. data/lib/devkitkat/service/predefined_command/add_script.rb +35 -0
  22. data/lib/devkitkat/service/predefined_command/add_shared_script.rb +21 -0
  23. data/lib/devkitkat/service/predefined_command/base.rb +17 -0
  24. data/lib/devkitkat/service/predefined_command/clean.rb +22 -0
  25. data/lib/devkitkat/service/predefined_command/clone.rb +25 -0
  26. data/lib/devkitkat/service/predefined_command/exec.rb +18 -0
  27. data/lib/devkitkat/service/predefined_command/poop.rb +17 -0
  28. data/lib/devkitkat/service/predefined_command/pull.rb +19 -0
  29. data/lib/devkitkat/service/predefined_command/reconfigure.rb +26 -0
  30. data/lib/devkitkat/service/predefined_command/show_variables.rb +17 -0
  31. data/lib/devkitkat/service.rb +13 -214
  32. data/lib/devkitkat/version.rb +1 -1
  33. data/lib/devkitkat.rb +12 -5
  34. metadata +41 -12
  35. data/docs/READ.md +0 -1
  36. data/docs/config/READ.md +0 -1
  37. data/docs/machine/READ.md +0 -1
  38. data/docs/service/READ.md +0 -1
  39. data/lib/devkitkat/executor/docker.rb +0 -154
  40. data/lib/devkitkat/executor/local.rb +0 -25
  41. data/lib/devkitkat/executor.rb +0 -62
  42. data/lib/devkitkat/main.rb +0 -50
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45003b239d330518c51308aec36f8f04c18dc36f3599f2c33482ee354bb76f16
4
- data.tar.gz: b09492e98b456d7afd6ba31720509c1c5ae22b7516532443661e2a7efa5132eb
3
+ metadata.gz: 19d4a68e881590b167d09fb7564e53f0e6b337386ad4de76043d4ed5c1d8d3ab
4
+ data.tar.gz: 5d1150ee9dcdd3820b60d8f460da8d69ed9eef314f13626da409d8481e78d7e3
5
5
  SHA512:
6
- metadata.gz: f0ca0b9427f4176b02c8e15d8df4a2a12a2b4e1f265cfb6cae875ac4d422e33407ea2eb503285c47015f5df76245f352a59f7bc5cfa35fea3a886b86595aec8f
7
- data.tar.gz: 2ffb303ad8506c435fda82b563e26c03877e4eaa20a4ebf4c84a43314041daf969b6406b4a132886a48df6f254ef8c217c4e897e418c6af7af7bacdca7762c8b
6
+ metadata.gz: eee0fd0f5ab8ebea39250f607ec29871f2f860305d601a1c161caf87c5b97066a6f26cecc019bd88797e9a6210b7a678b1eac793422d308b40fdfba2ce5a669b
7
+ data.tar.gz: 5c133cd5b4d58a45711ee7192b39980a0519e5d786377674d2399ff0f43b57f8dc4cb72044ba2c0b3bfb535d6e38b47f72ca4e19158a3c04845e885aa4918eac
data/Gemfile.lock CHANGED
@@ -1,36 +1,37 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- devkitkat (0.1.21)
4
+ devkitkat (0.1.22)
5
5
  activesupport (~> 6.0.0)
6
6
  colorize (~> 0.8.1)
7
7
  docker-api (~> 1.34.2)
8
8
  parallel (~> 1.17.0)
9
9
  pry (~> 0.12.2)
10
10
  pry-nav
11
+ require_all (~> 3.0.0)
11
12
  ruby-progressbar (~> 1.10.1)
12
13
 
13
14
  GEM
14
15
  remote: https://rubygems.org/
15
16
  specs:
16
- activesupport (6.0.0)
17
+ activesupport (6.0.2.2)
17
18
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
19
  i18n (>= 0.7, < 2)
19
20
  minitest (~> 5.1)
20
21
  tzinfo (~> 1.1)
21
- zeitwerk (~> 2.1, >= 2.1.8)
22
+ zeitwerk (~> 2.2)
22
23
  coderay (1.1.2)
23
24
  colorize (0.8.1)
24
- concurrent-ruby (1.1.5)
25
+ concurrent-ruby (1.1.6)
25
26
  diff-lcs (1.3)
26
27
  docker-api (1.34.2)
27
28
  excon (>= 0.47.0)
28
29
  multi_json
29
- excon (0.68.0)
30
- i18n (1.7.0)
30
+ excon (0.73.0)
31
+ i18n (1.8.2)
31
32
  concurrent-ruby (~> 1.0)
32
33
  method_source (0.9.2)
33
- minitest (5.12.2)
34
+ minitest (5.14.0)
34
35
  multi_json (1.14.1)
35
36
  parallel (1.17.0)
36
37
  pry (0.12.2)
@@ -38,7 +39,8 @@ GEM
38
39
  method_source (~> 0.9.0)
39
40
  pry-nav (0.3.0)
40
41
  pry (>= 0.9.10, < 0.13.0)
41
- rake (10.5.0)
42
+ rake (12.3.3)
43
+ require_all (3.0.0)
42
44
  rspec (3.8.0)
43
45
  rspec-core (~> 3.8.0)
44
46
  rspec-expectations (~> 3.8.0)
@@ -56,9 +58,9 @@ GEM
56
58
  rspec (>= 3.0)
57
59
  ruby-progressbar (1.10.1)
58
60
  thread_safe (0.3.6)
59
- tzinfo (1.2.5)
61
+ tzinfo (1.2.7)
60
62
  thread_safe (~> 0.1)
61
- zeitwerk (2.2.0)
63
+ zeitwerk (2.3.0)
62
64
 
63
65
  PLATFORMS
64
66
  ruby
@@ -66,7 +68,7 @@ PLATFORMS
66
68
  DEPENDENCIES
67
69
  bundler (~> 1.17)
68
70
  devkitkat!
69
- rake (~> 10.0)
71
+ rake (~> 12.3.3)
70
72
  rspec (~> 3.0)
71
73
  rspec-temp_dir (~> 1.1.0)
72
74
 
data/README.md CHANGED
@@ -264,11 +264,11 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
264
264
 
265
265
  **Execute only fast tests**
266
266
 
267
- `bundle exec rspec /home/shinya/workspace/devkitkat/spec/devkitkat_spec.rb -t ~slow`
267
+ `bundle exec rspec -t ~slow`
268
268
 
269
269
  **Execute only slow tests**
270
270
 
271
- `bundle exec rspec /home/shinya/workspace/devkitkat/spec/devkitkat_spec.rb -t slow`
271
+ `bundle exec rspec -t slow`
272
272
 
273
273
  ## Contributing
274
274
 
data/bin/devkitkat CHANGED
@@ -3,4 +3,4 @@ require 'bundler/setup' if ENV['DEVKITKAT_DEBUG']
3
3
  require "devkitkat"
4
4
  require 'pry'
5
5
 
6
- Devkitkat::Main.new.execute
6
+ Devkitkat::Main.execute
data/devkitkat.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.require_paths = ["lib"]
25
25
 
26
26
  spec.add_development_dependency "bundler", "~> 1.17"
27
- spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rake", "~> 12.3.3"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
29
  spec.add_development_dependency "rspec-temp_dir", "~> 1.1.0"
30
30
  spec.add_runtime_dependency "pry", "~> 0.12.2"
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
34
  spec.add_runtime_dependency "ruby-progressbar", "~> 1.10.1"
35
35
  spec.add_runtime_dependency "colorize", "~> 0.8.1"
36
36
  spec.add_runtime_dependency "docker-api", "~> 1.34.2"
37
+ spec.add_runtime_dependency "require_all", "~> 3.0.0"
37
38
  end
@@ -1,3 +1,5 @@
1
+ require 'optparse'
2
+
1
3
  module Devkitkat
2
4
  class Command
3
5
  attr_reader :options, :script, :target, :args
@@ -28,18 +30,14 @@ module Devkitkat
28
30
  options[:quiet]
29
31
  end
30
32
 
31
- def tmp_dir
32
- File.join(kit_root, '.devkitkat')
33
- end
34
-
35
- def create_tmp_dir
36
- FileUtils.mkdir_p(tmp_dir)
37
- end
38
-
39
33
  def kit_root
40
34
  options[:root_path] || Dir.pwd
41
35
  end
42
36
 
37
+ def name
38
+ script.tr('-', '_')
39
+ end
40
+
43
41
  private
44
42
 
45
43
  def option_parser
@@ -1,9 +1,10 @@
1
+ require 'yaml'
2
+
1
3
  module Devkitkat
2
4
  class Config
3
5
  DEVKITKAT_FILE_NAME = '.devkitkat.yml'
4
6
  HIDDEN_SERVICES = %w[system]
5
7
  DEFAULT_APPLICATION_NAME = 'devkitkat'
6
- DEFAULT_IMAGE = 'registry.gitlab.com/dosuken123/thin-gdk/thin-gdk-monolith:master'
7
8
 
8
9
  attr_reader :devkitkat_yml, :kit_root
9
10
 
@@ -18,34 +19,46 @@ module Devkitkat
18
19
 
19
20
  def resolve!(target, exclude: nil)
20
21
  services = if target.nil? || target == 'system'
21
- %w[system]
22
- elsif target == 'all'
23
- all_services
24
- elsif group = find_group(target)
25
- services_for_group(group)
26
- elsif services = find_comma_separated_services(target)
22
+ %w[system]
23
+ elsif target == 'all'
24
+ all_services
25
+ elsif group = find_group(target)
26
+ services_for_group(group)
27
+ elsif services = find_comma_separated_services(target)
27
28
  services
28
- elsif service = find_service(target)
29
- [service]
30
- else
31
- raise_error(target)
32
- end
29
+ elsif service = find_service(target)
30
+ [service]
31
+ else
32
+ raise_error(target)
33
+ end
33
34
 
34
35
  services = services - exclude if exclude
35
36
 
36
37
  services
37
38
  end
38
39
 
39
- def environment_type
40
- if devkitkat_yml.key?('image')
41
- 'docker'
42
- else
43
- 'local'
44
- end
40
+ def machine_driver
41
+ devkitkat_yml.dig('machine', 'driver') || 'none'
42
+ end
43
+
44
+ def machine_location
45
+ devkitkat_yml.dig('machine', 'location') || 'local'
46
+ end
47
+
48
+ def machine_image
49
+ devkitkat_yml.dig('machine', 'image')
50
+ end
51
+
52
+ def machine_extra_hosts
53
+ devkitkat_yml.dig('machine', 'extra_hosts')
54
+ end
55
+
56
+ def machine_network_mode
57
+ devkitkat_yml.dig('machine', 'network_mode')
45
58
  end
46
59
 
47
- def image
48
- devkitkat_yml.fetch('image', DEFAULT_IMAGE)
60
+ def extra_write_accesses
61
+ devkitkat_yml.dig('machine', 'extra_write_accesses')
49
62
  end
50
63
 
51
64
  def application
@@ -0,0 +1,48 @@
1
+ require 'parallel'
2
+
3
+ module Devkitkat
4
+ class Processor
5
+ attr_reader :services, :config, :command
6
+
7
+ def initialize(services, command, config)
8
+ @services = services
9
+ @command = command
10
+ @config = config
11
+ end
12
+
13
+ def execute
14
+ results = []
15
+
16
+ print_log_paths
17
+
18
+ if services.count == 1
19
+ # If the target is only one, it could be console access (TTY)
20
+ # so we can't run in parallel.
21
+ results << services.first.execute
22
+ else
23
+ results = Parallel.map(services, progress: 'Executing', in_processes: 8) do |service|
24
+ service.execute.tap do |success|
25
+ raise Parallel::Kill unless success
26
+ end
27
+ end
28
+ end
29
+
30
+ results&.all? { |result| result == true } || terminate_process_group!
31
+ end
32
+
33
+ private
34
+
35
+ def terminate_process_group!
36
+ pgid = Process.getpgid(Process.pid)
37
+
38
+ Process.kill('TERM', -pgid)
39
+ end
40
+
41
+ def print_log_paths
42
+ return if command.interactive? || command.quiet?
43
+
44
+ log_paths = services.map(&:log_path)
45
+ puts %Q{See the log at \n#{log_paths.join("\n")}}
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module Devkitkat
4
+ class Service
5
+ module Concerns
6
+ module ServiceInitializer
7
+ attr_reader :service
8
+
9
+ delegate :config, :command, to: :service
10
+
11
+ def initialize(service)
12
+ @service = service
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module Devkitkat
2
+ class Service
3
+ class Driver
4
+ class Base
5
+ include Concerns::ServiceInitializer
6
+
7
+ PreparationError = Class.new(StandardError)
8
+
9
+ def prepare
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def cleanup
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def execute(script_file)
18
+ raise NotImplementedError
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,163 @@
1
+ module Devkitkat
2
+ class Service
3
+ class Driver
4
+ class Docker < Base
5
+ class Container
6
+ include Concerns::ServiceInitializer
7
+
8
+ ROOT_IN_CONTAINER = '/devkitkat'
9
+
10
+ attr_reader :container
11
+
12
+ def start
13
+ if @container = find
14
+ container.start
15
+ else
16
+ @container = create
17
+ container.start
18
+ create_host_user
19
+ end
20
+ end
21
+
22
+ def stop
23
+ raise 'Container has not started yet' unless container
24
+
25
+ container.stop
26
+ end
27
+
28
+ def exec(cmds, params = {})
29
+ params.merge!(user: user_name)
30
+ safe_exec(cmds, params)
31
+ end
32
+
33
+ def exec_as_host(cmds, params = {})
34
+ safe_exec(cmds, params)
35
+ end
36
+
37
+ private
38
+
39
+ def safe_exec(cmds, params)
40
+ params.merge!(wait: 604800) # Default timeout is 1 minute, so setting 1 week instead
41
+ stdout_messages, stderr_messages, exit_code =
42
+ container.exec(cmds, params)
43
+
44
+ if exit_code != 0 || command.debug?
45
+ puts "#{self.class.name} - #{__callee__}: stdout_messages: #{stdout_messages} stderr_messages: #{stderr_messages} exit_code: #{exit_code}"
46
+ end
47
+
48
+ exit_code == 0 ? true : false
49
+ rescue ::Docker::Error::ConflictError => e
50
+ puts "#{self.class.name} - #{__callee__}: #{e.message}"
51
+ false
52
+ end
53
+
54
+ def image
55
+ config.machine_image
56
+ end
57
+
58
+ def name
59
+ @name ||=
60
+ "#{config.application}-#{service.name}-#{Digest::SHA1.hexdigest(command.kit_root)[8..12]}"
61
+ end
62
+
63
+ def find
64
+ ::Docker::Container.get(name)
65
+ rescue ::Docker::Error::NotFoundError
66
+ nil
67
+ end
68
+
69
+ def create
70
+ ::Docker::Container.create(create_parameter)
71
+ end
72
+
73
+ def create_parameter
74
+ params = {
75
+ 'Cmd' => %w[tail -f],
76
+ 'Image' => image,
77
+ 'name' => name,
78
+ 'HostConfig' => {
79
+ 'Binds' => all_mounts
80
+ }
81
+ }
82
+
83
+ if service.port
84
+ params.deep_merge!(
85
+ 'ExposedPorts' => { "#{service.port}/tcp" => {} },
86
+ 'HostConfig' => {
87
+ 'PortBindings' => {
88
+ "#{service.port}/tcp" => [{ 'HostPort' => service.port.to_s }]
89
+ }
90
+ }
91
+ )
92
+ end
93
+
94
+ if config.machine_extra_hosts
95
+ params.deep_merge!('HostConfig' => { 'ExtraHosts' => config.machine_extra_hosts })
96
+ end
97
+
98
+ if config.machine_network_mode
99
+ params.deep_merge!('HostConfig' => { 'NetworkMode' => config.machine_network_mode })
100
+ end
101
+
102
+ params
103
+ end
104
+
105
+ def all_mounts
106
+ config.all_services.map do |service_name|
107
+ service = Service.new(service_name, config, command)
108
+
109
+ FileUtils.mkdir_p(service.dir)
110
+
111
+ if self.service.name == service_name || service.system? || allowed_by_extra_write_accesses?(service)
112
+ "#{service.dir}:#{ROOT_IN_CONTAINER}/services/#{service.name}"
113
+ else
114
+ "#{service.dir}:#{ROOT_IN_CONTAINER}/services/#{service.name}:ro"
115
+ end
116
+ end
117
+ end
118
+
119
+ def allowed_by_extra_write_accesses?(service)
120
+ config.extra_write_accesses&.any? do |access|
121
+ from, _, to = access.split(':')
122
+ self.service.name == from && service.name == to
123
+ end
124
+ end
125
+
126
+ def user_name
127
+ 'devkitkat'
128
+ end
129
+
130
+ def group_id
131
+ @group_id ||= `id -u`.delete("\n")
132
+ end
133
+
134
+ def user_id
135
+ @user_id ||= `id -g`
136
+ end
137
+
138
+ def create_host_user
139
+ prepare!(['addgroup', '--gid', group_id, user_name])
140
+
141
+ prepare!(['adduser',
142
+ '--uid', user_id,
143
+ '--gid', group_id,
144
+ '--shell', '/bin/bash',
145
+ '--home', ROOT_IN_CONTAINER,
146
+ '--gecos', '',
147
+ '--disabled-password',
148
+ user_name])
149
+
150
+ prepare!(['chown', "#{user_name}:#{user_name}", ROOT_IN_CONTAINER])
151
+ prepare!(['chown', '-R', "#{user_name}:#{user_name}", "#{ROOT_IN_CONTAINER}/services/#{service.name}"])
152
+ end
153
+
154
+ def prepare!(cmds, params = {})
155
+ unless exec_as_host(cmds, params)
156
+ raise Driver::Base::PreparationError, "Failed to execute command in container. cmds: #{cmds}"
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,33 @@
1
+ module Devkitkat
2
+ class Service
3
+ class Driver
4
+ class Docker < Base
5
+ class Image
6
+ include Concerns::ServiceInitializer
7
+
8
+ def pull
9
+ image_exist? || pull_image
10
+ end
11
+
12
+ private
13
+
14
+ def pull_image
15
+ puts "Pulling image #{image}..."
16
+ ::Docker::Image.create('fromImage' => image)
17
+ puts "Pulled image #{image}..."
18
+ end
19
+
20
+ def image_exist?
21
+ ::Docker::Image.get(image)
22
+ rescue
23
+ false
24
+ end
25
+
26
+ def image
27
+ config.machine_image
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,45 @@
1
+ require 'docker'
2
+ require_relative 'docker/container'
3
+ require_relative 'docker/image'
4
+
5
+ module Devkitkat
6
+ class Service
7
+ class Driver
8
+ class Docker < Base
9
+ def prepare
10
+ image.pull
11
+ container.start
12
+ end
13
+
14
+ def execute(script_file)
15
+ new_path = rewrite_root_path!(script_file)
16
+
17
+ container.exec([new_path])
18
+ end
19
+
20
+ def cleanup
21
+ container.stop
22
+ end
23
+
24
+ private
25
+
26
+ def rewrite_root_path!(script_file)
27
+ content = File.read(script_file)
28
+ new_content = content.gsub(command.kit_root, Container::ROOT_IN_CONTAINER)
29
+ File.write(script_file, new_content)
30
+
31
+ relative_path = script_file.delete_prefix(command.kit_root)
32
+ File.join(Container::ROOT_IN_CONTAINER, relative_path)
33
+ end
34
+
35
+ def container
36
+ @container ||= Container.new(service)
37
+ end
38
+
39
+ def image
40
+ @image ||= Image.new(service)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ module Devkitkat
2
+ class Service
3
+ class Driver
4
+ class None < Base
5
+ def prepare
6
+ # no-op
7
+ end
8
+
9
+ def cleanup
10
+ # no-op
11
+ end
12
+
13
+ def execute(script_file)
14
+ system(script_file)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module Devkitkat
2
+ class Service
3
+ class Executor
4
+ class Logger
5
+ include Concerns::ServiceInitializer
6
+
7
+ def to_script
8
+ "exec > #{service.log_path} 2>&1"
9
+ end
10
+
11
+ def available?
12
+ !command.interactive?
13
+ end
14
+
15
+ def new_file
16
+ FileUtils.rm_f(service.log_path)
17
+ FileUtils.mkdir_p(service.log_dir)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,48 @@
1
+ module Devkitkat
2
+ class Service
3
+ class Executor
4
+ class Scripter
5
+ include Concerns::ServiceInitializer
6
+
7
+ SCRIPT_HEADER = <<~EOS
8
+ #!/bin/bash
9
+ EOS
10
+
11
+ def file_path
12
+ File.join(service.dir, "script-#{service.name}-#{command.script}")
13
+ end
14
+
15
+ def new_file
16
+ delete_file
17
+ create_file
18
+
19
+ yield
20
+ ensure
21
+ delete_file
22
+ end
23
+
24
+ def write(cmd)
25
+ File.open(file_path, 'a') do |stream|
26
+ stream.write(cmd + "\n")
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def create_file
33
+ ensure_service_root_dir
34
+ File.write(file_path, SCRIPT_HEADER)
35
+ File.chmod(0777, file_path)
36
+ end
37
+
38
+ def delete_file
39
+ FileUtils.rm_f(file_path)
40
+ end
41
+
42
+ def ensure_service_root_dir
43
+ FileUtils.mkdir_p(service.root_dir)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end