replr 0.3.0 → 0.9.5
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 +4 -4
- data/Gemfile +3 -0
- data/bin/replr +1 -1
- data/lib/replr.rb +1 -1
- data/lib/replr/argument_processor.rb +31 -15
- data/lib/replr/boot.rb +48 -0
- data/lib/replr/process_runner.rb +26 -1
- data/lib/replr/stack/node/Dockerfile.template +6 -0
- data/lib/replr/stack/node/repl_maker.rb +59 -0
- data/lib/replr/stack/node/replr-bootstrap.js +1 -0
- data/lib/replr/stack/python/Dockerfile.template +6 -0
- data/lib/replr/stack/python/repl_maker.rb +43 -0
- data/lib/replr/stack/repl_maker.rb +121 -0
- data/lib/replr/{Dockerfile.template → stack/ruby/Dockerfile.template} +0 -0
- data/lib/replr/stack/ruby/repl_maker.rb +45 -0
- data/lib/replr/{replr-bootstrap.rb → stack/ruby/replr-bootstrap.rb} +0 -1
- metadata +41 -6
- data/lib/replr/repl_maker.rb +0 -114
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97e6344e0f3d944df4c3ee74081b41fa096b51a5ac7c510b5b870a55e3d41562
|
4
|
+
data.tar.gz: 7476054ed59966a2a910b78b85b8274cb8246df9854de7a9459e13febe5cd302
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4382a006858f642290cf762b9f433fd9e74a60cb4faa07a96d53a55dbed7dc5212411f9c82508a1a83952699becfb42461c3dc2d96dca84ccfd6576fc345b1ff
|
7
|
+
data.tar.gz: 3924726d63a00d8e6da33d90cfe3d9067b7a0f0da5a7a1d190633fd0e615df82bba15a25ef9ddf5e6b5c57723a6bd7733e81182a7078146a0afa6959e1113b25
|
data/Gemfile
CHANGED
data/bin/replr
CHANGED
data/lib/replr.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require_relative 'replr/base'
|
2
|
-
require_relative 'replr/
|
2
|
+
require_relative 'replr/boot'
|
@@ -1,13 +1,11 @@
|
|
1
|
-
require_relative '../replr'
|
2
|
-
|
3
1
|
# :nodoc:
|
4
2
|
module Replr
|
5
3
|
# Processes command-line arguments
|
6
4
|
class ArgumentProcessor
|
7
|
-
COMMANDS = ['prune']
|
8
|
-
STACKS = ['ruby']
|
5
|
+
COMMANDS = ['prune'].freeze
|
6
|
+
STACKS = ['ruby', 'python', 'node'].freeze
|
9
7
|
|
10
|
-
attr_reader :arguments
|
8
|
+
attr_reader :arguments, :stack, :command, :libraries
|
11
9
|
|
12
10
|
def initialize
|
13
11
|
@arguments = ARGV.map { |argument| argument.downcase.strip }
|
@@ -23,27 +21,45 @@ module Replr
|
|
23
21
|
end
|
24
22
|
|
25
23
|
def check_arguments!
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
valid_command = COMMANDS.detect do |command|
|
30
|
-
arguments[0] == command
|
31
|
-
end
|
24
|
+
detect_stack
|
25
|
+
detect_command
|
26
|
+
detect_libraries
|
32
27
|
|
33
|
-
unless
|
28
|
+
unless stack || command
|
34
29
|
puts_error "First argument must be either be a command:
|
35
|
-
\t#{COMMANDS.join(' ')}
|
36
|
-
or one of a supported stack:
|
30
|
+
\t#{COMMANDS.join(' ')}\nor one of a supported stack:
|
37
31
|
\t#{STACKS.join(' ')}"
|
38
32
|
puts_usage
|
39
33
|
exit
|
40
34
|
end
|
41
35
|
end
|
42
36
|
|
37
|
+
def detect_stack
|
38
|
+
detected_stack = STACKS.detect do |stack|
|
39
|
+
arguments[0].match(/^#{stack}:?.*?/)
|
40
|
+
end
|
41
|
+
|
42
|
+
# return the full stack string (that includes version)
|
43
|
+
# instead of just the stack name
|
44
|
+
if detected_stack
|
45
|
+
@stack = arguments[0]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def detect_command
|
50
|
+
@command = COMMANDS.detect do |command|
|
51
|
+
arguments[0] == command
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def detect_libraries
|
56
|
+
@libraries = arguments[1..-1].sort!
|
57
|
+
end
|
58
|
+
|
43
59
|
def puts_usage
|
44
60
|
puts_error "\nUsage: replr <stack> <libraries...>\n\n"
|
45
61
|
puts_error "A single line REPL for your favorite languages & libraries\n\n"
|
46
|
-
puts_error "\t<stack> is now
|
62
|
+
puts_error "\t<stack> is now one of #{STACKS.join(', ')}"
|
47
63
|
puts_error "\t<libraries...> is a space separated list of libraries for the stack\n\n"
|
48
64
|
puts_error "More commands:\n\n\treplr prune to delete all replr docker images (this saves space)"
|
49
65
|
end
|
data/lib/replr/boot.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'argument_processor'
|
2
|
+
require_relative 'process_runner'
|
3
|
+
require_relative 'stack/repl_maker'
|
4
|
+
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
module Replr
|
9
|
+
# Starts up REPL creation & wires up rest of the pieces
|
10
|
+
class Boot
|
11
|
+
attr_reader :argument_processor, :process_runner
|
12
|
+
|
13
|
+
def start
|
14
|
+
@argument_processor = Replr::ArgumentProcessor.new
|
15
|
+
@process_runner = Replr::ProcessRunner.new
|
16
|
+
|
17
|
+
check_docker!
|
18
|
+
execute_processsed_arguments!
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def check_docker!
|
24
|
+
unless process_runner.process_exists?('docker')
|
25
|
+
puts_error 'Needs docker installed & in path to work.'
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute_processsed_arguments!
|
31
|
+
if argument_processor.command == 'prune'
|
32
|
+
execute_prune_command
|
33
|
+
elsif argument_processor.stack
|
34
|
+
Replr::Stack::REPLMaker.load(stack: argument_processor.stack,
|
35
|
+
libraries: argument_processor.libraries)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def execute_prune_command
|
40
|
+
prune_command = %q(docker images -a | grep "replr/" | awk '{print $3}' | xargs docker rmi)
|
41
|
+
process_runner.execute_command(prune_command)
|
42
|
+
end
|
43
|
+
|
44
|
+
def puts_error(string)
|
45
|
+
STDERR.puts(string)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/replr/process_runner.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'open3'
|
2
|
+
require 'pty'
|
3
|
+
require 'expect'
|
2
4
|
|
3
5
|
module Replr
|
4
6
|
# Executes and manages processes
|
@@ -44,5 +46,28 @@ module Replr
|
|
44
46
|
STDERR.puts outerror
|
45
47
|
end
|
46
48
|
end
|
49
|
+
|
50
|
+
def execute_repl_with_input(command:, inputs:, prompt_line:, expected_output:, debug: false)
|
51
|
+
outputs = []
|
52
|
+
inputs << ''
|
53
|
+
|
54
|
+
PTY.spawn(command) do |read, write, _pid|
|
55
|
+
read.expect(prompt_line)
|
56
|
+
inputs.each do |cmd|
|
57
|
+
begin
|
58
|
+
write.puts cmd
|
59
|
+
read.flush
|
60
|
+
read.expect(/(.*?)\r\n(.*)>/m) do |output|
|
61
|
+
puts "DEBUG: OUTPUT: #{output.inspect}" if debug
|
62
|
+
outputs << output[2].match(expected_output) if output
|
63
|
+
end
|
64
|
+
rescue Errno::EIO
|
65
|
+
next
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
outputs.any? { |output| output.is_a? MatchData }
|
71
|
+
end
|
47
72
|
end
|
48
73
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '../../../replr'
|
2
|
+
require_relative '../../process_runner'
|
3
|
+
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# :nodoc:
|
7
|
+
module Replr
|
8
|
+
module Stack
|
9
|
+
module Node
|
10
|
+
# Creates a Ruby REPL using docker for a stack and libraries combo
|
11
|
+
class REPLMaker < Replr::Stack::REPLMaker
|
12
|
+
private
|
13
|
+
|
14
|
+
def set_library_file_name
|
15
|
+
@library_file_name = 'package.json'
|
16
|
+
end
|
17
|
+
|
18
|
+
# It's optional to set a bootstrap file
|
19
|
+
def set_bootstrap_file_name
|
20
|
+
@bootstrap_file_name = 'replr-bootstrap.js'
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_template_dir
|
24
|
+
@template_dir = __dir__
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_filter_lines_for_install
|
28
|
+
@filter_matching_lines_for_install = [/packages/i, /download/i]
|
29
|
+
@filter_not_matching_lines_for_install = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def library_file_with(libraries)
|
33
|
+
package_file = {
|
34
|
+
name: "@#{docker_image_tag}",
|
35
|
+
version: '1.0.0',
|
36
|
+
description: 'Replr for Node',
|
37
|
+
author: 'Vishnu Gopal <vishnugopal@users.noreply.github.com>',
|
38
|
+
repository: 'https://github.com/vishnugopal/replr',
|
39
|
+
license: 'MIT',
|
40
|
+
scripts: {
|
41
|
+
start: 'node replr-bootstrap.js'
|
42
|
+
}
|
43
|
+
}
|
44
|
+
dependencies = {}
|
45
|
+
libraries.each do |library|
|
46
|
+
if library.include?(':')
|
47
|
+
library, version = library.split(':')
|
48
|
+
dependencies[library] = version
|
49
|
+
else
|
50
|
+
dependencies[library] = '*'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
package_file[:dependencies] = dependencies
|
54
|
+
package_file.to_json
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require("repl").start();
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../../../replr'
|
2
|
+
require_relative '../../process_runner'
|
3
|
+
|
4
|
+
require_relative '../../../replr'
|
5
|
+
require_relative '../../process_runner'
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
module Replr
|
9
|
+
module Stack
|
10
|
+
module Python
|
11
|
+
# Creates a Python REPL using docker for a stack and libraries combo
|
12
|
+
class REPLMaker < Replr::Stack::REPLMaker
|
13
|
+
private
|
14
|
+
|
15
|
+
def set_library_file_name
|
16
|
+
@library_file_name = 'requirements.txt'
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_template_dir
|
20
|
+
@template_dir = __dir__
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_filter_lines_for_install
|
24
|
+
@filter_matching_lines_for_install = [/pip/i]
|
25
|
+
@filter_not_matching_lines_for_install = [/\.cache/i]
|
26
|
+
end
|
27
|
+
|
28
|
+
def library_file_with(libraries)
|
29
|
+
requirements = ''
|
30
|
+
libraries.each do |library|
|
31
|
+
if library.include?(':')
|
32
|
+
library, version = library.split(':')
|
33
|
+
requirements << "#{library}==#{version}\n"
|
34
|
+
else
|
35
|
+
requirements << "#{library}\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
requirements
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require_relative '../process_runner'
|
2
|
+
|
3
|
+
# :nodoc:
|
4
|
+
module Replr
|
5
|
+
module Stack
|
6
|
+
# Abstract class to do many things common when creating a REPL
|
7
|
+
# across stacks
|
8
|
+
class REPLMaker
|
9
|
+
attr_reader :process_runner
|
10
|
+
attr_reader :stack, :libraries, :work_dir
|
11
|
+
attr_reader :library_file_name, :bootstrap_file_name, :template_dir,
|
12
|
+
:filter_matching_lines_for_install,
|
13
|
+
:filter_not_matching_lines_for_install
|
14
|
+
|
15
|
+
def self.load(stack:, libraries:)
|
16
|
+
stack_name, _stack_version = stack.split(':')
|
17
|
+
require_relative "#{stack_name}/repl_maker"
|
18
|
+
|
19
|
+
repl_maker_class_name = "Replr::Stack::#{stack_name.capitalize}::REPLMaker"
|
20
|
+
repl_maker = Object.const_get(repl_maker_class_name).new(
|
21
|
+
stack: stack,
|
22
|
+
libraries: libraries
|
23
|
+
)
|
24
|
+
repl_maker.create
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(stack:, libraries:)
|
28
|
+
@process_runner = Replr::ProcessRunner.new
|
29
|
+
|
30
|
+
@stack = stack
|
31
|
+
@libraries = libraries
|
32
|
+
@work_dir = Dir.mktmpdir
|
33
|
+
end
|
34
|
+
|
35
|
+
def create
|
36
|
+
set_template_dir
|
37
|
+
set_library_file_name
|
38
|
+
set_bootstrap_file_name
|
39
|
+
set_filter_lines_for_install
|
40
|
+
|
41
|
+
copy_library_file
|
42
|
+
copy_initialization_files
|
43
|
+
initialize_docker_repl
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def set_template_dir
|
49
|
+
raise NotImplementedError, 'This needs to be implemented by a subclass'
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_library_file_name
|
53
|
+
raise NotImplementedError, 'This needs to be implemented by a subclass'
|
54
|
+
end
|
55
|
+
|
56
|
+
# It's optional to set a bootstrap file
|
57
|
+
def set_bootstrap_file_name; end
|
58
|
+
|
59
|
+
def set_filter_lines_for_install
|
60
|
+
raise NotImplementedError, 'This needs to be implemented by a subclass'
|
61
|
+
end
|
62
|
+
|
63
|
+
def library_file_with(libraries)
|
64
|
+
raise NotImplementedError, 'This needs to be implemented by a subclass'
|
65
|
+
end
|
66
|
+
|
67
|
+
def copy_library_file
|
68
|
+
Dir.chdir(work_dir) do
|
69
|
+
File.open(library_file_name, 'w') do |f|
|
70
|
+
f.write(library_file_with(libraries))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def copy_initialization_files
|
76
|
+
create_docker_file
|
77
|
+
if bootstrap_file_name
|
78
|
+
bootstrap_file = File.join(template_dir, bootstrap_file_name)
|
79
|
+
FileUtils.cp(bootstrap_file, work_dir)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def create_docker_file
|
84
|
+
_stack, version = stack.split(':')
|
85
|
+
docker_file_template = File.join(template_dir, "Dockerfile.template")
|
86
|
+
docker_file_contents = File.read(docker_file_template)
|
87
|
+
docker_file_contents.gsub!('%%VERSION%%', version ? "#{version}-" : '')
|
88
|
+
File.open(File.join(work_dir, 'Dockerfile'), 'w') do |file|
|
89
|
+
file.puts docker_file_contents
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def initialize_docker_repl
|
94
|
+
Dir.chdir(work_dir) do
|
95
|
+
build_command = "docker build -t #{docker_image_tag} ."
|
96
|
+
run_command = "docker run --rm -it #{docker_image_tag}"
|
97
|
+
matching = Regexp.union([/upgrading/i, /installing/i] +
|
98
|
+
filter_matching_lines_for_install)
|
99
|
+
not_matching = Regexp.union([/step/i] + filter_not_matching_lines_for_install)
|
100
|
+
process_runner.execute_filtered_process(build_command, matching,
|
101
|
+
not_matching) do |stderr, process_thread|
|
102
|
+
process_runner.execute_command_if_not_stderr(run_command, stderr, process_thread)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def docker_image_tag
|
108
|
+
normalized_library_string = libraries.map do |library|
|
109
|
+
library.gsub(':', '-v')
|
110
|
+
end.join('-')
|
111
|
+
normalized_stack_string = stack.gsub(':', '-v')
|
112
|
+
|
113
|
+
if normalized_library_string.empty?
|
114
|
+
"replr/#{normalized_stack_string}"
|
115
|
+
else
|
116
|
+
"replr/#{normalized_stack_string}-#{normalized_library_string}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../../../replr'
|
2
|
+
require_relative '../../process_runner'
|
3
|
+
|
4
|
+
# :nodoc:
|
5
|
+
module Replr
|
6
|
+
module Stack
|
7
|
+
module Ruby
|
8
|
+
# Creates a Ruby REPL using docker for a stack and libraries combo
|
9
|
+
class REPLMaker < Replr::Stack::REPLMaker
|
10
|
+
private
|
11
|
+
|
12
|
+
def set_library_file_name
|
13
|
+
@library_file_name = 'Gemfile'
|
14
|
+
end
|
15
|
+
|
16
|
+
# It's optional to set a bootstrap file
|
17
|
+
def set_bootstrap_file_name
|
18
|
+
@bootstrap_file_name = 'replr-bootstrap.rb'
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_template_dir
|
22
|
+
@template_dir = __dir__
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_filter_lines_for_install
|
26
|
+
@filter_matching_lines_for_install = [/gem/i]
|
27
|
+
@filter_not_matching_lines_for_install = []
|
28
|
+
end
|
29
|
+
|
30
|
+
def library_file_with(libraries)
|
31
|
+
gemfile = "source 'https://rubygems.org/'\n"
|
32
|
+
libraries.each do |library|
|
33
|
+
if library.include?(':')
|
34
|
+
library, version = library.split(':')
|
35
|
+
gemfile << "gem '#{library}', '#{version}'\n"
|
36
|
+
else
|
37
|
+
gemfile << "gem '#{library}'\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
gemfile
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: replr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vishnu Gopal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
12
|
-
dependencies:
|
11
|
+
date: 2018-08-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
13
41
|
description:
|
14
42
|
email: vg@vishnugopal.com
|
15
43
|
executables:
|
@@ -20,12 +48,19 @@ files:
|
|
20
48
|
- Gemfile
|
21
49
|
- bin/replr
|
22
50
|
- lib/replr.rb
|
23
|
-
- lib/replr/Dockerfile.template
|
24
51
|
- lib/replr/argument_processor.rb
|
25
52
|
- lib/replr/base.rb
|
53
|
+
- lib/replr/boot.rb
|
26
54
|
- lib/replr/process_runner.rb
|
27
|
-
- lib/replr/
|
28
|
-
- lib/replr/
|
55
|
+
- lib/replr/stack/node/Dockerfile.template
|
56
|
+
- lib/replr/stack/node/repl_maker.rb
|
57
|
+
- lib/replr/stack/node/replr-bootstrap.js
|
58
|
+
- lib/replr/stack/python/Dockerfile.template
|
59
|
+
- lib/replr/stack/python/repl_maker.rb
|
60
|
+
- lib/replr/stack/repl_maker.rb
|
61
|
+
- lib/replr/stack/ruby/Dockerfile.template
|
62
|
+
- lib/replr/stack/ruby/repl_maker.rb
|
63
|
+
- lib/replr/stack/ruby/replr-bootstrap.rb
|
29
64
|
homepage: https://github.com/vishnugopal/replr
|
30
65
|
licenses:
|
31
66
|
- MIT
|
data/lib/replr/repl_maker.rb
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
require_relative '../replr'
|
2
|
-
require_relative 'argument_processor'
|
3
|
-
require_relative 'process_runner'
|
4
|
-
|
5
|
-
require 'tmpdir'
|
6
|
-
require 'open3'
|
7
|
-
|
8
|
-
# :nodoc:
|
9
|
-
module Replr
|
10
|
-
# Creates a REPL using template Dockerfiles & libraries
|
11
|
-
class REPLMaker
|
12
|
-
attr_reader :argument_processor, :process_runner
|
13
|
-
attr_reader :stack, :libraries, :workdir
|
14
|
-
|
15
|
-
def start
|
16
|
-
@argument_processor = Replr::ArgumentProcessor.new
|
17
|
-
@process_runner = Replr::ProcessRunner.new
|
18
|
-
|
19
|
-
@stack = argument_processor.arguments[0]
|
20
|
-
@libraries = argument_processor.arguments[1..-1].sort!
|
21
|
-
@workdir = Dir.mktmpdir
|
22
|
-
|
23
|
-
check_docker!
|
24
|
-
execute_processsed_arguments!
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def check_docker!
|
30
|
-
unless process_runner.process_exists?('docker')
|
31
|
-
puts_error 'Needs docker installed & in path to work.'
|
32
|
-
exit
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def execute_processsed_arguments!
|
37
|
-
if argument_processor.arguments[0] == 'prune'
|
38
|
-
execute_prune_command
|
39
|
-
else
|
40
|
-
copy_library_file
|
41
|
-
copy_initialization_files
|
42
|
-
initialize_docker_repl
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def execute_prune_command
|
47
|
-
prune_command = %q(docker images -a | grep "replr/" | awk '{print $3}' | xargs docker rmi)
|
48
|
-
process_runner.execute_command(prune_command)
|
49
|
-
end
|
50
|
-
|
51
|
-
def puts_error(string)
|
52
|
-
STDERR.puts(string)
|
53
|
-
end
|
54
|
-
|
55
|
-
def copy_library_file
|
56
|
-
Dir.chdir(workdir) do
|
57
|
-
File.open('Gemfile', 'w') do |f|
|
58
|
-
f.write(library_file_with(libraries))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def copy_initialization_files
|
64
|
-
create_docker_file
|
65
|
-
bootstrap_file = "#{__dir__}/replr-bootstrap.rb"
|
66
|
-
FileUtils.cp(bootstrap_file, workdir)
|
67
|
-
end
|
68
|
-
|
69
|
-
def create_docker_file
|
70
|
-
_stack, version = stack.split(':')
|
71
|
-
docker_file_template = "#{__dir__}/Dockerfile.template"
|
72
|
-
docker_file_contents = File.read(docker_file_template)
|
73
|
-
docker_file_contents.gsub!('%%VERSION%%', version ? "#{version}-" : '')
|
74
|
-
File.open(File.join(workdir, 'Dockerfile'), 'w') do |file|
|
75
|
-
file.puts docker_file_contents
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def library_file_with(libraries)
|
80
|
-
gemfile = "source 'https://rubygems.org/'\n"
|
81
|
-
libraries.each do |library|
|
82
|
-
if library.include?(':')
|
83
|
-
library, version = library.split(':')
|
84
|
-
gemfile << "gem '#{library}', '#{version}'\n"
|
85
|
-
else
|
86
|
-
gemfile << "gem '#{library}'\n"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
gemfile
|
90
|
-
end
|
91
|
-
|
92
|
-
def initialize_docker_repl
|
93
|
-
Dir.chdir(workdir) do
|
94
|
-
build_command = "docker build -t #{docker_image_tag} ."
|
95
|
-
run_command = "docker run --rm -it #{docker_image_tag}"
|
96
|
-
matching = Regexp.union([/upgrading/i, /installing/i, /gem/i])
|
97
|
-
not_matching = Regexp.union([/step/i])
|
98
|
-
process_runner.execute_filtered_process(build_command, matching,
|
99
|
-
not_matching) do |stderr, process_thread|
|
100
|
-
process_runner.execute_command_if_not_stderr(run_command, stderr, process_thread)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def docker_image_tag
|
106
|
-
normalized_library_string = libraries.map do |library|
|
107
|
-
library.gsub(':', '-v')
|
108
|
-
end.join('-')
|
109
|
-
normalized_stack_string = stack.gsub(':', '-v')
|
110
|
-
|
111
|
-
"replr/#{normalized_stack_string}-#{normalized_library_string}"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|