dockdev 0.3.8 → 0.4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aef435aebef51b0a8aa6535d4f75b6ea8151bd7c474e15547421cc31d7e4dfbc
4
- data.tar.gz: 727d3c78e3c9ae406e4e0dda8c399cced4e86a6c79c4f899d06f626cf365f7d3
3
+ metadata.gz: dc457c18386138fb748fcc182da23a0a53613bcdfad90288ff2e4f553fe81ab7
4
+ data.tar.gz: 6a9d639a8a4a09f76c3948cead657f50688e42c0aaada6f45222dd766b45e947
5
5
  SHA512:
6
- metadata.gz: 81a9a8152486d15d21db57fcaf83a95480bd948c500c28aef61bb3b1f321d5d2d39c5c1d07eb782905ff48b3e763a1db9bf284da78dcc3258d172b6e237684b7
7
- data.tar.gz: 1f9a94feef8e90938743c97623671dcf37ee96153723db7e3f1964c2d0ca08ef8cfbf2bdabc78946c33f37dcbb002a1106c42c6e3b3958a60463e62826876809
6
+ metadata.gz: fa1e22aafc5d128eef30ab82e3b5545d616efda9c30eccc5e85a414aa0638b260be020d3d4d376cceeca0197417f3b9f61098c7fbd607f68576e218ce00e40aa
7
+ data.tar.gz: 677f6dcc88a354185760d1abed3064f8292352ae9f6efb08c4493f1ac42f45eccdb25e70e5ea4b71708aa2cd458ce42de6d3704edcbc658b812f7d257a58e768
data/exe/dockdev CHANGED
@@ -7,13 +7,19 @@
7
7
 
8
8
  require_relative '../lib/dockdev'
9
9
 
10
- contName = ARGV.first || File.basename(Dir.getwd)
11
- cmd = ARGV[1]
10
+ #contName = ARGV.first || File.basename(Dir.getwd)
11
+ #cmd = ARGV[1]
12
+ #input = ARGV[1]
13
+
14
+ uconf = Dockdev::UserConfig.new(ARGV.first)
15
+ contName = uconf.container_name || File.basename(Dir.getwd)
12
16
 
13
17
  begin
14
- Dockdev.with_running_container(contName, command: cmd, root: Dir.getwd)
18
+ #Dockdev.with_running_container(contName, command: cmd, root: Dir.getwd)
19
+ Dockdev.with_running_container(contName, user_config: uconf, root: Dir.getwd)
15
20
  rescue StandardError => ex
16
21
  STDERR.puts ex.message
22
+ STDERR.puts ex.backtrace.join("\n")
17
23
  end
18
24
 
19
25
 
@@ -69,5 +69,6 @@ module Dockdev
69
69
  end
70
70
  end
71
71
 
72
+
72
73
  end
73
74
  end
@@ -88,14 +88,20 @@ module Dockdev
88
88
  [@mounts, @ports]
89
89
  end
90
90
 
91
- def process_mount(opts = {}, &block)
92
- mounts, _ = parse_docker_compose
93
- mounts
94
- end
91
+ def apply_context(dockdev_config)
92
+ ddConf = dockdev_config
93
+
94
+ if not ddConf.nil?
95
+ mounts, ports = parse_docker_compose
96
+ mounts.each do |host, docker|
97
+ ddConf.add_mount(host, docker)
98
+ end
99
+ ports.each do |host, docker|
100
+ ddConf.add_port(host, docker)
101
+ end
102
+ end
95
103
 
96
- def process_port(opts = {}, &block)
97
- _, ports = parse_docker_compose
98
- ports
104
+ ddConf
99
105
  end
100
106
 
101
107
  private
@@ -4,6 +4,7 @@ require 'bundler'
4
4
  module Dockdev
5
5
  module Context
6
6
  class Rubygems
7
+ include TR::CondUtils
7
8
 
8
9
  def self.init_path(path)
9
10
  Rubygems.new(path)
@@ -23,15 +24,10 @@ module Dockdev
23
24
  Dir.glob(File.join(@path,"Gemfile"))
24
25
  end
25
26
 
26
- def process_mount(opts = { dir_inside_docker: "/opt" })
27
+ def apply_context(dockdev_config)
28
+ ddConf = dockdev_config
27
29
 
28
- if @mounts.empty?
29
-
30
- dir_inside_docker = opts[:dir_inside_docker]
31
-
32
- script = ["#!/bin/bash"]
33
- #script << "alias be > /dev/null 2>&1 && echo 'alias be=bundle exec' >> ~/.bashrc"
34
- script << "echo 'alias be=\"bundle exec\"' >> ~/.bashrc"
30
+ if not_empty?(ddConf)
35
31
 
36
32
  #
37
33
  # looking at source code
@@ -39,33 +35,91 @@ module Dockdev
39
35
  # seems this is the way to set root for Bundler
40
36
  #
41
37
  ENV['BUNDLE_GEMFILE'] = find_gemfile.first
42
- Bundler.load.dependencies.each do |d|
43
- if not d.source.nil?
44
- src = d.source
45
- if src.path.to_s != "."
46
- pathInsideDocker = File.join(dir_inside_docker, d.name)
47
- @mounts[src.path.expand_path.to_s] = pathInsideDocker
48
- script << "bundle config --global local.#{d.name} #{pathInsideDocker}"
49
- #res[d.name] = src.path.expand_path.to_s
38
+ if not_empty?(ENV['BUNDLE_GEMFILE'])
39
+
40
+ cmd = ["echo 'alias be = \"bundle exec\"' >> /etc/bash.bashrc"]
41
+
42
+ Bundler.load.dependencies.each do |d|
43
+ if not d.source.nil?
44
+ src = d.source
45
+ if src.path.to_s != "."
46
+ pathInsideDocker = File.join(ddConf.workdir, d.name)
47
+ ddConf.add_mount(src.path.expand_path.to_s,pathInsideDocker)
48
+ # following line assumed 'bundle' program already installed inside the image
49
+ cmd << "bundle config --global local.#{d.name} #{pathInsideDocker}"
50
+ end
50
51
  end
51
52
  end
52
- end
53
53
 
54
- scriptOut = File.join(@path,"to-be-executed-once-inside-docker.sh")
55
- File.open(scriptOut,"w") do |f|
56
- f.write script.join("\n")
54
+ if not_empty?(cmd)
55
+
56
+ script = ["#!/bin/bash"]
57
+ script << "if ! command -v bundle &> /dev/null"
58
+ script << " echo \"Command 'bundle' is available!\""
59
+ script.concat(cmd.collect { |e| " #{e}"})
60
+ script << "then"
61
+ script << " echo \"Command 'bundle' not available\""
62
+ #script << " exit 1"
63
+ script << "fi"
64
+
65
+ File.open("rubygems_init.sh","w") do |f|
66
+ f.write script.join("\n")
67
+ end
68
+
69
+ ddConf.append_Dockerfile("COPY rubygems_init.sh /tmp/rubygems_init.sh")
70
+ ddConf.append_Dockerfile("RUN chmod +x /tmp/rubygems_init.sh && /tmp/rubygems_init.sh")
71
+ end
72
+
57
73
  end
58
- `chmod +x #{scriptOut}`
59
74
 
60
75
  end
61
76
 
62
- @mounts
63
-
77
+ ddConf
64
78
  end
65
79
 
66
- def process_port(opts = {})
67
- @ports
68
- end
80
+ #def process_mount(opts = { dir_inside_docker: "/opt" })
81
+
82
+ # if @mounts.empty?
83
+
84
+ # dir_inside_docker = opts[:dir_inside_docker]
85
+
86
+ # script = ["#!/bin/bash"]
87
+ # #script << "alias be > /dev/null 2>&1 && echo 'alias be=bundle exec' >> ~/.bashrc"
88
+ # script << "echo 'alias be=\"bundle exec\"' >> ~/.bashrc"
89
+
90
+ # #
91
+ # # looking at source code
92
+ # # https://github.com/rubygems/rubygems/blob/master/bundler/lib/bundler/shared_helpers.rb#L246
93
+ # # seems this is the way to set root for Bundler
94
+ # #
95
+ # ENV['BUNDLE_GEMFILE'] = find_gemfile.first
96
+ # Bundler.load.dependencies.each do |d|
97
+ # if not d.source.nil?
98
+ # src = d.source
99
+ # if src.path.to_s != "."
100
+ # pathInsideDocker = File.join(dir_inside_docker, d.name)
101
+ # @mounts[src.path.expand_path.to_s] = pathInsideDocker
102
+ # script << "bundle config --global local.#{d.name} #{pathInsideDocker}"
103
+ # #res[d.name] = src.path.expand_path.to_s
104
+ # end
105
+ # end
106
+ # end
107
+
108
+ # scriptOut = File.join(@path,"to-be-executed-once-inside-docker.sh")
109
+ # File.open(scriptOut,"w") do |f|
110
+ # f.write script.join("\n")
111
+ # end
112
+ # `chmod +x #{scriptOut}`
113
+
114
+ # end
115
+
116
+ # @mounts
117
+
118
+ #end
119
+
120
+ #def process_port(opts = {})
121
+ # @ports
122
+ #end
69
123
 
70
124
  end
71
125
  end
@@ -14,12 +14,26 @@ module Dockdev
14
14
  @ctx[name] = cls
15
15
  end
16
16
 
17
+ def registered_context
18
+ @ctx.keys.freeze
19
+ end
20
+
21
+ def registered_context_by_name(name, path)
22
+ ctx = @ctx[id]
23
+ if not ctx.nil?
24
+ ctx.init_path(path)
25
+ end
26
+
27
+ ctx
28
+ end
29
+
17
30
  def get_context(path)
18
- ctx = []
19
- @ctx.values.each do |v|
31
+ ctx = {}
32
+ @ctx.each do |k, v|
20
33
  vv = v.init_path(path)
21
34
  if vv.is_context?
22
- ctx << vv
35
+ #ctx << vv
36
+ ctx[k] = vv
23
37
  end
24
38
  end
25
39
  ctx
@@ -0,0 +1,311 @@
1
+
2
+ require 'toolrack'
3
+
4
+ module Dockdev
5
+
6
+
7
+ ## Support multiple Dockerfile different configurations
8
+ ## Default config is the default Dockerfile file name
9
+ #class Configs
10
+ # include TR::CondUtils
11
+
12
+ # def initialize
13
+ # @configs = { default: Config.new }
14
+ # end
15
+
16
+ # def config_names
17
+ # @configs.keys.freeze
18
+ # end
19
+
20
+ # def default_config_name
21
+ # :default
22
+ # end
23
+
24
+ # def default_config
25
+ # @configs[:default]
26
+ # end
27
+
28
+ # def config(name)
29
+ # indx = File.basename(name)
30
+ # indx = :default if indx == "Dockerfile"
31
+
32
+ # conf = @configs[indx]
33
+ # if conf.nil?
34
+ # conf = Config.new
35
+ # @configs[indx] = conf
36
+ # end
37
+ # conf
38
+ # end
39
+
40
+ # def is_config_exist?(name)
41
+ # not_empty?(config(name))
42
+ # end
43
+
44
+ # private
45
+ # def method_missing(mtd, *args, &block)
46
+ # default_config.send(mtd, *args, &block)
47
+ # end
48
+ #end # end class Configs
49
+
50
+ # Content of the config file
51
+ # which shall configure the to be run docker instance
52
+ # Hence mostly the accessors/readers are related to docker configuration items
53
+ class Config
54
+ include TR::CondUtils
55
+
56
+ # for image
57
+ attr_accessor :workdir
58
+
59
+ # for container
60
+ attr_reader :mounts, :ports
61
+ attr_accessor :network
62
+
63
+ # for image
64
+ attr_reader :dockerfile_entries
65
+
66
+ # since context activation is automated:
67
+ # 1. skip_context shall skip all found automated activated context
68
+ # 2. activate_context shall add those context which is not found by automated discovery
69
+ attr_reader :skip_context, :activate_context
70
+ def initialize(val = {})
71
+ @mounts = val[:mounts] || {}
72
+ @ports = val[:ports] || {}
73
+ @network = val[:network] || nil
74
+ @dockerfile_entries = val[:dockerfile_entries] || []
75
+ @workdir = val[:workdir] || "/opt"
76
+ @skip_context = val[:skip_context] || []
77
+ @activate_context = val[:activate_context] || []
78
+ end
79
+
80
+
81
+ # Convert internal value into hash to be written to file to get rid of the object
82
+ # encoding in the yaml file
83
+ def to_storage
84
+ { mounts: @mounts, ports: @ports, dockerfile_entries: @dockerfile_entries, workdir: @workdir, skip_context: @skip_context, activate_context: @activate_context }
85
+ end
86
+
87
+
88
+ # Add mount mapping of host => docker follows docker-cli which follows
89
+ # docker cli -v format
90
+ #
91
+ # @param on_host [String] path on host
92
+ # @param on_docker [String] path on docker
93
+ # @param opts [Hash] options for the mount spec definition. Value keys including:
94
+ # @option opts [Symbol] :duplicated_entry_policy :error (default) raise error if the on_host is duplicated/already defined
95
+ # @option opts [Symbol] :duplicated_entry_policy :warn_replace raise warning if the on_host is duplicated/already defined and new entry shall replace the old entry
96
+ # @option opts [Symbol] :duplicated_entry_policy :warn_discard raise warning if the on_host is duplicated/already defined and new entry is discarded
97
+ def add_mount(on_host, on_docker, opts = { duplicated_entry_policy: :error })
98
+ if not_empty?(on_host) and not_empty?(on_docker)
99
+ if @mounts.keys.include?(on_host)
100
+ policy = opts[:duplicated_entry_policy] || :error
101
+ case policy
102
+ when :warn_replace
103
+ logger.warn "on_host '#{on_host}' was mapped to '#{@mounts[on_host]}'. It shall be replaced with '#{on_docker}'"
104
+ @mounts[on_host] = on_docker
105
+
106
+ when :warn_discard
107
+ logger.warn "on_host '#{on_host}' already mapped to '#{@mounts[on_host]}'. New value on_docker is ignored."
108
+
109
+ else
110
+ # default policy always raise error
111
+ raise Error, "on_host '#{on_host}' already mapped to '#{@mounts[on_host]}'"
112
+ end
113
+ else
114
+ @mounts[on_host] = on_docker
115
+ end
116
+ else
117
+ logger.debug "add_mount unsuccessful = on_host : #{on_host} / on_docker : #{on_docker}"
118
+ raise Error, "on_host mount entry cannot be empty" if is_empty?(on_host)
119
+ raise Error, "on_docker mount entry cannot be empty" if is_empty?(on_docker)
120
+ end
121
+ end
122
+
123
+
124
+ # Add port mapping of host => docker follows docker-cli which follows
125
+ # docker cli -p format
126
+ #
127
+ # @param on_host [String] port on host
128
+ # @param on_docker [String] port on docker
129
+ # @param opts [Hash] options for the port spec definition. Value keys including:
130
+ # @option opts [Symbol] :duplicated_entry_policy :error (default) raise error if the on_host is duplicated/already defined
131
+ # @option opts [Symbol] :duplicated_entry_policy :warn_replace raise warning if the on_host is duplicated/already defined and new entry shall replace the old entry
132
+ # @option opts [Symbol] :duplicated_entry_policy :warn_discard raise warning if the on_host is duplicated/already defined and new entry is discarded
133
+ def add_port(on_host, on_docker, opts = { duplicated_entry_policy: :error })
134
+ if not_empty?(on_host) and not_empty?(on_docker)
135
+ if @ports.keys.include?(on_host)
136
+ policy = opts[:duplicated_entry_policy] || :error
137
+ case policy
138
+ when :warn_replace
139
+ logger.warn "on_host '#{on_host}' was mapped to '#{@mounts[on_host]}'. It shall be replaced with '#{on_docker}'"
140
+ @ports[on_host] = on_docker
141
+
142
+ when :warn_discard
143
+ logger.warn "on_host '#{on_host}' already mapped to '#{@mounts[on_host]}'. New value on_docker is ignored."
144
+
145
+ else
146
+ # default policy always raise error
147
+ raise Error, "on_host '#{on_host}' already mapped to '#{@mounts[on_host]}'"
148
+ end
149
+ else
150
+ @ports[on_host] = on_docker
151
+ end
152
+ else
153
+ logger.debug "add_port unsuccessful = on_host : #{on_host} / on_docker : #{on_docker}"
154
+ raise Error, "on_host port entry cannot be empty" if is_empty?(on_host)
155
+ raise Error, "on_docker port entry cannot be empty" if is_empty?(on_docker)
156
+ end
157
+
158
+ end
159
+
160
+ # Any instruction to be appended into Dockerfile.
161
+ # Note this did not presume the entry is RUN, COPY or anyting.
162
+ # A full valid Dockerfile entry has to be provided here
163
+ #
164
+ # @param st [String] Full valid Dockerfile line to be embed into Dockerfile
165
+ def append_Dockerfile(st)
166
+ logger.debug "Appending : #{st}"
167
+ @dockerfile_entries << st
168
+ end
169
+
170
+ def is_context_should_skip?(name)
171
+ @skip_context.include?(name)
172
+ end
173
+
174
+
175
+ def manual_activated_context
176
+ @activate_context.freeze
177
+ end
178
+
179
+
180
+ private
181
+ def logger
182
+ Dockdev.logger(:config)
183
+ end
184
+
185
+ def has_additional_entries?
186
+ not @dockerfile_entries.empty?
187
+ end
188
+ end
189
+
190
+ # Managing the config
191
+ class DockdevConfig
192
+ include TR::CondUtils
193
+
194
+ DOCDEV_CONFIG_FILE = "dockdev-config"
195
+
196
+ def self.load(root = Dir.getwd, &block)
197
+ confFile = Dir.glob(File.join(root,"#{DOCDEV_CONFIG_FILE}.*")).grep(/.yml|.yaml$/)
198
+ if confFile.length > 1
199
+ block.call(:found_more, contFile)
200
+ elsif confFile.length == 0
201
+ block.call(:not_found)
202
+ else
203
+ block.call(:found, confFile.first)
204
+ end
205
+ end
206
+
207
+ def initialize(conf = nil)
208
+ logger.debug "Given to initialize : #{conf}"
209
+ if not_empty?(conf)
210
+ @config = parse(conf)
211
+ else
212
+ @config = Config.new
213
+ end
214
+ end
215
+
216
+
217
+ def save(root = Dir.getwd)
218
+ path = File.join(root,"#{DOCDEV_CONFIG_FILE}.yml")
219
+ File.open(path,"w") do |f|
220
+ f.write YAML.dump(@config.to_storage)
221
+ end
222
+ path
223
+ end
224
+
225
+
226
+ # Build the docker image by embedding additional entries into the Dockerfile.
227
+ # This likely will need a temporary file to be created and it should be managed by
228
+ # this operation.
229
+ #
230
+ # @param [Dockdev::Image] image instance
231
+ # @param [String] path to selected Dockerfile
232
+ def build_image(image, dockerfile_path, opts = { root: Dir.getwd }, &block)
233
+
234
+ if has_additional_entries?
235
+
236
+ logger.debug "dockdev_config has additional entry for Dockerfile. Merging additional entries into Dockerfile"
237
+
238
+ root = opts[:root] || Dir.getwd
239
+ # make it static name so:
240
+ # 1. No file removal is required
241
+ # 2. Allow debug on generated Dockerfile
242
+ # 3. Replace Dockerfile on each run and only single Dockerfile is left on system
243
+ # 4. Allow this temporary to be added to .gitignore
244
+ tmpFile = File.join(root, "#{File.basename(dockerfile_path)}-dockdev")
245
+ File.open(tmpFile,"w") do |f|
246
+ found = false
247
+ File.open(dockerfile_path,"r").each_line do |line|
248
+ # detecting the CMD line if there is any
249
+ if line =~ /^CMD/
250
+ found = true
251
+ # here we append the lines
252
+ dockerfile_entries.each do |al|
253
+ f.puts al
254
+ end
255
+ f.write line
256
+
257
+ else
258
+ f.write line
259
+
260
+ end
261
+ end
262
+
263
+ if not found
264
+ @dockerfile_entries.each do |al|
265
+ f.puts al
266
+ end
267
+ end
268
+
269
+ end
270
+
271
+ image.build(tmpFile)
272
+
273
+ else
274
+ logger.debug "dockdev_config has no additional entry for Dockerfile. Proceed to build found Dockerfile"
275
+ image.build(dockerfile_path)
276
+ end
277
+
278
+ end
279
+
280
+
281
+ private
282
+ def parse(conf)
283
+ logger.debug "Given to parse : #{conf}"
284
+ cont = File.read(conf)
285
+ val = YAML.unsafe_load(cont)
286
+ Config.new(val)
287
+ end
288
+
289
+ def method_missing(mtd, *args, &block)
290
+ logger.debug "method_missing '#{mtd}' / #{args}"
291
+ @config.send(mtd, *args, &block)
292
+ end
293
+
294
+ def logger
295
+ Dockdev.logger(:dockdev_config)
296
+ end
297
+
298
+ end
299
+ end
300
+
301
+
302
+ if $0 == __FILE__
303
+
304
+ require_relative '../dockdev'
305
+
306
+ c = Dockdev::DockdevConfig.new
307
+ c.add_mount("/Users/chris/01.Workspaces/02.Code-Factory/08-Workspace/docker-cli","/opt/docker-cli")
308
+ c.save
309
+ end
310
+
311
+
data/lib/dockdev/image.rb CHANGED
@@ -53,10 +53,12 @@ module Dockdev
53
53
  dockerfile: dockerfilePath
54
54
  }
55
55
  optss.merge!(opts)
56
- @cmd_fact.build_image(@image_name, optss).run
56
+ res = @cmd_fact.build_image(@image_name, optss).run
57
57
 
58
58
  FileUtils.rm(generated_dockerfile) if File.exist?(generated_dockerfile) and not is_keep_generated_dockerfile?
59
59
 
60
+ res
61
+
60
62
  end
61
63
 
62
64
  def destroy
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dockdev
4
- VERSION = "0.3.8"
4
+ VERSION = "0.4.1"
5
5
  end
@@ -12,11 +12,27 @@ module Dockdev
12
12
  end
13
13
 
14
14
  def has_dockerfile?
15
- Dir.glob(File.join(@root,"Dockerfile")).length > 0
15
+ found_dockerfile_count > 0
16
+ end
17
+
18
+ def found_dockerfile_count
19
+ dockerfiles.length
20
+ end
21
+
22
+ def has_multiple_dockerfiles?
23
+ found_dockerfile_count > 1
24
+ end
25
+
26
+ def dockerfiles
27
+ Dir.glob(File.join(@root,"Dockerfile*"))
16
28
  end
17
29
 
18
30
  def dockerfile
19
- Dir.glob(File.join(@root,"Dockerfile")).first
31
+ if has_dockerfile?
32
+ dockerfiles.first
33
+ else
34
+ nil
35
+ end
20
36
  end
21
37
 
22
38
  def has_docker_compose?
data/lib/dockdev.rb CHANGED
@@ -5,82 +5,217 @@ require 'toolrack'
5
5
  require 'docker/cli'
6
6
  require 'colorize'
7
7
 
8
+ require 'tty/prompt'
9
+
8
10
  require_relative "dockdev/version"
9
11
 
10
12
  require_relative 'dockdev/workspace'
11
13
  require_relative 'dockdev/image'
12
14
  require_relative 'dockdev/container'
13
15
 
16
+ require_relative 'dockdev/dockdev_config'
17
+
18
+ require_relative 'dockdev/user_config'
19
+
14
20
  module Dockdev
15
21
  include TR::CondUtils
16
22
 
17
23
  class Error < StandardError; end
18
24
  # Your code goes here...
19
25
 
26
+ # main entry points to start docker
20
27
  def self.with_running_container(contName, opts = {})
21
28
 
29
+ pmt = TTY::Prompt.new
22
30
  root = opts[:root]
23
- cmd = opts[:command]
31
+ cmd = opts[:command] || ""
24
32
 
25
- ctx = Dockdev::Context::ContextManager.instance.get_context(root)
26
- logger.debug("Found context : #{ctx}")
33
+ ddConf = load_config(root)
34
+
35
+ user_config = opts[:user_config]
27
36
 
28
37
  cont = Container.new(contName)
29
38
  if cont.has_container?
39
+
40
+ logger.debug "Container '#{contName}' already exist. Just run the container"
30
41
  if cont.running?
31
42
  cont.attach_and_exec(command: cmd)
32
43
  else
33
44
  cont.start_with_command(command: cmd)
34
45
  end
46
+
35
47
  else
48
+
49
+ logger.debug "Container '#{contName}' does not exist. Creating the container"
50
+
36
51
  img = Image.new(contName)
37
52
  ws = opts[:workspace] || root
38
53
  wss = Workspace.new(ws)
39
- if img.has_image?
40
- mount = { root => File.join("/opt",File.basename(root)) }
41
- port = {}
42
- ctx.each do |cctx|
43
- mnts = cctx.process_mount(dir_inside_docker: "/opt")
44
- logger.debug "Mount points by context : #{mnts}"
45
54
 
46
- mount.merge!(mnts) if not mnts.empty?
55
+ # root directory is mounted by default
56
+ ddConf.add_mount(root, File.join(ddConf.workdir,File.basename(root)))
47
57
 
48
- prt = cctx.process_port
49
- port.merge!(prt) if not prt.empty?
58
+ if user_config.has_key?(:network)
59
+ ddConf.network = user_config.network
60
+ end
61
+
62
+ ctx = Dockdev::Context::ContextManager.instance.get_context(root)
63
+ logger.debug("Found context : #{ctx}")
64
+
65
+ ctx.each do |name, cctx|
50
66
 
51
- logger.debug "Ports by context #{cctx} : #{prt}"
67
+ if ddConf.is_context_should_skip?(name)
68
+ logger.debug "Context '#{name}' is asked to be skipped"
69
+ next
52
70
  end
53
71
 
54
- param = { command: cmd, mounts: mount }
55
- param[:ports] = port if not port.empty?
72
+ logger.debug "Appying context '#{name}' "
73
+ # here allow context to add additional Dockerfile entries, mounts and ports
74
+ ddConf = cctx.apply_context(ddConf)
75
+ end
56
76
 
57
- img.new_container(cont.name, param)
77
+ ddConf.manual_activated_context.each do |cctx|
78
+ mctx = Dockdev::Context::ContextManager.instance.registered_context_by_name(cctx)
79
+ logger.debug "Executing manual activated context : #{mctx}"
80
+ ddConf = mctx.apply_context(ddConf) if not mctx.nil?
81
+ end
58
82
 
59
- elsif wss.has_dockerfile?
60
- img.build(wss.dockerfile)
61
-
62
- mount = { root => File.join("/opt",File.basename(root)) }
63
- port = {}
64
- ctx.each do |cctx|
65
- mnt = cctx.process_mount(dir_inside_docker: "/opt")
66
- mount.merge!(mnt) if not mnt.empty?
83
+ if not img.has_image?
67
84
 
68
- logger.debug "Mount points by context #{cctx} : #{mnt}"
85
+ if wss.has_dockerfile?
69
86
 
70
- prt = cctx.process_port
71
- port.merge!(prt) if not prt.empty?
87
+ if wss.has_multiple_dockerfiles?
72
88
 
73
- logger.debug "Ports by context #{cctx} : #{prt}"
74
- end
89
+ selDockerFile = pmt.select("Please select one of the Dockerfile to proceed : ") do |m|
90
+ wss.dockerfiles.each do |df|
91
+ m.choice File.basename(df), df
92
+ end
93
+ end
75
94
 
76
- param = { command: cmd, mounts: mount }
77
- param[:ports] = port if not port.empty?
95
+ else
96
+ selDockerFile = wss.dockerfile
97
+ end
78
98
 
79
- img.new_container(cont.name, param)
99
+ # Delegated to config file to allow
100
+ # config file to embed addtional entries (if there is any) and proceed to build it.
101
+ # During the process it is very likey a temporary Dockerfile shall be created since
102
+ # docker cli works on file basis and this temporary file need to be managed after the process.
103
+ # Hence this makes more sense to let the config handle all those inside the operation
104
+ res = ddConf.build_image(img, selDockerFile, root: root)
105
+ raise Error, "Image failed to be built. Error was : #{res.err_stream}" if res.failed?
106
+ STDOUT.puts "\n Image '#{contName}' built successfully\n\n".green
107
+ #img.build(wss.dockerfile)
80
108
 
81
- else
82
- raise Error, "\n No image and no Dockerfile found to build the image found. Operation aborted. \n\n".red
109
+ else
110
+ raise Error, "\n No image and no Dockerfile found to build the image. Operation aborted. \n\n".red
111
+
112
+ end
113
+ end
114
+
115
+ # image already exist!
116
+ # Since reach here means container doesn't exist yet.
117
+ # Proceed to create container
118
+
119
+ param = { command: cmd, mounts: ddConf.mounts, ports: ddConf.ports }
120
+ if not_empty?(ddConf.network)
121
+ cmd_fact = Docker::Cli::CommandFactory.new
122
+ res = cmd_fact.create_network(ddConf.network).run
123
+ if res.success? and not res.is_out_stream_empty?
124
+ param[:network] = ddConf.network
125
+ else
126
+ err = res.err_stream
127
+ if err =~ /already exist/
128
+ param[:network] = ddConf.network
129
+ else
130
+ raise Error, "\n Failed to create network. Error was : #{res.err_stream}\n"
131
+ end
132
+ end
83
133
  end
134
+ img.new_container(cont.name, param)
135
+
136
+ #if img.has_image?
137
+ #
138
+ # # has image but no container
139
+ # ctx.each do |cctx|
140
+ #
141
+ # ddConf = cctx.apply_context(ddConf)
142
+
143
+ # #cctx.process_mount(dir_inside_docker: ddConf.workdir).each do |host,docker|
144
+ # # logger.debug "Mount points by context '#{cctx}' : #{host} => #{docker}"
145
+ # # ddConf.add_mount(host, docker)
146
+ # #end
147
+
148
+ # #cctx.process_port.each do |host, docker|
149
+ # # logger.debug "Ports mapping by context '#{cctx}' : #{host} => #{docker}"
150
+ # # ddConf.add_port(host, docker)
151
+ # #end
152
+
153
+ # #mnts = cctx.process_mount(dir_inside_docker: ddConf.workdir)
154
+ # #logger.debug "Mount points by context : #{mnts}"
155
+
156
+ # #mount.merge!(mnts) if not mnts.empty?
157
+
158
+ # #prt = cctx.process_port
159
+ # #port.merge!(prt) if not prt.empty?
160
+
161
+ # #logger.debug "Ports by context #{cctx} : #{prt}"
162
+ # end
163
+
164
+ # #param = { command: cmd, mounts: mount }
165
+ # #param[:ports] = port if not port.empty?
166
+ # param = { command: cmd, mounts: ddConf.mounts, ports: ddConf.ports }
167
+
168
+ # img.new_container(cont.name, param)
169
+
170
+ #elsif wss.has_dockerfile?
171
+
172
+ # logger.debug "Dockerfile '#{wss.dockerfile}' found. Proceed building the image."
173
+
174
+ # # Delegated to config file to allow
175
+ # # config file to embed addtional entries (if there is any) and proceed to build it.
176
+ # # During the process it is very likey a temporary Dockerfile shall be created since
177
+ # # docker cli works on file basis and this temporary file need to be managed after the process.
178
+ # # Hence this makes more sense to let the config handle all those inside the operation
179
+ # ddConf.build_image(img, wss, root: root)
180
+ # #img.build(wss.dockerfile)
181
+ #
182
+ # ddConf.add_mount(root, File.join(ddConf.workdir,File.basename(root)))
183
+ # #mount = { root => File.join(ddConf.workdir,File.basename(root)) }
184
+ # #port = {}
185
+ # ctx.each do |cctx|
186
+
187
+ # ddConf = cctx.apply_context(ddConf)
188
+
189
+ # #cctx.process_mount(dir_inside_docker: ddConf.workdir).each do |host,docker|
190
+ # # logger.debug "Mount points by context '#{cctx}' : #{host} => #{docker}"
191
+ # # ddConf.add_mount(host, docker)
192
+ # #end
193
+
194
+ # #cctx.process_port.each do |host, docker|
195
+ # # logger.debug "Ports mapping by context '#{cctx}' : #{host} => #{docker}"
196
+ # # ddConf.add_port(host, docker)
197
+ # #end
198
+
199
+ # #mnt = cctx.process_mount(dir_inside_docker: ddConf.workdir)
200
+ # #mount.merge!(mnt) if not mnt.empty?
201
+
202
+ # #logger.debug "Mount points by context #{cctx} : #{mnt}"
203
+
204
+ # #prt = cctx.process_port
205
+ # #port.merge!(prt) if not prt.empty?
206
+
207
+ # #logger.debug "Ports by context #{cctx} : #{prt}"
208
+ # end
209
+
210
+ # #param = { command: cmd, mounts: mount }
211
+ # #param[:ports] = port if not port.empty?
212
+ # param = { command: cmd, mounts: ddConf.mounts, ports: ddConf.ports }
213
+
214
+ # img.new_container(cont.name, param)
215
+
216
+ #else
217
+ # raise Error, "\n No image and no Dockerfile found to build the image found. Operation aborted. \n\n".red
218
+ #end
84
219
  end
85
220
  end
86
221
 
@@ -99,6 +234,33 @@ module Dockdev
99
234
 
100
235
  end
101
236
 
237
+ # detect if the additional configuration file exist
238
+ def self.load_config(root)
239
+
240
+ ddConf = DockdevConfig.new
241
+ DockdevConfig.load(root) do |ops, *args|
242
+ case ops
243
+ when :found_more
244
+ found = args.first
245
+ pmt = TTY::Prompt.new
246
+ selConf = pmt.select("There are more config files found. Please select one of the files below :") do |m|
247
+ found.each do |f|
248
+ m.choice Pathname.new(f).relative_path_from(root),f
249
+ end
250
+ end
251
+ ddConf = DockdevConfig.new(selConf)
252
+ when :found
253
+ ddConf = DockdevConfig.new(args.first)
254
+ else
255
+ logger.debug "Load config got ops : #{ops}"
256
+ end
257
+ end
258
+
259
+ logger.debug "Loaded config : #{ddConf}"
260
+ ddConf
261
+
262
+ end
263
+
102
264
  def self.logger(tag = nil, &block)
103
265
  if @_logger.nil?
104
266
  @_logger = TeLogger::Tlogger.new(STDOUT)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dockdev
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-17 00:00:00.000000000 Z
11
+ date: 2024-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: teLogger
@@ -128,6 +128,7 @@ files:
128
128
  - lib/dockdev/context.rb
129
129
  - lib/dockdev/context/docker-compose.rb
130
130
  - lib/dockdev/context/rubygems.rb
131
+ - lib/dockdev/dockdev_config.rb
131
132
  - lib/dockdev/image.rb
132
133
  - lib/dockdev/user_info.rb
133
134
  - lib/dockdev/version.rb
@@ -136,7 +137,7 @@ files:
136
137
  homepage: ''
137
138
  licenses: []
138
139
  metadata: {}
139
- post_install_message:
140
+ post_install_message:
140
141
  rdoc_options: []
141
142
  require_paths:
142
143
  - lib
@@ -151,8 +152,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
152
  - !ruby/object:Gem::Version
152
153
  version: '0'
153
154
  requirements: []
154
- rubygems_version: 3.5.3
155
- signing_key:
155
+ rubygems_version: 3.5.1
156
+ signing_key:
156
157
  specification_version: 4
157
158
  summary: ''
158
159
  test_files: []