docker-compose 0.6.1 → 0.7.0

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: a853f3487ee69fdc0fcc4e0ee79e9b4c67e188b8
4
- data.tar.gz: 861e629aed8646e04ce22facae96cdaa52c58a67
3
+ metadata.gz: 76d9302ebcd4e76f964dd3f7b85b65cfe6ab0f22
4
+ data.tar.gz: 0d62eabe174c7b93d7a80d120287550e48031457
5
5
  SHA512:
6
- metadata.gz: 8c5bb344080f92b0fe28834510a8cd1c81de3bae182628304bfa108bf97d7c4b7bd32aecf14576b6c33375ff47c0725a018887ad1d3f842257d01b180b53eecc
7
- data.tar.gz: c7e6f3387437334bc5ab9444e36b88ebb58f827c4adaab2698de603d80c04fa61f4c6e13cf6d889598c1ddf947d82fca74ff73ced52a588766440d2b7a5b3cf6
6
+ metadata.gz: ea304f03ad24a904e99af6ce03241f4553cb05cef8876b508c641cc69e05ff7cf7b055dcb7e8ab599069736f3eb597933d97daa1c8915cdea73b0bf9bc40b102
7
+ data.tar.gz: ee9da68c8abe02a2430959bc238c4d79c456da0ae7c7089daf01e5f3db00049afa11f84e597cad3e53b77feae55b9686f00d4c46f1fdeabf0ea56d010cca1c4a
@@ -0,0 +1,35 @@
1
+ # CODING CONVENTIONS
2
+ # - any cop that can be auto-corrected with `rubocop -a` is mandatory
3
+ # - other cops may be enabled if committer fixes all issues
4
+ AllCops:
5
+ Exclude:
6
+ - features/**/*
7
+ - spec/**/*
8
+ Style/Encoding:
9
+ Enabled: true
10
+ Style/FormatString:
11
+ Enabled: false
12
+ Style/GuardClause:
13
+ Enabled: false
14
+ Lint/AmbiguousRegexpLiteral:
15
+ Enabled: false
16
+ Metrics/AbcSize:
17
+ Enabled: false
18
+ Metrics/ClassLength:
19
+ Enabled: false
20
+ Metrics/LineLength:
21
+ Enabled: false
22
+ Metrics/MethodLength:
23
+ Enabled: false
24
+ Metrics/CyclomaticComplexity:
25
+ Enabled: false
26
+ Metrics/PerceivedComplexity:
27
+ Enabled: false
28
+ Style/ClassAndModuleChildren:
29
+ Enabled: false
30
+ Style/Documentation:
31
+ Enabled: false
32
+ Style/RaiseArgs:
33
+ Enabled: false
34
+ Style/Semicolon:
35
+ Enabled: false
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in docker-compose.gemspec
@@ -5,4 +6,6 @@ gemspec
5
6
 
6
7
  group :development do
7
8
  gem 'pry'
8
- end
9
+ gem 'pry-byebug'
10
+ gem 'rubocop'
11
+ end
data/README.md CHANGED
@@ -6,11 +6,10 @@ container orchestration tool from Docker Inc.
6
6
  In addition to wrapping the CLI, this gem provides an environment-variable mapping
7
7
  feature that allows you to export environment variables into your _host_ that point
8
8
  to network services exposed by containers. This allows you to run an application on
9
- your host for quicker and easier development, but run all of its architectural
10
- dependencies -- database, cache, adjacent services -- in containers. The
11
- dependencies can even be running on another machine, e.g. a cloud instance or a
12
- container cluster, provided your development machine has TCP connectivity on every
13
- port exposed by a container.
9
+ your host for quicker and easier development, but run all of its dependencies --
10
+ database, cache, adjacent services -- in containers. The dependencies can even run
11
+ on another machine, e.g. a cloud instance or a container cluster, provided your
12
+ development machine has TCP connectivity to every port exposed by a container.
14
13
 
15
14
  Throughout this documentation we will refer to this gem as `Docker::Compose`
16
15
  as opposed to the `docker-compose` tool that this gem wraps.
@@ -45,6 +44,12 @@ compose = Docker::Compose.new
45
44
  compose.version
46
45
 
47
46
  compose.up(detached:true)
47
+
48
+ exited = compose.ps.where { |c| !c.up? }
49
+ puts "We have some exited containers: " + exited.join(', ')
50
+
51
+ sum = compose.ps.inject(0) { |a,c| a + c.size }
52
+ puts format("Composition is using %.1f MiB disk space", sum/1024.0**2)
48
53
  ```
49
54
 
50
55
  ### Invoking from Rake
@@ -62,7 +67,7 @@ end
62
67
  ```
63
68
 
64
69
  Notice that `rake -T` now has a few additional tasks for invoking gem
65
- functionality. You can `docker:compose:env` print shell exports for
70
+ functionality. You can `docker:compose:env` to print shell exports for
66
71
  host-to-container environment mapping, or you can `docker:compose:host[foo]`.
67
72
 
68
73
  ### Hosting a Command
@@ -71,7 +76,7 @@ To run a process on your host and allow it to talk to containers, use
71
76
  the `docker:compose:host` task. For example, I could enter a shell
72
77
  with `rake docker:compose:host[bash]`.
73
78
 
74
- Before "hosting" your command, the Rake task export ssome environment
79
+ Before "hosting" your command, the Rake task exports some environment
75
80
  variables that your command can use to discover services running in
76
81
  containers. Your Rakefile specifies which variables your app needs
77
82
  (the `host_env` option) and which container information each variable should
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # encoding: utf-8
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
5
6
 
6
- task :default => :spec
7
+ task default: :spec
@@ -1,14 +1,18 @@
1
- #!/usr/bin/env ruby
1
+ #! /usr/bin/env ruby
2
+ # encoding: utf-8
2
3
 
3
- require "bundler/setup"
4
- require "docker/compose"
4
+ require 'bundler/setup'
5
+ require 'docker/compose'
5
6
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
7
+ @session = Docker::Compose::Session.new
8
8
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
9
+ begin
10
+ require 'pry'
11
+ Pry.start(@session)
12
+ rescue LoadError
13
+ require 'irb'
14
+ IRB.setup nil
15
+ IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
16
+ require 'irb/ext/multi-irb'
17
+ IRB.irb nil, @session
18
+ end
@@ -4,24 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'docker/compose/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "docker-compose"
7
+ spec.name = 'docker-compose'
8
8
  spec.version = Docker::Compose::VERSION
9
- spec.authors = ["Tony Spataro"]
10
- spec.email = ["xeger@xeger.net"]
9
+ spec.authors = ['Tony Spataro']
10
+ spec.email = ['xeger@xeger.net']
11
11
 
12
- spec.summary = %q{Wrapper docker-compose with added Rake smarts.}
13
- spec.description = %q{Provides an OOP interface to docker-compose and facilitates container-to-host and host-to-container networking.}
14
- spec.homepage = "https://github.com/xeger/docker-compose"
15
- spec.license = "MIT"
12
+ spec.summary = 'Wrapper docker-compose with added Rake smarts.'
13
+ spec.description = 'Provides an OOP interface to docker-compose and facilitates container-to-host and host-to-container networking.'
14
+ spec.homepage = 'https://github.com/xeger/docker-compose'
15
+ spec.license = 'MIT'
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- spec.bindir = "exe"
18
+ spec.bindir = 'exe'
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
- spec.require_paths = ["lib"]
20
+ spec.require_paths = ['lib']
21
21
 
22
- spec.add_dependency "backticks", "~> 0.4"
22
+ spec.add_dependency 'backticks', '~> 0.4'
23
23
 
24
- spec.add_development_dependency "bundler", "~> 1.10"
25
- spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency 'bundler', '~> 1.10'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'rspec'
27
27
  end
@@ -0,0 +1,6 @@
1
+ apple:
2
+ image: busybox
3
+ command: /bin/sh -c 'sleep 3600'
4
+ orange:
5
+ image: busybox
6
+ command: /bin/sh -c 'sleep 3600'
@@ -1,5 +1,10 @@
1
+ # encoding: utf-8
2
+ require 'net/http'
3
+
1
4
  require_relative 'compose/version'
2
5
  require_relative 'compose/error'
6
+ require_relative 'compose/container'
7
+ require_relative 'compose/collection'
3
8
  require_relative 'compose/session'
4
9
  require_relative 'compose/net_info'
5
10
  require_relative 'compose/mapper'
@@ -0,0 +1,13 @@
1
+ module Docker::Compose
2
+ class Collection < Array
3
+ # @example find containers that are up
4
+ # who_is_up = coll.where { |c| c.up? }
5
+ # @example count space taken by all containers
6
+ # coll.map { |c| c.size }.inject(0) { |a, x| a + x }
7
+ def where
8
+ hits = Collection.new
9
+ self.each { |c| hits << c if yield(c) }
10
+ hits
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,70 @@
1
+ module Docker::Compose
2
+ class Container
3
+ # Format string for `docker ps`
4
+ PS_FMT = '({{.ID}}) ({{.Image}}) ({{.Size}}) ({{.Status}}) ({{.Names}}) ({{.Labels}}) ({{.Ports}})'
5
+ # Number of template substitutions in PS_FMT
6
+ PS_FMT_LEN = PS_FMT.count('.')
7
+ # Pattern that parses human-readable values from ps .Status
8
+ PS_STATUS = /^([A-Za-z]+) ?\(?([0-9]*)\)? ?(.*)$/i
9
+
10
+ attr_reader :id, :image, :size, :status, :exitstatus
11
+ attr_reader :names, :labels, :ports
12
+
13
+ # @param [String] id
14
+ # @param [String] image
15
+ # @param [String,Numeric] size
16
+ # @param [String,#map] status e.g. ['Exited', '0', '3 minutes ago']
17
+ # @param [String,Array] names list of container names (CSV)
18
+ # @param [String,Array] labels list of container labels (CSV)
19
+ # @param [String,Array] ports list of exposed ports (CSV)
20
+ def initialize(id, image, size, status, names, labels, ports)
21
+ if size.is_a?(String)
22
+ scalar, units = size.split(' ')
23
+ scalar = size[0].to_i # lazy: invalid --> 0
24
+ mult = case units.downcase
25
+ when 'b' then 1
26
+ when 'kb' then 1_024
27
+ when 'mb' then 1_024^2
28
+ when 'gb' then 1_024^3
29
+ when 'tb' then 1_024^4
30
+ else
31
+ raise Error.new('Service#new', units, 'Impossibly large unit')
32
+ end
33
+ size = scalar * mult
34
+ end
35
+
36
+ if status.is_a?(String)
37
+ status = PS_STATUS.match(status)
38
+ raise Error.new('Service#new', status, 'Unrecognized status') unless status
39
+ end
40
+
41
+ names = names.split(',') if names.is_a?(String)
42
+ labels = labels.split(',') if labels.is_a?(String)
43
+ ports = ports.split(',') if ports.is_a?(String)
44
+
45
+ @id = id
46
+ @image = image
47
+ @size = size
48
+ @status = status[1].downcase.to_sym
49
+ @exitstatus = !status[2].empty? && status[2].to_i # sloppy!
50
+ @names = names
51
+ @labels = labels
52
+ @ports = ports
53
+ end
54
+
55
+ # static sanity checking ftw!
56
+ unless ( initarity = instance_method(:initialize).arity ) == ( psfmtcnt = PS_FMT.count('.') )
57
+ raise LoadError.new("#{__FILE__}:#{__LINE__} - arity(\#initialize) != len(PS_FMT); #{initarity} != #{psfmtcnt}")
58
+ end
59
+
60
+ # @return [String]
61
+ def name
62
+ names.first
63
+ end
64
+
65
+ # @return [Boolean]
66
+ def up?
67
+ self.status == :up
68
+ end
69
+ end
70
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Docker::Compose
2
3
  class Error < RuntimeError
3
4
  attr_reader :status, :detail
@@ -8,9 +9,18 @@ module Docker::Compose
8
9
  def initialize(cmd, status, detail)
9
10
  @status = status
10
11
  @detail = detail
12
+
11
13
  brief = detail.split("\n").first || '(no output)'
12
- message = format("'%s' failed with status %d: %s", cmd, status, brief)
14
+
15
+ case status
16
+ when Numeric
17
+ status = status.to_s
18
+ else
19
+ status = "'#{status}'"
20
+ end
21
+
22
+ message = format("'%s' failed with status %s: %s", cmd, status, brief)
13
23
  super(message)
14
24
  end
15
25
  end
16
- end
26
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Docker::Compose
2
3
  # Uses a Session to discover information about services' IP addresses and
3
4
  # ports as reachable from the host, then
@@ -31,7 +32,7 @@ module Docker::Compose
31
32
  override_host = net_info.docker_routable_ip
32
33
  end
33
34
 
34
- mapper = self.new(session, override_host)
35
+ mapper = new(session, override_host)
35
36
  env.each_pair do |k, v|
36
37
  begin
37
38
  v = mapper.map(v)
@@ -46,7 +47,7 @@ module Docker::Compose
46
47
  # @param [Docker::Compose::Session] session
47
48
  # @param [String] override_host forcible address or DNS hostname to use;
48
49
  # leave nil to trust docker-compose output.
49
- def initialize(session, override_host=nil)
50
+ def initialize(session, override_host = nil)
50
51
  @session = session
51
52
  @override_host = override_host
52
53
  end
@@ -93,7 +94,7 @@ module Docker::Compose
93
94
  host, port = result.split(':')
94
95
  host = @override_host if @override_host
95
96
  [host, Integer(port)]
96
- rescue RuntimeError
97
+ rescue RuntimeError, TypeError
97
98
  raise NoService, "Service '#{service}' not running, or does not publish port '#{port}'"
98
99
  end
99
100
 
@@ -102,7 +103,11 @@ module Docker::Compose
102
103
  # @param [String] value
103
104
  # @return [String]
104
105
  private def map_scalar(value)
105
- uri = URI.parse(value) rescue nil
106
+ uri = begin
107
+ URI.parse(value)
108
+ rescue
109
+ nil
110
+ end
106
111
  pair = value.split(':')
107
112
 
108
113
  if uri && uri.scheme && uri.host
@@ -121,7 +126,7 @@ module Docker::Compose
121
126
  # the service is running.
122
127
  service = pair.first
123
128
  port = pair.last.gsub(REMOVE_ELIDED, '')
124
- host, _ = host_and_port(service, port)
129
+ host, = host_and_port(service, port)
125
130
  return host
126
131
  else
127
132
  # output port:hostname pair
@@ -129,7 +134,7 @@ module Docker::Compose
129
134
  return "#{host}:#{port}"
130
135
  end
131
136
  else
132
- raise BadSubstitution, "Can't understand '#{value}'"
137
+ fail BadSubstitution, "Can't understand '#{value}'"
133
138
  end
134
139
  end
135
140
  end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Docker::Compose
2
3
  # Utility that gathers information about the relationship between the host
3
4
  # on which the Ruby VM is running and the docker host, then makes an
@@ -23,8 +24,8 @@ module Docker::Compose
23
24
  # Create a new instance of this class.
24
25
  # @param [String] docker_host a URI pointing to the docker host
25
26
  # @param [Array] list of String dotted-quad IPv4 addresses of local host
26
- def initialize(docker_host=ENV['DOCKER_HOST'],
27
- my_ips=self.class.ipv4_interfaces)
27
+ def initialize(docker_host = ENV['DOCKER_HOST'],
28
+ my_ips = self.class.ipv4_interfaces)
28
29
  docker_host ||= 'unix:/var/run/docker.sock'
29
30
  @docker_url = URI.parse(docker_host)
30
31
  @my_ips = my_ips
@@ -39,7 +40,7 @@ module Docker::Compose
39
40
  #
40
41
  # @return [String] IPv4 address of host machine that _may_ be reachable from
41
42
  # Docker machine
42
- def host_routable_ip(target_ip=docker_routable_ip)
43
+ def host_routable_ip(target_ip = docker_routable_ip)
43
44
  best_match = ''
44
45
  best_prefix = 0
45
46
 
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'json'
2
3
  require 'rake/tasklib'
3
4
  require 'shellwords'
@@ -63,7 +64,7 @@ module Docker::Compose
63
64
  yield self if block_given?
64
65
 
65
66
  @shell = Backticks::Runner.new
66
- @session = Docker::Compose::Session.new(@shell, dir:dir, file:file)
67
+ @session = Docker::Compose::Session.new(@shell, dir: dir, file: file)
67
68
  @net_info = Docker::Compose::NetInfo.new
68
69
  @shell_printer = Docker::Compose::ShellPrinter.new
69
70
 
@@ -73,7 +74,7 @@ module Docker::Compose
73
74
  end
74
75
 
75
76
  private def define
76
- namespace self.rake_namespace do
77
+ namespace rake_namespace do
77
78
  desc 'Print bash exports with IP/ports of running services'
78
79
  task :env do
79
80
  @shell.interactive = false # suppress useless 'port' output
@@ -85,18 +86,17 @@ module Docker::Compose
85
86
  # how we intend it to be used.
86
87
  print_usage if tty && tlt
87
88
 
88
- export_env(print:tlt)
89
+ export_env(print: tlt)
89
90
 
90
91
  @shell.interactive = true
91
92
  end
92
93
 
93
94
  desc 'Run command on host, linked to services in containers'
94
- task :host, [:command] => ['docker:compose:env'] do |task, args|
95
-
96
- if self.host_services
97
- @session.up(*self.host_services, detached:true)
95
+ task :host, [:command] => ['docker:compose:env'] do |_task, args|
96
+ if host_services
97
+ @session.up(*host_services, detached: true)
98
98
  else
99
- @session.up(detached:true)
99
+ @session.up(detached: true)
100
100
  end
101
101
 
102
102
  exec(args[:command])
@@ -108,14 +108,14 @@ module Docker::Compose
108
108
  # published by docker-compose services. Optionally also print bash export
109
109
  # statements so this information can be made available to a user's shell.
110
110
  private def export_env(print:)
111
- Docker::Compose::Mapper.map(self.host_env,
112
- session:@session,
113
- net_info:@net_info) do |k, v|
111
+ Docker::Compose::Mapper.map(host_env,
112
+ session: @session,
113
+ net_info: @net_info) do |k, v|
114
114
  ENV[k] = serialize_for_env(v)
115
115
  print_env(k, ENV[k]) if print
116
116
  end
117
117
 
118
- self.extra_host_env.each do |k, v|
118
+ extra_host_env.each do |k, v|
119
119
  ENV[k] = serialize_for_env(v)
120
120
  print_env(k, ENV[k]) if print
121
121
  end
@@ -133,7 +133,7 @@ module Docker::Compose
133
133
  when Array
134
134
  JSON.dump(v)
135
135
  else
136
- raise ArgumentError, "Can't represent a #{v.class} in the environment"
136
+ fail ArgumentError, "Can't represent a #{v.class} in the environment"
137
137
  end
138
138
  end
139
139
 
@@ -146,10 +146,9 @@ module Docker::Compose
146
146
  end
147
147
  end
148
148
 
149
-
150
149
  private def print_usage
151
150
  command = "rake #{rake_namespace}:env"
152
- command = "bundle exec " + command if defined?(Bundler)
151
+ command = 'bundle exec ' + command if defined?(Bundler)
153
152
  puts @shell_printer.comment('To export these variables to your shell, run:')
154
153
  puts @shell_printer.comment(@shell_printer.eval_output(command))
155
154
  end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'backticks'
2
3
  require 'yaml'
3
4
 
@@ -16,7 +17,7 @@ module Docker::Compose
16
17
  class Session
17
18
  attr_reader :dir, :file
18
19
 
19
- def initialize(shell=Backticks::Runner.new(interactive:true),
20
+ def initialize(shell = Backticks::Runner.new(interactive: true),
20
21
  dir:Dir.pwd, file:'docker-compose.yml')
21
22
  @shell = shell
22
23
  @dir = dir
@@ -40,6 +41,23 @@ module Docker::Compose
40
41
  true
41
42
  end
42
43
 
44
+ def ps()
45
+ inter = @shell.interactive
46
+ @shell.interactive = false
47
+
48
+
49
+ lines = run!('ps', q:true).split(/[\r\n]+/)
50
+ containers = Collection.new
51
+
52
+ lines.each do |id|
53
+ containers << docker_ps(id)
54
+ end
55
+
56
+ containers
57
+ ensure
58
+ @shell.interactive = inter
59
+ end
60
+
43
61
  # Idempotently up the given services in the project.
44
62
  # @param [Array] services list of String service names to run
45
63
  # @param [Boolean] detached if true, to start services in the background;
@@ -54,12 +72,16 @@ module Docker::Compose
54
72
  def up(*services,
55
73
  detached:false, timeout:10, no_build:false, no_deps:false)
56
74
  run!('up',
57
- {d:detached, timeout:timeout, no_build:no_build, no_deps:no_deps},
75
+ { d: detached, timeout: timeout, no_build: no_build, no_deps: no_deps },
58
76
  services)
59
77
  true
60
78
  end
61
79
 
62
- # Idempotently run a service in the project.
80
+ def rm(*services, force:false, volumes:false, all:true)
81
+ run!('rm', { f: force, v: volumes, a: all }, services)
82
+ end
83
+
84
+ # Idempotently run an arbitrary command with a service container.
63
85
  # @param [String] service name to run
64
86
  # @param [String] cmd command statement to run
65
87
  # @param [Boolean] detached if true, to start services in the background;
@@ -70,9 +92,9 @@ module Docker::Compose
70
92
  # @param [Boolean] rm remove the container when done
71
93
  # @raise [Error] if command fails
72
94
  def run(service, *cmd, detached:false, no_deps:false, env_vars:[], rm:false)
73
- formated_vars = env_vars.map{|v| {e: v}}
95
+ formated_vars = env_vars.map { |v| { e: v } }
74
96
  run!('run',
75
- {d:detached, no_deps:no_deps, rm:rm}, *formated_vars, service, cmd)
97
+ { d: detached, no_deps: no_deps, rm: rm }, *formated_vars, service, cmd)
76
98
  end
77
99
 
78
100
  # Stop running services.
@@ -80,7 +102,7 @@ module Docker::Compose
80
102
  # @param [Integer] timeout how long to wait for each service to stop
81
103
  # @raise [Error] if command fails
82
104
  def stop(*services, timeout:10)
83
- run!('stop', {timeout:timeout}, services)
105
+ run!('stop', { timeout: timeout }, services)
84
106
  end
85
107
 
86
108
  # Figure out which host a port a given service port has been published to.
@@ -90,7 +112,7 @@ module Docker::Compose
90
112
  # @param [Integer] index of container (if multiple instances running)
91
113
  # @raise [Error] if command fails
92
114
  def port(service, port, protocol:'tcp', index:1)
93
- run!('port', {protocol:protocol, index:index}, service, port)
115
+ run!('port', { protocol: protocol, index: index }, service, port)
94
116
  end
95
117
 
96
118
  # Determine the installed version of docker-compose.
@@ -99,7 +121,7 @@ module Docker::Compose
99
121
  # otherwise, returns a Hash of component-name strings to version strings
100
122
  # @raise [Error] if command fails
101
123
  def version(short:false)
102
- result = run!('version', short:short, file:false, dir:false)
124
+ result = run!('version', short: short, file: false, dir: false)
103
125
 
104
126
  if short
105
127
  result.strip
@@ -129,10 +151,62 @@ module Docker::Compose
129
151
 
130
152
  Dir.chdir(@dir) do
131
153
  cmd = @shell.run('docker-compose', project_opts, *args).join
132
- status, out, err = cmd.status, cmd.captured_output, cmd.captured_error
133
- status.success? || raise(Error.new(args.first, status, err))
154
+ status = cmd.status
155
+ out = cmd.captured_output
156
+ err = cmd.captured_error
157
+ status.success? || fail(Error.new(args.first, status, err))
134
158
  out
135
159
  end
136
160
  end
161
+
162
+ private
163
+
164
+ def docker_ps(id)
165
+ cmd = @shell.run('docker', 'ps', a:true, f:"id=#{id}", format:Container::PS_FMT).join
166
+ status, out, err = cmd.status, cmd.captured_output, cmd.captured_error
167
+ raise Error.new('docker ps', status, "Unexpected output") unless status.success?
168
+ lines = out.split(/[\r\n]+/)
169
+ return nil if lines.empty?
170
+ l = lines.shift
171
+ m = parse(l)
172
+ raise Error.new('docker ps', status, "Cannot parse output: '#{l}'") unless m
173
+ return Container.new(*m)
174
+ end
175
+
176
+ # parse values enclosed within parentheses; values may contain nested
177
+ # matching pairs of parentheses
178
+ def parse(str)
179
+ fields = []
180
+ nest = 0
181
+ field = ''
182
+ str.each_char do |ch|
183
+ got = false
184
+ if nest == 0
185
+ if ch == '('
186
+ nest += 1
187
+ end
188
+ else
189
+ if ch == '('
190
+ nest += 1
191
+ elsif ch == ')'
192
+ nest -= 1
193
+ if nest == 0
194
+ got = true
195
+ else
196
+ field << ch
197
+ end
198
+ else
199
+ field << ch
200
+ end
201
+ end
202
+
203
+ if got
204
+ fields << field
205
+ field = ''
206
+ end
207
+ end
208
+
209
+ fields
210
+ end
137
211
  end
138
212
  end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'etc'
2
3
 
3
4
  module Docker::Compose
@@ -10,7 +11,11 @@ module Docker::Compose
10
11
  basename[0] = basename[0].upcase
11
12
 
12
13
  # Find adapter class named after shell; default to posix if nothing found
13
- klass = const_get(basename.to_sym) rescue Posix
14
+ klass = begin
15
+ const_get(basename.to_sym)
16
+ rescue
17
+ Posix
18
+ end
14
19
 
15
20
  klass.new
16
21
  end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Docker::Compose::ShellPrinter
2
3
  # Printer that works with the Friendly Interactive Shell (fish).
3
4
  class Fish < Posix
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module Docker::Compose::ShellPrinter
2
3
  # Printer that works with any POSIX-compliant shell e.g. sh, bash, zsh
3
4
  class Posix
@@ -29,4 +30,4 @@ module Docker::Compose::ShellPrinter
29
30
  "'#{escaped}'"
30
31
  end
31
32
  end
32
- end
33
+ end
@@ -1,5 +1,6 @@
1
+ # encoding: utf-8
1
2
  module Docker
2
3
  module Compose
3
- VERSION = "0.6.1"
4
+ VERSION = '0.7.0'
4
5
  end
5
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Spataro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-04 00:00:00.000000000 Z
11
+ date: 2016-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backticks
@@ -76,6 +76,7 @@ extra_rdoc_files: []
76
76
  files:
77
77
  - ".gitignore"
78
78
  - ".rspec"
79
+ - ".rubocop.yml"
79
80
  - ".ruby-version"
80
81
  - ".travis.yml"
81
82
  - CHANGELOG.md
@@ -87,7 +88,10 @@ files:
87
88
  - bin/console
88
89
  - bin/setup
89
90
  - docker-compose.gemspec
91
+ - docker-compose.yml
90
92
  - lib/docker/compose.rb
93
+ - lib/docker/compose/collection.rb
94
+ - lib/docker/compose/container.rb
91
95
  - lib/docker/compose/error.rb
92
96
  - lib/docker/compose/mapper.rb
93
97
  - lib/docker/compose/net_info.rb