rvt 0.9.9
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/MIT-LICENSE +20 -0
- data/Rakefile +25 -0
- data/app/assets/javascripts/rvt/application.js +1 -0
- data/app/assets/javascripts/rvt/console_sessions.js +182 -0
- data/app/assets/stylesheets/rvt/application.css +13 -0
- data/app/assets/stylesheets/rvt/console_sessions.css.erb +6 -0
- data/app/controllers/rvt/application_controller.rb +13 -0
- data/app/controllers/rvt/console_sessions_controller.rb +47 -0
- data/app/models/rvt/console_session.rb +109 -0
- data/app/views/layouts/rvt/application.html.erb +14 -0
- data/app/views/rvt/console_sessions/index.html.erb +17 -0
- data/config/routes.rb +11 -0
- data/lib/assets/javascripts/rvt.js +41 -0
- data/lib/rvt.rb +21 -0
- data/lib/rvt/colors.rb +87 -0
- data/lib/rvt/colors/light.rb +24 -0
- data/lib/rvt/colors/monokai.rb +24 -0
- data/lib/rvt/colors/solarized.rb +47 -0
- data/lib/rvt/colors/tango.rb +24 -0
- data/lib/rvt/colors/xterm.rb +24 -0
- data/lib/rvt/engine.rb +85 -0
- data/lib/rvt/slave.rb +147 -0
- data/lib/rvt/version.rb +3 -0
- data/test/controllers/rvt/console_sessions_controller_test.rb +100 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/controller_helper_test/index.html.erb +1 -0
- data/test/dummy/app/views/exception_test/xhr.html.erb +1 -0
- data/test/dummy/app/views/helper_test/index.html.erb +220 -0
- data/test/dummy/app/views/layouts/application.html.erb +16 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +44 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +34 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +16 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +247222 -0
- data/test/dummy/log/test.log +963 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/0509a6e0e75d9ac5a88bba7291b04686 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2bd9d10dae311aa2dfb6dea9c1e0ad50 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2f41a6a41d0a16db31cabd2b8689ca00 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/4de66e84a0d6f009fac50cd608fb8581 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/56e8026311075410507152df2aea4307 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9542de15712d45f70221931bf78c00e5 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/98cea396a602c53d876e79bf4b89de3b +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9df3968b0f171feec749766fffa50b2e +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/aa5fc4cb46c5294192c9d3af8824f88b +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ac7197dc7dd9ab362d915d19e37a8e01 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b238befd6eff46b26d56322c1450ea45 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/c69b8b79c21fd48ad84c3fad87945a5c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/da4318a4d8364d0616edd706508371bc +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/dd71b14df42fd6dc95355cded9e4d0f9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/eb06cae1627276e46965809e766aff13 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/edffb5017d27ddb65965203636286405 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/f0ced5f3d4a75fce1c596d6c3f97a42d +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/fb9e611526e612ba797f0c11b987826b +0 -0
- data/test/models/console_session_test.rb +58 -0
- data/test/rvt/colors_test.rb +58 -0
- data/test/rvt/engine_test.rb +145 -0
- data/test/rvt/slave_test.rb +72 -0
- data/test/test_helper.rb +27 -0
- data/vendor/assets/javascripts/term.js +5771 -0
- metadata +284 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
var config = {
|
|
3
|
+
terminal: {
|
|
4
|
+
colors: <%= raw RVT.config.style.colors.to_json %>
|
|
5
|
+
},
|
|
6
|
+
|
|
7
|
+
transport: {
|
|
8
|
+
url: {
|
|
9
|
+
input: "<%= rvt.input_console_session_path(@console_session) %>",
|
|
10
|
+
pendingOutput: "<%= rvt.pending_output_console_session_path(@console_session) %>",
|
|
11
|
+
configuration: "<%= rvt.configuration_console_session_path(@console_session) %>"
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
uid: "<%= @console_session.uid %>"
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
</script>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//= require term
|
|
2
|
+
|
|
3
|
+
;(function(BaseTerminal) {
|
|
4
|
+
|
|
5
|
+
// Expose the main RVT namespace.
|
|
6
|
+
var RVT = this.RVT = {};
|
|
7
|
+
|
|
8
|
+
// Follow term.js example and expose inherits and EventEmitter.
|
|
9
|
+
var inherits = RVT.inherits = BaseTerminal.inherits;
|
|
10
|
+
var EventEmitter = RVT.EventEmitter = BaseTerminal.EventEmitter;
|
|
11
|
+
|
|
12
|
+
var Terminal = RVT.Terminal = function(options) {
|
|
13
|
+
if (typeof options === 'number') {
|
|
14
|
+
return BaseTerminal.apply(this, arguments);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
BaseTerminal.call(this, options || (options = {}));
|
|
18
|
+
|
|
19
|
+
this.open();
|
|
20
|
+
|
|
21
|
+
if (!(options.rows || options.cols) || !options.geometry) {
|
|
22
|
+
this.fitScreen();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Make RVT.Terminal inherit from BaseTerminal (term.js).
|
|
27
|
+
inherits(Terminal, BaseTerminal);
|
|
28
|
+
|
|
29
|
+
Terminal.prototype.fitScreen = function() {
|
|
30
|
+
var width = Math.floor(this.element.clientWidth / this.cols);
|
|
31
|
+
var height = Math.floor(this.element.clientHeight / this.rows);
|
|
32
|
+
|
|
33
|
+
var rows = Math.floor(window.innerHeight / height);
|
|
34
|
+
var cols = Math.floor(this.parent.clientWidth / width);
|
|
35
|
+
|
|
36
|
+
this.resize(cols, rows);
|
|
37
|
+
|
|
38
|
+
return [cols, rows];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
}).call(this, Terminal);
|
data/lib/rvt.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'active_support/lazy_load_hooks'
|
|
2
|
+
require 'active_support/inflector'
|
|
3
|
+
|
|
4
|
+
require 'rvt/colors'
|
|
5
|
+
require 'rvt/engine'
|
|
6
|
+
require 'rvt/slave'
|
|
7
|
+
|
|
8
|
+
module RVT
|
|
9
|
+
# Shortcut for +RVT::Engine.config.rvt+.
|
|
10
|
+
def self.config
|
|
11
|
+
Engine.config.rvt
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
ActiveSupport.run_load_hooks(:rvt, self)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Inflect the name as an acronym to help Rails auto loading find constants
|
|
18
|
+
# under +RVT::+ instead of +Rvt::+.
|
|
19
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
20
|
+
inflect.acronym 'RVT'
|
|
21
|
+
end
|
data/lib/rvt/colors.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
|
2
|
+
|
|
3
|
+
module RVT
|
|
4
|
+
# = Colors
|
|
5
|
+
#
|
|
6
|
+
# Manages the creation and serialization of terminal color themes.
|
|
7
|
+
#
|
|
8
|
+
# Colors is a subclass of +Array+ and it stores a collection of CSS color
|
|
9
|
+
# values, to be used from the client-side terminal.
|
|
10
|
+
#
|
|
11
|
+
# You can specify 8 or 16 colors and additional +background+ and +foreground+
|
|
12
|
+
# colors. If not explicitly specified, +background+ and +foreground+ are
|
|
13
|
+
# considered to be the first and the last of the given colors.
|
|
14
|
+
class Colors < Array
|
|
15
|
+
class << self
|
|
16
|
+
# Registry of color themes mapped to a name.
|
|
17
|
+
#
|
|
18
|
+
# Don't manually alter the registry. Use RVT::Colors.register_theme
|
|
19
|
+
# for adding entries.
|
|
20
|
+
def themes
|
|
21
|
+
@@themes ||= {}.with_indifferent_access
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Register a color theme into the color themes registry.
|
|
25
|
+
#
|
|
26
|
+
# Registration maps a name and Colors instance.
|
|
27
|
+
#
|
|
28
|
+
# If a block is given, it would be yielded with a new Colors instance to
|
|
29
|
+
# populate the theme colors in.
|
|
30
|
+
#
|
|
31
|
+
# If a Colors instance is already instantiated it can be passed directly
|
|
32
|
+
# as the second (_colors_) argument. In this case, if a block is given,
|
|
33
|
+
# it won't be executed.
|
|
34
|
+
def register_theme(name, colors = nil)
|
|
35
|
+
themes[name] = colors || new.tap { |c| yield c }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The default colors theme.
|
|
39
|
+
def default
|
|
40
|
+
self[:light]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Shortcut for RVT::Colors.themes#[].
|
|
44
|
+
def [](name)
|
|
45
|
+
themes[name]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
alias :add :<<
|
|
50
|
+
|
|
51
|
+
# Background color getter and setter.
|
|
52
|
+
#
|
|
53
|
+
# If called without arguments it acts like a getter. Otherwise it acts like
|
|
54
|
+
# a setter.
|
|
55
|
+
#
|
|
56
|
+
# The default background color will be the first entry in the colors theme.
|
|
57
|
+
def background(value = nil)
|
|
58
|
+
@background = value unless value.nil?
|
|
59
|
+
@background ||= self.first
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
alias :background= :background
|
|
63
|
+
|
|
64
|
+
# Foreground color getter and setter.
|
|
65
|
+
#
|
|
66
|
+
# If called without arguments it acts like a getter. Otherwise it acts like
|
|
67
|
+
# a setter.
|
|
68
|
+
#
|
|
69
|
+
# The default foreground color will be the last entry in the colors theme.
|
|
70
|
+
def foreground(value = nil)
|
|
71
|
+
@foreground = value unless value.nil?
|
|
72
|
+
@foreground ||= self.last
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
alias :foreground= :foreground
|
|
76
|
+
|
|
77
|
+
def as_json(*)
|
|
78
|
+
(dup << background << foreground).to_a
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
require 'rvt/colors/light'
|
|
84
|
+
require 'rvt/colors/monokai'
|
|
85
|
+
require 'rvt/colors/solarized'
|
|
86
|
+
require 'rvt/colors/tango'
|
|
87
|
+
require 'rvt/colors/xterm'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module RVT
|
|
2
|
+
Colors.register_theme(:light) do |c|
|
|
3
|
+
c.add '#000000'
|
|
4
|
+
c.add '#cd0000'
|
|
5
|
+
c.add '#00cd00'
|
|
6
|
+
c.add '#cdcd00'
|
|
7
|
+
c.add '#0000ee'
|
|
8
|
+
c.add '#cd00cd'
|
|
9
|
+
c.add '#00cdcd'
|
|
10
|
+
c.add '#e5e5e5'
|
|
11
|
+
|
|
12
|
+
c.add '#7f7f7f'
|
|
13
|
+
c.add '#ff0000'
|
|
14
|
+
c.add '#00ff00'
|
|
15
|
+
c.add '#ffff00'
|
|
16
|
+
c.add '#5c5cff'
|
|
17
|
+
c.add '#ff00ff'
|
|
18
|
+
c.add '#00ffff'
|
|
19
|
+
c.add '#ffffff'
|
|
20
|
+
|
|
21
|
+
c.background '#ffffff'
|
|
22
|
+
c.foreground '#000000'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module RVT
|
|
2
|
+
Colors.register_theme(:monokai) do |c|
|
|
3
|
+
c.add '#1c1d19'
|
|
4
|
+
c.add '#d01b24'
|
|
5
|
+
c.add '#a7d32C'
|
|
6
|
+
c.add '#d8cf67'
|
|
7
|
+
c.add '#61b8d0'
|
|
8
|
+
c.add '#695abb'
|
|
9
|
+
c.add '#d53864'
|
|
10
|
+
c.add '#fefffe'
|
|
11
|
+
|
|
12
|
+
c.add '#1c1d19'
|
|
13
|
+
c.add '#d12a24'
|
|
14
|
+
c.add '#a7d32c'
|
|
15
|
+
c.add '#d8cf67'
|
|
16
|
+
c.add '#61b8d0'
|
|
17
|
+
c.add '#695abb'
|
|
18
|
+
c.add '#d53864'
|
|
19
|
+
c.add '#fefffe'
|
|
20
|
+
|
|
21
|
+
c.background '#1c1d19'
|
|
22
|
+
c.foreground '#fefffe'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module RVT
|
|
2
|
+
Colors.register_theme(:solarized_dark) do |c|
|
|
3
|
+
c.add '#073642'
|
|
4
|
+
c.add '#dc322f'
|
|
5
|
+
c.add '#859900'
|
|
6
|
+
c.add '#b58900'
|
|
7
|
+
c.add '#268bd2'
|
|
8
|
+
c.add '#d33682'
|
|
9
|
+
c.add '#2aa198'
|
|
10
|
+
c.add '#eee8d5'
|
|
11
|
+
|
|
12
|
+
c.add '#002b36'
|
|
13
|
+
c.add '#cb4b16'
|
|
14
|
+
c.add '#586e75'
|
|
15
|
+
c.add '#657b83'
|
|
16
|
+
c.add '#839496'
|
|
17
|
+
c.add '#6c71c4'
|
|
18
|
+
c.add '#93a1a1'
|
|
19
|
+
c.add '#fdf6e3'
|
|
20
|
+
|
|
21
|
+
c.background '#002b36'
|
|
22
|
+
c.foreground '#657b83'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Colors.register_theme(:solarized_light) do |c|
|
|
26
|
+
c.add '#073642'
|
|
27
|
+
c.add '#dc322f'
|
|
28
|
+
c.add '#859900'
|
|
29
|
+
c.add '#b58900'
|
|
30
|
+
c.add '#268bd2'
|
|
31
|
+
c.add '#d33682'
|
|
32
|
+
c.add '#2aa198'
|
|
33
|
+
c.add '#eee8d5'
|
|
34
|
+
|
|
35
|
+
c.add '#002b36'
|
|
36
|
+
c.add '#cb4b16'
|
|
37
|
+
c.add '#586e75'
|
|
38
|
+
c.add '#657b83'
|
|
39
|
+
c.add '#839496'
|
|
40
|
+
c.add '#6c71c4'
|
|
41
|
+
c.add '#93a1a1'
|
|
42
|
+
c.add '#fdf6e3'
|
|
43
|
+
|
|
44
|
+
c.background '#fdf6e3'
|
|
45
|
+
c.foreground '#657b83'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module RVT
|
|
2
|
+
Colors.register_theme(:tango) do |c|
|
|
3
|
+
c.add '#2e3436'
|
|
4
|
+
c.add '#cc0000'
|
|
5
|
+
c.add '#4e9a06'
|
|
6
|
+
c.add '#c4a000'
|
|
7
|
+
c.add '#3465a4'
|
|
8
|
+
c.add '#75507b'
|
|
9
|
+
c.add '#06989a'
|
|
10
|
+
c.add '#d3d7cf'
|
|
11
|
+
|
|
12
|
+
c.add '#555753'
|
|
13
|
+
c.add '#ef2929'
|
|
14
|
+
c.add '#8ae234'
|
|
15
|
+
c.add '#fce94f'
|
|
16
|
+
c.add '#729fcf'
|
|
17
|
+
c.add '#ad7fa8'
|
|
18
|
+
c.add '#34e2e2'
|
|
19
|
+
c.add '#eeeeec'
|
|
20
|
+
|
|
21
|
+
c.background '#2e3436'
|
|
22
|
+
c.foreground '#eeeeec'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module RVT
|
|
2
|
+
Colors.register_theme(:xterm) do |c|
|
|
3
|
+
c.add '#000000'
|
|
4
|
+
c.add '#cd0000'
|
|
5
|
+
c.add '#00cd00'
|
|
6
|
+
c.add '#cdcd00'
|
|
7
|
+
c.add '#0000ee'
|
|
8
|
+
c.add '#cd00cd'
|
|
9
|
+
c.add '#00cdcd'
|
|
10
|
+
c.add '#e5e5e5'
|
|
11
|
+
|
|
12
|
+
c.add '#7f7f7f'
|
|
13
|
+
c.add '#ff0000'
|
|
14
|
+
c.add '#00ff00'
|
|
15
|
+
c.add '#ffff00'
|
|
16
|
+
c.add '#5c5cff'
|
|
17
|
+
c.add '#ff00ff'
|
|
18
|
+
c.add '#00ffff'
|
|
19
|
+
c.add '#ffffff'
|
|
20
|
+
|
|
21
|
+
c.background '#000000'
|
|
22
|
+
c.foreground '#ffffff'
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/rvt/engine.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'ipaddr'
|
|
2
|
+
require 'active_support/core_ext/numeric/time'
|
|
3
|
+
require 'rails/engine'
|
|
4
|
+
|
|
5
|
+
require 'active_model'
|
|
6
|
+
require 'sprockets/rails'
|
|
7
|
+
|
|
8
|
+
module RVT
|
|
9
|
+
class Engine < ::Rails::Engine
|
|
10
|
+
isolate_namespace RVT
|
|
11
|
+
|
|
12
|
+
config.rvt = ActiveSupport::OrderedOptions.new.tap do |c|
|
|
13
|
+
c.automount = true
|
|
14
|
+
c.command = nil
|
|
15
|
+
c.default_mount_path = '/console'
|
|
16
|
+
c.timeout = 0.seconds
|
|
17
|
+
c.term = 'xterm-color'
|
|
18
|
+
c.whitelisted_ips = ['127.0.0.1', '::1']
|
|
19
|
+
|
|
20
|
+
c.style = ActiveSupport::OrderedOptions.new.tap do |s|
|
|
21
|
+
s.colors = 'light'
|
|
22
|
+
s.font = 'large Menlo, DejaVu Sans Mono, Liberation Mono, monospace'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
initializer 'rvt.add_default_route' do |app|
|
|
27
|
+
# While we don't need the route in the test environment, we define it
|
|
28
|
+
# there as well, so we can easily test it.
|
|
29
|
+
if config.rvt.automount && (Rails.env.development? || Rails.env.test?)
|
|
30
|
+
app.routes.append do
|
|
31
|
+
mount RVT::Engine => app.config.rvt.default_mount_path
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
initializer 'rvt.process_whitelisted_ips' do
|
|
37
|
+
config.rvt.tap do |c|
|
|
38
|
+
# Ensure that it is an array of IPAddr instances and it is defaulted to
|
|
39
|
+
# 127.0.0.1 if not present. Only unique entries are left in the end.
|
|
40
|
+
c.whitelisted_ips = Array(c.whitelisted_ips).map { |ip|
|
|
41
|
+
if ip.is_a?(IPAddr)
|
|
42
|
+
ip
|
|
43
|
+
else
|
|
44
|
+
IPAddr.new(ip.presence || '127.0.0.1')
|
|
45
|
+
end
|
|
46
|
+
}.uniq
|
|
47
|
+
|
|
48
|
+
# IPAddr instances can cover whole networks, so simplify the #include?
|
|
49
|
+
# check for the most common case.
|
|
50
|
+
def (c.whitelisted_ips).include?(ip)
|
|
51
|
+
if ip.is_a?(IPAddr)
|
|
52
|
+
super
|
|
53
|
+
else
|
|
54
|
+
any? { |net| net.include?(ip.to_s) }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
initializer 'rvt.process_command' do
|
|
61
|
+
config.rvt.tap do |c|
|
|
62
|
+
# +Rails.root+ is not available while we set the default values of the
|
|
63
|
+
# other options. Default it during initialization.
|
|
64
|
+
|
|
65
|
+
# Not all people created their Rails 4 applications with the Rails 4
|
|
66
|
+
# generator, so bin/rails may not be available.
|
|
67
|
+
if c.command.blank?
|
|
68
|
+
local_rails = Rails.root.join('bin/rails')
|
|
69
|
+
c.command = "#{local_rails.executable? ? local_rails : 'rails'} console"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
initializer 'rvt.process_colors' do
|
|
75
|
+
config.rvt.style.tap do |c|
|
|
76
|
+
case colors = c.colors
|
|
77
|
+
when Symbol, String
|
|
78
|
+
c.colors = Colors[colors] || Colors.default
|
|
79
|
+
else
|
|
80
|
+
c.colors = Colors.new(colors)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/rvt/slave.rb
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module RVT
|
|
2
|
+
# = Slave\ Process\ Wrapper
|
|
3
|
+
#
|
|
4
|
+
# Creates and communicates with slave processes.
|
|
5
|
+
#
|
|
6
|
+
# The communication happens through an input with attached psuedo-terminal.
|
|
7
|
+
# All of the communication is done in asynchronous way, meaning that when you
|
|
8
|
+
# send input to the process, you have get the output by polling for it.
|
|
9
|
+
class Slave
|
|
10
|
+
# Different OS' and platforms raises different errors when trying to read
|
|
11
|
+
# on output end of a closed process.
|
|
12
|
+
READING_ON_CLOSED_END_ERRORS = [ Errno::EIO, EOFError ]
|
|
13
|
+
|
|
14
|
+
# Raised when trying to read from a closed (exited) process.
|
|
15
|
+
Closed = Class.new(IOError)
|
|
16
|
+
|
|
17
|
+
# The slave process id.
|
|
18
|
+
attr_reader :pid
|
|
19
|
+
|
|
20
|
+
# Unique identifier for each slave process.
|
|
21
|
+
attr_reader :uid
|
|
22
|
+
|
|
23
|
+
def initialize(command = RVT.config.command, options = {})
|
|
24
|
+
# Windows doesn't have PTY, requiring it at the top level will fail the
|
|
25
|
+
# whole program execution.
|
|
26
|
+
require 'pty'
|
|
27
|
+
require 'io/console'
|
|
28
|
+
|
|
29
|
+
@uid = SecureRandom.hex(16)
|
|
30
|
+
|
|
31
|
+
using_term(options[:term] || RVT.config.term) do
|
|
32
|
+
@output, @input, @pid = PTY.spawn(command.to_s)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
configure(options)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Configure the psuedo terminal properties.
|
|
39
|
+
#
|
|
40
|
+
# Options:
|
|
41
|
+
# :width The width of the terminal in number of columns.
|
|
42
|
+
# :height The height of the terminal in number of rows.
|
|
43
|
+
#
|
|
44
|
+
# If any of the width or height is missing (or zero), the terminal size
|
|
45
|
+
# won't be set.
|
|
46
|
+
def configure(options = {})
|
|
47
|
+
dimentions = options.values_at(:height, :width).collect(&:to_i)
|
|
48
|
+
@input.winsize = dimentions unless dimentions.any?(&:zero?)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Sends input to the slave process STDIN.
|
|
52
|
+
#
|
|
53
|
+
# Returns immediately.
|
|
54
|
+
def send_input(input)
|
|
55
|
+
raise ArgumentError if input.nil? or input.try(:empty?)
|
|
56
|
+
input.each_char { |char| @input.putc(char) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Returns whether the slave process has any pending output in +wait+
|
|
60
|
+
# seconds.
|
|
61
|
+
#
|
|
62
|
+
# By default, the +timeout+ follows +config.rvt.timeout+. Usually,
|
|
63
|
+
# it is zero, making the response immediate.
|
|
64
|
+
def pending_output?(timeout = RVT.config.timeout)
|
|
65
|
+
# JRuby's select won't automatically coerce ActiveSupport::Duration.
|
|
66
|
+
!!IO.select([@output], [], [], timeout.to_i)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Gets the pending output of the process.
|
|
70
|
+
#
|
|
71
|
+
# The pending output is read in an non blocking way by chunks, in the size
|
|
72
|
+
# of +chunk_len+. By default, +chunk_len+ is 49152 bytes.
|
|
73
|
+
#
|
|
74
|
+
# Returns +nil+, if there is no pending output at the moment. Otherwise,
|
|
75
|
+
# returns the output that hasn't been read since the last invocation.
|
|
76
|
+
#
|
|
77
|
+
# Raises Errno:EIO on closed output stream. This can happen if the
|
|
78
|
+
# underlying process exits.
|
|
79
|
+
def pending_output(chunk_len = 49152)
|
|
80
|
+
# Returns nil if there is no pending output.
|
|
81
|
+
return unless pending_output?
|
|
82
|
+
|
|
83
|
+
pending = String.new
|
|
84
|
+
while chunk = @output.read_nonblock(chunk_len)
|
|
85
|
+
pending << chunk
|
|
86
|
+
end
|
|
87
|
+
pending.force_encoding('UTF-8')
|
|
88
|
+
rescue IO::WaitReadable
|
|
89
|
+
pending.force_encoding('UTF-8')
|
|
90
|
+
rescue
|
|
91
|
+
raise Closed if READING_ON_CLOSED_END_ERRORS.any? { |exc| $!.is_a?(exc) }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Dispose the underlying process, sending +SIGTERM+.
|
|
95
|
+
#
|
|
96
|
+
# After the process is disposed, it is detached from the parent to prevent
|
|
97
|
+
# zombies.
|
|
98
|
+
#
|
|
99
|
+
# If the process is already disposed an Errno::ESRCH will be raised and
|
|
100
|
+
# handled internally. If you want to handle Errno::ESRCH yourself, pass
|
|
101
|
+
# +{raise: true}+ as options.
|
|
102
|
+
#
|
|
103
|
+
# Returns a thread, which can be used to wait for the process termination.
|
|
104
|
+
def dispose(options = {})
|
|
105
|
+
dispose_with(:SIGTERM, options)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Dispose the underlying process, sending +SIGKILL+.
|
|
109
|
+
#
|
|
110
|
+
# After the process is disposed, it is detached from the parent to prevent
|
|
111
|
+
# zombies.
|
|
112
|
+
#
|
|
113
|
+
# If the process is already disposed an Errno::ESRCH will be raised and
|
|
114
|
+
# handled internally. If you want to handle Errno::ESRCH yourself, pass
|
|
115
|
+
# +{raise: true}+ as options.
|
|
116
|
+
#
|
|
117
|
+
# Returns a thread, which can be used to wait for the process termination.
|
|
118
|
+
def dispose!(options = {})
|
|
119
|
+
dispose_with(:SIGKILL, options)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
LOCK = Mutex.new
|
|
125
|
+
|
|
126
|
+
def using_term(term)
|
|
127
|
+
if term.nil?
|
|
128
|
+
yield
|
|
129
|
+
else
|
|
130
|
+
LOCK.synchronize do
|
|
131
|
+
begin
|
|
132
|
+
(previous_term, ENV['TERM'] = ENV['TERM'], term) and yield
|
|
133
|
+
ensure
|
|
134
|
+
ENV['TERM'] = previous_term
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def dispose_with(signal, options = {})
|
|
141
|
+
Process.kill(signal, @pid)
|
|
142
|
+
Process.detach(@pid)
|
|
143
|
+
rescue Errno::ESRCH
|
|
144
|
+
raise if options[:raise]
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|