railsdock 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CHANGELOG.md +0 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +173 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +55 -0
  11. data/Rakefile +14 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/exe/railsdock +18 -0
  15. data/ext/railsdock/extconf.rb +3 -0
  16. data/ext/railsdock/railsdock.c +9 -0
  17. data/ext/railsdock/railsdock.h +6 -0
  18. data/lib/railsdock.rb +6 -0
  19. data/lib/railsdock/cli.rb +33 -0
  20. data/lib/railsdock/command.rb +101 -0
  21. data/lib/railsdock/commands/install.rb +142 -0
  22. data/lib/railsdock/logo.rb +49 -0
  23. data/lib/railsdock/templates/install/default/Dockerfile +101 -0
  24. data/lib/railsdock/templates/install/default/default.env.erb +44 -0
  25. data/lib/railsdock/templates/install/default/docker-compose.mac.yml +7 -0
  26. data/lib/railsdock/templates/install/default/docker-compose.yml.erb +51 -0
  27. data/lib/railsdock/templates/install/memcached/Dockerfile +7 -0
  28. data/lib/railsdock/templates/install/memcached/docker-compose.yml.erb +11 -0
  29. data/lib/railsdock/templates/install/mysql/Dockerfile +7 -0
  30. data/lib/railsdock/templates/install/mysql/database.yml.erb +18 -0
  31. data/lib/railsdock/templates/install/mysql/docker-compose.yml.erb +13 -0
  32. data/lib/railsdock/templates/install/postgres/Dockerfile +7 -0
  33. data/lib/railsdock/templates/install/postgres/database.yml.erb +18 -0
  34. data/lib/railsdock/templates/install/postgres/docker-compose.yml.erb +11 -0
  35. data/lib/railsdock/templates/install/redis/Dockerfile +7 -0
  36. data/lib/railsdock/templates/install/redis/docker-compose.yml.erb +11 -0
  37. data/lib/railsdock/version.rb +3 -0
  38. data/railsdock.gemspec +60 -0
  39. data/railsdock.png +0 -0
  40. metadata +393 -0
@@ -0,0 +1,9 @@
1
+ #include "railsdock.h"
2
+
3
+ VALUE rb_mRailsdock;
4
+
5
+ void
6
+ Init_railsdock(void)
7
+ {
8
+ rb_mRailsdock = rb_define_module("Railsdock");
9
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef RAILSDOCK_H
2
+ #define RAILSDOCK_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #endif /* RAILSDOCK_H */
data/lib/railsdock.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'railsdock/version'
2
+ require 'railsdock/cli'
3
+
4
+ module Railsdock
5
+ class Error < StandardError; end
6
+ end
@@ -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