docker-compose 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 39373275b82cf434210606a3f6f11d69677db295
4
- data.tar.gz: b504d7029a2a6150eb5a4e5994d87bf48fa1a03d
3
+ metadata.gz: 03253ecae7a727eaba835a5042ec07bd4af06aee
4
+ data.tar.gz: f82b24d7ade2a1621eab41bb8dc8da1188b7afef
5
5
  SHA512:
6
- metadata.gz: 652113dd63815d7e8261b02e5029d81fc49e6fb0edfd65ffd1f70aa03c3a3f068be1b4d8b361cbb048f7ffff2dd1018ce98ce20d5c82ce15b69df3dd65873f3c
7
- data.tar.gz: 734de8b8783c44a666e6485b5bce36d5d81a9158d421f2721f27a165ed5fb6d7cf53de0027b1223960a2b7dc475a91fe2b1c9d7ae5d3defa4b4d258474d51df9
6
+ metadata.gz: 49ae1c849beb8c5b9623faea4fd73057be4660979f1ea570e4ce013deb4d4e6807498090ae741859a530036ce420b068a587153514aa7b77b9c41072e7d72f59
7
+ data.tar.gz: 3350c7abbd3ae4fcefba35661b82abc314de369f8b7105b0430c10fd7b7031efc9e10e550d47da23898250fc00d76c9bb715d224fe8ebcf0cfbace0623f00d54
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.add_dependency "backticks", "~> 0.1"
23
+
22
24
  spec.add_development_dependency "bundler", "~> 1.10"
23
25
  spec.add_development_dependency "rake", "~> 10.0"
24
26
  spec.add_development_dependency "rspec"
@@ -1,6 +1,5 @@
1
1
  require_relative 'compose/version'
2
2
  require_relative 'compose/error'
3
- require_relative 'compose/shell'
4
3
  require_relative 'compose/session'
5
4
  require_relative 'compose/net_info'
6
5
  require_relative 'compose/mapper'
@@ -53,7 +53,7 @@ module Docker::Compose
53
53
  self.extra_server_env = {}
54
54
  yield self if block_given?
55
55
 
56
- @shell = Docker::Compose::Shell.new
56
+ @shell = Backticks::Runner.new
57
57
  @session = Docker::Compose::Session.new(@shell, dir:dir, file:file)
58
58
  @net_info = Docker::Compose::NetInfo.new
59
59
 
@@ -1,3 +1,5 @@
1
+ require 'backticks'
2
+
1
3
  module Docker::Compose
2
4
  # A Ruby OOP interface to a docker-compose session. A session is bound to
3
5
  # a particular directory and docker-compose file (which are set at initialize
@@ -13,7 +15,7 @@ module Docker::Compose
13
15
  class Session
14
16
  attr_reader :dir, :file
15
17
 
16
- def initialize(shell=Docker::Compose::Shell.new,
18
+ def initialize(shell=Backticks::Runner.new,
17
19
  dir:Dir.pwd, file:'docker-compose.yml')
18
20
  @shell = shell
19
21
  @dir = dir
@@ -89,20 +91,20 @@ module Docker::Compose
89
91
  #
90
92
  # @see Docker::Compose::Shell#command
91
93
  #
92
- # @param [Array] cmd subcommand words and options in the format accepted by
93
- # Shell#command
94
+ # @param [Array] args command-line arguments in the format accepted by
95
+ # Backticks::Runner#command
94
96
  # @return [String] output of the command
95
97
  # @raise [RuntimeError] if command fails
96
- def run!(*cmd)
98
+ def run!(*args)
97
99
  project_opts = {
98
100
  file: @file
99
101
  }
100
102
 
101
103
  Dir.chdir(@dir) do
102
- result, output, error =
103
- @shell.command('docker-compose', project_opts, *cmd)
104
- (result == 0) || raise(Error.new(cmd.first, result, error))
105
- output
104
+ cmd = @shell.command('docker-compose', project_opts, *args).join
105
+ status, out, err= cmd.status, cmd.captured_output, cmd.captured_error
106
+ status.success? || raise(Error.new(args.first, status, err))
107
+ out
106
108
  end
107
109
  end
108
110
  end
@@ -1,5 +1,5 @@
1
1
  module Docker
2
2
  module Compose
3
- VERSION = "0.3.0"
3
+ VERSION = "0.3.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Spataro
@@ -10,6 +10,20 @@ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2015-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: backticks
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.1'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -78,7 +92,6 @@ files:
78
92
  - lib/docker/compose/net_info.rb
79
93
  - lib/docker/compose/rake_tasks.rb
80
94
  - lib/docker/compose/session.rb
81
- - lib/docker/compose/shell.rb
82
95
  - lib/docker/compose/version.rb
83
96
  homepage: https://github.com/xeger/docker-compose
84
97
  licenses:
@@ -1,210 +0,0 @@
1
- require 'open3'
2
- require 'pty'
3
-
4
- module Docker::Compose
5
- # An easy-to-use interface for invoking commands and capturing their output.
6
- # Instances of Shell can be interactive, which prints the command's output
7
- # to the terminal and also allows the user to interact with the command.
8
- class Shell
9
- # If true, commands run in the shell will have their stdio streams tied
10
- # to the parent process so the user can view their output and send input
11
- # to them. Commands' stdout is still captured normally when they are
12
- # interactive.
13
- #
14
- # Note that interactivity doesn't work very well because we use popen,
15
- # which uses pipes to communicate with the child process and pipes have
16
- # a fixed buffer size; the displayed output tends to "lag" behind the
17
- # actual program, and bytes sent to stdin may not arrive until you send
18
- # a lot of them!
19
- #
20
- # @return [Boolean]
21
- attr_accessor :interactive
22
-
23
- # Convert Ruby keyword arguments into CLI parameters that are compatible
24
- # with the syntax of golang's flags package.
25
- #
26
- # Options are translated to CLI parameters using the following convention:
27
- # 1) Snake-case symbols are hyphenated, e.g. :no_foo => "--no-foo"
28
- # 2) boolean values indicate a CLI flag; true includes the flag, false or nil omits it
29
- # 3) other values indicate a CLI option that has a value.
30
- # 4) single character values are passed as short options e.g. "-X V"
31
- # 5) multi-character values are passed as long options e.g. "--XXX=V"
32
- #
33
- def self.options(**opts)
34
- flags = []
35
-
36
- # Transform opts into golang flags-style command line parameters;
37
- # append them to the command.
38
- opts.each do |kw, arg|
39
- if kw.length == 1
40
- if arg == true
41
- # true: boolean flag
42
- flags << "-#{kw}"
43
- elsif arg
44
- # truthey: option that has a value
45
- flags << "-#{kw}" << arg.to_s
46
- else
47
- # falsey: omit boolean flag
48
- end
49
- else
50
- kw = kw.to_s.gsub('_','-')
51
- if arg == true
52
- # true: boolean flag
53
- flags << "--#{kw}"
54
- elsif arg
55
- # truthey: option that has a value
56
- flags << "--#{kw}=#{arg}"
57
- else
58
- # falsey: omit boolean flag
59
- end
60
- end
61
- end
62
-
63
- flags
64
- end
65
-
66
- # Create an instance of Shell.
67
- def initialize
68
- @interactive = false
69
- end
70
-
71
- # Run a shell command whose arguments and flags are expressed using some
72
- # Rubyish sugar. This method accepts an arbitrary number of positional
73
- # parameters; each parameter can be a Hash, an array, or a simple Object.
74
- # Arrays and simple objects are appended to argv as "bare" words; Hashes
75
- # are translated to golang flags and then appended to argv.
76
- #
77
- # @return [Array] an (Integer,String,String) triple of exitstatus, stdout and stderr
78
- #
79
- # @example Run docker-compose with complex parameters
80
- # command('docker-compose', {file: 'joe.yml'}, 'up', {d:true}, 'mysvc')
81
- #
82
- # @see #options for information on Hash-to-flag translation
83
- def command(*cmd)
84
- argv = []
85
-
86
- cmd.each do |item|
87
- case item
88
- when Array
89
- # list of words to append to argv
90
- argv.concat(item.map { |e| e.to_s })
91
- when Hash
92
- # list of options to convert to CLI parameters
93
- argv.concat(self.class.options(item))
94
- else
95
- # single word to append to argv
96
- argv << item.to_s
97
- end
98
- end
99
-
100
- run(argv)
101
- end
102
-
103
- # Run a simple command.
104
- #
105
- # @param [Array] argv list of command words
106
- # @return [Array] triple of integer exitstatus, string stdout, and stderr
107
- private def run(argv)
108
- if self.interactive
109
- run_interactive(argv)
110
- else
111
- run_noninteractive(argv)
112
- end
113
- end
114
-
115
- # Run a shell command. Use a pty to capture the unbuffered output.
116
- #
117
- # @param [Array] argv command to run; argv[0] is program name and the
118
- # remaining elements are parameters and flags
119
- # @return [Array] an (Integer,String,String) triple of exitstatus, stdout and (empty) stderr
120
- private def run_interactive(argv)
121
- stdout, stdout_w = PTY.open
122
- stdin_r, stdin = IO.pipe
123
- stderr, stderr_w = IO.pipe
124
- pid = spawn(*argv, in: stdin_r, out: stdout_w, err: stderr_w)
125
- stdin_r.close
126
- stdout_w.close
127
- stderr_w.close
128
-
129
- output, error = run_inner(stdin, stdout, stderr)
130
-
131
- Process.waitpid(pid)
132
-
133
- [$?.exitstatus, output, error]
134
- end
135
-
136
- # Run a shell command. Perform no translation or substitution. Use a pipe
137
- # to read the output, which may be buffered by the OS. Return the program's
138
- # exit status and stdout.
139
- #
140
- # TODO eliminate interactive path (it can't happen anymore) and move flourishes to run_interactive
141
- #
142
- # @param [Array] argv command to run; argv[0] is program name and the
143
- # remaining elements are parameters and flags
144
- # @return [Array] an (Integer,String,String) triple of exitstatus, stdout and stderr
145
- private def run_noninteractive(argv)
146
- stdin, stdout, stderr, thr = Open3.popen3(*argv)
147
-
148
- output, error = run_inner(stdin, stdout, stderr)
149
-
150
- # This blocks until the process exits (which probably already happened,
151
- # given that we have received EOF on its output streams).
152
- status = thr.value.exitstatus
153
-
154
- [status, output, error]
155
- rescue Interrupt
156
- # Proxy Ctrl+C to our child process
157
- Process.kill('INT', thr.pid) rescue nil
158
- raise
159
- end
160
-
161
- private def run_inner(stdin, stdout, stderr)
162
- streams = [stdout, stderr]
163
-
164
- if @interactive
165
- streams << STDIN
166
- else
167
- stdin.close
168
- end
169
-
170
- output = String.new.force_encoding(Encoding::BINARY)
171
- error = String.new.force_encoding(Encoding::BINARY)
172
-
173
- until streams.empty? || (streams.length == 1 && streams.first == STDIN)
174
- ready, _, _ = IO.select(streams, [], [], 1)
175
-
176
- if ready && ready.include?(STDIN)
177
- input = STDIN.readpartial(1_024) rescue nil
178
- if input
179
- stdin.write(input)
180
- else
181
- # our own STDIN got closed; proxy to child's stdin
182
- stdin.close
183
- end
184
- end
185
-
186
- if ready && ready.include?(stderr)
187
- data = stderr.readpartial(1_024) rescue nil
188
- if data
189
- error << data
190
- STDERR.write(data) if @interactive
191
- else
192
- streams.delete(stderr)
193
- end
194
- end
195
-
196
- if ready && ready.include?(stdout)
197
- data = stdout.readpartial(1_024) rescue nil
198
- if data
199
- output << data
200
- STDOUT.write(data) if @interactive
201
- else
202
- streams.delete(stdout)
203
- end
204
- end
205
- end
206
-
207
- [output, error]
208
- end
209
- end
210
- end