docker-compose 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.github/workflows/publish.yml +42 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +38 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +32 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +170 -0
- data/Rakefile +7 -0
- data/bin/console +18 -0
- data/bin/setup +7 -0
- data/docker-compose.gemspec +29 -0
- data/docker-compose.yml +11 -0
- data/lib/docker/compose/collection.rb +13 -0
- data/lib/docker/compose/container.rb +80 -0
- data/lib/docker/compose/error.rb +26 -0
- data/lib/docker/compose/mapper.rb +159 -0
- data/lib/docker/compose/net_info.rb +89 -0
- data/lib/docker/compose/rake_tasks.rb +171 -0
- data/lib/docker/compose/session.rb +354 -0
- data/lib/docker/compose/shell_printer/fish.rb +17 -0
- data/lib/docker/compose/shell_printer/posix.rb +33 -0
- data/lib/docker/compose/shell_printer.rb +26 -0
- data/lib/docker/compose/version.rb +6 -0
- data/lib/docker/compose.rb +19 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bb5c46f2fc1351385671bc66a27b8a5ae3a92769c91c2f5d3470b91f31d38e07
|
4
|
+
data.tar.gz: 19800f852de5921b296eda4d9e64a207ce60a6a1fc7959cfaba11965dfb9b823
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2bf97d99fb8c03cbb2dcbd833d743ef508c7474e6833abf415a0d7534199c67d557585a55ad0dd35d58e92747d8bcada2deb4ce036e7ad86cc79929ad9239a11
|
7
|
+
data.tar.gz: 67f91befe87b16d4f2305bba853eff604abec12d0c3a5f63e1a38f2517838e47a2f1b2db49937630876c6acace00f9abd2f176a17974835eef45465e590217c8
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
repo_token: hMWX6XPNvG4Gfy9gCDEvrxhQVKdyN5e2m
|
@@ -0,0 +1,42 @@
|
|
1
|
+
name: publish
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [actions]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
publish:
|
9
|
+
name: publish
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
permissions:
|
12
|
+
contents: read
|
13
|
+
packages: write
|
14
|
+
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v3
|
17
|
+
- uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: 3.0.0
|
20
|
+
bundler-cache: true
|
21
|
+
- name: build
|
22
|
+
run: |
|
23
|
+
release='v0.0.0'
|
24
|
+
version=`echo $release | cut -b2-`
|
25
|
+
if ! echo $release | grep -q '^v[0-9]\+\.[0-9]\+\.[0-9]\+$'; then
|
26
|
+
echo "Release name must be in the format of 'vX.Y.Z', got '$release'"
|
27
|
+
exit 1
|
28
|
+
fi
|
29
|
+
sed -i -r "s/VERSION = '.+'/VERSION = '$version'/" lib/docker/compose/version.rb
|
30
|
+
bundle exec rake build
|
31
|
+
- name: push
|
32
|
+
run: |
|
33
|
+
mkdir -p $HOME/.gem
|
34
|
+
touch $HOME/.gem/credentials
|
35
|
+
chmod 0600 $HOME/.gem/credentials
|
36
|
+
printf -- "---\n:rubygems_api_key: ${RUBYGEMS_TOKEN}\n:github: Bearer ${GITHUB_TOKEN}\n" > $HOME/.gem/credentials
|
37
|
+
gem push pkg/*.gem
|
38
|
+
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} pkg/*.gem
|
39
|
+
env:
|
40
|
+
GITHUB_TOKEN: "Bearer ${{ secrets.GITHUB_TOKEN }}"
|
41
|
+
OWNER: ${{ github.repository_owner }}
|
42
|
+
RUBYGEMS_TOKEN: "${{ secrets.RUBYGEMS_TOKEN }}"
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,38 @@
|
|
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
|
+
NewCops: enable
|
6
|
+
Exclude:
|
7
|
+
- features/**/*
|
8
|
+
- spec/**/*
|
9
|
+
Style/Encoding:
|
10
|
+
Enabled: true
|
11
|
+
Style/FormatString:
|
12
|
+
Enabled: false
|
13
|
+
Style/GuardClause:
|
14
|
+
Enabled: false
|
15
|
+
Layout/LineLength:
|
16
|
+
Enabled: false
|
17
|
+
Lint/AmbiguousRegexpLiteral:
|
18
|
+
Enabled: false
|
19
|
+
Metrics/AbcSize:
|
20
|
+
Enabled: false
|
21
|
+
Metrics/BlockLength:
|
22
|
+
Enabled: false
|
23
|
+
Metrics/ClassLength:
|
24
|
+
Enabled: false
|
25
|
+
Metrics/MethodLength:
|
26
|
+
Enabled: false
|
27
|
+
Metrics/CyclomaticComplexity:
|
28
|
+
Enabled: false
|
29
|
+
Metrics/PerceivedComplexity:
|
30
|
+
Enabled: false
|
31
|
+
Style/ClassAndModuleChildren:
|
32
|
+
Enabled: false
|
33
|
+
Style/Documentation:
|
34
|
+
Enabled: false
|
35
|
+
Style/RaiseArgs:
|
36
|
+
Enabled: false
|
37
|
+
Style/Semicolon:
|
38
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.0
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
1.1
|
2
|
+
---
|
3
|
+
|
4
|
+
#### New features
|
5
|
+
|
6
|
+
Add `scale` command to Session methods.
|
7
|
+
|
8
|
+
|
9
|
+
1.0
|
10
|
+
---
|
11
|
+
|
12
|
+
No significant changes; the 1.0 increment is to indicate that Docker::Compose now has test coverage, and that we intend to maintain a stable API until 2.0.
|
13
|
+
|
14
|
+
0.6
|
15
|
+
---
|
16
|
+
|
17
|
+
#### Interface-breaking changes
|
18
|
+
|
19
|
+
- Replaced `docker:compose:server` Rake task with more general `docker:compose:host`
|
20
|
+
- Replaced `server_env` option with `host_env`
|
21
|
+
- Replaced `extra_server_env` option with `extra_host_env`
|
22
|
+
- Stopped mapping values in `extra_host_env`; they are now exported verbatim
|
23
|
+
|
24
|
+
#### New features
|
25
|
+
|
26
|
+
Produce `docker:compose:env` output that is compatible with user's login shell.
|
27
|
+
|
28
|
+
0.5
|
29
|
+
---
|
30
|
+
|
31
|
+
Initial public release of prototype. Features work well, but there is no test
|
32
|
+
coverage.
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in docker-compose.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem 'pry'
|
8
|
+
gem 'pry-byebug'
|
9
|
+
gem 'rubocop'
|
10
|
+
gem 'rubocop-rake'
|
11
|
+
gem 'rubocop-rspec'
|
12
|
+
end
|
13
|
+
|
14
|
+
group :test do
|
15
|
+
gem 'coveralls', require: false
|
16
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Tony Spataro
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/xeger/docker-compose.svg)](https://travis-ci.org/xeger/docker-compose) [![Coverage Status](https://coveralls.io/repos/github/xeger/docker-compose/badge.svg?branch=coveralls)](https://coveralls.io/github/xeger/docker-compose?branch=coveralls) [![Docs](https://img.shields.io/badge/docs-rubydoc-blue.svg)](http://www.rubydoc.info/gems/docker-compose)
|
2
|
+
|
3
|
+
# Docker::Compose
|
4
|
+
|
5
|
+
This is a Ruby OOP wrapper for the [docker-compose](https://github.com/docker/compose)
|
6
|
+
container orchestration tool from Docker Inc.
|
7
|
+
|
8
|
+
In addition to wrapping the CLI, this gem provides an environment-variable mapping
|
9
|
+
feature that allows you to export environment variables into your _host_ that point
|
10
|
+
to network services exposed by containers. This allows you to run an application on
|
11
|
+
your host for quicker and easier development, but run all of its dependencies --
|
12
|
+
database, cache, adjacent services -- in containers. The dependencies can even run
|
13
|
+
on another machine, e.g. a cloud instance or a container cluster, provided your
|
14
|
+
development machine has TCP connectivity to every port exposed by a container.
|
15
|
+
|
16
|
+
Throughout this documentation we will refer to this gem as `Docker::Compose`
|
17
|
+
as opposed to the `docker-compose` tool that this gem wraps.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'docker-compose'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
$ bundle
|
30
|
+
|
31
|
+
Or install it yourself as:
|
32
|
+
|
33
|
+
$ gem install docker-compose
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
### Invoking from Ruby code
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
require 'docker/compose'
|
41
|
+
|
42
|
+
# Create a new session in Dir.pwd using the file "docker-compose.yml".
|
43
|
+
# For fine-grained control over options, see Docker::Compose::Session#new
|
44
|
+
compose = Docker::Compose.new
|
45
|
+
|
46
|
+
compose.version
|
47
|
+
|
48
|
+
compose.up(detached:true)
|
49
|
+
|
50
|
+
exited = compose.ps.where { |c| !c.up? }
|
51
|
+
puts "We have some exited containers: " + exited.join(', ')
|
52
|
+
|
53
|
+
sum = compose.ps.inject(0) { |a,c| a + c.size }
|
54
|
+
puts format("Composition is using %.1f MiB disk space", sum/1024.0**2)
|
55
|
+
```
|
56
|
+
|
57
|
+
### Invoking from Rake
|
58
|
+
|
59
|
+
Open your Rakefile and add the Docker::Compose tasks.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
require 'docker/compose/rake_tasks'
|
63
|
+
|
64
|
+
Docker::Compose::RakeTasks.new do |tasks|
|
65
|
+
# customize by calling setter methods of tasks;
|
66
|
+
# see the class documentation for details
|
67
|
+
end
|
68
|
+
|
69
|
+
```
|
70
|
+
|
71
|
+
Notice that `rake -T` now has a few additional tasks for invoking gem
|
72
|
+
functionality. You can `docker:compose:env` to print shell exports for
|
73
|
+
host-to-container environment mapping, or you can `docker:compose:host[foo]`.
|
74
|
+
|
75
|
+
### Hosting a Command
|
76
|
+
|
77
|
+
To run a process on your host and allow it to talk to containers, use
|
78
|
+
the `docker:compose:host` task. For example, I could enter a shell
|
79
|
+
with `rake docker:compose:host[bash]`.
|
80
|
+
|
81
|
+
Before "hosting" your command, the Rake task exports some environment
|
82
|
+
variables that your command can use to discover services running in
|
83
|
+
containers. Your Rakefile specifies which variables your app needs
|
84
|
+
(the `host_env` option) and which container information each variable should
|
85
|
+
map to.
|
86
|
+
|
87
|
+
By hosting commands, you benefit from easier debugging and code editing of
|
88
|
+
the app you're working on, but still get to rely on containers to provide
|
89
|
+
the companion services your app requires to run.
|
90
|
+
|
91
|
+
### Mapping container IPs and ports
|
92
|
+
|
93
|
+
As a trivial example, let's say that your `docker-compose.yml` contains one
|
94
|
+
service, the database that your app needs in order to run.
|
95
|
+
|
96
|
+
```yaml
|
97
|
+
db:
|
98
|
+
image: mysql:latest
|
99
|
+
environment:
|
100
|
+
MYSQL_DATABASE: myapp_development
|
101
|
+
MYSQL_ROOT_PASSWORD: opensesame
|
102
|
+
ports:
|
103
|
+
- "3306"
|
104
|
+
|
105
|
+
```
|
106
|
+
|
107
|
+
Your app needs two inputs, `DATABASE_HOST` and `DATABASE_PORT`. You can specify
|
108
|
+
this with the host_env option of the Rake task:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
Docker::Compose::RakeTasks.new do |tasks|
|
112
|
+
tasks.host_env = {
|
113
|
+
'DATABASE_HOST' => 'db:[3306]',
|
114
|
+
'DATABASE_PORT' => '[db]:3306',
|
115
|
+
}
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
Now, I can run my services, ask Docker::Compose to map the environment values
|
120
|
+
to the actual IP and port that `db` has been published to, and run my app:
|
121
|
+
|
122
|
+
```bash
|
123
|
+
# First, bring up the containers we will be interested in
|
124
|
+
user@machine$ docker-compose up -d
|
125
|
+
|
126
|
+
# The rake task prints bash code resembling the following:
|
127
|
+
# export DATABASE_HOST='127.0.0.1'
|
128
|
+
# export DATABASE_PORT='34387'
|
129
|
+
# We eval it, which makes the variables available to our shell and to all
|
130
|
+
# subprocesses.
|
131
|
+
user@machine$ eval "$(bundle exec rake docker:compose:env)"
|
132
|
+
|
133
|
+
user@machine$ bundle exec rackup
|
134
|
+
```
|
135
|
+
|
136
|
+
The `host_env` option also handles substitution of URLs, and arrays of values
|
137
|
+
(which are serialized back to the environment as JSON)
|
138
|
+
For example:
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
tasks.host_env = {
|
142
|
+
'DATABASE_URL' => 'mysql://db:3306/myapp_development',
|
143
|
+
'MIXED_FRUIT' => ['db:[3306]', '[db]:3306']
|
144
|
+
}
|
145
|
+
```
|
146
|
+
|
147
|
+
This would result in the following exports:
|
148
|
+
|
149
|
+
```bash
|
150
|
+
export DATABASE_URL='mysql://127.0.0.1:34387/myapp_development'
|
151
|
+
export MIXED_FRUIT='["127.0.0.1", "34387"]'
|
152
|
+
```
|
153
|
+
|
154
|
+
To learn more about mapping, read the class documentation for
|
155
|
+
`Docker::Compose::Mapper`.
|
156
|
+
|
157
|
+
## Development
|
158
|
+
|
159
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
160
|
+
|
161
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
162
|
+
|
163
|
+
## Contributing
|
164
|
+
|
165
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/xeger/docker-compose. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
166
|
+
|
167
|
+
|
168
|
+
## License
|
169
|
+
|
170
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'docker/compose'
|
6
|
+
|
7
|
+
@session = Docker::Compose::Session.new
|
8
|
+
|
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
|
data/bin/setup
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'docker/compose/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'docker-compose'
|
8
|
+
spec.version = Docker::Compose::VERSION
|
9
|
+
spec.authors = ['Tony Spataro']
|
10
|
+
spec.email = ['xeger@xeger.net']
|
11
|
+
|
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
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.0', '< 4.0')
|
23
|
+
|
24
|
+
spec.add_dependency 'backticks', '~> 1.0'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 2.3'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
+
spec.add_development_dependency 'rspec'
|
29
|
+
end
|
data/docker-compose.yml
ADDED
@@ -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,80 @@
|
|
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
|
+
# Pattern that parses FIRST occurrence of container size from a string,
|
10
|
+
# along with its units.
|
11
|
+
PS_SIZE = /^([0-9.]+)\s*([kmgt]?B)/i
|
12
|
+
|
13
|
+
attr_reader :id, :image, :size, :status, :exitstatus
|
14
|
+
attr_reader :names, :labels, :ports
|
15
|
+
|
16
|
+
# @param [String] id
|
17
|
+
# @param [String] image
|
18
|
+
# @param [String,Integer] size e.g. "0B (virtual 100MB)"
|
19
|
+
# @param [String,#map] status e.g. ['Exited', '0', '3 minutes ago']
|
20
|
+
# @param [String,Array] names list of container names (CSV)
|
21
|
+
# @param [String,Array] labels list of container labels (CSV)
|
22
|
+
# @param [String,Array] ports list of exposed ports (CSV)
|
23
|
+
def initialize(id, image, size, status, names, labels, ports)
|
24
|
+
if size.is_a?(String) && (m = PS_SIZE.match(size))
|
25
|
+
scalar, units = m[1], m[2]
|
26
|
+
scalar = scalar.to_f # lazy: invalid --> 0.0
|
27
|
+
mult = case units.downcase
|
28
|
+
when 'b' then 1
|
29
|
+
when 'kb' then 1_024
|
30
|
+
when 'mb' then 1_024**2
|
31
|
+
when 'gb' then 1_024**3
|
32
|
+
when 'tb' then 1_024**4
|
33
|
+
else
|
34
|
+
raise Error.new('Service#new', units, 'Impossibly large unit')
|
35
|
+
end
|
36
|
+
size = scalar * mult
|
37
|
+
end
|
38
|
+
|
39
|
+
if status.is_a?(String)
|
40
|
+
status = PS_STATUS.match(status)
|
41
|
+
raise Error.new('Service#new', status, 'Unrecognized status') unless status
|
42
|
+
end
|
43
|
+
|
44
|
+
names = names.split(',').map{ |x| x.strip } if names.is_a?(String)
|
45
|
+
labels = labels.split(',').map{ |x| x.strip } if labels.is_a?(String)
|
46
|
+
ports = ports.split(',').map{ |x| x.strip } if ports.is_a?(String)
|
47
|
+
|
48
|
+
@id = id
|
49
|
+
@image = image
|
50
|
+
@size = size
|
51
|
+
@status = status[1].downcase.to_sym
|
52
|
+
|
53
|
+
@exitstatus = case @status
|
54
|
+
when :up
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
status[2].to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
@names = names
|
61
|
+
@labels = labels
|
62
|
+
@ports = ports
|
63
|
+
end
|
64
|
+
|
65
|
+
# static sanity checking ftw!
|
66
|
+
unless ( initarity = instance_method(:initialize).arity ) == PS_FMT_LEN
|
67
|
+
raise LoadError.new("#{__FILE__}:#{__LINE__} - arity(\#initialize) != PS_FMT_LEN; #{initarity} != #{PS_FMT_LEN}")
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String]
|
71
|
+
def name
|
72
|
+
names.first
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Boolean]
|
76
|
+
def up?
|
77
|
+
self.status == :up
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Docker::Compose
|
3
|
+
class Error < RuntimeError
|
4
|
+
attr_reader :status, :detail
|
5
|
+
|
6
|
+
# @param [String] cmd
|
7
|
+
# @param [Integer] status
|
8
|
+
# @param [String] detail
|
9
|
+
def initialize(cmd, status, detail)
|
10
|
+
@status = status
|
11
|
+
@detail = detail
|
12
|
+
|
13
|
+
brief = detail.split(/[\r\n]+/).select { |l| !l.empty? }.first || '(no output)'
|
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)
|
23
|
+
super(message)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|