docker-compose 0.3.0 → 0.3.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
  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