pione 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/.gitignore +2 -1
  2. data/History.txt +11 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +1 -1
  5. data/bin/pione-log +5 -0
  6. data/example/CountChar/CountChar.pione +1 -1
  7. data/example/SieveOfEratosthenes/SieveOfEratosthenes.pione +39 -38
  8. data/lib/pione.rb +14 -35
  9. data/lib/pione/agent/input-generator.rb +38 -40
  10. data/lib/pione/agent/logger.rb +52 -19
  11. data/lib/pione/agent/rule-provider.rb +5 -8
  12. data/lib/pione/agent/task-worker.rb +25 -32
  13. data/lib/pione/agent/tuple-space-client.rb +22 -14
  14. data/lib/pione/command.rb +21 -0
  15. data/lib/pione/command/basic-command.rb +267 -84
  16. data/lib/pione/command/child-process.rb +21 -18
  17. data/lib/pione/command/daemon-process.rb +9 -8
  18. data/lib/pione/command/front-owner-command.rb +8 -25
  19. data/lib/pione/command/pione-broker.rb +27 -24
  20. data/lib/pione/command/pione-clean.rb +6 -6
  21. data/lib/pione/command/pione-client.rb +143 -128
  22. data/lib/pione/command/pione-log.rb +61 -0
  23. data/lib/pione/command/pione-relay-account-db.rb +40 -38
  24. data/lib/pione/command/pione-relay-client-db.rb +38 -42
  25. data/lib/pione/command/pione-relay.rb +19 -20
  26. data/lib/pione/command/pione-syntax-checker.rb +70 -45
  27. data/lib/pione/command/pione-task-worker.rb +56 -66
  28. data/lib/pione/command/pione-tuple-space-provider.rb +36 -45
  29. data/lib/pione/command/pione-tuple-space-receiver.rb +34 -32
  30. data/lib/pione/command/pione-tuple-space-viewer.rb +63 -47
  31. data/lib/pione/location.rb +10 -0
  32. data/lib/pione/location/basic-location.rb +272 -0
  33. data/lib/pione/location/dropbox-location.rb +139 -0
  34. data/lib/pione/location/ftp-location.rb +156 -0
  35. data/lib/pione/location/local-location.rb +116 -0
  36. data/lib/pione/log.rb +10 -0
  37. data/lib/pione/log/domain-info.rb +72 -0
  38. data/lib/pione/log/process-log.rb +176 -0
  39. data/lib/pione/log/process-record.rb +189 -0
  40. data/lib/pione/log/xes-log.rb +105 -0
  41. data/lib/pione/model/assignment.rb +88 -80
  42. data/lib/pione/model/binary-operator.rb +74 -68
  43. data/lib/pione/model/block.rb +218 -207
  44. data/lib/pione/model/boolean.rb +123 -112
  45. data/lib/pione/model/call-rule.rb +72 -65
  46. data/lib/pione/model/data-expr.rb +596 -290
  47. data/lib/pione/model/float.rb +108 -103
  48. data/lib/pione/model/integer.rb +133 -129
  49. data/lib/pione/model/message.rb +79 -72
  50. data/lib/pione/model/package.rb +42 -38
  51. data/lib/pione/model/parameters.rb +265 -236
  52. data/lib/pione/model/rule-expr.rb +247 -242
  53. data/lib/pione/model/rule-io.rb +137 -133
  54. data/lib/pione/model/rule.rb +307 -292
  55. data/lib/pione/model/string.rb +110 -99
  56. data/lib/pione/model/variable-table.rb +300 -271
  57. data/lib/pione/model/variable.rb +88 -83
  58. data/lib/pione/option.rb +13 -0
  59. data/lib/pione/option/child-process-option.rb +19 -0
  60. data/lib/pione/{command-option → option}/common-option.rb +6 -5
  61. data/lib/pione/option/option-interface.rb +73 -0
  62. data/lib/pione/{command-option → option}/presence-notifier-option.rb +4 -3
  63. data/lib/pione/option/task-worker-owner-option.rb +24 -0
  64. data/lib/pione/{command-option → option}/tuple-space-provider-option.rb +6 -4
  65. data/lib/pione/option/tuple-space-provider-owner-option.rb +18 -0
  66. data/lib/pione/option/tuple-space-receiver-option.rb +8 -0
  67. data/lib/pione/parser/common-parser.rb +3 -2
  68. data/lib/pione/parser/expr-parser.rb +6 -1
  69. data/lib/pione/patch/em-ftpd-patch.rb +21 -0
  70. data/lib/pione/patch/rinda-patch.rb +31 -23
  71. data/lib/pione/rule-handler/action-handler.rb +35 -25
  72. data/lib/pione/rule-handler/basic-handler.rb +92 -18
  73. data/lib/pione/rule-handler/flow-handler.rb +104 -98
  74. data/lib/pione/rule-handler/root-handler.rb +11 -0
  75. data/lib/pione/system/common.rb +10 -0
  76. data/lib/pione/system/file-cache.rb +103 -84
  77. data/lib/pione/system/global.rb +67 -12
  78. data/lib/pione/system/init.rb +20 -0
  79. data/lib/pione/transformer/expr-transformer.rb +6 -1
  80. data/lib/pione/tuple-space/data-finder.rb +33 -6
  81. data/lib/pione/tuple-space/tuple-space-receiver.rb +4 -3
  82. data/lib/pione/tuple-space/tuple-space-server-interface.rb +58 -13
  83. data/lib/pione/tuple-space/tuple-space-server.rb +13 -11
  84. data/lib/pione/tuple-space/update-criteria.rb +8 -7
  85. data/lib/pione/tuple/base-location-tuple.rb +9 -0
  86. data/lib/pione/tuple/basic-tuple.rb +7 -7
  87. data/lib/pione/tuple/data-tuple.rb +5 -2
  88. data/lib/pione/tuple/lift-tuple.rb +14 -0
  89. data/lib/pione/tuple/rule-tuple.rb +1 -1
  90. data/lib/pione/tuple/task-tuple.rb +5 -1
  91. data/lib/pione/version.rb +1 -1
  92. data/pione.gemspec +5 -1
  93. data/test/location/spec_basic-location.rb +35 -0
  94. data/test/location/spec_ftp-location.rb +100 -0
  95. data/test/location/spec_local-location.rb +99 -0
  96. data/test/log/data/sample.log +1003 -0
  97. data/test/log/spec_xes-log.rb +11 -0
  98. data/test/model/spec_data-expr.rb +249 -6
  99. data/test/model/spec_data-expr.yml +45 -0
  100. data/test/parser/spec_expr-parser.yml +4 -0
  101. data/test/spec_data-finder.rb +13 -7
  102. data/test/spec_data-finder.yml +42 -13
  103. data/test/system/spec_file-cache.rb +39 -0
  104. data/test/test-util.rb +226 -1
  105. data/test/transformer/spec_expr-transformer.rb +12 -1
  106. metadata +107 -24
  107. data/bin/pione-search-log +0 -30
  108. data/lib/pione/command-option/basic-option.rb +0 -42
  109. data/lib/pione/command-option/child-process-option.rb +0 -17
  110. data/lib/pione/command-option/daemon-option.rb +0 -12
  111. data/lib/pione/command-option/task-worker-owner-option.rb +0 -17
  112. data/lib/pione/command-option/tuple-space-provider-owner-option.rb +0 -16
  113. data/lib/pione/command-option/tuple-space-receiver-option.rb +0 -12
  114. data/lib/pione/command/tuple-space-provider-owner.rb +0 -6
  115. data/lib/pione/resource/basic-resource.rb +0 -92
  116. data/lib/pione/resource/dropbox-resource.rb +0 -106
  117. data/lib/pione/resource/ftp.rb +0 -84
  118. data/lib/pione/resource/local.rb +0 -113
  119. data/lib/pione/tuple/base-uri-tuple.rb +0 -9
  120. data/lib/pione/tuple/shift-tuple.rb +0 -13
  121. data/lib/pione/util/log.rb +0 -79
  122. data/test/spec_resource.rb +0 -73
@@ -0,0 +1,10 @@
1
+ module Pione
2
+ # Location is a name space for all location classes.
3
+ module Location; end
4
+ end
5
+
6
+ require 'pione/location/basic-location'
7
+ require 'pione/location/local-location'
8
+ require 'pione/location/ftp-location'
9
+ require 'pione/location/dropbox-location'
10
+
@@ -0,0 +1,272 @@
1
+ module Pione
2
+ module Location
3
+ # LocationError is raised when any resource errors happen.
4
+ class LocationError < Exception
5
+ def initialize(location)
6
+ @location = location
7
+ end
8
+ end
9
+
10
+ # ExistAlready is raised when there is data on the location already.
11
+ class ExistAlready < LocationError; end
12
+
13
+ # NotFound is raised when there isn't data on the location.
14
+ class NotFound < LocationError
15
+ def message
16
+ "%s not found" % @location.inspect
17
+ end
18
+ end
19
+
20
+ # known schemes table
21
+ SCHEMES = {}
22
+
23
+ # Return the location object corresponding to the URI.
24
+ #
25
+ # @param uri [URI,String]
26
+ # URI or location representing string
27
+ # @return [BasicLocation]
28
+ # location object
29
+ def self.[](uri)
30
+ uri = URI.parse(uri.to_s)
31
+ uri = uri.scheme ? uri : URI.parse("local:%s" % Pathname.new(uri.path).expand_path)
32
+ if location_class = SCHEMES[uri.scheme]
33
+ location_class.new(uri)
34
+ else
35
+ raise ArgumentError.new(uri)
36
+ end
37
+ end
38
+
39
+ # BasicLocation is a class for all location classes.
40
+ class BasicLocation
41
+ class << self
42
+ # @return [String]
43
+ # location's scheme name
44
+ attr_reader :scheme
45
+
46
+ # Declare the name as location scheme.
47
+ #
48
+ # @param name [String]
49
+ # scheme name
50
+ def set_scheme(name)
51
+ @scheme = name
52
+ SCHEMES[name] = self
53
+ end
54
+ end
55
+
56
+ forward :class, :scheme
57
+ forward :@uri, :host
58
+
59
+ # @return [URI]
60
+ # URI of the location
61
+ attr_reader :uri
62
+
63
+ # @return [Pathname]
64
+ # path of the location
65
+ attr_reader :path
66
+
67
+ # Create a location with the URI.
68
+ #
69
+ # @param uri [URI]
70
+ # location URI
71
+ def initialize(uri)
72
+ @uri = uri.kind_of?(URI::Generic) ? uri : URI.parse(uri)
73
+ @path = Pathname.new(uri.path)
74
+ raise ArgumentError.new(uri) unless @uri.scheme = scheme
75
+ end
76
+
77
+ # Create new location appended the name.
78
+ #
79
+ # @param name [String]
80
+ # filename or directory name
81
+ # @return [BasicLocation]
82
+ # new location
83
+ def +(name)
84
+ self.class.new(@uri.as_directory + name)
85
+ end
86
+
87
+ # Create new location that has URI as a directory.
88
+ #
89
+ # @return [BasicLocation]
90
+ # new location
91
+ def as_directory
92
+ self.class.new(@uri.as_directory)
93
+ end
94
+
95
+ # Return the basename of the location.
96
+ #
97
+ # @param suffix [String]
98
+ # suffix name
99
+ # @return [String]
100
+ # basename
101
+ def basename(suffix="")
102
+ File.basename(@path, suffix)
103
+ end
104
+
105
+ # Rebuild location with the path.
106
+ #
107
+ # @param path [Pathname]
108
+ # new path
109
+ # @return [Location]
110
+ # location with new path
111
+ def rebuild(path)
112
+ scheme = @uri.scheme
113
+ auth = "%s:%s@" % [@uri.user, @uri.password] if @uri.user and @uri.password
114
+ host = @uri.host
115
+ port = ":%i" % @uri.port
116
+ path = path.expand_path("/").to_s
117
+ Location["%s://%s%s%s%s" % [scheme, auth, host, port, path]]
118
+ end
119
+
120
+ # Return true if the location is cached.
121
+ #
122
+ # @return [Boolean]
123
+ # true if the location is cached
124
+ def cached?
125
+ System::FileCache.cached?(self)
126
+ end
127
+
128
+ # Creates a location.
129
+ #
130
+ # @param data [String]
131
+ # data content
132
+ # @return[void]
133
+ def create(data)
134
+ raise NotImplementedError
135
+ end
136
+
137
+ # Append data to the location data.
138
+ #
139
+ # @param data [String]
140
+ # data content
141
+ # @return [void]
142
+ def append(data)
143
+ raise NotImplmentedError
144
+ end
145
+
146
+ # Read location data.
147
+ #
148
+ # @return [String]
149
+ # data content
150
+ def read
151
+ raise NotImplementedError
152
+ end
153
+
154
+ # Update with the data.
155
+ #
156
+ # @param data [String]
157
+ # new data content
158
+ # @return [void]
159
+ def update(data)
160
+ raise NotImplementedError
161
+ end
162
+
163
+ # Delete data of the location.
164
+ #
165
+ # @return [void]
166
+ def delete
167
+ raise NotImplementedError
168
+ end
169
+
170
+ # Return last modification time of the location.
171
+ #
172
+ # @return [Time]
173
+ # last modification time
174
+ def mtime
175
+ raise NotImplementedError
176
+ end
177
+
178
+ # Return byte size of data in the location.
179
+ #
180
+ # @return [Integer]
181
+ # byte size of data
182
+ def size
183
+ raise NotImplementedError
184
+ end
185
+
186
+ # Return entries of the resource path.
187
+ #
188
+ # @return [Array<Location>]
189
+ # entries of the location path
190
+ def entries
191
+ raise NotImplementedError
192
+ end
193
+
194
+ # Return true if there is data in the location.
195
+ #
196
+ # @return [Boolean]
197
+ # if there is data in the location
198
+ def exist?
199
+ raise NotImplementedError
200
+ end
201
+
202
+ # Return true if data in the location is a file.
203
+ #
204
+ # @return [Boolean]
205
+ # true if data in the location is a file
206
+ def file?
207
+ raise NotImplementedError
208
+ end
209
+
210
+ # Return true if data in the location is a directory.
211
+ #
212
+ # @return [Boolean]
213
+ # true if data in the location is a directory
214
+ def directory?
215
+ raise NotImplementedError
216
+ end
217
+
218
+ # Move to the destination.
219
+ #
220
+ # @param dest [BasicLocation]
221
+ # destination
222
+ # @return [void]
223
+ def move(dest)
224
+ raise NotImplementedError
225
+ end
226
+
227
+ # Copy location's content to the destination.
228
+ #
229
+ # @param dest [BasicLocation]
230
+ # destination
231
+ # @return [void]
232
+ def copy(dest)
233
+ raise NotImplementedError
234
+ end
235
+
236
+ # Link to the destination.
237
+ #
238
+ # @param dest [BasicLocation]
239
+ # destination
240
+ # @return [void]
241
+ def link(dest)
242
+ raise NotImplementedError
243
+ end
244
+
245
+ # Move data to the destination and link self to it.
246
+ #
247
+ # @param dest [BasicLocation]
248
+ # destination
249
+ # @return [void]
250
+ def turn(dest)
251
+ raise NotImplementedError
252
+ end
253
+
254
+ # @api private
255
+ def inspect
256
+ "#<%s %s:%s>" % [self.class, scheme, @path.to_s]
257
+ end
258
+
259
+ # @api private
260
+ def ==(other)
261
+ return false unless other.kind_of?(self.class)
262
+ @uri == other.uri
263
+ end
264
+ alias :eql? :"=="
265
+
266
+ # @api private
267
+ def hash
268
+ @uri.hash
269
+ end
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,139 @@
1
+ module Pione
2
+ module Location
3
+ # DropboxLocation represents locations on Dropbox server.
4
+ class DropboxLocation < BasicLocation
5
+ set_scheme "dropbox"
6
+
7
+ class << self
8
+ attr_reader :session
9
+
10
+ # Initialize dropbox settings.
11
+ #
12
+ # @param tuple_space_server [TupleSpaceServer]
13
+ # tuple space server
14
+ # @return [void]
15
+ def self.init(tuple_space_server)
16
+ tuple_consumer_key = Tuple[:attribute].new("dropbox_consumer_key", nil)
17
+ tuple_consumer_secret = Tuple[:attribute].new("dropbox_consumer_secret", nil)
18
+ tuple_access_token_key = Tuple[:attribute].new("dropbox_access_token_key", nil)
19
+ tuple_access_token_secret = Tuple[:attribute].new("dropbox_access_token_secret", nil)
20
+
21
+ consumer_key = tuple_space_server.read(tuple_consumer_key, 0).value rescue nil
22
+ consumer_secret = tuple_space_server.read(tuple_consumer_secret, 0).value rescue nil
23
+ access_token_key = tuple_space_server.read(tuple_access_token_key, 0).value rescue nil
24
+ access_token_secret = tuple_space_server.read(tuple_access_token_secret, 0).value rescue nil
25
+
26
+ @session = DropboxSession.new(consumer_key, consumer_secret)
27
+ @session.set_access_token(access_token_key, access_token_secret)
28
+ end
29
+
30
+ # Share dropbox's access token with PIONE agents.
31
+ #
32
+ # @param tuple_space_server [TupleSpaceServer]
33
+ # tuple space server
34
+ # @param consumer_key [String]
35
+ # consumer key
36
+ # @param consumer_secret [String]
37
+ # consumer secret
38
+ # @return [void]
39
+ def share_access_token(tuple_space_server, consumer_key, consumer_secret)
40
+ access_token = session.get_access_token
41
+ [ Tuple[:attribute].new("dropbox_consumer_key", consumer_key),
42
+ Tuple[:attribute].new("dropbox_consumer_secret", consumer_secret),
43
+ Tuple[:attribute].new("dropbox_access_token_key", access_token.key),
44
+ Tuple[:attribute].new("dropbox_access_token_secret", access_token.secret)
45
+ ].each {|tuple| tuple_space_server.write(tuple) }
46
+ end
47
+
48
+ # Return true if dropbox session is authorized.
49
+ #
50
+ # @return [Boolean]
51
+ # true if dropbox session is authorized
52
+ def ready?
53
+ @session.authorized?
54
+ end
55
+
56
+ # Set the session.
57
+ #
58
+ # @param session [String]
59
+ # dropbox session
60
+ # @return [void]
61
+ def self.set_session(session)
62
+ @session = session
63
+ end
64
+ end
65
+
66
+ def initialize(uri)
67
+ super(uri)
68
+ @client = DropboxClient.new(self.class.session, "app_folder")
69
+ end
70
+
71
+ def create(data)
72
+ @client.put_file(@path, StringIO.new(data))
73
+ end
74
+
75
+ def read
76
+ @client.get_file(@path)
77
+ end
78
+
79
+ def update(data)
80
+ @client.put_file(@path, StringIO.new(data), true)
81
+ end
82
+
83
+ def delete
84
+ @client.file_delete(@path)
85
+ end
86
+
87
+ def mtime
88
+ metadata = @client.metadata(@path)
89
+ Time.parse(metadata["modified"])
90
+ end
91
+
92
+ def entries
93
+ metadata = @client.metadata(@path)
94
+ if not(metadata["is_dir"]) or metadata["is_deleted"]
95
+ raise NotFound.new(self)
96
+ end
97
+ metadata["contents"].select{|entry| not(entry["is_dir"]) and not(entry["is_deleted"])}.map do |entry|
98
+ Location["dropbox:%s" % entry["path"]]
99
+ end
100
+ end
101
+
102
+ def exist?
103
+ metadata = @client.metadata(@path)
104
+ return not(metadata["is_deleted"])
105
+ rescue DropboxError
106
+ return false
107
+ end
108
+
109
+ def move(dest)
110
+ if dest.scheme == scheme
111
+ @client.file_move(@path, dest.path)
112
+ else
113
+ copy(dest)
114
+ delete
115
+ end
116
+ end
117
+
118
+ def copy(dest)
119
+ if dest.scheme == scheme
120
+ @client.file_copy(@path, dest.path)
121
+ else
122
+ dest.update(read)
123
+ end
124
+ end
125
+
126
+ def link(orig)
127
+ if orig.scheme == scheme
128
+ orig.copy(link)
129
+ else
130
+ update(orig.read)
131
+ end
132
+ end
133
+
134
+ def turn(dest)
135
+ copy(dest)
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,156 @@
1
+ module Pione
2
+ module Location
3
+ # FTPLocation represents locations on FTP server.
4
+ class FTPLocation < BasicLocation
5
+ set_scheme "ftp"
6
+
7
+ def rebuild(path)
8
+ scheme = @uri.scheme
9
+ auth = "%s:%s@" % [@uri.user, @uri.password] if @uri.user and @uri.password
10
+ host = @uri.host
11
+ port = ":%i" % @uri.port
12
+ path = Pathname.new(path).expand_path("/").to_s
13
+ Location["%s://%s%s%s%s" % [scheme, auth, host, port, path]]
14
+ end
15
+
16
+ def create(data)
17
+ if exist?
18
+ raise ExistAlready.new(self)
19
+ else
20
+ connect do |ftp|
21
+ makedirs(ftp, @path.dirname)
22
+ file = Temppath.create
23
+ file.open("w") {|f| f.write(data)}
24
+ ftp.put(file.to_s, @path.to_s)
25
+ end
26
+ end
27
+ end
28
+
29
+ def append(data)
30
+ exist? ? update(read + data) : create(data)
31
+ end
32
+
33
+ def read
34
+ begin
35
+ data = nil
36
+ file = Temppath.create
37
+ connect {|ftp| ftp.get(@path, file.to_s)}
38
+ data = File.read(file.to_s)
39
+ return data
40
+ rescue Net::FTPPermError
41
+ raise NotFound.new(@uri)
42
+ end
43
+ end
44
+
45
+ def update(data)
46
+ connect do |ftp|
47
+ begin
48
+ ftp.dir(@path.dirname.to_s)
49
+ src = Temppath.create.tap{|x| x.open("w") {|f| f.write(data)}}.to_s
50
+ ftp.put(src, @path.to_s)
51
+ rescue Net::FTPPermError
52
+ raise NotFound.new(@uri)
53
+ end
54
+ end
55
+ end
56
+
57
+ def delete
58
+ connect {|ftp| ftp.delete(@path.to_s)} if exist?
59
+ end
60
+
61
+ def mtime
62
+ connect {|ftp| exist? ? ftp.mtime(@path.to_s) : (raise NotFound.new(self))}
63
+ end
64
+
65
+ def size
66
+ connect {|ftp| exist? ? ftp.size(@path.to_s) : (raise NotFound.new(self))}
67
+ end
68
+
69
+ def entries
70
+ connect do |ftp|
71
+ ftp.nlst(@path.to_s).map do |entry|
72
+ rebuild(@path + entry)
73
+ end.select {|entry| entry.file?}
74
+ end
75
+ end
76
+
77
+ def exist?
78
+ file? or directory?
79
+ end
80
+
81
+ def file?
82
+ begin
83
+ connect {|ftp| ftp.size(@path.to_s) > -1}
84
+ rescue
85
+ false
86
+ end
87
+ end
88
+
89
+ def directory?
90
+ connect do |ftp|
91
+ begin
92
+ ftp.chdir(@path.to_s)
93
+ return true
94
+ rescue
95
+ return false
96
+ end
97
+ end
98
+ end
99
+
100
+ def copy(dest)
101
+ dest.create(read)
102
+ end
103
+
104
+ def link(orig)
105
+ orig.copy(self)
106
+ end
107
+
108
+ def move(dest)
109
+ if dest.scheme == scheme and dest.host == host
110
+ ftp.rename(@path.to_s, dest.path.to_s)
111
+ else
112
+ copy(dest)
113
+ delete
114
+ end
115
+ end
116
+
117
+ def turn(dest)
118
+ copy(dest)
119
+ end
120
+
121
+ def inspect
122
+ scheme = @uri.scheme
123
+ auth = "%s:%s@" % [@uri.user, @uri.password] if @uri.user and @uri.password
124
+ host = @uri.host
125
+ port = ":%i" % @uri.port
126
+ path = @path.expand_path("/").to_s
127
+ "#<%s %s://%s%s%s%s>" % [self.class, scheme, auth, host, port, path]
128
+ end
129
+
130
+ private
131
+
132
+ # Connect to FTP server with the block.
133
+ def connect(&b)
134
+ 3.times do
135
+ begin
136
+ ftp = Net::FTP.new
137
+ ftp.connect(@uri.host, @uri.port)
138
+ ftp.passive = true
139
+ ftp.login(@uri.user, @uri.password) if @uri.user
140
+ return yield ftp
141
+ rescue Errno::ECONNREFUSED
142
+ sleep 1
143
+ end
144
+ end
145
+ raise
146
+ end
147
+
148
+ # @api private
149
+ def makedirs(ftp, path, size=0)
150
+ path.descend do |dpath|
151
+ ftp.mkdir(dpath.to_s) unless rebuild(dpath).exist?
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end