pups 1.0.3 → 1.1.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.
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ require 'shellwords'
3
+
4
+ class Pups::Docker
5
+ class << self
6
+ def generate_env_arguments(config)
7
+ output = []
8
+ config&.each do |k, v|
9
+ if !v.to_s.empty?
10
+ output << "--env #{k}=#{escape_user_string_literal(v)}"
11
+ end
12
+ end
13
+ normalize_output(output)
14
+ end
15
+
16
+ def generate_link_arguments(config)
17
+ output = []
18
+ config&.each do |c|
19
+ output << "--link #{c['link']['name']}:#{c['link']['alias']}"
20
+ end
21
+ normalize_output(output)
22
+ end
23
+
24
+ def generate_expose_arguments(config)
25
+ output = []
26
+ config&.each do |c|
27
+ if c.to_s.include?(":")
28
+ output << "--publish #{c}"
29
+ else
30
+ output << "--expose #{c}"
31
+ end
32
+ end
33
+ normalize_output(output)
34
+ end
35
+
36
+ def generate_volume_arguments(config)
37
+ output = []
38
+ config&.each do |c|
39
+ output << "--volume #{c['volume']['host']}:#{c['volume']['guest']}"
40
+ end
41
+ normalize_output(output)
42
+ end
43
+
44
+ def generate_label_arguments(config)
45
+ output = []
46
+ config&.each do |k, v|
47
+ output << "--label #{k}=#{escape_user_string_literal(v)}"
48
+ end
49
+ normalize_output(output)
50
+ end
51
+
52
+ private
53
+ def escape_user_string_literal(str)
54
+ # We need to escape the following strings as they are more likely to contain
55
+ # special characters than any of the other config variables on a Linux system:
56
+ # - the value side of an environment variable
57
+ # - the value side of a label.
58
+ if str.to_s.include?(" ")
59
+ "\"#{Shellwords.escape(str)}\""
60
+ else
61
+ Shellwords.escape(str)
62
+ end
63
+ end
64
+
65
+ def normalize_output(output)
66
+ if output.empty?
67
+ ""
68
+ else
69
+ output.join(" ")
70
+ end
71
+ end
72
+ end
73
+ end
@@ -1,124 +1,128 @@
1
- require 'timeout'
1
+ # frozen_string_literal: true
2
2
 
3
- class Pups::ExecCommand < Pups::Command
4
- attr_reader :commands, :cd
5
- attr_accessor :background, :raise_on_fail, :stdin, :stop_signal
3
+ require 'timeout'
4
+ require 'English'
6
5
 
7
- def self.terminate_async(opts={})
6
+ module Pups
7
+ class ExecCommand < Pups::Command
8
+ attr_reader :commands, :cd
9
+ attr_accessor :background, :raise_on_fail, :stdin, :stop_signal
8
10
 
9
- return unless defined? @@asyncs
11
+ def self.terminate_async(opts = {})
12
+ return unless defined? @@asyncs
10
13
 
11
- Pups.log.info("Terminating async processes")
14
+ Pups.log.info('Terminating async processes')
12
15
 
13
- @@asyncs.each do |async|
14
- Pups.log.info("Sending #{async[:stop_signal]} to #{async[:command]} pid: #{async[:pid]}")
15
- Process.kill(async[:stop_signal],async[:pid]) rescue nil
16
- end
17
-
18
- @@asyncs.map do |async|
19
- Thread.new do
16
+ @@asyncs.each do |async|
17
+ Pups.log.info("Sending #{async[:stop_signal]} to #{async[:command]} pid: #{async[:pid]}")
20
18
  begin
19
+ Process.kill(async[:stop_signal], async[:pid])
20
+ rescue StandardError
21
+ nil
22
+ end
23
+ end
24
+
25
+ @@asyncs.map do |async|
26
+ Thread.new do
21
27
  Timeout.timeout(opts[:wait] || 10) do
22
- Process.wait(async[:pid]) rescue nil
28
+ Process.wait(async[:pid])
29
+ rescue StandardError
30
+ nil
23
31
  end
24
32
  rescue Timeout::Error
25
33
  Pups.log.info("#{async[:command]} pid:#{async[:pid]} did not terminate cleanly, forcing termination!")
26
34
  begin
27
- Process.kill("KILL",async[:pid])
35
+ Process.kill('KILL', async[:pid])
28
36
  Process.wait(async[:pid])
29
37
  rescue Errno::ESRCH
30
38
  rescue Errno::ECHILD
31
39
  end
32
-
33
40
  end
34
- end
35
- end.each(&:join)
36
-
37
- end
38
-
39
- def self.from_hash(hash, params)
40
- cmd = new(params, hash["cd"])
41
-
42
- case c = hash["cmd"]
43
- when String then cmd.add(c)
44
- when Array then c.each{|i| cmd.add(i)}
41
+ end.each(&:join)
45
42
  end
46
43
 
47
- cmd.background = hash["background"]
48
- cmd.stop_signal = hash["stop_signal"] || "TERM"
49
- cmd.raise_on_fail = hash["raise_on_fail"] if hash.key? "raise_on_fail"
50
- cmd.stdin = interpolate_params(hash["stdin"], params)
44
+ def self.from_hash(hash, params)
45
+ cmd = new(params, hash['cd'])
51
46
 
52
- cmd
53
- end
47
+ case c = hash['cmd']
48
+ when String then cmd.add(c)
49
+ when Array then c.each { |i| cmd.add(i) }
50
+ end
54
51
 
55
- def self.from_str(str, params)
56
- cmd = new(params)
57
- cmd.add(str)
58
- cmd
59
- end
52
+ cmd.background = hash['background']
53
+ cmd.stop_signal = hash['stop_signal'] || 'TERM'
54
+ cmd.raise_on_fail = hash['raise_on_fail'] if hash.key? 'raise_on_fail'
55
+ cmd.stdin = interpolate_params(hash['stdin'], params)
60
56
 
61
- def initialize(params, cd = nil)
62
- @commands = []
63
- @params = params
64
- @cd = interpolate_params(cd)
65
- @raise_on_fail = true
66
- end
57
+ cmd
58
+ end
67
59
 
68
- def add(cmd)
69
- @commands << process_params(cmd)
70
- end
60
+ def self.from_str(str, params)
61
+ cmd = new(params)
62
+ cmd.add(str)
63
+ cmd
64
+ end
71
65
 
72
- def run
73
- commands.each do |command|
74
- Pups.log.info("> #{command}")
75
- pid = spawn(command)
76
- Pups.log.info(@result.readlines.join("\n")) if @result
77
- pid
66
+ def initialize(params, cd = nil)
67
+ @commands = []
68
+ @params = params
69
+ @cd = interpolate_params(cd)
70
+ @raise_on_fail = true
78
71
  end
79
- rescue
80
- raise if @raise_on_fail
81
- end
82
72
 
83
- def spawn(command)
84
- if background
85
- pid = Process.spawn(command)
86
- (@@asyncs ||= []) << {pid: pid, command: command, stop_signal: (stop_signal || "TERM")}
87
- Thread.new do
88
- begin
89
- Process.wait(pid)
90
- rescue Errno::ECHILD
91
- # already exited so skip
92
- end
93
- @@asyncs.delete_if{|async| async[:pid] == pid}
94
- end
95
- return pid
73
+ def add(cmd)
74
+ @commands << process_params(cmd)
96
75
  end
97
76
 
98
- IO.popen(command, "w+") do |f|
99
- if stdin
100
- # need a way to get stdout without blocking
101
- Pups.log.info(stdin)
102
- f.write stdin
103
- f.close
104
- else
105
- Pups.log.info(f.readlines.join)
77
+ def run
78
+ commands.each do |command|
79
+ Pups.log.info("> #{command}")
80
+ pid = spawn(command)
81
+ Pups.log.info(@result.readlines.join("\n")) if @result
82
+ pid
106
83
  end
84
+ rescue StandardError
85
+ raise if @raise_on_fail
107
86
  end
108
87
 
109
- unless $? == 0
110
- err = Pups::ExecError.new("#{command} failed with return #{$?.inspect}")
111
- err.exit_code = $?.exitstatus
112
- raise err
113
- end
88
+ def spawn(command)
89
+ if background
90
+ pid = Process.spawn(command)
91
+ (@@asyncs ||= []) << { pid: pid, command: command, stop_signal: (stop_signal || 'TERM') }
92
+ Thread.new do
93
+ begin
94
+ Process.wait(pid)
95
+ rescue Errno::ECHILD
96
+ # already exited so skip
97
+ end
98
+ @@asyncs.delete_if { |async| async[:pid] == pid }
99
+ end
100
+ return pid
101
+ end
114
102
 
115
- nil
103
+ IO.popen(command, 'w+') do |f|
104
+ if stdin
105
+ # need a way to get stdout without blocking
106
+ Pups.log.info(stdin)
107
+ f.write stdin
108
+ f.close
109
+ else
110
+ Pups.log.info(f.readlines.join)
111
+ end
112
+ end
116
113
 
117
- end
114
+ unless $CHILD_STATUS == 0
115
+ err = Pups::ExecError.new("#{command} failed with return #{$CHILD_STATUS.inspect}")
116
+ err.exit_code = $CHILD_STATUS.exitstatus
117
+ raise err
118
+ end
118
119
 
119
- def process_params(cmd)
120
- processed = interpolate_params(cmd)
121
- @cd ? "cd #{cd} && #{processed}" : processed
122
- end
120
+ nil
121
+ end
123
122
 
123
+ def process_params(cmd)
124
+ processed = interpolate_params(cmd)
125
+ @cd ? "cd #{cd} && #{processed}" : processed
126
+ end
127
+ end
124
128
  end
@@ -1,41 +1,37 @@
1
- class Pups::FileCommand < Pups::Command
2
- attr_accessor :path, :contents, :params, :type, :chmod, :chown
1
+ # frozen_string_literal: true
3
2
 
4
- def self.from_hash(hash, params)
5
- command = new
6
- command.path = hash["path"]
7
- command.contents = hash["contents"]
8
- command.chmod = hash["chmod"]
9
- command.chown = hash["chown"]
10
- command.params = params
3
+ module Pups
4
+ class FileCommand < Pups::Command
5
+ attr_accessor :path, :contents, :params, :type, :chmod, :chown
11
6
 
12
- command
13
- end
7
+ def self.from_hash(hash, params)
8
+ command = new
9
+ command.path = hash['path']
10
+ command.contents = hash['contents']
11
+ command.chmod = hash['chmod']
12
+ command.chown = hash['chown']
13
+ command.params = params
14
14
 
15
- def initialize
16
- @params = {}
17
- @type = :bash
18
- end
15
+ command
16
+ end
19
17
 
20
- def params=(p)
21
- @params = p
22
- end
18
+ def initialize
19
+ @params = {}
20
+ @type = :bash
21
+ end
23
22
 
24
- def run
25
- path = interpolate_params(@path)
23
+ attr_writer :params
26
24
 
27
- `mkdir -p #{File.dirname(path)}`
28
- File.open(path, "w") do |f|
29
- f.write(interpolate_params(contents))
30
- end
31
- if @chmod
32
- `chmod #{@chmod} #{path}`
33
- end
34
- if @chown
35
- `chown #{@chown} #{path}`
25
+ def run
26
+ path = interpolate_params(@path)
27
+
28
+ `mkdir -p #{File.dirname(path)}`
29
+ File.open(path, 'w') do |f|
30
+ f.write(interpolate_params(contents))
31
+ end
32
+ `chmod #{@chmod} #{path}` if @chmod
33
+ `chown #{@chown} #{path}` if @chown
34
+ Pups.log.info("File > #{path} chmod: #{@chmod} chown: #{@chown}")
36
35
  end
37
- Pups.log.info("File > #{path} chmod: #{@chmod} chown: #{@chown}")
38
36
  end
39
-
40
37
  end
41
-
@@ -1,48 +1,50 @@
1
- class Pups::MergeCommand < Pups::Command
2
- attr_reader :filename
3
- attr_reader :merge_hash
4
-
5
- def self.from_str(command, params)
6
- new(command,params)
7
- end
8
-
9
- def self.parse_command(command)
10
- split = command.split(" ")
11
- raise ArgumentError.new("Invalid merge command #{command}") unless split[-1][0] == "$"
12
-
13
- [split[0..-2].join(" ") , split[-1][1..-1]]
14
- end
15
-
16
- def initialize(command, params)
17
- @params = params
18
-
19
- filename, target_param = Pups::MergeCommand.parse_command(command)
20
- @filename = interpolate_params(filename)
21
- @merge_hash = params[target_param]
22
- end
23
-
24
- def run
25
- merged = self.class.deep_merge(YAML.load_file(@filename), @merge_hash)
26
- File.open(@filename,"w"){|f| f.write(merged.to_yaml) }
27
- Pups.log.info("Merge: #{@filename} with: \n#{@merge_hash.inspect}")
1
+ # frozen_string_literal: true
2
+
3
+ module Pups
4
+ class MergeCommand < Pups::Command
5
+ attr_reader :filename, :merge_hash
6
+
7
+ def self.from_str(command, params)
8
+ new(command, params)
9
+ end
10
+
11
+ def self.parse_command(command)
12
+ split = command.split(' ')
13
+ raise ArgumentError, "Invalid merge command #{command}" unless split[-1][0] == '$'
14
+
15
+ [split[0..-2].join(' '), split[-1][1..-1]]
16
+ end
17
+
18
+ def initialize(command, params)
19
+ @params = params
20
+
21
+ filename, target_param = Pups::MergeCommand.parse_command(command)
22
+ @filename = interpolate_params(filename)
23
+ @merge_hash = params[target_param]
24
+ end
25
+
26
+ def run
27
+ merged = self.class.deep_merge(YAML.load_file(@filename), @merge_hash)
28
+ File.open(@filename, 'w') { |f| f.write(merged.to_yaml) }
29
+ Pups.log.info("Merge: #{@filename} with: \n#{@merge_hash.inspect}")
30
+ end
31
+
32
+ def self.deep_merge(first, second, *args)
33
+ args ||= []
34
+ merge_arrays = args.include? :merge_arrays
35
+
36
+ merger = proc { |_key, v1, v2|
37
+ if v1.is_a?(Hash) && v2.is_a?(Hash)
38
+ v1.merge(v2, &merger)
39
+ elsif v1.is_a?(Array) && v2.is_a?(Array)
40
+ merge_arrays ? v1 + v2 : v2
41
+ elsif v2.is_a?(NilClass)
42
+ v1
43
+ else
44
+ v2
45
+ end
46
+ }
47
+ first.merge(second, &merger)
48
+ end
28
49
  end
29
-
30
- def self.deep_merge(first,second, *args)
31
- args ||= []
32
- merge_arrays = args.include? :merge_arrays
33
-
34
- merger = proc { |key, v1, v2|
35
- if Hash === v1 && Hash === v2
36
- v1.merge(v2, &merger)
37
- elsif Array === v1 && Array === v2
38
- merge_arrays ? v1 + v2 : v2
39
- elsif NilClass === v2
40
- v1
41
- else
42
- v2
43
- end
44
- }
45
- first.merge(second, &merger)
46
- end
47
-
48
50
  end