egg 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 +7 -0
- data/.circleci/config.yml +33 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +26 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +90 -0
- data/LICENSE.txt +13 -0
- data/README.md +48 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/doc/README.md +49 -0
- data/exe/leash +6 -0
- data/leash.gemspec +38 -0
- data/lib/dockerfile.rb +15 -0
- data/lib/dockerfile/base.rb +39 -0
- data/lib/dockerfile/node_js.rb +30 -0
- data/lib/dockerfile/ruby.rb +35 -0
- data/lib/dotenv_util.rb +31 -0
- data/lib/egg.rb +16 -0
- data/lib/egg/cli.rb +48 -0
- data/lib/egg/configuration.rb +89 -0
- data/lib/egg/docker_compose.rb +34 -0
- data/lib/egg/docker_compose/service.rb +41 -0
- data/lib/egg/templates.rb +16 -0
- data/lib/egg/version.rb +5 -0
- data/templates/.dockerignore +7 -0
- data/templates/docker-compose.yml +10 -0
- data/templates/smokey_config.rb +27 -0
- data/templates/supervisord.conf +17 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ac6c50558dd050db0f1815e74af300537bc7a600
|
4
|
+
data.tar.gz: 047271f09e9961ba6d0fc471fa156f12770e9063
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3b32e62253c64394302b7a48011c6ad6c36a9904dff693f842b9bf44b4a64ff6049076a2fe193e10bb97bb022e73a463848cb448ab67a2e90b43d00d8598766
|
7
|
+
data.tar.gz: fdffb864c3ab84bd7ecd5b91ad16f9accc6e02c69708ab4faf03532db7957805c3480f1bd4102a66638a702878e8d39ce140420e352de13fc24005aed457ed95
|
@@ -0,0 +1,33 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
working_directory: ~/egg
|
5
|
+
docker:
|
6
|
+
- image: ruby:2.4.0
|
7
|
+
steps:
|
8
|
+
- run:
|
9
|
+
name: build-deps
|
10
|
+
command: |
|
11
|
+
apt-get -qq update
|
12
|
+
apt-get install -qqy cmake
|
13
|
+
- checkout
|
14
|
+
- type: cache-restore
|
15
|
+
key: egg-bundler-{{ checksum "Gemfile.lock" }}
|
16
|
+
- run: bundle install --path vendor/bundle
|
17
|
+
- type: cache-save
|
18
|
+
key: egg-bundler-{{ checksum "Gemfile.lock" }}
|
19
|
+
paths:
|
20
|
+
- vendor/bundle
|
21
|
+
- run:
|
22
|
+
name: rspec
|
23
|
+
command: |
|
24
|
+
mkdir -p "/tmp/test-results"
|
25
|
+
export TEST_FILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
|
26
|
+
bundle exec rspec --profile 10 \
|
27
|
+
-r rspec_junit_formatter \
|
28
|
+
--format RspecJunitFormatter \
|
29
|
+
--out /tmp/test-results/rspec.xml \
|
30
|
+
--format progress \
|
31
|
+
${TEST_FILES}
|
32
|
+
- type: store_test_results
|
33
|
+
path: /tmp/test-results
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'bin/**/*'
|
4
|
+
- 'vendor/**/*'
|
5
|
+
- 'spec/fixtures/**/*'
|
6
|
+
- 'tmp/**/*'
|
7
|
+
- 'db/schema.rb'
|
8
|
+
- 'db/migrate/**/*'
|
9
|
+
TargetRubyVersion: 2.2
|
10
|
+
|
11
|
+
Style/FrozenStringLiteralComment:
|
12
|
+
EnforcedStyle: when_needed
|
13
|
+
|
14
|
+
Style/StringLiterals:
|
15
|
+
EnforcedStyle: double_quotes
|
16
|
+
|
17
|
+
Metrics/LineLength:
|
18
|
+
Max: 119
|
19
|
+
IgnoreCopDirectives: true
|
20
|
+
|
21
|
+
Metrics/AbcSize:
|
22
|
+
Max: 16.5
|
23
|
+
|
24
|
+
Metrics/BlockLength:
|
25
|
+
Exclude:
|
26
|
+
- 'spec/**/*_spec.rb'
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.1
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at carlthuringer@gmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
egg (0.3.0)
|
5
|
+
thor (~> 0.19.4)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.5.1)
|
11
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
12
|
+
ast (2.3.0)
|
13
|
+
builder (3.2.3)
|
14
|
+
diff-lcs (1.3)
|
15
|
+
faraday (0.12.1)
|
16
|
+
multipart-post (>= 1.2, < 3)
|
17
|
+
gitlab (4.1.0)
|
18
|
+
httparty
|
19
|
+
terminal-table
|
20
|
+
httparty (0.14.0)
|
21
|
+
multi_xml (>= 0.5.2)
|
22
|
+
multi_xml (0.6.0)
|
23
|
+
multipart-post (2.0.0)
|
24
|
+
octokit (4.7.0)
|
25
|
+
sawyer (~> 0.8.0, >= 0.5.3)
|
26
|
+
parallel (1.11.2)
|
27
|
+
parser (2.4.0.0)
|
28
|
+
ast (~> 2.2)
|
29
|
+
powerpack (0.1.1)
|
30
|
+
pronto (0.9.3)
|
31
|
+
gitlab (~> 4.0, >= 4.0.0)
|
32
|
+
httparty (>= 0.13.7, < 0.15)
|
33
|
+
octokit (~> 4.7, >= 4.7.0)
|
34
|
+
rainbow (~> 2.1)
|
35
|
+
rugged (~> 0.24, >= 0.23.0)
|
36
|
+
thor (~> 0.19.0)
|
37
|
+
pronto-rubocop (0.9.0)
|
38
|
+
pronto (~> 0.9.0)
|
39
|
+
rubocop (~> 0.38, >= 0.35.0)
|
40
|
+
public_suffix (2.0.5)
|
41
|
+
rainbow (2.2.2)
|
42
|
+
rake
|
43
|
+
rake (12.0.0)
|
44
|
+
rspec (3.6.0)
|
45
|
+
rspec-core (~> 3.6.0)
|
46
|
+
rspec-expectations (~> 3.6.0)
|
47
|
+
rspec-mocks (~> 3.6.0)
|
48
|
+
rspec-core (3.6.0)
|
49
|
+
rspec-support (~> 3.6.0)
|
50
|
+
rspec-expectations (3.6.0)
|
51
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
52
|
+
rspec-support (~> 3.6.0)
|
53
|
+
rspec-mocks (3.6.0)
|
54
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
55
|
+
rspec-support (~> 3.6.0)
|
56
|
+
rspec-support (3.6.0)
|
57
|
+
rspec_junit_formatter (0.2.3)
|
58
|
+
builder (< 4)
|
59
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
60
|
+
rubocop (0.49.1)
|
61
|
+
parallel (~> 1.10)
|
62
|
+
parser (>= 2.3.3.1, < 3.0)
|
63
|
+
powerpack (~> 0.1)
|
64
|
+
rainbow (>= 1.99.1, < 3.0)
|
65
|
+
ruby-progressbar (~> 1.7)
|
66
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
67
|
+
ruby-progressbar (1.8.1)
|
68
|
+
rugged (0.25.1.1)
|
69
|
+
sawyer (0.8.1)
|
70
|
+
addressable (>= 2.3.5, < 2.6)
|
71
|
+
faraday (~> 0.8, < 1.0)
|
72
|
+
terminal-table (1.8.0)
|
73
|
+
unicode-display_width (~> 1.1, >= 1.1.1)
|
74
|
+
thor (0.19.4)
|
75
|
+
unicode-display_width (1.3.0)
|
76
|
+
|
77
|
+
PLATFORMS
|
78
|
+
ruby
|
79
|
+
|
80
|
+
DEPENDENCIES
|
81
|
+
bundler (~> 1.15)
|
82
|
+
egg!
|
83
|
+
pronto (~> 0.9.3)
|
84
|
+
pronto-rubocop (~> 0.9.0)
|
85
|
+
rake (~> 12.0)
|
86
|
+
rspec (~> 3.6, >= 3.6.0)
|
87
|
+
rspec_junit_formatter (~> 0.2.3)
|
88
|
+
|
89
|
+
BUNDLED WITH
|
90
|
+
1.15.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright [2017] [Carl Thuringer]
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Egg
|
2
|
+
|
3
|
+
Egg helps prevent code fires! Also he makes it easy to run complex multi-service apps with Docker.
|
4
|
+
|
5
|
+
Maintainers:
|
6
|
+
* [Carl Thuringer](https://github.com/carlthuringer)
|
7
|
+
* [Jason Sisk](https://github.com/sisk)
|
8
|
+
|
9
|
+
This gem is currently heavily focused on Ruby and Rails projects relevant within
|
10
|
+
the Belly organization. The eventual goal is for this to become language and
|
11
|
+
framework agnostic, though the configuration language will be Ruby.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'egg'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install egg
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
* `init` - Initialize a repo for use with Egg. Creates the `egg_config.rb`
|
31
|
+
* `readme` - Display the Usage readme
|
32
|
+
* `setup` - Generates the docker files from the configuration, runs all setup hooks, then boots the application.
|
33
|
+
|
34
|
+
## Development
|
35
|
+
|
36
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
37
|
+
|
38
|
+
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).
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bellycard/egg. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
43
|
+
|
44
|
+
|
45
|
+
## License
|
46
|
+
|
47
|
+
The gem is available as open source under the terms of the [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
48
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'egg'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start
|
data/bin/setup
ADDED
data/doc/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Egg
|
2
|
+
|
3
|
+
Egg makes it easy to set up a cluster of applications for local development, using the magic of docker.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```bash
|
8
|
+
egg setup
|
9
|
+
```
|
10
|
+
Once finished, the services will be running.
|
11
|
+
|
12
|
+
### Stopping, Starting, Updating
|
13
|
+
|
14
|
+
Most docker compose commands can apply to a single service if you follow the command with the service name (app, db)
|
15
|
+
|
16
|
+
```bash
|
17
|
+
// Pause processes
|
18
|
+
docker-compose pause
|
19
|
+
// Unpause processes
|
20
|
+
docker-compose unpause
|
21
|
+
// Kill processes, but keep the containers intact.
|
22
|
+
docker-compose kill
|
23
|
+
// Start processes from stopped containers.
|
24
|
+
docker-compose start
|
25
|
+
// Restart services
|
26
|
+
docker-compose restart
|
27
|
+
// Rebuild all changed images, and start in the background.
|
28
|
+
docker-compose up -d
|
29
|
+
// List processes
|
30
|
+
docker-compose ps
|
31
|
+
// Kill and remove all containers.
|
32
|
+
docker-compose down
|
33
|
+
```
|
34
|
+
|
35
|
+
### Getting into it
|
36
|
+
```bash
|
37
|
+
// Get into a running service
|
38
|
+
docker-compose exec [service-name] [command]
|
39
|
+
// ex. docker-compose exec app bash
|
40
|
+
// >> root@156b321e6ec8:/enterprise-admin#
|
41
|
+
```
|
42
|
+
|
43
|
+
You can run tests, or anything, while inside the container, or run rake tasks and rspec directly without first launching a bash process.
|
44
|
+
```bash
|
45
|
+
docker-compose exec app bin/rake db:migrate
|
46
|
+
docker-compose exec app rspec spec/controllers/api/v2/chains_controller_spec.rb
|
47
|
+
```
|
48
|
+
|
49
|
+
More at [docker compose](https://docs.docker.com/compose/compose-file)
|
data/exe/leash
ADDED
data/leash.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "Egg/version"
|
6
|
+
|
7
|
+
description = <<-EOT
|
8
|
+
Egg helps initialize, manage, and execute on complex multi-service architectures using Docker and Docker Compose
|
9
|
+
EOT
|
10
|
+
|
11
|
+
Gem::Specification.new do |spec|
|
12
|
+
spec.name = "egg"
|
13
|
+
spec.version = Egg::VERSION
|
14
|
+
spec.authors = ["Carl Thuringer", "Jason Sisk"]
|
15
|
+
spec.email = ["tech@bellycard.com"]
|
16
|
+
|
17
|
+
spec.summary = "Egg helps you develop with Docker!"
|
18
|
+
spec.description = description
|
19
|
+
spec.homepage = "http://github.com/bellycard/egg"
|
20
|
+
spec.license = "Apache-2.0"
|
21
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
22
|
+
|
23
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
f.match(%r{^(test|spec|features)/})
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_runtime_dependency "thor", "~> 0.19.4"
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
33
|
+
spec.add_development_dependency "rake", "~> 12.0"
|
34
|
+
spec.add_development_dependency "rspec", '~> 3.6', '>= 3.6.0'
|
35
|
+
spec.add_development_dependency "rspec_junit_formatter", "~> 0.2.3"
|
36
|
+
spec.add_development_dependency "pronto", "~> 0.9.3"
|
37
|
+
spec.add_development_dependency "pronto-rubocop", "~> 0.9.0"
|
38
|
+
end
|
data/lib/dockerfile.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Module that wraps configuration of Dockerfiles from Templates.
|
2
|
+
module Dockerfile
|
3
|
+
class NoDockerfileError < StandardError; end
|
4
|
+
class MissingPropertyError < StandardError; end
|
5
|
+
|
6
|
+
def self.use(klass)
|
7
|
+
const_get("Dockerfile::#{klass}").new
|
8
|
+
rescue NameError
|
9
|
+
raise(NoDockerfileError, "No Dockerfile subclass for #{klass}.")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require_relative "dockerfile/base"
|
14
|
+
require_relative "dockerfile/ruby"
|
15
|
+
require_relative "dockerfile/node_js"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Dockerfile
|
2
|
+
# Provides shared behavior for dockerfile template classes.
|
3
|
+
class Base
|
4
|
+
attr_reader :template
|
5
|
+
attr_accessor :command
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@template = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def required_attributes
|
12
|
+
[:command]
|
13
|
+
end
|
14
|
+
|
15
|
+
def render
|
16
|
+
required_attributes.each do |attr|
|
17
|
+
raise(MissingPropertyError, "Must populate #{attr}") if send(attr).nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
unrendered_output = template.reduce("") do |out, (command, string)|
|
21
|
+
out << command.to_s.upcase << " " << string << "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
ERB.new(unrendered_output).result(binding)
|
25
|
+
end
|
26
|
+
|
27
|
+
def run(command, before: [:cmd])
|
28
|
+
template.insert(do_before(before), [:run, command])
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def do_before(before)
|
34
|
+
template.index(before) ||
|
35
|
+
template.index { |tc| tc[0] == before[0] } ||
|
36
|
+
-1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Dockerfile
|
2
|
+
# Wrapper for templating of NodeJS Dockerfile
|
3
|
+
class NodeJS < Base
|
4
|
+
def required_attributes
|
5
|
+
super + [:node_version]
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_accessor :node_version
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@template = dockerfile
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def dockerfile # rubocop:disable Metrics/MethodLength
|
17
|
+
[
|
18
|
+
[:from, "node:<%= node_version %>"],
|
19
|
+
[:env, "APP_HOME /app"],
|
20
|
+
[:run, "mkdir $APP_HOME"],
|
21
|
+
[:workdir, "$APP_HOME"],
|
22
|
+
[:add, "package.json $APP_HOME/"],
|
23
|
+
[:add, "yarn.lock $APP_HOME/"],
|
24
|
+
[:run, "yarn install"],
|
25
|
+
[:add, ". $APP_HOME"],
|
26
|
+
[:cmd, "<%= command %>"]
|
27
|
+
]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Dockerfile
|
2
|
+
# Ruby Dockerfile Template
|
3
|
+
# Required Attributes:
|
4
|
+
# @ruby_version: Version of Ruby to use for the ruby image.
|
5
|
+
class Ruby < Base
|
6
|
+
def required_attributes
|
7
|
+
super + [:ruby_version]
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :ruby_version
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@template = dockerfile
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def dockerfile # rubocop:disable Metrics/MethodLength
|
19
|
+
[
|
20
|
+
[:from, "ruby:<%= ruby_version %>"],
|
21
|
+
[:run, "apt-get update -qq && apt-get upgrade -qqy"],
|
22
|
+
[:run, "apt-get -qqy install cmake"],
|
23
|
+
[:run, "gem install bundler"],
|
24
|
+
[:env, "APP_HOME /app"],
|
25
|
+
[:run, "mkdir $APP_HOME"],
|
26
|
+
[:workdir, "$APP_HOME"],
|
27
|
+
[:add, ".ruby-version $APP_HOME/"],
|
28
|
+
[:add, "Gemfile* $APP_HOME/"],
|
29
|
+
[:env, "BUNDLE_GEMFILE=$APP_HOME/Gemfile BUNDLE_JOBS=4 BUNDLE_WITHOUT=production:staging"],
|
30
|
+
[:run, "bundle install"],
|
31
|
+
[:add, ". $APP_HOME"]
|
32
|
+
]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/dotenv_util.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Provides Generic support for manipulating Dotenv files
|
4
|
+
class DotenvUtil
|
5
|
+
attr_reader :env_text, :env
|
6
|
+
def initialize(env_file)
|
7
|
+
@env_text = env_file
|
8
|
+
@env = parse_env_file
|
9
|
+
end
|
10
|
+
|
11
|
+
def set(target, value)
|
12
|
+
env[target] = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_env
|
16
|
+
env.collect do |key, val|
|
17
|
+
%(#{key}="#{val}")
|
18
|
+
end.join("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def parse_env_file
|
24
|
+
env_text.split.each_with_object({}) do |line, hash|
|
25
|
+
match = line.match(/^([A-Z_]+)="?(.+)?"?$/)
|
26
|
+
next unless match
|
27
|
+
hash.store(*match.captures)
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/egg.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :nodoc:
|
4
|
+
module Egg
|
5
|
+
def self.root_join(*joins)
|
6
|
+
path_parts = [File.dirname(__FILE__)] + joins.map(&:to_s)
|
7
|
+
joined_path = File.join(*path_parts)
|
8
|
+
File.expand_path(joined_path)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require_relative "egg/version"
|
13
|
+
require_relative "egg/cli"
|
14
|
+
require_relative "egg/templates"
|
15
|
+
require_relative "egg/configuration"
|
16
|
+
require_relative "egg/docker_compose"
|
data/lib/egg/cli.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module Egg
|
7
|
+
# Defines the CLI interface to egg functions
|
8
|
+
class CLI < Thor
|
9
|
+
desc "init", "Initialize the current directory as a egg repo."
|
10
|
+
option :force
|
11
|
+
def init
|
12
|
+
config = Templates["egg_config.rb"]
|
13
|
+
if File.exist?("egg_config.rb") && !options[:force]
|
14
|
+
print "egg has already been initialized! (maybe you want to --force)\n"
|
15
|
+
exit(1)
|
16
|
+
else
|
17
|
+
File.write("egg_config.rb", config.result)
|
18
|
+
print "Wrote example egg_config.rb, customize it to suit your app"
|
19
|
+
write_git_ignorance
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "readme", "Display readme for egg apps."
|
24
|
+
def readme
|
25
|
+
# Print out the readme
|
26
|
+
readme_path = File.expand_path("../../../doc/README.md", __FILE__)
|
27
|
+
File.open(readme_path, "r") do |f|
|
28
|
+
print(f.read)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "setup", "Run all setup"
|
33
|
+
def setup
|
34
|
+
config = Configuration.load "./egg_config.rb"
|
35
|
+
config.run_setup
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def write_git_ignorance
|
41
|
+
gitignore = File.read(".gitignore")
|
42
|
+
gitignore << "Dockerfile\n" unless /^Dockerfile$/ =~ gitignore
|
43
|
+
gitignore << ".dockerignore\n" unless /^\.dockerignore$/ =~ gitignore
|
44
|
+
gitignore << "docker-compose.yml\n" unless /^docker-compose\.yml$/ =~ gitignore
|
45
|
+
File.write(".gitignore", gitignore)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
require "fileutils"
|
5
|
+
require "dotenv_util"
|
6
|
+
require "dockerfile"
|
7
|
+
require "open3"
|
8
|
+
|
9
|
+
module Egg
|
10
|
+
# Reads and Processes the egg_config.rb file.
|
11
|
+
class Configuration
|
12
|
+
# Based on rubygems' specification load:
|
13
|
+
# https://github.com/rubygems/rubygems/blob/0749715e4bd9e7f0fb631a352ddc649574da91c1/lib/rubygems/specification.rb#L1146
|
14
|
+
def self.load(file)
|
15
|
+
code = File.read file
|
16
|
+
config = eval code, binding, file # rubocop:disable Security/Eval
|
17
|
+
|
18
|
+
return config if config.is_a? Egg::Configuration
|
19
|
+
rescue SignalException, SystemExit
|
20
|
+
raise
|
21
|
+
rescue SyntaxError, StandardError => e
|
22
|
+
warn "Invalid configuration in [#{file}]: #{e}"
|
23
|
+
warn e.backtrace.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :docker_compose,
|
27
|
+
:ssh_support,
|
28
|
+
:ruby_version,
|
29
|
+
:supervisor,
|
30
|
+
:dotenv,
|
31
|
+
:dockerfile
|
32
|
+
|
33
|
+
def initialize(&configuration_block)
|
34
|
+
self.docker_compose = DockerCompose.new
|
35
|
+
self.ssh_support = false
|
36
|
+
self.ruby_version = "2.4"
|
37
|
+
self.dotenv = DotenvUtil.new(File.read(".env.template"))
|
38
|
+
instance_eval(&configuration_block)
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def after_startup(&block)
|
43
|
+
@after_startup = block
|
44
|
+
end
|
45
|
+
|
46
|
+
# You may pass a block to docker_exec to read the output in a controlled manner.
|
47
|
+
def docker_exec(app, command)
|
48
|
+
print "docker-compose exec #{app} #{command}\n"
|
49
|
+
Open3.popen2(%(docker-compose exec #{app} #{command})) do |_input, output, wait_thread|
|
50
|
+
output_read = output.read
|
51
|
+
print output_read + "\n"
|
52
|
+
yield output_read if block_given?
|
53
|
+
wait_thread.value.success? || raise(StandardError, "docker_exec exited with #{wait_thread.value.to_i}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def run_setup
|
58
|
+
write_docker_files
|
59
|
+
|
60
|
+
docker_pull_build
|
61
|
+
File.write(".env", dotenv.generate_env)
|
62
|
+
system("docker-compose up -d")
|
63
|
+
|
64
|
+
run_after_startup
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def run_after_startup
|
70
|
+
return unless @after_startup
|
71
|
+
print "Running after-startup block\n"
|
72
|
+
@after_startup.call
|
73
|
+
end
|
74
|
+
|
75
|
+
def docker_pull_build
|
76
|
+
system("docker-compose pull")
|
77
|
+
system("docker-compose build") || raise($CHILD_STATUS)
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_docker_files
|
81
|
+
File.write("Dockerfile", dockerfile.render) if dockerfile
|
82
|
+
|
83
|
+
dockerignore = Templates[".dockerignore"].result(binding)
|
84
|
+
File.write(".dockerignore", dockerignore)
|
85
|
+
|
86
|
+
File.write("docker-compose.yml", docker_compose.to_yaml)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
# Wraps the generation of Docker Compose file
|
6
|
+
class DockerCompose
|
7
|
+
attr_reader :docker_compose,
|
8
|
+
:services
|
9
|
+
|
10
|
+
def initialize(_compose_config = {})
|
11
|
+
@services = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure
|
15
|
+
yield docker_compose
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_yaml
|
19
|
+
output = { "version" => "2" }
|
20
|
+
output["services"] = services.each_with_object({}) do |service, hash|
|
21
|
+
hash[service.name] = service.to_hash
|
22
|
+
end
|
23
|
+
|
24
|
+
output.to_yaml
|
25
|
+
end
|
26
|
+
|
27
|
+
def service(name)
|
28
|
+
service = Service.new(name)
|
29
|
+
services << service
|
30
|
+
service
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
require_relative "docker_compose/service"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DockerCompose
|
4
|
+
# Wraps the definition of docker-compose services
|
5
|
+
class Service
|
6
|
+
attr_reader :name, :links, :environment
|
7
|
+
attr_accessor :dockerfile,
|
8
|
+
:command,
|
9
|
+
:ports,
|
10
|
+
:volumes,
|
11
|
+
:image
|
12
|
+
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
|
16
|
+
@links = []
|
17
|
+
@environment = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def link(service)
|
21
|
+
@links << service.name
|
22
|
+
end
|
23
|
+
|
24
|
+
def env(variable, value)
|
25
|
+
@environment << "#{variable}=#{value}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hash
|
29
|
+
output = {
|
30
|
+
"environment" => environment,
|
31
|
+
"links" => links,
|
32
|
+
"volumes" => volumes,
|
33
|
+
"ports" => ports
|
34
|
+
}
|
35
|
+
|
36
|
+
image ? output["image"] = image : output["build"] = "."
|
37
|
+
output["command"] = command if command
|
38
|
+
output.each_with_object({}) { |(k, v), hash| hash[k] = v if v }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
|
5
|
+
module Egg
|
6
|
+
# Aids in the loading of template files bundled in the gem.
|
7
|
+
class Templates
|
8
|
+
class TemplateNotFoundError < StandardError; end
|
9
|
+
|
10
|
+
def self.[](filename)
|
11
|
+
template_path = Egg.root_join("..", "templates", filename)
|
12
|
+
raise(TemplateNotFoundError, "No #{filename}") unless File.exist?(template_path)
|
13
|
+
ERB.new(File.read(template_path))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/egg/version.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Egg::Configuration.new do |config|
|
4
|
+
# Do stuff here.
|
5
|
+
|
6
|
+
# Example dockerfile config.
|
7
|
+
# Available arguments for use: ["Ruby", "NodeJS"]
|
8
|
+
# self.dockerfile = Dockerfile.use "Ruby"
|
9
|
+
# self.dockerfile.ruby_version = "2.4.0"
|
10
|
+
# self.dockerfile.command = "bin/rails server -p 3000"
|
11
|
+
|
12
|
+
# Example docker_compose config:
|
13
|
+
# app = config.docker_compose.service "app"
|
14
|
+
# app.ports = ["3000:3000"]
|
15
|
+
# app.volumes = [".:/app"]
|
16
|
+
|
17
|
+
# db = config.docker_compose.service "db"
|
18
|
+
# db.image = "mysql"
|
19
|
+
# db.env "MYSQL_ROOT_PASSWORD", "mysqliswebscale"
|
20
|
+
# app.link db
|
21
|
+
|
22
|
+
# after_startup do
|
23
|
+
# docker_exec "app", "rake db:setup db:seed"
|
24
|
+
# dotenv.set("foo", "bar")
|
25
|
+
# File.write(".env", dotenv.generate_env)
|
26
|
+
# end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
[supervisord]
|
2
|
+
nodaemon=true
|
3
|
+
loglevel=debug
|
4
|
+
logfile=/var/log/supervisor/supervisord.log
|
5
|
+
pidfile=/var/run/supervisord.pid
|
6
|
+
childlogdir=/var/log/supervisor
|
7
|
+
|
8
|
+
[program:sshd]
|
9
|
+
command=/usr/sbin/sshd -D
|
10
|
+
|
11
|
+
[program:app]
|
12
|
+
command=/bin/bash -c "rails server -p 3000"
|
13
|
+
redirect_stderr=true
|
14
|
+
|
15
|
+
[program:guard]
|
16
|
+
command=/bin/bash -c "guard"
|
17
|
+
redirect_stderr=true
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: egg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Carl Thuringer
|
8
|
+
- Jason Sisk
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-08-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.19.4
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.19.4
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.15'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.15'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '12.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '12.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.6'
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 3.6.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - "~>"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '3.6'
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.6.0
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: rspec_junit_formatter
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.2.3
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.2.3
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: pronto
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.9.3
|
97
|
+
type: :development
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.9.3
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: pronto-rubocop
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.9.0
|
111
|
+
type: :development
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.9.0
|
118
|
+
description: " Egg helps initialize, manage, and execute on complex multi-service
|
119
|
+
architectures using Docker and Docker Compose\n"
|
120
|
+
email:
|
121
|
+
- tech@bellycard.com
|
122
|
+
executables:
|
123
|
+
- leash
|
124
|
+
extensions: []
|
125
|
+
extra_rdoc_files: []
|
126
|
+
files:
|
127
|
+
- ".circleci/config.yml"
|
128
|
+
- ".gitignore"
|
129
|
+
- ".rspec"
|
130
|
+
- ".rubocop.yml"
|
131
|
+
- ".ruby-version"
|
132
|
+
- CODE_OF_CONDUCT.md
|
133
|
+
- Gemfile
|
134
|
+
- Gemfile.lock
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- bin/console
|
139
|
+
- bin/setup
|
140
|
+
- doc/README.md
|
141
|
+
- exe/leash
|
142
|
+
- leash.gemspec
|
143
|
+
- lib/dockerfile.rb
|
144
|
+
- lib/dockerfile/base.rb
|
145
|
+
- lib/dockerfile/node_js.rb
|
146
|
+
- lib/dockerfile/ruby.rb
|
147
|
+
- lib/dotenv_util.rb
|
148
|
+
- lib/egg.rb
|
149
|
+
- lib/egg/cli.rb
|
150
|
+
- lib/egg/configuration.rb
|
151
|
+
- lib/egg/docker_compose.rb
|
152
|
+
- lib/egg/docker_compose/service.rb
|
153
|
+
- lib/egg/templates.rb
|
154
|
+
- lib/egg/version.rb
|
155
|
+
- templates/.dockerignore
|
156
|
+
- templates/docker-compose.yml
|
157
|
+
- templates/smokey_config.rb
|
158
|
+
- templates/supervisord.conf
|
159
|
+
homepage: http://github.com/bellycard/egg
|
160
|
+
licenses:
|
161
|
+
- Apache-2.0
|
162
|
+
metadata:
|
163
|
+
allowed_push_host: https://rubygems.org
|
164
|
+
post_install_message:
|
165
|
+
rdoc_options: []
|
166
|
+
require_paths:
|
167
|
+
- lib
|
168
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
requirements: []
|
179
|
+
rubyforge_project:
|
180
|
+
rubygems_version: 2.6.11
|
181
|
+
signing_key:
|
182
|
+
specification_version: 4
|
183
|
+
summary: Egg helps you develop with Docker!
|
184
|
+
test_files: []
|