railsdock 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +0 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +173 -0
- data/LICENSE.txt +20 -0
- data/README.md +55 -0
- data/Rakefile +14 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/railsdock +18 -0
- data/ext/railsdock/extconf.rb +3 -0
- data/ext/railsdock/railsdock.c +9 -0
- data/ext/railsdock/railsdock.h +6 -0
- data/lib/railsdock.rb +6 -0
- data/lib/railsdock/cli.rb +33 -0
- data/lib/railsdock/command.rb +101 -0
- data/lib/railsdock/commands/install.rb +142 -0
- data/lib/railsdock/logo.rb +49 -0
- data/lib/railsdock/templates/install/default/Dockerfile +101 -0
- data/lib/railsdock/templates/install/default/default.env.erb +44 -0
- data/lib/railsdock/templates/install/default/docker-compose.mac.yml +7 -0
- data/lib/railsdock/templates/install/default/docker-compose.yml.erb +51 -0
- data/lib/railsdock/templates/install/memcached/Dockerfile +7 -0
- data/lib/railsdock/templates/install/memcached/docker-compose.yml.erb +11 -0
- data/lib/railsdock/templates/install/mysql/Dockerfile +7 -0
- data/lib/railsdock/templates/install/mysql/database.yml.erb +18 -0
- data/lib/railsdock/templates/install/mysql/docker-compose.yml.erb +13 -0
- data/lib/railsdock/templates/install/postgres/Dockerfile +7 -0
- data/lib/railsdock/templates/install/postgres/database.yml.erb +18 -0
- data/lib/railsdock/templates/install/postgres/docker-compose.yml.erb +11 -0
- data/lib/railsdock/templates/install/redis/Dockerfile +7 -0
- data/lib/railsdock/templates/install/redis/docker-compose.yml.erb +11 -0
- data/lib/railsdock/version.rb +3 -0
- data/railsdock.gemspec +60 -0
- data/railsdock.png +0 -0
- metadata +393 -0
data/lib/railsdock.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module Railsdock
|
6
|
+
# Handle the application command line parsing
|
7
|
+
# and the dispatch to various command objects
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
class CLI < Thor
|
11
|
+
# Error raised by this runner
|
12
|
+
Error = Class.new(StandardError)
|
13
|
+
|
14
|
+
desc 'version', 'railsdock version'
|
15
|
+
def version
|
16
|
+
require_relative 'version'
|
17
|
+
puts "Railsdock v#{Railsdock::VERSION}"
|
18
|
+
end
|
19
|
+
map %w[--version -v] => :version
|
20
|
+
|
21
|
+
desc 'install', 'Install Railsdock in an existing rails application'
|
22
|
+
method_option :help, aliases: '-h', type: :boolean,
|
23
|
+
desc: 'Display usage information'
|
24
|
+
def install(app_name = nil)
|
25
|
+
if options[:help]
|
26
|
+
invoke :help, ['install']
|
27
|
+
else
|
28
|
+
require_relative 'commands/install'
|
29
|
+
Railsdock::Commands::Install.new(options.merge(app_name: app_name)).execute
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Railsdock
|
6
|
+
class Command
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :command, :run
|
10
|
+
|
11
|
+
# Execute this command
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
def execute(*)
|
15
|
+
raise(
|
16
|
+
NotImplementedError,
|
17
|
+
"#{self.class}##{__method__} must be implemented"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# The external commands runner
|
22
|
+
#
|
23
|
+
# @see http://www.rubydoc.info/gems/tty-command
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def cmd(**options)
|
27
|
+
require 'tty-command'
|
28
|
+
TTY::Command.new(options)
|
29
|
+
end
|
30
|
+
|
31
|
+
# The cursor movement
|
32
|
+
#
|
33
|
+
# @see http://www.rubydoc.info/gems/tty-cursor
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
def cursor
|
37
|
+
require 'tty-cursor'
|
38
|
+
TTY::Cursor
|
39
|
+
end
|
40
|
+
|
41
|
+
# The generating config files
|
42
|
+
#
|
43
|
+
# @see http://www.rubydoc.info/gems/tty-config
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def config
|
47
|
+
require 'tty-config'
|
48
|
+
TTY::Config
|
49
|
+
end
|
50
|
+
|
51
|
+
# Open a file or text in the user's preferred editor
|
52
|
+
#
|
53
|
+
# @see http://www.rubydoc.info/gems/tty-editor
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
def editor
|
57
|
+
require 'tty-editor'
|
58
|
+
TTY::Editor
|
59
|
+
end
|
60
|
+
|
61
|
+
# File manipulation utility methods.
|
62
|
+
#
|
63
|
+
# @see http://www.rubydoc.info/gems/tty-file
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def file
|
67
|
+
require 'tty-file'
|
68
|
+
TTY::File
|
69
|
+
end
|
70
|
+
|
71
|
+
# Terminal platform and OS properties
|
72
|
+
#
|
73
|
+
# @see http://www.rubydoc.info/gems/tty-platform
|
74
|
+
#
|
75
|
+
# @api public
|
76
|
+
def platform
|
77
|
+
require 'tty-platform'
|
78
|
+
TTY::Platform.new
|
79
|
+
end
|
80
|
+
|
81
|
+
# The interactive prompt
|
82
|
+
#
|
83
|
+
# @see http://www.rubydoc.info/gems/tty-prompt
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
def prompt(**options)
|
87
|
+
require 'tty-prompt'
|
88
|
+
TTY::Prompt.new(options)
|
89
|
+
end
|
90
|
+
|
91
|
+
def progress(*options)
|
92
|
+
require 'tty-progressbar'
|
93
|
+
TTY::ProgressBar.new(*options)
|
94
|
+
end
|
95
|
+
|
96
|
+
def color
|
97
|
+
require 'pastel'
|
98
|
+
Pastel.new
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
require 'erb'
|
5
|
+
require_relative '../command'
|
6
|
+
require_relative '../logo'
|
7
|
+
|
8
|
+
module Railsdock
|
9
|
+
module Commands
|
10
|
+
class Install < Railsdock::Command
|
11
|
+
OPTIONS_HASH = {
|
12
|
+
database: {
|
13
|
+
name: 'Database',
|
14
|
+
options: %i[postgres mysql]
|
15
|
+
},
|
16
|
+
mem_store: {
|
17
|
+
name: 'In-Memory Store',
|
18
|
+
options: %i[redis memcached]
|
19
|
+
}
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
POST_INSTALL_MESSAGE =<<~PIM
|
23
|
+
Railsdock successfully installed
|
24
|
+
|
25
|
+
Run `docker-compose build` then `docker-compose up` to start your app,
|
26
|
+
|
27
|
+
PIM
|
28
|
+
|
29
|
+
BASE_TEMPLATE_DIR = File.expand_path("#{__dir__}/../templates/install").freeze
|
30
|
+
|
31
|
+
def initialize(options)
|
32
|
+
@options = options
|
33
|
+
@variables = OpenStruct.new(
|
34
|
+
app_name: options[:app_name] || get_app_name,
|
35
|
+
is_windows?: platform.windows?,
|
36
|
+
is_mac?: platform.mac?,
|
37
|
+
uid: cmd.run('id -u').out.chomp
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def execute(input: $stdin, output: $stdout)
|
42
|
+
output.puts Railsdock::Logo.call
|
43
|
+
@variables[:dockerfile_dir] = prompt_for_dockerfile_directory
|
44
|
+
copy_default_files
|
45
|
+
service_hash = collect_service_selections
|
46
|
+
service_hash.each do |type, service|
|
47
|
+
file.copy_file("#{BASE_TEMPLATE_DIR}/#{service}/Dockerfile", [@variables.dockerfile_dir, service, "/Dockerfile"].join)
|
48
|
+
inject_driver_config(service)
|
49
|
+
append_erb_to_compose_file(service)
|
50
|
+
file.inject_into_file('./docker-compose.yml', "\n #{service}:", after: "\nvolumes:")
|
51
|
+
append_service_config_to_env(service)
|
52
|
+
copy_db_yml("#{BASE_TEMPLATE_DIR}/#{service}/database.yml.erb") if type == :database
|
53
|
+
end
|
54
|
+
output.puts POST_INSTALL_MESSAGE
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def get_app_name
|
60
|
+
::File.open('./config/application.rb').read.match(/module (.+)\s/)[1].downcase
|
61
|
+
end
|
62
|
+
|
63
|
+
def copy_db_yml(erb_file)
|
64
|
+
file.copy_file(erb_file, './config/database.yml', context: @variables)
|
65
|
+
end
|
66
|
+
|
67
|
+
def collect_service_selections
|
68
|
+
prompt.collect do
|
69
|
+
OPTIONS_HASH.each do |key, value|
|
70
|
+
key(key).select("Select the #{value[:name]} used by your application:", value[:options])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def inject_driver_config(service)
|
76
|
+
file.inject_into_file('./docker-compose.yml', after: " node_modules:\n driver: ${VOLUMES_DRIVER}\n") do
|
77
|
+
<<-YAML
|
78
|
+
#{service}:
|
79
|
+
driver: ${VOLUMES_DRIVER}
|
80
|
+
YAML
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def generate_erb(source_path)
|
85
|
+
template = if ERB.version.scan(/\d+\.\d+\.\d+/)[0].to_f >= 2.2
|
86
|
+
ERB.new(::File.binread(source_path), trim_mode: '-', eoutvar: '@output_buffer')
|
87
|
+
else
|
88
|
+
ERB.new(::File.binread(source_path), nil, '-', '@output_buffer')
|
89
|
+
end
|
90
|
+
template.result(@variables.instance_eval('binding'))
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_or_append_to_file(source_path, destination_path)
|
94
|
+
if ::File.exist?(destination_path) && generate_erb(source_path) != ::File.binread(destination_path)
|
95
|
+
file.safe_append_to_file(destination_path, generate_erb(source_path))
|
96
|
+
else
|
97
|
+
file.copy_file(source_path, destination_path, context: @variables)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def append_erb_to_compose_file(service)
|
102
|
+
file.safe_append_to_file('./docker-compose.yml') do
|
103
|
+
generate_erb("#{BASE_TEMPLATE_DIR}/#{service}/docker-compose.yml.erb")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def append_service_config_to_env(service)
|
108
|
+
file.safe_append_to_file('./.env') do
|
109
|
+
::File.binread("#{BASE_TEMPLATE_DIR}/#{service}/#{service}.env")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def prompt_for_dockerfile_directory
|
114
|
+
prompt.ask('Where would you like your docker container configuration files to live?') do |q|
|
115
|
+
q.default './docker/'
|
116
|
+
q.validate(%r{\.\/[A-z\/]+\/})
|
117
|
+
q.modify :remove
|
118
|
+
q.messages[:valid?] = 'Invalid directory path (should start with ./ and end with /)'
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def copy_default_files
|
123
|
+
Dir["#{BASE_TEMPLATE_DIR}/default/*"].each do |path|
|
124
|
+
destination_file(path)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def destination_file(path)
|
129
|
+
case File.basename(path)
|
130
|
+
when 'Dockerfile'
|
131
|
+
file.copy_file(path, "#{@variables.dockerfile_dir}ruby/Dockerfile", context: @variables)
|
132
|
+
when 'docker-compose.yml.erb'
|
133
|
+
file.copy_file(path, './docker-compose.yml', context: @variables)
|
134
|
+
when 'default.env.erb'
|
135
|
+
create_or_append_to_file(path, './.env')
|
136
|
+
else
|
137
|
+
file.copy_file(path, "./#{File.basename(path)}", context: @variables)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pastel'
|
2
|
+
|
3
|
+
module Railsdock
|
4
|
+
class Logo
|
5
|
+
def self.call
|
6
|
+
color = Pastel.new
|
7
|
+
color.red(" `yy: `.
|
8
|
+
-oo` .-/+ooyysooo//-/sy
|
9
|
+
`+ooyyhhhhhhhhhhhhhhhys/-`
|
10
|
+
`-oyhhhhhhhhhhhhhhhyyyyyhhhys/-
|
11
|
+
.- .:yhhhhhhhhhhhhysoo+````:os-:/oyyy+.
|
12
|
+
:yy:/yhhhhhhhhhhhyo-` :o/ `.- ``:oss:`
|
13
|
+
.+shhhhhhhhhhhho++ `-+o.
|
14
|
+
`oyhhhhhhhhhhhy-.so` `
|
15
|
+
.shhhhhhhhhhhhy. `
|
16
|
+
` -yhhhhhhhhhhhhh/:`", color.cyan(" -+/. "), color.red("
|
17
|
+
:ys/-yhhhhhhhhhhhhho/hs"), color.cyan(" -oooo/. "), color.red("
|
18
|
+
/os:yhhhhhhhhhhhhhh:`::"), color.cyan(" `ooooooo: "), color.red("
|
19
|
+
`ohhhhhhhhhhhhhhh."), color.cyan(" :oooooooo: "), color.red("
|
20
|
+
:hhhhhhhhhhhhhhhh...`"), color.cyan(" /ooooooooo:////::.` "), color.red("
|
21
|
+
`yhhhhhhhhhhhhhhhh-sys"), color.cyan(" -oooooooooooooooooo:"), color.red("
|
22
|
+
-yyyyyyyyyyyyyyyyy/-/+."), color.cyan(" /oooooooooooooooo+.
|
23
|
+
.-------"), color.red("/////////////////:"), color.cyan("---------------------------:/+oooooooooooooo+:`
|
24
|
+
:oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo++/-`
|
25
|
+
+oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-..``
|
26
|
+
/ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-
|
27
|
+
:oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-
|
28
|
+
.ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-
|
29
|
+
+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo-
|
30
|
+
.ooooooooooooooooooooooooooooooooooooooooooooooooooooooo+.
|
31
|
+
:ooooooooooooooooooooooooooooooooooooooooooooooooooooo:`
|
32
|
+
/oooooooooooooooooooooooooooooooooooooooooooooooooo:`
|
33
|
+
/ooooooooooooooooooooooooooooooooooooooooooooooo/`
|
34
|
+
-+oooooooooooooooooooooooooooooooooooooooooo+-`
|
35
|
+
-+ooooooooooooooooooooooooooooooooooooo/-`
|
36
|
+
.:/ooooooooooooooooooooooooooooo+/-.
|
37
|
+
`.-:/++oooooooooooo++//:-.`
|
38
|
+
|
39
|
+
╠╬ ╠╬
|
40
|
+
╠░ ╠░"), color.red("
|
41
|
+
████████▖ ▄██████▄ ███ ███ ▟█████▌"), color.cyan(" ╓φ╬╬░╬╦╬░ ,φ╬╬░╬▒╦ ╦╬╬░╬▒╦ ╠░ ,╦╬╬"), color.red("
|
42
|
+
███ ▐███ ███ ███ ███ ███ ▐██▙▄▄"), color.cyan(" ╠░╩ `╬░ ╔░╩ ╬╬ ╒╬╩ ` ╠░╓φ╬╩╜"), color.red("
|
43
|
+
███▄▄███▘ ███▄▄███ ███ ███ ▀▀████▙"), color.cyan(" ░░ ╠░ ╠░ ░░⌐░░⌐ ╠░╜╙╬╦"), color.red("
|
44
|
+
███▀███▄ ███▀▀███ ███ ███▄▄▄▄ ▄▄▄▄▄██"), color.cyan(" ╙╬╬╖, ╓φ░╩ ╬╬╦, ,φ░╩ ╠╠╦, ,╦╦ ╠░ ╙░╦"), color.red("
|
45
|
+
▀▀▀ ▝▀▀▀ ▀▀▀ ▀▀▀ ▀▀▀ ▀▀▀▀▀▀▀ ▀▀▀▀▀▀▘"), color.cyan(" `╙╨╩╜^ `╙╨╩╜╜ ╙╙╨╜╜ ╙╜ ╙╜"))
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
ARG RAILSDOCK_RUBY_VERSION=2.6
|
2
|
+
|
3
|
+
FROM ruby:$RAILSDOCK_RUBY_VERSION
|
4
|
+
|
5
|
+
LABEL maintainer="Nate Vick <nate.vick@hint.io>"
|
6
|
+
|
7
|
+
ARG DEBIAN_FRONTEND=noninteractive
|
8
|
+
|
9
|
+
###############################################################################
|
10
|
+
# Base Software Install
|
11
|
+
###############################################################################
|
12
|
+
|
13
|
+
ARG RAILSDOCK_NODE_VERSION=11
|
14
|
+
|
15
|
+
RUN curl -sL https://deb.nodesource.com/setup_$RAILSDOCK_NODE_VERSION.x | bash -
|
16
|
+
|
17
|
+
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
|
18
|
+
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
19
|
+
|
20
|
+
RUN apt-get update && apt-get install -y \
|
21
|
+
build-essential \
|
22
|
+
nodejs \
|
23
|
+
yarn \
|
24
|
+
locales \
|
25
|
+
git \
|
26
|
+
netcat \
|
27
|
+
vim \
|
28
|
+
sudo
|
29
|
+
|
30
|
+
###############################################################################
|
31
|
+
# Railsdock non-root user
|
32
|
+
###############################################################################
|
33
|
+
|
34
|
+
ARG RUBY_UID
|
35
|
+
ENV RUBY_UID $RUBY_UID
|
36
|
+
ARG RUBY_GID
|
37
|
+
ENV RUBY_GID $RUBY_GID
|
38
|
+
ARG USER=ruby
|
39
|
+
ENV USER $USER
|
40
|
+
|
41
|
+
RUN groupadd -g $RUBY_GID $USER && \
|
42
|
+
useradd -u $RUBY_UID -g $USER -m $USER && \
|
43
|
+
usermod -p "*" $USER && \
|
44
|
+
usermod -aG sudo $USER && \
|
45
|
+
echo "$USER ALL=NOPASSWD: ALL" >> /etc/sudoers.d/50-$USER
|
46
|
+
|
47
|
+
###############################################################################
|
48
|
+
# Ruby, Rubygems, and Bundler Defaults
|
49
|
+
###############################################################################
|
50
|
+
|
51
|
+
ENV LANG C.UTF-8
|
52
|
+
|
53
|
+
# Point Bundler at /gems. This will cause Bundler to re-use gems that have already been installed on the gems volume
|
54
|
+
ENV BUNDLE_PATH /gems
|
55
|
+
ENV BUNDLE_HOME /gems
|
56
|
+
|
57
|
+
# Increase how many threads Bundler uses when installing. Optional!
|
58
|
+
ARG RAILSDOCK_BUNDLE_JOBS=20
|
59
|
+
ENV BUNDLE_JOBS $RAILSDOCK_BUNDLE_JOBS
|
60
|
+
|
61
|
+
# How many times Bundler will retry a gem download. Optional!
|
62
|
+
ARG RAILSDOCK_BUNDLE_RETRY=5
|
63
|
+
ENV BUNDLE_RETRY $RAILSDOCK_BUNDLE_RETRY
|
64
|
+
|
65
|
+
# Where Rubygems will look for gems, similar to BUNDLE_ equivalents.
|
66
|
+
ENV GEM_HOME /gems
|
67
|
+
ENV GEM_PATH /gems
|
68
|
+
|
69
|
+
# Add /gems/bin to the path so any installed gem binaries are runnable from bash.
|
70
|
+
ENV PATH /gems/bin:$PATH
|
71
|
+
|
72
|
+
###############################################################################
|
73
|
+
# Optional Software Install
|
74
|
+
###############################################################################
|
75
|
+
|
76
|
+
#------------------------------------------------------------------------------
|
77
|
+
# Postgres Client:
|
78
|
+
#------------------------------------------------------------------------------
|
79
|
+
|
80
|
+
ARG INSTALL_PG_CLIENT=false
|
81
|
+
|
82
|
+
RUN if [ "$INSTALL_PG_CLIENT" = true ]; then \
|
83
|
+
# Install the pgsql client
|
84
|
+
apt-get install -y postgresql-client \
|
85
|
+
;fi
|
86
|
+
|
87
|
+
###############################################################################
|
88
|
+
# Final Touches
|
89
|
+
###############################################################################
|
90
|
+
|
91
|
+
RUN mkdir -p "$GEM_HOME" && chown $USER:$USER "$GEM_HOME"
|
92
|
+
|
93
|
+
RUN mkdir -p /app
|
94
|
+
WORKDIR /app
|
95
|
+
|
96
|
+
RUN mkdir -p node_modules && chown $USER:$USER node_modules
|
97
|
+
|
98
|
+
USER $USER
|
99
|
+
|
100
|
+
# Install latest bundler
|
101
|
+
RUN gem install bundler
|