ebb 0.1.0 → 0.2.0
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.
- data/README +4 -7
- data/benchmark/application.rb +12 -4
- data/benchmark/server_test.rb +10 -11
- data/bin/ebb_rails +0 -0
- data/libev/ev.c +235 -128
- data/libev/ev.h +84 -27
- data/libev/ev_epoll.c +30 -22
- data/libev/ev_kqueue.c +30 -22
- data/libev/ev_poll.c +30 -22
- data/libev/ev_port.c +30 -22
- data/libev/ev_select.c +34 -26
- data/libev/ev_vars.h +49 -0
- data/libev/ev_win32.c +31 -23
- data/libev/ev_wrap.h +12 -0
- data/ruby_lib/ebb.rb +94 -67
- data/ruby_lib/ebb/runner.rb +4 -5
- data/ruby_lib/ebb/runner/rails.rb +1 -4
- data/ruby_lib/rack/adapter/rails.rb +5 -0
- data/src/ebb.c +261 -387
- data/src/ebb.h +19 -29
- data/src/ebb_ruby.c +113 -108
- data/src/extconf.rb +0 -1
- data/src/parser.c +1755 -724
- data/src/parser.h +13 -10
- data/test/basic_test.rb +18 -1
- data/test/env_test.rb +6 -5
- data/test/helper.rb +53 -1
- metadata +3 -4
- data/benchmark/bench_results.rb +0 -58
data/libev/ev_vars.h
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
/*
|
2
|
+
* loop member variable declarations
|
3
|
+
*
|
4
|
+
* Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
|
5
|
+
* All rights reserved.
|
6
|
+
*
|
7
|
+
* Redistribution and use in source and binary forms, with or without modifica-
|
8
|
+
* tion, are permitted provided that the following conditions are met:
|
9
|
+
*
|
10
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
* this list of conditions and the following disclaimer.
|
12
|
+
*
|
13
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
*
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
18
|
+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
19
|
+
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
20
|
+
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
21
|
+
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
23
|
+
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
25
|
+
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
26
|
+
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
*
|
28
|
+
* Alternatively, the contents of this file may be used under the terms of
|
29
|
+
* the GNU General Public License ("GPL") version 2 or any later version,
|
30
|
+
* in which case the provisions of the GPL are applicable instead of
|
31
|
+
* the above. If you wish to allow the use of your version of this file
|
32
|
+
* only under the terms of the GPL and not to allow others to use your
|
33
|
+
* version of this file under the BSD license, indicate your decision
|
34
|
+
* by deleting the provisions above and replace them with the notice
|
35
|
+
* and other provisions required by the GPL. If you do not delete the
|
36
|
+
* provisions above, a recipient may use your version of this file under
|
37
|
+
* either the BSD or the GPL.
|
38
|
+
*/
|
39
|
+
|
1
40
|
#define VARx(type,name) VAR(name, type name)
|
2
41
|
|
3
42
|
VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */
|
@@ -16,6 +55,9 @@ VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */
|
|
16
55
|
VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev))
|
17
56
|
VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout))
|
18
57
|
|
58
|
+
VAR (evpipe, int evpipe [2])
|
59
|
+
VARx(ev_io, pipeev)
|
60
|
+
|
19
61
|
#if !defined(_WIN32) || EV_GENWRAP
|
20
62
|
VARx(pid_t, curpid)
|
21
63
|
#endif
|
@@ -98,6 +140,13 @@ VARx(int, forkmax)
|
|
98
140
|
VARx(int, forkcnt)
|
99
141
|
#endif
|
100
142
|
|
143
|
+
VARx(EV_ATOMIC_T, gotasync)
|
144
|
+
#if EV_ASYNC_ENABLE || EV_GENWRAP
|
145
|
+
VARx(struct ev_async **, asyncs)
|
146
|
+
VARx(int, asyncmax)
|
147
|
+
VARx(int, asynccnt)
|
148
|
+
#endif
|
149
|
+
|
101
150
|
#if EV_USE_INOTIFY || EV_GENWRAP
|
102
151
|
VARx(int, fs_fd)
|
103
152
|
VARx(ev_io, fs_w)
|
data/libev/ev_win32.c
CHANGED
@@ -1,32 +1,40 @@
|
|
1
1
|
/*
|
2
|
-
* libev win32 compatibility cruft
|
2
|
+
* libev win32 compatibility cruft (_not_ a backend)
|
3
3
|
*
|
4
4
|
* Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
|
5
5
|
* All rights reserved.
|
6
6
|
*
|
7
|
-
* Redistribution and use in source and binary forms, with or without
|
8
|
-
*
|
9
|
-
*
|
7
|
+
* Redistribution and use in source and binary forms, with or without modifica-
|
8
|
+
* tion, are permitted provided that the following conditions are met:
|
9
|
+
*
|
10
|
+
* 1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
* this list of conditions and the following disclaimer.
|
12
|
+
*
|
13
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
*
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
18
|
+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
19
|
+
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
20
|
+
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
21
|
+
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
23
|
+
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
25
|
+
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
26
|
+
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
10
27
|
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
17
|
-
*
|
18
|
-
*
|
19
|
-
*
|
20
|
-
*
|
21
|
-
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
22
|
-
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
23
|
-
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
24
|
-
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
25
|
-
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
26
|
-
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
27
|
-
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
28
|
-
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
* Alternatively, the contents of this file may be used under the terms of
|
29
|
+
* the GNU General Public License ("GPL") version 2 or any later version,
|
30
|
+
* in which case the provisions of the GPL are applicable instead of
|
31
|
+
* the above. If you wish to allow the use of your version of this file
|
32
|
+
* only under the terms of the GPL and not to allow others to use your
|
33
|
+
* version of this file under the BSD license, indicate your decision
|
34
|
+
* by deleting the provisions above and replace them with the notice
|
35
|
+
* and other provisions required by the GPL. If you do not delete the
|
36
|
+
* provisions above, a recipient may use your version of this file under
|
37
|
+
* either the BSD or the GPL.
|
30
38
|
*/
|
31
39
|
|
32
40
|
#ifdef _WIN32
|
data/libev/ev_wrap.h
CHANGED
@@ -13,6 +13,8 @@
|
|
13
13
|
#define backend_fudge ((loop)->backend_fudge)
|
14
14
|
#define backend_modify ((loop)->backend_modify)
|
15
15
|
#define backend_poll ((loop)->backend_poll)
|
16
|
+
#define evpipe ((loop)->evpipe)
|
17
|
+
#define pipeev ((loop)->pipeev)
|
16
18
|
#define curpid ((loop)->curpid)
|
17
19
|
#define postfork ((loop)->postfork)
|
18
20
|
#define vec_ri ((loop)->vec_ri)
|
@@ -61,6 +63,10 @@
|
|
61
63
|
#define forks ((loop)->forks)
|
62
64
|
#define forkmax ((loop)->forkmax)
|
63
65
|
#define forkcnt ((loop)->forkcnt)
|
66
|
+
#define gotasync ((loop)->gotasync)
|
67
|
+
#define asyncs ((loop)->asyncs)
|
68
|
+
#define asyncmax ((loop)->asyncmax)
|
69
|
+
#define asynccnt ((loop)->asynccnt)
|
64
70
|
#define fs_fd ((loop)->fs_fd)
|
65
71
|
#define fs_w ((loop)->fs_w)
|
66
72
|
#define fs_hash ((loop)->fs_hash)
|
@@ -78,6 +84,8 @@
|
|
78
84
|
#undef backend_fudge
|
79
85
|
#undef backend_modify
|
80
86
|
#undef backend_poll
|
87
|
+
#undef evpipe
|
88
|
+
#undef pipeev
|
81
89
|
#undef curpid
|
82
90
|
#undef postfork
|
83
91
|
#undef vec_ri
|
@@ -126,6 +134,10 @@
|
|
126
134
|
#undef forks
|
127
135
|
#undef forkmax
|
128
136
|
#undef forkcnt
|
137
|
+
#undef gotasync
|
138
|
+
#undef asyncs
|
139
|
+
#undef asyncmax
|
140
|
+
#undef asynccnt
|
129
141
|
#undef fs_fd
|
130
142
|
#undef fs_w
|
131
143
|
#undef fs_hash
|
data/ruby_lib/ebb.rb
CHANGED
@@ -3,33 +3,37 @@
|
|
3
3
|
# See README file for details.
|
4
4
|
require 'stringio'
|
5
5
|
module Ebb
|
6
|
+
VERSION = "0.2.0"
|
6
7
|
LIBDIR = File.dirname(__FILE__)
|
7
|
-
require Ebb::LIBDIR + '/../src/ebb_ext'
|
8
8
|
autoload :Runner, LIBDIR + '/ebb/runner'
|
9
|
+
autoload :FFI, LIBDIR + '/../src/ebb_ext'
|
9
10
|
|
10
11
|
def self.start_server(app, options={})
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
if options.has_key?(:fileno)
|
13
|
+
fd = options[:fileno].to_i
|
14
|
+
FFI::server_listen_on_fd(fd)
|
15
|
+
log.puts "Ebb is listening on file descriptor #{fd}"
|
16
|
+
elsif options.has_key?(:unix_socket)
|
17
|
+
socketfile = options[:unix_socket]
|
18
|
+
FFI::server_listen_on_unix_socket(socketfile)
|
19
|
+
log.puts "Ebb is listening on unix socket #{socketfile}"
|
14
20
|
else
|
15
|
-
|
21
|
+
port = (options[:port] || 4001).to_i
|
22
|
+
FFI::server_listen_on_port(port)
|
23
|
+
log.puts "Ebb is listening at http://0.0.0.0:#{port}/"
|
16
24
|
end
|
25
|
+
log.puts "Ebb PID #{Process.pid}"
|
17
26
|
|
18
|
-
Client::BASE_ENV['rack.multithread'] = threaded_processing
|
19
|
-
|
20
|
-
FFI::server_listen_on_port(port)
|
21
27
|
@running = true
|
22
28
|
trap('INT') { stop_server }
|
23
29
|
|
24
|
-
log.puts "Ebb listening at http://0.0.0.0:#{port}/ (#{threaded_processing ? 'threaded' : 'sequential'} processing, PID #{Process.pid})"
|
25
|
-
|
26
30
|
while @running
|
27
31
|
FFI::server_process_connections()
|
28
|
-
while client = FFI::
|
29
|
-
if
|
30
|
-
Thread.new(client) { |c| process(app, c) }
|
31
|
-
else
|
32
|
+
while client = FFI::server_waiting_clients.shift
|
33
|
+
if app.respond_to?(:deferred?) and !app.deferred?(client.env)
|
32
34
|
process(app, client)
|
35
|
+
else
|
36
|
+
Thread.new(client) { |c| process(app, c) }
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -45,34 +49,40 @@ module Ebb
|
|
45
49
|
end
|
46
50
|
|
47
51
|
def self.process(app, client)
|
48
|
-
|
49
|
-
|
50
|
-
rescue
|
51
|
-
raise if $DEBUG
|
52
|
-
status = 500
|
53
|
-
headers = {'Content-Type' => 'text/plain'}
|
54
|
-
body = "Internal Server Error\n"
|
55
|
-
end
|
52
|
+
#p client.env
|
53
|
+
status, headers, body = app.call(client.env)
|
56
54
|
|
55
|
+
# Write the status
|
57
56
|
client.write_status(status)
|
58
57
|
|
59
|
-
|
60
|
-
|
58
|
+
# Add Content-Length to the headers.
|
59
|
+
if headers['Content-Length'].nil? and
|
60
|
+
headers.respond_to?(:[]=) and
|
61
|
+
body.respond_to?(:length) and
|
62
|
+
status != 304
|
63
|
+
then
|
61
64
|
headers['Content-Length'] = body.length.to_s
|
62
65
|
end
|
63
66
|
|
67
|
+
# Decide if we should keep the connection alive or not
|
68
|
+
if headers['Connection'].nil?
|
69
|
+
if headers['Content-Length'] and client.should_keep_alive?
|
70
|
+
headers['Connection'] = 'Keep-Alive'
|
71
|
+
else
|
72
|
+
headers['Connection'] = 'close'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Write the headers
|
64
77
|
headers.each { |field, value| client.write_header(field, value) }
|
65
|
-
client.write("\r\n")
|
66
78
|
|
79
|
+
# Write the body
|
67
80
|
if body.kind_of?(String)
|
68
|
-
client.
|
69
|
-
client.body_written()
|
70
|
-
client.begin_transmission()
|
81
|
+
client.write_body(body)
|
71
82
|
else
|
72
|
-
client.
|
73
|
-
body.each { |p| client.write(p) }
|
74
|
-
client.body_written()
|
83
|
+
body.each { |p| client.write_body(p) }
|
75
84
|
end
|
85
|
+
|
76
86
|
rescue => e
|
77
87
|
log.puts "Ebb Error! #{e.class} #{e.message}"
|
78
88
|
log.puts e.backtrace.join("\n")
|
@@ -88,16 +98,12 @@ module Ebb
|
|
88
98
|
@@log
|
89
99
|
end
|
90
100
|
|
91
|
-
# This array is created and manipulated in the C extension.
|
92
|
-
def FFI.waiting_clients
|
93
|
-
@waiting_clients
|
94
|
-
end
|
95
|
-
|
96
101
|
class Client
|
102
|
+
attr_reader :fd, :body_head, :content_length
|
97
103
|
BASE_ENV = {
|
98
104
|
'SERVER_NAME' => '0.0.0.0',
|
99
105
|
'SCRIPT_NAME' => '',
|
100
|
-
'SERVER_SOFTWARE' => "Ebb #{Ebb::VERSION}",
|
106
|
+
'SERVER_SOFTWARE' => "Ebb-Ruby #{Ebb::VERSION}",
|
101
107
|
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
102
108
|
'rack.version' => [0, 1],
|
103
109
|
'rack.errors' => STDERR,
|
@@ -107,9 +113,11 @@ module Ebb
|
|
107
113
|
}
|
108
114
|
|
109
115
|
def env
|
110
|
-
env
|
111
|
-
|
112
|
-
|
116
|
+
@env ||= begin
|
117
|
+
env = FFI::client_env(self).update(BASE_ENV)
|
118
|
+
env['rack.input'] = RequestBody.new(self)
|
119
|
+
env
|
120
|
+
end
|
113
121
|
end
|
114
122
|
|
115
123
|
def write_status(status)
|
@@ -117,8 +125,8 @@ module Ebb
|
|
117
125
|
FFI::client_write_status(self, s, HTTP_STATUS_CODES[s])
|
118
126
|
end
|
119
127
|
|
120
|
-
def
|
121
|
-
FFI::
|
128
|
+
def write_body(data)
|
129
|
+
FFI::client_write_body(self, data)
|
122
130
|
end
|
123
131
|
|
124
132
|
def write_header(field, value)
|
@@ -127,50 +135,53 @@ module Ebb
|
|
127
135
|
end
|
128
136
|
end
|
129
137
|
|
130
|
-
def
|
131
|
-
FFI::
|
138
|
+
def release
|
139
|
+
FFI::client_release(self)
|
132
140
|
end
|
133
141
|
|
134
|
-
def
|
135
|
-
FFI::
|
142
|
+
def set_keep_alive
|
143
|
+
FFI::client_set_keep_alive(self)
|
136
144
|
end
|
137
145
|
|
138
|
-
def
|
139
|
-
|
146
|
+
def should_keep_alive?
|
147
|
+
if env['HTTP_VERSION'] == 'HTTP/1.0'
|
148
|
+
return true if env['HTTP_CONNECTION'] =~ /Keep-Alive/i
|
149
|
+
else
|
150
|
+
return true unless env['HTTP_CONNECTION'] =~ /close/i
|
151
|
+
end
|
152
|
+
false
|
140
153
|
end
|
141
154
|
end
|
142
155
|
|
143
156
|
class RequestBody
|
144
157
|
def initialize(client)
|
145
|
-
@
|
158
|
+
@content_length = client.content_length
|
159
|
+
if client.body_head
|
160
|
+
@body_head = StringIO.new(client.body_head)
|
161
|
+
if @body_head.length < @content_length
|
162
|
+
@socket = IO.new(client.fd)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
@total_read = 0
|
146
166
|
end
|
147
167
|
|
148
168
|
def read(len = nil)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
if
|
153
|
-
|
154
|
-
while(chunk = read(10*1024)) do
|
155
|
-
s << chunk
|
156
|
-
end
|
157
|
-
s
|
158
|
-
else
|
159
|
-
FFI::client_read_input(@client, len)
|
160
|
-
end
|
169
|
+
to_read = len.nil? ? @content_length - @total_read : min(len, @content_length - @total_read)
|
170
|
+
return nil if to_read == 0 or @body_head.nil?
|
171
|
+
unless out = @body_head.read(to_read)
|
172
|
+
return nil if @socket.nil?
|
173
|
+
out = @socket.read(to_read)
|
161
174
|
end
|
175
|
+
@total_read += out.length
|
176
|
+
out
|
162
177
|
end
|
163
178
|
|
164
179
|
def gets
|
165
|
-
|
180
|
+
raise NotImplemented
|
166
181
|
end
|
167
182
|
|
168
183
|
def each(&block)
|
169
|
-
|
170
|
-
end
|
171
|
-
|
172
|
-
def io
|
173
|
-
@io ||= StringIO.new(read)
|
184
|
+
raise NotImplemented
|
174
185
|
end
|
175
186
|
end
|
176
187
|
|
@@ -215,3 +226,19 @@ module Ebb
|
|
215
226
|
505 => 'HTTP Version not supported'
|
216
227
|
}.freeze
|
217
228
|
end
|
229
|
+
|
230
|
+
|
231
|
+
module Rack
|
232
|
+
module Handler
|
233
|
+
module Ebb
|
234
|
+
def self.run(app, options={})
|
235
|
+
::Ebb.start_server(app, options)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# cause i don't want to create an array
|
242
|
+
def min(a,b)
|
243
|
+
a > b ? b : a
|
244
|
+
end
|
data/ruby_lib/ebb/runner.rb
CHANGED
@@ -58,8 +58,7 @@ module Ebb
|
|
58
58
|
@parser = OptionParser.new
|
59
59
|
@options = {
|
60
60
|
:port => 4001,
|
61
|
-
:timeout => 60
|
62
|
-
:threaded_processing => true
|
61
|
+
:timeout => 60
|
63
62
|
}
|
64
63
|
end
|
65
64
|
|
@@ -69,8 +68,8 @@ module Ebb
|
|
69
68
|
extra_options if respond_to?(:extra_options)
|
70
69
|
|
71
70
|
@parser.separator ""
|
72
|
-
|
73
|
-
@parser.on("-
|
71
|
+
@parser.on("-p", "--port PORT", "(default: #{@options[:port]})") { |p| @options[:port] = p }
|
72
|
+
@parser.on("-s", "--socket SOCKET", "listen on unix domain socket") { |socket| options[:unix_socket] = socket }
|
74
73
|
@parser.on("-d", "--daemonize", "Daemonize") { @options[:daemonize] = true }
|
75
74
|
@parser.on("-l", "--log-file FILE", "File to redirect output") { |f| @options[:log_file]=f }
|
76
75
|
@parser.on("-P", "--pid-file FILE", "File to store PID") { |f| @options[:pid_file]=f }
|
@@ -82,7 +81,7 @@ module Ebb
|
|
82
81
|
exit
|
83
82
|
end
|
84
83
|
@parser.on_tail('-v', '--version', "Show version") do
|
85
|
-
Ebb.log.puts
|
84
|
+
Ebb.log.puts Ebb::Client::BASE_ENV['SERVER_SOFTWARE']
|
86
85
|
exit
|
87
86
|
end
|
88
87
|
|