zookeeper 0.9.3-java

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.
Files changed (53) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +119 -0
  3. data/Gemfile +17 -0
  4. data/LICENSE +23 -0
  5. data/Manifest +29 -0
  6. data/README.markdown +59 -0
  7. data/Rakefile +139 -0
  8. data/examples/cloud_config.rb +125 -0
  9. data/ext/.gitignore +6 -0
  10. data/ext/Rakefile +51 -0
  11. data/ext/c_zookeeper.rb +212 -0
  12. data/ext/dbg.h +53 -0
  13. data/ext/depend +5 -0
  14. data/ext/extconf.rb +85 -0
  15. data/ext/generate_gvl_code.rb +316 -0
  16. data/ext/zkc-3.3.5.tar.gz +0 -0
  17. data/ext/zkrb_wrapper.c +731 -0
  18. data/ext/zkrb_wrapper.h +330 -0
  19. data/ext/zkrb_wrapper_compat.c +15 -0
  20. data/ext/zkrb_wrapper_compat.h +11 -0
  21. data/ext/zookeeper_base.rb +211 -0
  22. data/ext/zookeeper_c.c +725 -0
  23. data/ext/zookeeper_lib.c +677 -0
  24. data/ext/zookeeper_lib.h +172 -0
  25. data/java/zookeeper_base.rb +477 -0
  26. data/lib/zookeeper.rb +297 -0
  27. data/lib/zookeeper/acls.rb +40 -0
  28. data/lib/zookeeper/callbacks.rb +91 -0
  29. data/lib/zookeeper/common.rb +174 -0
  30. data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
  31. data/lib/zookeeper/constants.rb +57 -0
  32. data/lib/zookeeper/em_client.rb +55 -0
  33. data/lib/zookeeper/exceptions.rb +100 -0
  34. data/lib/zookeeper/stat.rb +21 -0
  35. data/lib/zookeeper/version.rb +6 -0
  36. data/notes.txt +14 -0
  37. data/spec/c_zookeeper_spec.rb +50 -0
  38. data/spec/chrooted_connection_spec.rb +81 -0
  39. data/spec/default_watcher_spec.rb +41 -0
  40. data/spec/em_spec.rb +51 -0
  41. data/spec/log4j.properties +17 -0
  42. data/spec/shared/all_success_return_values.rb +10 -0
  43. data/spec/shared/connection_examples.rb +1018 -0
  44. data/spec/spec_helper.rb +119 -0
  45. data/spec/support/progress_formatter.rb +15 -0
  46. data/spec/zookeeper_spec.rb +24 -0
  47. data/test/test_basic.rb +37 -0
  48. data/test/test_callback1.rb +36 -0
  49. data/test/test_close.rb +16 -0
  50. data/test/test_esoteric.rb +7 -0
  51. data/test/test_watcher1.rb +56 -0
  52. data/test/test_watcher2.rb +52 -0
  53. metadata +181 -0
@@ -0,0 +1,330 @@
1
+ #ifndef ZKRB_WRAPPER_H
2
+ #define ZKRB_WRAPPER_H
3
+ #if 0
4
+
5
+ AUTOGENERATED BY generate_gvl_code.rb
6
+
7
+ #endif
8
+
9
+ #include "ruby.h"
10
+ #include "c-client-src/zookeeper.h"
11
+ #include "zkrb_wrapper_compat.h"
12
+ #include "dbg.h"
13
+
14
+ #define ZKRB_FAIL -1
15
+
16
+ typedef struct {
17
+ zhandle_t *zh;
18
+ int rc;
19
+ } zkrb_zoo_recv_timeout_args_t;
20
+
21
+ typedef struct {
22
+ zhandle_t *zh;
23
+ int rc;
24
+ } zkrb_zoo_state_args_t;
25
+
26
+ typedef struct {
27
+ zhandle_t *zh;
28
+ const char *path;
29
+ const char *value;
30
+ int valuelen;
31
+ const struct ACL_vector *acl;
32
+ int flags;
33
+ string_completion_t completion;
34
+ const void *data;
35
+ int rc;
36
+ } zkrb_zoo_acreate_args_t;
37
+
38
+ typedef struct {
39
+ zhandle_t *zh;
40
+ const char *path;
41
+ int version;
42
+ void_completion_t completion;
43
+ const void *data;
44
+ int rc;
45
+ } zkrb_zoo_adelete_args_t;
46
+
47
+ typedef struct {
48
+ zhandle_t *zh;
49
+ const char *path;
50
+ int watch;
51
+ stat_completion_t completion;
52
+ const void *data;
53
+ int rc;
54
+ } zkrb_zoo_aexists_args_t;
55
+
56
+ typedef struct {
57
+ zhandle_t *zh;
58
+ const char *path;
59
+ watcher_fn watcher;
60
+ void* watcherCtx;
61
+ stat_completion_t completion;
62
+ const void *data;
63
+ int rc;
64
+ } zkrb_zoo_awexists_args_t;
65
+
66
+ typedef struct {
67
+ zhandle_t *zh;
68
+ const char *path;
69
+ int watch;
70
+ data_completion_t completion;
71
+ const void *data;
72
+ int rc;
73
+ } zkrb_zoo_aget_args_t;
74
+
75
+ typedef struct {
76
+ zhandle_t *zh;
77
+ const char *path;
78
+ watcher_fn watcher;
79
+ void* watcherCtx;
80
+ data_completion_t completion;
81
+ const void *data;
82
+ int rc;
83
+ } zkrb_zoo_awget_args_t;
84
+
85
+ typedef struct {
86
+ zhandle_t *zh;
87
+ const char *path;
88
+ const char *buffer;
89
+ int buflen;
90
+ int version;
91
+ stat_completion_t completion;
92
+ const void *data;
93
+ int rc;
94
+ } zkrb_zoo_aset_args_t;
95
+
96
+ typedef struct {
97
+ zhandle_t *zh;
98
+ const char *path;
99
+ int watch;
100
+ strings_completion_t completion;
101
+ const void *data;
102
+ int rc;
103
+ } zkrb_zoo_aget_children_args_t;
104
+
105
+ typedef struct {
106
+ zhandle_t *zh;
107
+ const char *path;
108
+ watcher_fn watcher;
109
+ void* watcherCtx;
110
+ strings_completion_t completion;
111
+ const void *data;
112
+ int rc;
113
+ } zkrb_zoo_awget_children_args_t;
114
+
115
+ typedef struct {
116
+ zhandle_t *zh;
117
+ const char *path;
118
+ int watch;
119
+ strings_stat_completion_t completion;
120
+ const void *data;
121
+ int rc;
122
+ } zkrb_zoo_aget_children2_args_t;
123
+
124
+ typedef struct {
125
+ zhandle_t *zh;
126
+ const char *path;
127
+ watcher_fn watcher;
128
+ void* watcherCtx;
129
+ strings_stat_completion_t completion;
130
+ const void *data;
131
+ int rc;
132
+ } zkrb_zoo_awget_children2_args_t;
133
+
134
+ typedef struct {
135
+ zhandle_t *zh;
136
+ const char *path;
137
+ string_completion_t completion;
138
+ const void *data;
139
+ int rc;
140
+ } zkrb_zoo_async_args_t;
141
+
142
+ typedef struct {
143
+ zhandle_t *zh;
144
+ const char *path;
145
+ acl_completion_t completion;
146
+ const void *data;
147
+ int rc;
148
+ } zkrb_zoo_aget_acl_args_t;
149
+
150
+ typedef struct {
151
+ zhandle_t *zh;
152
+ const char *path;
153
+ int version;
154
+ struct ACL_vector *acl;
155
+ void_completion_t completion;
156
+ const void *data;
157
+ int rc;
158
+ } zkrb_zoo_aset_acl_args_t;
159
+
160
+ typedef struct {
161
+ zhandle_t *zh;
162
+ const char* scheme;
163
+ const char* cert;
164
+ int certLen;
165
+ void_completion_t completion;
166
+ const void *data;
167
+ int rc;
168
+ } zkrb_zoo_add_auth_args_t;
169
+
170
+ typedef struct {
171
+ zhandle_t *zh;
172
+ const char *path;
173
+ const char *value;
174
+ int valuelen;
175
+ const struct ACL_vector *acl;
176
+ int flags;
177
+ char *path_buffer;
178
+ int path_buffer_len;
179
+ int rc;
180
+ } zkrb_zoo_create_args_t;
181
+
182
+ typedef struct {
183
+ zhandle_t *zh;
184
+ const char *path;
185
+ int version;
186
+ int rc;
187
+ } zkrb_zoo_delete_args_t;
188
+
189
+ typedef struct {
190
+ zhandle_t *zh;
191
+ const char *path;
192
+ int watch;
193
+ struct Stat *stat;
194
+ int rc;
195
+ } zkrb_zoo_exists_args_t;
196
+
197
+ typedef struct {
198
+ zhandle_t *zh;
199
+ const char *path;
200
+ watcher_fn watcher;
201
+ void* watcherCtx;
202
+ struct Stat *stat;
203
+ int rc;
204
+ } zkrb_zoo_wexists_args_t;
205
+
206
+ typedef struct {
207
+ zhandle_t *zh;
208
+ const char *path;
209
+ int watch;
210
+ char *buffer;
211
+ int* buffer_len;
212
+ struct Stat *stat;
213
+ int rc;
214
+ } zkrb_zoo_get_args_t;
215
+
216
+ typedef struct {
217
+ zhandle_t *zh;
218
+ const char *path;
219
+ watcher_fn watcher;
220
+ void* watcherCtx;
221
+ char *buffer;
222
+ int* buffer_len;
223
+ struct Stat *stat;
224
+ int rc;
225
+ } zkrb_zoo_wget_args_t;
226
+
227
+ typedef struct {
228
+ zhandle_t *zh;
229
+ const char *path;
230
+ const char *buffer;
231
+ int buflen;
232
+ int version;
233
+ int rc;
234
+ } zkrb_zoo_set_args_t;
235
+
236
+ typedef struct {
237
+ zhandle_t *zh;
238
+ const char *path;
239
+ const char *buffer;
240
+ int buflen;
241
+ int version;
242
+ struct Stat *stat;
243
+ int rc;
244
+ } zkrb_zoo_set2_args_t;
245
+
246
+ typedef struct {
247
+ zhandle_t *zh;
248
+ const char *path;
249
+ int watch;
250
+ struct String_vector *strings;
251
+ int rc;
252
+ } zkrb_zoo_get_children_args_t;
253
+
254
+ typedef struct {
255
+ zhandle_t *zh;
256
+ const char *path;
257
+ watcher_fn watcher;
258
+ void* watcherCtx;
259
+ struct String_vector *strings;
260
+ int rc;
261
+ } zkrb_zoo_wget_children_args_t;
262
+
263
+ typedef struct {
264
+ zhandle_t *zh;
265
+ const char *path;
266
+ int watch;
267
+ struct String_vector *strings;
268
+ struct Stat *stat;
269
+ int rc;
270
+ } zkrb_zoo_get_children2_args_t;
271
+
272
+ typedef struct {
273
+ zhandle_t *zh;
274
+ const char *path;
275
+ watcher_fn watcher;
276
+ void* watcherCtx;
277
+ struct String_vector *strings;
278
+ struct Stat *stat;
279
+ int rc;
280
+ } zkrb_zoo_wget_children2_args_t;
281
+
282
+ typedef struct {
283
+ zhandle_t *zh;
284
+ const char *path;
285
+ struct ACL_vector *acl;
286
+ struct Stat *stat;
287
+ int rc;
288
+ } zkrb_zoo_get_acl_args_t;
289
+
290
+ typedef struct {
291
+ zhandle_t *zh;
292
+ const char *path;
293
+ int version;
294
+ const struct ACL_vector *acl;
295
+ int rc;
296
+ } zkrb_zoo_set_acl_args_t;
297
+
298
+ int zkrb_call_zoo_recv_timeout(zhandle_t *zh);
299
+ int zkrb_call_zoo_state(zhandle_t *zh);
300
+ int zkrb_call_zoo_acreate(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, string_completion_t completion, const void *data);
301
+ int zkrb_call_zoo_adelete(zhandle_t *zh, const char *path, int version, void_completion_t completion, const void *data);
302
+ int zkrb_call_zoo_aexists(zhandle_t *zh, const char *path, int watch, stat_completion_t completion, const void *data);
303
+ int zkrb_call_zoo_awexists(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, stat_completion_t completion, const void *data);
304
+ int zkrb_call_zoo_aget(zhandle_t *zh, const char *path, int watch, data_completion_t completion, const void *data);
305
+ int zkrb_call_zoo_awget(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, data_completion_t completion, const void *data);
306
+ int zkrb_call_zoo_aset(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version, stat_completion_t completion, const void *data);
307
+ int zkrb_call_zoo_aget_children(zhandle_t *zh, const char *path, int watch, strings_completion_t completion, const void *data);
308
+ int zkrb_call_zoo_awget_children(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, strings_completion_t completion, const void *data);
309
+ int zkrb_call_zoo_aget_children2(zhandle_t *zh, const char *path, int watch, strings_stat_completion_t completion, const void *data);
310
+ int zkrb_call_zoo_awget_children2(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, strings_stat_completion_t completion, const void *data);
311
+ int zkrb_call_zoo_async(zhandle_t *zh, const char *path, string_completion_t completion, const void *data);
312
+ int zkrb_call_zoo_aget_acl(zhandle_t *zh, const char *path, acl_completion_t completion, const void *data);
313
+ int zkrb_call_zoo_aset_acl(zhandle_t *zh, const char *path, int version, struct ACL_vector *acl, void_completion_t completion, const void *data);
314
+ int zkrb_call_zoo_add_auth(zhandle_t *zh, const char* scheme, const char* cert, int certLen, void_completion_t completion, const void *data);
315
+ int zkrb_call_zoo_create(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, char *path_buffer, int path_buffer_len);
316
+ int zkrb_call_zoo_delete(zhandle_t *zh, const char *path, int version);
317
+ int zkrb_call_zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat);
318
+ int zkrb_call_zoo_wexists(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct Stat *stat);
319
+ int zkrb_call_zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer, int* buffer_len, struct Stat *stat);
320
+ int zkrb_call_zoo_wget(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, char *buffer, int* buffer_len, struct Stat *stat);
321
+ int zkrb_call_zoo_set(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version);
322
+ int zkrb_call_zoo_set2(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version, struct Stat *stat);
323
+ int zkrb_call_zoo_get_children(zhandle_t *zh, const char *path, int watch, struct String_vector *strings);
324
+ int zkrb_call_zoo_wget_children(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct String_vector *strings);
325
+ int zkrb_call_zoo_get_children2(zhandle_t *zh, const char *path, int watch, struct String_vector *strings, struct Stat *stat);
326
+ int zkrb_call_zoo_wget_children2(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct String_vector *strings, struct Stat *stat);
327
+ int zkrb_call_zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl, struct Stat *stat);
328
+ int zkrb_call_zoo_set_acl(zhandle_t *zh, const char *path, int version, const struct ACL_vector *acl);
329
+
330
+ #endif /* ZKRB_WRAPPER_H */
@@ -0,0 +1,15 @@
1
+ #include "ruby.h"
2
+ #include "zkrb_wrapper_compat.h"
3
+
4
+
5
+ VALUE zkrb_thread_blocking_region(zkrb_blocking_function_t *func, void *data1) {
6
+
7
+ #ifdef ZKRB_RUBY_187
8
+ return func(data1);
9
+ #else
10
+ return rb_thread_blocking_region((rb_blocking_function_t *)func, data1, RUBY_UBF_IO, 0);
11
+ #endif
12
+
13
+ }
14
+
15
+ // vim:sts=2:sw=2:et
@@ -0,0 +1,11 @@
1
+ #ifndef ZKRB_WRAPPER_COMPAT_H
2
+ #define ZKRB_WRAPPER_COMPAT_H
3
+
4
+ typedef VALUE zkrb_blocking_function_t(void *);
5
+ typedef void zkrb_unblock_function_t(void *);
6
+
7
+ // delegates to rb_thread_blocking_region on 1.9.x, always uses UBF_IO
8
+ VALUE zkrb_thread_blocking_region(zkrb_blocking_function_t *func, void *data1);
9
+
10
+
11
+ #endif /* ZKRB_WRAPPER_COMPAT_H */
@@ -0,0 +1,211 @@
1
+ require File.expand_path('../c_zookeeper', __FILE__)
2
+ require 'forwardable'
3
+
4
+ # The low-level wrapper-specific methods for the C lib
5
+ # subclassed by the top-level Zookeeper class
6
+ class ZookeeperBase
7
+ extend Forwardable
8
+ include ZookeeperCommon
9
+ include ZookeeperCallbacks
10
+ include ZookeeperConstants
11
+ include ZookeeperExceptions
12
+ include ZookeeperACLs
13
+ include ZookeeperStat
14
+
15
+ # @private
16
+ class ClientShutdownException < StandardError; end
17
+
18
+ # @private
19
+ KILL_TOKEN = Object.new unless defined?(KILL_TOKEN)
20
+
21
+ ZKRB_GLOBAL_CB_REQ = -1
22
+
23
+ # debug levels
24
+ ZOO_LOG_LEVEL_ERROR = 1
25
+ ZOO_LOG_LEVEL_WARN = 2
26
+ ZOO_LOG_LEVEL_INFO = 3
27
+ ZOO_LOG_LEVEL_DEBUG = 4
28
+
29
+ def_delegators :czk,
30
+ :get_children, :exists, :delete, :get, :set, :set_acl, :get_acl, :client_id, :sync, :selectable_io
31
+
32
+ # some state methods need to be more paranoid about locking to ensure the correct
33
+ # state is returned
34
+ #
35
+ def self.threadsafe_inquisitor(*syms)
36
+ syms.each do |sym|
37
+ class_eval(<<-EOM, __FILE__, __LINE__+1)
38
+ def #{sym}
39
+ false|@mutex.synchronize { @czk and @czk.#{sym} }
40
+ end
41
+ EOM
42
+ end
43
+ end
44
+
45
+ threadsafe_inquisitor :connected?, :connecting?, :associating?, :running?
46
+
47
+ attr_reader :event_queue
48
+
49
+ def reopen(timeout = 10, watcher=nil)
50
+ if watcher and (watcher != @default_watcher)
51
+ raise "You cannot set the watcher to a different value this way anymore!"
52
+ end
53
+
54
+ @mutex.synchronize do
55
+ # flushes all outstanding watcher reqs.
56
+ @watcher_reqs.clear
57
+ set_default_global_watcher
58
+
59
+ orig_czk, @czk = @czk, CZookeeper.new(@host, @event_queue)
60
+
61
+ orig_czk.close if orig_czk
62
+
63
+ @czk.wait_until_connected(timeout)
64
+ end
65
+
66
+ setup_dispatch_thread!
67
+ state
68
+ end
69
+
70
+ def initialize(host, timeout = 10, watcher=nil)
71
+ @watcher_reqs = {}
72
+ @completion_reqs = {}
73
+
74
+ @mutex = Monitor.new
75
+ @dispatch_shutdown_cond = @mutex.new_cond
76
+
77
+ @current_req_id = 0
78
+ @event_queue = QueueWithPipe.new
79
+ @czk = nil
80
+
81
+ # approximate the java behavior of raising java.lang.IllegalArgumentException if the host
82
+ # argument ends with '/'
83
+ raise ArgumentError, "Host argument #{host.inspect} may not end with /" if host.end_with?('/')
84
+
85
+ @host = host
86
+
87
+ @default_watcher = (watcher or get_default_global_watcher)
88
+
89
+ yield self if block_given?
90
+
91
+ reopen(timeout)
92
+ end
93
+
94
+ # synchronized accessor to the @czk instance
95
+ # @private
96
+ def czk
97
+ @mutex.synchronize { @czk }
98
+ end
99
+
100
+ # if either of these happen, the user will need to renegotiate a connection via reopen
101
+ def assert_open
102
+ raise ZookeeperException::SessionExpired if state == ZOO_EXPIRED_SESSION_STATE
103
+ raise ZookeeperException::NotConnected unless connected?
104
+ end
105
+
106
+ def close
107
+ shutdown_thread = Thread.new do
108
+ @mutex.synchronize do
109
+ stop_dispatch_thread!
110
+ @czk.close
111
+ end
112
+ end
113
+
114
+ shutdown_thread.join unless event_dispatch_thread?
115
+ end
116
+
117
+ # the C lib doesn't strip the chroot path off of returned path values, which
118
+ # is pretty damn annoying. this is used to clean things up.
119
+ def create(*args)
120
+ # since we don't care about the inputs, just glob args
121
+ rc, new_path = czk.create(*args)
122
+ [rc, strip_chroot_from(new_path)]
123
+ end
124
+
125
+ def set_debug_level(int)
126
+ warn "DEPRECATION WARNING: #{self.class.name}#set_debug_level, it has moved to the class level and will be removed in a future release"
127
+ self.class.set_debug_level(int)
128
+ end
129
+
130
+ # set the watcher object/proc that will receive all global events (such as session/state events)
131
+ def set_default_global_watcher
132
+ warn "DEPRECATION WARNING: #{self.class}#set_default_global_watcher ignores block" if block_given?
133
+
134
+ @mutex.synchronize do
135
+ # @default_watcher = block # save this here for reopen() to use
136
+ @watcher_reqs[ZKRB_GLOBAL_CB_REQ] = { :watcher => @default_watcher, :watcher_context => nil }
137
+ end
138
+ end
139
+
140
+ def state
141
+ return ZOO_CLOSED_STATE if closed?
142
+ czk.state
143
+ end
144
+
145
+ def session_id
146
+ cid = client_id and cid.session_id
147
+ end
148
+
149
+ def session_passwd
150
+ cid = client_id and cid.passwd
151
+ end
152
+
153
+ # we are closed if there is no @czk instance or @czk.closed?
154
+ def closed?
155
+ @mutex.synchronize { !@czk or @czk.closed? }
156
+ end
157
+
158
+ protected
159
+ # this is a hack: to provide consistency between the C and Java drivers when
160
+ # using a chrooted connection, we wrap the callback in a block that will
161
+ # strip the chroot path from the returned path (important in an async create
162
+ # sequential call). This is the only place where we can hook *just* the C
163
+ # version. The non-async manipulation is handled in ZookeeperBase#create.
164
+ #
165
+ def setup_completion(req_id, meth_name, call_opts)
166
+ if (meth_name == :create) and cb = call_opts[:callback]
167
+ call_opts[:callback] = lambda do |hash|
168
+ # in this case the string will be the absolute zookeeper path (i.e.
169
+ # with the chroot still prepended to the path). Here's where we strip it off
170
+ hash[:string] = strip_chroot_from(hash[:string])
171
+
172
+ # call the original callback
173
+ cb.call(hash)
174
+ end
175
+ end
176
+
177
+ # pass this along to the ZookeeperCommon implementation
178
+ super(req_id, meth_name, call_opts)
179
+ end
180
+
181
+ # if we're chrooted, this method will strip the chroot prefix from +path+
182
+ def strip_chroot_from(path)
183
+ return path unless (chrooted? and path and path.start_with?(chroot_path))
184
+ path[chroot_path.length..-1]
185
+ end
186
+
187
+ def get_default_global_watcher
188
+ Proc.new { |args|
189
+ logger.debug { "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}" }
190
+ true
191
+ }
192
+ end
193
+
194
+ def chrooted?
195
+ !chroot_path.empty?
196
+ end
197
+
198
+ def chroot_path
199
+ if @chroot_path.nil?
200
+ @chroot_path =
201
+ if idx = @host.index('/')
202
+ @host.slice(idx, @host.length)
203
+ else
204
+ ''
205
+ end
206
+ end
207
+
208
+ @chroot_path
209
+ end
210
+ end
211
+