iostreams 1.6.2 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/io_streams/builder.rb +4 -2
- data/lib/io_streams/line/reader.rb +6 -6
- data/lib/io_streams/paths/s3.rb +22 -14
- data/lib/io_streams/paths/sftp.rb +87 -59
- data/lib/io_streams/pgp.rb +15 -15
- data/lib/io_streams/pgp/writer.rb +1 -2
- data/lib/io_streams/stream.rb +20 -10
- data/lib/io_streams/tabular/parser/fixed.rb +1 -1
- data/lib/io_streams/utils.rb +3 -5
- data/lib/io_streams/version.rb +1 -1
- data/lib/iostreams.rb +8 -0
- data/test/paths/file_test.rb +6 -8
- data/test/paths/sftp_test.rb +7 -1
- data/test/stream_test.rb +5 -5
- data/test/test_helper.rb +0 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 849ceda63eb30f95762a7c985cd215d424e62afd68ab20776e8d16c188dd6aed
|
4
|
+
data.tar.gz: 8e26af86c40bb673ce36855a7fb30d1c4b401edc3eac0b27a71b9760cfe865dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99318c4c64e0133df57b84429b1c2f9caa064abb1405ace5d55208e41b6bf8bb8fa83a75db8ae46d53753f10d566bab53971d95871ed4011bab4571d31bebe8a
|
7
|
+
data.tar.gz: bfba3a033c753e3fe05f798177b8f3c7ee8f566eabaf9223984fa902b288cb3515154f621a4e97f75b6c5bc31da88f284390c2d82c5015d7682ecf08c2a671d3
|
data/lib/io_streams/builder.rb
CHANGED
@@ -97,7 +97,9 @@ module IOStreams
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def format=(format)
|
100
|
-
|
100
|
+
unless format.nil? || IOStreams::Tabular.registered_formats.include?(format)
|
101
|
+
raise(ArgumentError, "Invalid format: #{format.inspect}")
|
102
|
+
end
|
101
103
|
|
102
104
|
@format = format
|
103
105
|
end
|
@@ -106,7 +108,7 @@ module IOStreams
|
|
106
108
|
|
107
109
|
def class_for_stream(type, stream)
|
108
110
|
ext = IOStreams.extensions[stream.nil? ? nil : stream.to_sym] ||
|
109
|
-
|
111
|
+
raise(ArgumentError, "Unknown Stream type: #{stream.inspect}")
|
110
112
|
ext.send("#{type}_class") || raise(ArgumentError, "No #{type} registered for Stream type: #{stream.inspect}")
|
111
113
|
end
|
112
114
|
|
@@ -96,17 +96,17 @@ module IOStreams
|
|
96
96
|
while line.count(@embedded_within).odd?
|
97
97
|
if eof? || line.length > @buffer_size * 10
|
98
98
|
raise(Errors::MalformedDataError.new(
|
99
|
-
|
100
|
-
|
101
|
-
|
99
|
+
"Unbalanced delimited field, delimiter: #{@embedded_within}",
|
100
|
+
initial_line_number
|
101
|
+
))
|
102
102
|
end
|
103
103
|
line << @delimiter
|
104
104
|
next_line = _readline
|
105
105
|
if next_line.nil?
|
106
106
|
raise(Errors::MalformedDataError.new(
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
"Unbalanced delimited field, delimiter: #{@embedded_within}",
|
108
|
+
initial_line_number
|
109
|
+
))
|
110
110
|
end
|
111
111
|
line << next_line
|
112
112
|
end
|
data/lib/io_streams/paths/s3.rb
CHANGED
@@ -3,7 +3,7 @@ require "uri"
|
|
3
3
|
module IOStreams
|
4
4
|
module Paths
|
5
5
|
class S3 < IOStreams::Path
|
6
|
-
attr_reader :bucket_name, :
|
6
|
+
attr_reader :bucket_name, :options
|
7
7
|
|
8
8
|
# Largest file size supported by the S3 copy object api.
|
9
9
|
S3_COPY_OBJECT_SIZE_LIMIT = 5 * 1024 * 1024 * 1024
|
@@ -141,16 +141,17 @@ module IOStreams
|
|
141
141
|
|
142
142
|
@bucket_name = uri.hostname
|
143
143
|
key = uri.path.sub(%r{\A/}, "")
|
144
|
-
|
145
|
-
|
146
|
-
client
|
147
|
-
@client = ::Aws::S3::Client.new(client)
|
144
|
+
|
145
|
+
if client && !client.is_a?(Hash)
|
146
|
+
@client = client
|
148
147
|
else
|
149
|
-
@
|
148
|
+
@client_options = client.is_a?(Hash) ? client.dup : {}
|
149
|
+
@client_options[:access_key_id] = access_key_id if access_key_id
|
150
|
+
@client_options[:secret_access_key] = secret_access_key if secret_access_key
|
150
151
|
end
|
151
|
-
@options = args
|
152
152
|
|
153
|
-
@options
|
153
|
+
@options = args
|
154
|
+
@options.merge!(uri.query.transform_keys(&:to_sym)) if uri.query
|
154
155
|
|
155
156
|
super(key)
|
156
157
|
end
|
@@ -190,11 +191,11 @@ module IOStreams
|
|
190
191
|
end
|
191
192
|
|
192
193
|
# Make S3 perform direct copies within S3 itself.
|
193
|
-
def copy_to(target_path, convert: true)
|
194
|
-
return super(target_path) if convert || (size.to_i >= S3_COPY_OBJECT_SIZE_LIMIT)
|
194
|
+
def copy_to(target_path, convert: true, **args)
|
195
|
+
return super(target_path, convert: convert, **args) if convert || (size.to_i >= S3_COPY_OBJECT_SIZE_LIMIT)
|
195
196
|
|
196
197
|
target = IOStreams.new(target_path)
|
197
|
-
return super(target) unless target.is_a?(self.class)
|
198
|
+
return super(target, convert: convert, **args) unless target.is_a?(self.class)
|
198
199
|
|
199
200
|
source_name = ::File.join(bucket_name, path)
|
200
201
|
client.copy_object(options.merge(bucket: target.bucket_name, key: target.path, copy_source: source_name))
|
@@ -202,11 +203,13 @@ module IOStreams
|
|
202
203
|
end
|
203
204
|
|
204
205
|
# Make S3 perform direct copies within S3 itself.
|
205
|
-
def copy_from(source_path, convert: true)
|
206
|
-
return super(source_path) if convert
|
206
|
+
def copy_from(source_path, convert: true, **args)
|
207
|
+
return super(source_path, convert: true, **args) if convert
|
207
208
|
|
208
209
|
source = IOStreams.new(source_path)
|
209
|
-
|
210
|
+
if !source.is_a?(self.class) || (source.size.to_i >= S3_COPY_OBJECT_SIZE_LIMIT)
|
211
|
+
return super(source, convert: convert, **args)
|
212
|
+
end
|
210
213
|
|
211
214
|
source_name = ::File.join(source.bucket_name, source.path)
|
212
215
|
client.copy_object(options.merge(bucket: bucket_name, key: path, copy_source: source_name))
|
@@ -312,6 +315,11 @@ module IOStreams
|
|
312
315
|
def partial_files_visible?
|
313
316
|
false
|
314
317
|
end
|
318
|
+
|
319
|
+
# Lazy load S3 client since it takes two seconds to create itself!
|
320
|
+
def client
|
321
|
+
@client ||= ::Aws::S3::Client.new(@client_options)
|
322
|
+
end
|
315
323
|
end
|
316
324
|
end
|
317
325
|
end
|
@@ -47,9 +47,23 @@ module IOStreams
|
|
47
47
|
# password: [String]
|
48
48
|
# Password for the user.
|
49
49
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
50
|
+
# ssh_options: [Hash]
|
51
|
+
# - IdentityKey [String]
|
52
|
+
# The identity key that this client should use to talk to this host.
|
53
|
+
# Under the covers this value is written to a file and then the file name is passed as `IdentityFile`
|
54
|
+
# - HostKey [String]
|
55
|
+
# The expected SSH Host key that is presented by the remote host.
|
56
|
+
# Instead of storing the host key in the `known_hosts` file, it can be supplied explicity
|
57
|
+
# using this option.
|
58
|
+
# Under the covers this value is written to a file and then the file name is passed as `UserKnownHostsFile`
|
59
|
+
# Notes:
|
60
|
+
# - It must contain the entire line that would be stored in `known_hosts`,
|
61
|
+
# including the hostname, ip address, key type and key value. This value is written as-is into a
|
62
|
+
# "known_hosts" like file and then passed into sftp using the `UserKnownHostsFile` option.
|
63
|
+
# - The easiest way to generate the required is to use `ssh-keyscan` and then supply that value in this field.
|
64
|
+
# For example: `ssh-keyscan hostname`
|
65
|
+
# - Any other options supported by ssh_config.
|
66
|
+
# `man ssh_config` to see all available options.
|
53
67
|
#
|
54
68
|
# Examples:
|
55
69
|
#
|
@@ -168,38 +182,36 @@ module IOStreams
|
|
168
182
|
def sftp_download(remote_file_name, local_file_name)
|
169
183
|
with_sftp_args do |args|
|
170
184
|
Open3.popen2e(*args) do |writer, reader, waith_thr|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
unless waith_thr.value.success?
|
185
|
-
raise(
|
186
|
-
Errors::CommunicationsFailure,
|
187
|
-
"Download failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}"
|
188
|
-
)
|
189
|
-
end
|
190
|
-
|
191
|
-
out
|
192
|
-
rescue Errno::EPIPE
|
193
|
-
out = begin
|
194
|
-
reader.read.chomp
|
195
|
-
rescue StandardError
|
196
|
-
nil
|
197
|
-
end
|
185
|
+
# Give time for remote sftp server to get ready to accept the password.
|
186
|
+
sleep self.class.before_password_wait_seconds
|
187
|
+
|
188
|
+
writer.puts password
|
189
|
+
|
190
|
+
# Give time for password to be processed and stdin to be passed to sftp process.
|
191
|
+
sleep self.class.sshpass_wait_seconds
|
192
|
+
|
193
|
+
writer.puts "get #{remote_file_name} #{local_file_name}"
|
194
|
+
writer.puts "bye"
|
195
|
+
writer.close
|
196
|
+
out = reader.read.chomp
|
197
|
+
unless waith_thr.value.success?
|
198
198
|
raise(
|
199
199
|
Errors::CommunicationsFailure,
|
200
200
|
"Download failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}"
|
201
201
|
)
|
202
202
|
end
|
203
|
+
|
204
|
+
out
|
205
|
+
rescue Errno::EPIPE
|
206
|
+
out = begin
|
207
|
+
reader.read.chomp
|
208
|
+
rescue StandardError
|
209
|
+
nil
|
210
|
+
end
|
211
|
+
raise(
|
212
|
+
Errors::CommunicationsFailure,
|
213
|
+
"Download failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}"
|
214
|
+
)
|
203
215
|
end
|
204
216
|
end
|
205
217
|
end
|
@@ -207,48 +219,64 @@ module IOStreams
|
|
207
219
|
def sftp_upload(local_file_name, remote_file_name)
|
208
220
|
with_sftp_args do |args|
|
209
221
|
Open3.popen2e(*args) do |writer, reader, waith_thr|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
unless waith_thr.value.success?
|
219
|
-
raise(
|
220
|
-
Errors::CommunicationsFailure,
|
221
|
-
"Upload failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}"
|
222
|
-
)
|
223
|
-
end
|
224
|
-
|
225
|
-
out
|
226
|
-
rescue Errno::EPIPE
|
227
|
-
out = begin
|
228
|
-
reader.read.chomp
|
229
|
-
rescue StandardError
|
230
|
-
nil
|
231
|
-
end
|
222
|
+
writer.puts(password) if password
|
223
|
+
# Give time for password to be processed and stdin to be passed to sftp process.
|
224
|
+
sleep self.class.sshpass_wait_seconds
|
225
|
+
writer.puts "put #{local_file_name.inspect} #{remote_file_name.inspect}"
|
226
|
+
writer.puts "bye"
|
227
|
+
writer.close
|
228
|
+
out = reader.read.chomp
|
229
|
+
unless waith_thr.value.success?
|
232
230
|
raise(
|
233
231
|
Errors::CommunicationsFailure,
|
234
232
|
"Upload failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}"
|
235
233
|
)
|
236
234
|
end
|
235
|
+
|
236
|
+
out
|
237
|
+
rescue Errno::EPIPE
|
238
|
+
out = begin
|
239
|
+
reader.read.chomp
|
240
|
+
rescue StandardError
|
241
|
+
nil
|
242
|
+
end
|
243
|
+
raise(
|
244
|
+
Errors::CommunicationsFailure,
|
245
|
+
"Upload failed calling #{self.class.sftp_bin} via #{self.class.sshpass_bin}: #{out}"
|
246
|
+
)
|
237
247
|
end
|
238
248
|
end
|
239
249
|
end
|
240
250
|
|
241
251
|
def with_sftp_args
|
242
|
-
return yield sftp_args(ssh_options)
|
252
|
+
return yield sftp_args(ssh_options) if !ssh_options.key?("IdentityKey") && !ssh_options.key?("HostKey")
|
253
|
+
|
254
|
+
with_identity_key(ssh_options.dup) do |options|
|
255
|
+
with_host_key(options) do |options2|
|
256
|
+
yield sftp_args(options2)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
def with_identity_key(options)
|
262
|
+
return yield options unless ssh_options.key?("IdentityKey")
|
263
|
+
|
264
|
+
with_temp_file(options, "IdentityFile", options.delete("IdentityKey")) { yield options }
|
265
|
+
end
|
266
|
+
|
267
|
+
def with_host_key(options)
|
268
|
+
return yield options unless ssh_options.key?("HostKey")
|
269
|
+
|
270
|
+
with_temp_file(options, "UserKnownHostsFile", options.delete("HostKey")) { yield options }
|
271
|
+
end
|
243
272
|
|
273
|
+
def with_temp_file(options, option, value)
|
244
274
|
Utils.temp_file_name("iostreams-sftp-args", "key") do |file_name|
|
245
|
-
options = ssh_options.dup
|
246
|
-
key = options.delete("IdentityKey")
|
247
275
|
# sftp requires that private key is only readable by the current user
|
248
|
-
::File.open(file_name, "wb", 0o600) { |io| io.write(
|
276
|
+
::File.open(file_name, "wb", 0o600) { |io| io.write(value) }
|
249
277
|
|
250
|
-
options[
|
251
|
-
yield
|
278
|
+
options[option] = file_name
|
279
|
+
yield options
|
252
280
|
end
|
253
281
|
end
|
254
282
|
|
@@ -277,7 +305,7 @@ module IOStreams
|
|
277
305
|
end
|
278
306
|
|
279
307
|
def build_ssh_options
|
280
|
-
options
|
308
|
+
options = ssh_options.dup
|
281
309
|
options[:logger] ||= logger if defined?(SemanticLogger)
|
282
310
|
options[:port] ||= port
|
283
311
|
options[:max_pkt_size] ||= 65_536
|
data/lib/io_streams/pgp.rb
CHANGED
@@ -48,8 +48,8 @@ module IOStreams
|
|
48
48
|
# See `man gpg` for the remaining options
|
49
49
|
def self.generate_key(name:,
|
50
50
|
email:,
|
51
|
-
comment: nil,
|
52
51
|
passphrase:,
|
52
|
+
comment: nil,
|
53
53
|
key_type: "RSA",
|
54
54
|
key_length: 4096,
|
55
55
|
subkey_type: "RSA",
|
@@ -291,10 +291,8 @@ module IOStreams
|
|
291
291
|
version_check
|
292
292
|
Open3.popen2e("#{executable} --list-keys --fingerprint --with-colons #{email}") do |_stdin, out, waith_thr|
|
293
293
|
output = out.read.chomp
|
294
|
-
|
295
|
-
|
296
|
-
raise(Pgp::Failure, "GPG Failed calling #{executable} to list keys for #{email}: #{output}")
|
297
|
-
end
|
294
|
+
if !waith_thr.value.success? && !(output !~ /(public key not found|No public key)/i)
|
295
|
+
raise(Pgp::Failure, "GPG Failed calling #{executable} to list keys for #{email}: #{output}")
|
298
296
|
end
|
299
297
|
|
300
298
|
output.each_line do |line|
|
@@ -336,9 +334,11 @@ module IOStreams
|
|
336
334
|
match[1]
|
337
335
|
end
|
338
336
|
else
|
339
|
-
|
337
|
+
if err !~ /(key not found|No (public|secret) key)/i
|
338
|
+
raise(Pgp::Failure, "GPG Failed calling #{executable} to list keys for #{email || key_id}: #{err}#{out}")
|
339
|
+
end
|
340
340
|
|
341
|
-
|
341
|
+
[]
|
342
342
|
end
|
343
343
|
end
|
344
344
|
end
|
@@ -382,10 +382,10 @@ module IOStreams
|
|
382
382
|
key_length: match[3].to_s.to_i,
|
383
383
|
key_type: match[2],
|
384
384
|
date: (begin
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
385
|
+
Date.parse(match[4].to_s)
|
386
|
+
rescue StandardError
|
387
|
+
match[4]
|
388
|
+
end)
|
389
389
|
}
|
390
390
|
elsif (match = line.match(%r{(pub|sec)\s+(\d+)(.*)/(\w+)\s+(\d+-\d+-\d+)(\s+(.+)<(.+)>)?}))
|
391
391
|
# Matches: pub 2048R/C7F9D9CB 2016-10-26
|
@@ -396,10 +396,10 @@ module IOStreams
|
|
396
396
|
key_type: match[3],
|
397
397
|
key_id: match[4],
|
398
398
|
date: (begin
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
399
|
+
Date.parse(match[5].to_s)
|
400
|
+
rescue StandardError
|
401
|
+
match[5]
|
402
|
+
end)
|
403
403
|
}
|
404
404
|
# Prior to gpg v2.0.30
|
405
405
|
if match[7]
|
data/lib/io_streams/stream.rb
CHANGED
@@ -151,6 +151,9 @@ module IOStreams
|
|
151
151
|
# Whether to apply the stream conversions during the copy.
|
152
152
|
# Default: true
|
153
153
|
#
|
154
|
+
# :mode [:line, :array, :hash]
|
155
|
+
# When convert is `true` then use this mode to convert the contents of the file.
|
156
|
+
#
|
154
157
|
# Examples:
|
155
158
|
#
|
156
159
|
# # Copy and convert streams based on file extensions
|
@@ -162,11 +165,17 @@ module IOStreams
|
|
162
165
|
# # Advanced copy with custom stream conversions on source and target.
|
163
166
|
# source = IOStreams.path("source_file").stream(encoding: "BINARY")
|
164
167
|
# IOStreams.path("target_file.pgp").option(:pgp, passphrase: "hello").copy_from(source)
|
165
|
-
def copy_from(source, convert: true)
|
168
|
+
def copy_from(source, convert: true, mode: nil, **args)
|
166
169
|
if convert
|
167
170
|
stream = IOStreams.new(source)
|
168
|
-
|
169
|
-
|
171
|
+
if mode
|
172
|
+
writer(mode, **args) do |target|
|
173
|
+
stream.each(mode) { |row| target << row }
|
174
|
+
end
|
175
|
+
else
|
176
|
+
writer(**args) do |target|
|
177
|
+
stream.reader { |src| IO.copy_stream(src, target) }
|
178
|
+
end
|
170
179
|
end
|
171
180
|
else
|
172
181
|
stream = source.is_a?(Stream) ? source.dup : IOStreams.new(source)
|
@@ -176,9 +185,9 @@ module IOStreams
|
|
176
185
|
end
|
177
186
|
end
|
178
187
|
|
179
|
-
def copy_to(target,
|
188
|
+
def copy_to(target, **args)
|
180
189
|
target = IOStreams.new(target)
|
181
|
-
target.copy_from(self,
|
190
|
+
target.copy_from(self, **args)
|
182
191
|
end
|
183
192
|
|
184
193
|
# Set/get the original file_name
|
@@ -365,8 +374,8 @@ module IOStreams
|
|
365
374
|
IOStreams::Row::Writer.stream(
|
366
375
|
io,
|
367
376
|
original_file_name: builder.file_name,
|
368
|
-
format:
|
369
|
-
format_options:
|
377
|
+
format: builder.format,
|
378
|
+
format_options: builder.format_options,
|
370
379
|
**args,
|
371
380
|
&block
|
372
381
|
)
|
@@ -380,10 +389,11 @@ module IOStreams
|
|
380
389
|
IOStreams::Record::Writer.stream(
|
381
390
|
io,
|
382
391
|
original_file_name: builder.file_name,
|
383
|
-
format:
|
384
|
-
format_options:
|
392
|
+
format: builder.format,
|
393
|
+
format_options: builder.format_options,
|
385
394
|
**args,
|
386
|
-
&block
|
395
|
+
&block
|
396
|
+
)
|
387
397
|
end
|
388
398
|
end
|
389
399
|
end
|
@@ -146,7 +146,7 @@ module IOStreams
|
|
146
146
|
|
147
147
|
attr_reader :key, :size, :type, :decimals
|
148
148
|
|
149
|
-
def initialize(key: nil,
|
149
|
+
def initialize(size:, key: nil, type: :string, decimals: 2)
|
150
150
|
@key = key
|
151
151
|
@size = size == :remainder ? -1 : size.to_i
|
152
152
|
@type = type.to_sym
|
data/lib/io_streams/utils.rb
CHANGED
@@ -28,11 +28,9 @@ module IOStreams
|
|
28
28
|
def self.temp_file_name(basename, extension = "")
|
29
29
|
result = nil
|
30
30
|
::Dir::Tmpname.create([basename, extension], IOStreams.temp_dir, max_try: MAX_TEMP_FILE_NAME_ATTEMPTS) do |tmpname|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
::File.unlink(tmpname) if ::File.exist?(tmpname)
|
35
|
-
end
|
31
|
+
result = yield(tmpname)
|
32
|
+
ensure
|
33
|
+
::File.unlink(tmpname) if ::File.exist?(tmpname)
|
36
34
|
end
|
37
35
|
result
|
38
36
|
end
|
data/lib/io_streams/version.rb
CHANGED
data/lib/iostreams.rb
CHANGED
@@ -23,33 +23,41 @@ module IOStreams
|
|
23
23
|
autoload :Reader, "io_streams/bzip2/reader"
|
24
24
|
autoload :Writer, "io_streams/bzip2/writer"
|
25
25
|
end
|
26
|
+
|
26
27
|
module Encode
|
27
28
|
autoload :Reader, "io_streams/encode/reader"
|
28
29
|
autoload :Writer, "io_streams/encode/writer"
|
29
30
|
end
|
31
|
+
|
30
32
|
module Gzip
|
31
33
|
autoload :Reader, "io_streams/gzip/reader"
|
32
34
|
autoload :Writer, "io_streams/gzip/writer"
|
33
35
|
end
|
36
|
+
|
34
37
|
module Line
|
35
38
|
autoload :Reader, "io_streams/line/reader"
|
36
39
|
autoload :Writer, "io_streams/line/writer"
|
37
40
|
end
|
41
|
+
|
38
42
|
module Record
|
39
43
|
autoload :Reader, "io_streams/record/reader"
|
40
44
|
autoload :Writer, "io_streams/record/writer"
|
41
45
|
end
|
46
|
+
|
42
47
|
module Row
|
43
48
|
autoload :Reader, "io_streams/row/reader"
|
44
49
|
autoload :Writer, "io_streams/row/writer"
|
45
50
|
end
|
51
|
+
|
46
52
|
module SymmetricEncryption
|
47
53
|
autoload :Reader, "io_streams/symmetric_encryption/reader"
|
48
54
|
autoload :Writer, "io_streams/symmetric_encryption/writer"
|
49
55
|
end
|
56
|
+
|
50
57
|
module Xlsx
|
51
58
|
autoload :Reader, "io_streams/xlsx/reader"
|
52
59
|
end
|
60
|
+
|
53
61
|
module Zip
|
54
62
|
autoload :Reader, "io_streams/zip/reader"
|
55
63
|
autoload :Writer, "io_streams/zip/writer"
|
data/test/paths/file_test.rb
CHANGED
@@ -126,15 +126,13 @@ module Paths
|
|
126
126
|
|
127
127
|
it "missing source file" do
|
128
128
|
IOStreams.temp_file("iostreams_move_test", ".txt") do |temp_file|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
temp_file.move_to(target)
|
134
|
-
end
|
135
|
-
refute target.exist?
|
136
|
-
refute temp_file.exist?
|
129
|
+
refute temp_file.exist?
|
130
|
+
target = temp_file.directory.join("move_test.txt")
|
131
|
+
assert_raises Errno::ENOENT do
|
132
|
+
temp_file.move_to(target)
|
137
133
|
end
|
134
|
+
refute target.exist?
|
135
|
+
refute temp_file.exist?
|
138
136
|
end
|
139
137
|
end
|
140
138
|
|
data/test/paths/sftp_test.rb
CHANGED
@@ -20,7 +20,13 @@ module Paths
|
|
20
20
|
let(:file_name) { File.join(File.dirname(__FILE__), "..", "files", "text file.txt") }
|
21
21
|
let(:raw) { File.read(file_name) }
|
22
22
|
|
23
|
-
let(:root_path)
|
23
|
+
let(:root_path) do
|
24
|
+
if ENV["SFTP_HOST_KEY"]
|
25
|
+
IOStreams::Paths::SFTP.new(url, username: username, password: password, ssh_options: {"HostKey" => ENV["SFTP_HOST_KEY"]})
|
26
|
+
else
|
27
|
+
IOStreams::Paths::SFTP.new(url, username: username, password: password)
|
28
|
+
end
|
29
|
+
end
|
24
30
|
|
25
31
|
let :existing_path do
|
26
32
|
path = root_path.join("test.txt")
|
data/test/stream_test.rb
CHANGED
@@ -45,9 +45,9 @@ class StreamTest < Minitest::Test
|
|
45
45
|
it "reads a zip file" do
|
46
46
|
File.open(multiple_zip_file_name, "rb") do |io|
|
47
47
|
result = IOStreams::Stream.new(io).
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
file_name(multiple_zip_file_name).
|
49
|
+
option(:zip, entry_file_name: "test.json").
|
50
|
+
read
|
51
51
|
assert_equal contents_test_json, result
|
52
52
|
end
|
53
53
|
end
|
@@ -55,8 +55,8 @@ class StreamTest < Minitest::Test
|
|
55
55
|
it "reads a zip file from within a gz file" do
|
56
56
|
File.open(zip_gz_file_name, "rb") do |io|
|
57
57
|
result = IOStreams::Stream.new(io).
|
58
|
-
|
59
|
-
|
58
|
+
file_name(zip_gz_file_name).
|
59
|
+
read
|
60
60
|
assert_equal contents_test_txt, result
|
61
61
|
end
|
62
62
|
end
|
data/test/test_helper.rb
CHANGED
@@ -2,7 +2,6 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
|
2
2
|
|
3
3
|
require "yaml"
|
4
4
|
require "minitest/autorun"
|
5
|
-
require "minitest/reporters"
|
6
5
|
require "iostreams"
|
7
6
|
require "amazing_print"
|
8
7
|
require "symmetric-encryption"
|
@@ -10,8 +9,6 @@ require "symmetric-encryption"
|
|
10
9
|
# Since PGP libraries use UTC for Dates
|
11
10
|
ENV["TZ"] = "UTC"
|
12
11
|
|
13
|
-
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
|
14
|
-
|
15
12
|
# Test cipher
|
16
13
|
SymmetricEncryption.cipher = SymmetricEncryption::Cipher.new(
|
17
14
|
cipher_name: "aes-128-cbc",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iostreams
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-23 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -125,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
125
|
requirements:
|
126
126
|
- - ">="
|
127
127
|
- !ruby/object:Gem::Version
|
128
|
-
version: '2.
|
128
|
+
version: '2.5'
|
129
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
130
|
requirements:
|
131
131
|
- - ">="
|