winrm-fs 1.2.1 → 1.3.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.
- checksums.yaml +4 -4
- data/README.md +4 -1
- data/VERSION +1 -1
- data/changelog.md +5 -0
- data/lib/winrm-fs/core/file_transporter.rb +63 -24
- data/lib/winrm-fs/core/tmp_zip.rb +1 -1
- data/spec/integration/file_manager_spec.rb +16 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7898b5512c391163a77d694860db51a5c15c5745031c2b34c0cd181a9bbda37
|
4
|
+
data.tar.gz: 87864314b0863331944c604d26c0721db568db238da87923b836d80097531dad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d468205639de56be5fcf4c4896a823f96760e03e23153b6e09cc9c1bc2779725d84f429a759d67088e622a288a3e002bb528f9e23749cded6416baac38b26614
|
7
|
+
data.tar.gz: b8787f4e3ae986aa32ae324cd1e6113081b83cb291ba519b027dea7ee67f0c4a0d9d15e50e38222328d94829735156a525c066cab56966c6e92de25754efc5b4
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[](https://ci.appveyor.com/project/winrb/winrm-fs)
|
5
5
|
|
6
6
|
## Uploading files
|
7
|
-
Files may be copied from the local machine to the winrm endpoint. Individual files or directories, as well as arrays of files and directories may be specified
|
7
|
+
Files may be copied from the local machine to the winrm endpoint. Individual files or directories, as well as arrays of files and directories may be specified. Data from a `StringIO` object may also be uploaded to a remote file.
|
8
8
|
```ruby
|
9
9
|
require 'winrm-fs'
|
10
10
|
|
@@ -17,6 +17,9 @@ file_manager.upload('file.txt', 'c:/file.txt')
|
|
17
17
|
# upload the my_dir directory to c:/foo/my_dir
|
18
18
|
file_manager.upload('/Users/sneal/my_dir', 'c:/foo/my_dir')
|
19
19
|
|
20
|
+
# upload from an in-memory buffer
|
21
|
+
file_manager.upload(StringIO.new('some data to upload'), 'c:/file.txt')
|
22
|
+
|
20
23
|
# upload multiple directories and a file to c:\programData
|
21
24
|
file_manager.upload([
|
22
25
|
'/Users/sneal/foo1',
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/changelog.md
CHANGED
@@ -21,6 +21,7 @@ require 'digest'
|
|
21
21
|
require 'securerandom'
|
22
22
|
require 'stringio'
|
23
23
|
|
24
|
+
require 'winrm/exceptions'
|
24
25
|
require 'winrm-fs/core/tmp_zip'
|
25
26
|
|
26
27
|
module WinRM
|
@@ -32,6 +33,14 @@ module WinRM
|
|
32
33
|
class FileTransporterFailed < ::WinRM::WinRMError; end
|
33
34
|
# rubocop:disable MethodLength, AbcSize, ClassLength
|
34
35
|
|
36
|
+
# Exception for the case where upload source contains more than one
|
37
|
+
# StringIO object, or a combination of file/directory paths and StringIO object
|
38
|
+
class UploadSourceError < StandardError
|
39
|
+
def initialize(msg = 'Only a single StringIO object may be uploaded.')
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
35
44
|
# Object which can upload one or more files or directories to a remote
|
36
45
|
# host over WinRM using PowerShell scripts and CMD commands. Note that
|
37
46
|
# this form of file transfer is *not* ideal and extremely costly on both
|
@@ -67,17 +76,16 @@ module WinRM
|
|
67
76
|
# * progress yields block like net-scp progress
|
68
77
|
# * final API: def upload(locals, remote, _options = {}, &_progress)
|
69
78
|
#
|
70
|
-
# @param locals [Array<String>,String] one or more
|
71
|
-
# directory paths
|
79
|
+
# @param locals [Array<String>,String,StringIO] one or more
|
80
|
+
# local file or directory paths, StringIO objects also accepted
|
72
81
|
# @param remote [String] the base destination path on the remote host
|
73
82
|
# @return [Hash] report hash, keyed by the local SHA1 digest
|
74
83
|
def upload(locals, remote)
|
75
84
|
files = nil
|
76
85
|
report = nil
|
77
86
|
remote = remote.to_s
|
78
|
-
|
79
87
|
elapsed1 = Benchmark.measure do
|
80
|
-
files = make_files_hash(
|
88
|
+
files = make_files_hash([locals].flatten, remote)
|
81
89
|
report = check_files(files)
|
82
90
|
merge_with_report!(files, report)
|
83
91
|
reconcile_destinations!(files)
|
@@ -183,16 +191,15 @@ module WinRM
|
|
183
191
|
# Adds an entry to a files Hash (keyed by local SHA1 digest) for a file.
|
184
192
|
#
|
185
193
|
# @param hash [Hash] hash to be mutated
|
186
|
-
# @param local [String] file path
|
194
|
+
# @param local [String, StringIO] file path or StringIO object
|
187
195
|
# @param remote [String] path to destination on remote host
|
188
196
|
# @api private
|
189
197
|
def add_file_hash!(hash, local, remote)
|
190
198
|
logger.debug "creating hash for file #{remote}"
|
191
|
-
|
192
199
|
hash[sha1sum(local)] = {
|
193
200
|
'src' => local,
|
194
201
|
'dst' => remote,
|
195
|
-
'size' => File.size(local)
|
202
|
+
'size' => local.is_a?(StringIO) ? local.size : File.size(local)
|
196
203
|
}
|
197
204
|
end
|
198
205
|
|
@@ -223,7 +230,7 @@ module WinRM
|
|
223
230
|
sha1,
|
224
231
|
{
|
225
232
|
'target' => data.fetch('tmpzip', data['dst']),
|
226
|
-
'src_basename' => File.basename(data['src']),
|
233
|
+
'src_basename' => data['src'].is_a?(StringIO) ? data['dst'] : File.basename(data['src']),
|
227
234
|
'dst' => data['dst']
|
228
235
|
}
|
229
236
|
]
|
@@ -302,33 +309,61 @@ module WinRM
|
|
302
309
|
# digest. Each file entry has a source and destination set, at a
|
303
310
|
# minimum.
|
304
311
|
#
|
305
|
-
# @param locals [Array<String>] a collection of local files
|
306
|
-
# directories
|
312
|
+
# @param locals [Array<String,StringIO>] a collection of local files,
|
313
|
+
# directories or StringIO objects
|
307
314
|
# @param remote [String] the base destination path on the remote host
|
308
315
|
# @return [Hash] files hash, keyed by the local SHA1 digest
|
309
316
|
# @api private
|
310
317
|
def make_files_hash(locals, remote)
|
311
318
|
hash = {}
|
319
|
+
check_locals_array(locals)
|
312
320
|
locals.each do |local|
|
313
|
-
|
314
|
-
|
315
|
-
expanded += local[-1] if local.end_with?('/', '\\')
|
316
|
-
|
317
|
-
if File.file?(expanded)
|
318
|
-
add_file_hash!(hash, expanded, remote)
|
319
|
-
elsif File.directory?(expanded)
|
320
|
-
add_directory_hash!(hash, expanded, remote)
|
321
|
+
if local.is_a?(StringIO)
|
322
|
+
add_file_hash!(hash, local, remote)
|
321
323
|
else
|
322
|
-
|
324
|
+
local = local.to_s
|
325
|
+
expanded = File.expand_path(local)
|
326
|
+
expanded += local[-1] if local.end_with?('/', '\\')
|
327
|
+
if File.file?(expanded)
|
328
|
+
add_file_hash!(hash, expanded, remote)
|
329
|
+
elsif File.directory?(expanded)
|
330
|
+
add_directory_hash!(hash, expanded, remote)
|
331
|
+
else
|
332
|
+
raise Errno::ENOENT, "No such file or directory #{expanded}"
|
333
|
+
end
|
323
334
|
end
|
324
335
|
end
|
325
336
|
hash
|
326
337
|
end
|
327
338
|
|
328
|
-
#
|
339
|
+
# Ensure that only a single StringIO object is uploaded at a time
|
340
|
+
# This is necessary because the contents of the buffer will be written
|
341
|
+
# to the destination.
|
342
|
+
# @param locals [Array<String,StringIO>] a collection of local files,
|
343
|
+
# directories or StringIO objects
|
344
|
+
# @api private
|
345
|
+
def check_locals_array(locals)
|
346
|
+
string_io = false
|
347
|
+
path = false
|
348
|
+
locals.each do |local|
|
349
|
+
raise UploadSourceError if string_io
|
350
|
+
if local.is_a?(StringIO)
|
351
|
+
string_io = true
|
352
|
+
else
|
353
|
+
path = true
|
354
|
+
end
|
355
|
+
raise UploadSourceError if string_io && path
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# @return [String] the SHA1 digest of a local file or StringIO
|
329
360
|
# @api private
|
330
361
|
def sha1sum(local)
|
331
|
-
|
362
|
+
if local.is_a?(StringIO)
|
363
|
+
Digest::SHA1.hexdigest(local.string)
|
364
|
+
else
|
365
|
+
Digest::SHA1.file(local).hexdigest
|
366
|
+
end
|
332
367
|
end
|
333
368
|
|
334
369
|
# Destructively merges a report Hash into an existing files Hash.
|
@@ -459,7 +494,7 @@ module WinRM
|
|
459
494
|
|
460
495
|
# Uploads a local file.
|
461
496
|
#
|
462
|
-
# @param src [String] path to a local file
|
497
|
+
# @param src [String, StringIO] path to a local file or StringIO object
|
463
498
|
# @param dest [String] path to the file on the remote host
|
464
499
|
# @return [Integer,Integer] the number of resulting upload chunks and
|
465
500
|
# the number of bytes transferred to the remote host
|
@@ -469,8 +504,12 @@ module WinRM
|
|
469
504
|
chunks = 0
|
470
505
|
bytes = 0
|
471
506
|
elapsed = Benchmark.measure do
|
472
|
-
|
473
|
-
chunks, bytes = stream_upload(
|
507
|
+
if src.is_a?(StringIO)
|
508
|
+
chunks, bytes = stream_upload(src, dest, &block)
|
509
|
+
else
|
510
|
+
File.open(src, 'rb') do |io|
|
511
|
+
chunks, bytes = stream_upload(io, dest, &block)
|
512
|
+
end
|
474
513
|
end
|
475
514
|
end
|
476
515
|
logger.debug(
|
@@ -125,7 +125,7 @@ module WinRM
|
|
125
125
|
# @api private
|
126
126
|
def produce_zip_entries(zos)
|
127
127
|
entries.each do |entry|
|
128
|
-
entry_path = entry.
|
128
|
+
entry_path = entry.relative_path_from(dir)
|
129
129
|
logger.debug "+++ Adding #{entry_path}"
|
130
130
|
zos.put_next_entry(
|
131
131
|
zip_entry(entry_path),
|
@@ -86,11 +86,27 @@ describe WinRM::FS::FileManager do
|
|
86
86
|
|
87
87
|
context 'upload file' do
|
88
88
|
let(:dest_file) { Pathname.new(File.join(dest_dir, File.basename(this_file))) }
|
89
|
+
let(:from_memory) { StringIO.new('Upload From Memory') }
|
89
90
|
|
90
91
|
before(:each) do
|
91
92
|
expect(subject.delete(dest_dir)).to be true
|
92
93
|
end
|
93
94
|
|
95
|
+
it 'should upload a single StringIO object to a remote file' do
|
96
|
+
subject.upload(from_memory, dest_file)
|
97
|
+
expect(subject).to have_created(dest_file).with_content(from_memory.string)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should error if multiple StringIO objects passed to upload' do
|
101
|
+
expect { subject.upload([from_memory, from_memory], dest_file) }
|
102
|
+
.to raise_error(WinRM::FS::Core::UploadSourceError)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should error if both a StringIO object and a file path passed to upload' do
|
106
|
+
expect { subject.upload([from_memory, this_file], dest_file) }
|
107
|
+
.to raise_error(WinRM::FS::Core::UploadSourceError)
|
108
|
+
end
|
109
|
+
|
94
110
|
it 'should upload the specified file' do
|
95
111
|
subject.upload(this_file, dest_file)
|
96
112
|
expect(subject).to have_created(dest_file).with_content(this_file)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: winrm-fs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shawn Neal
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-
|
12
|
+
date: 2018-08-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: erubis
|