winrm-fs 1.2.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f0f709ab1c583eaa7566b5adc461aaf46cf2b65e
4
- data.tar.gz: c8cdda9ef2983370cbc964dc9d89eddf348dbd22
2
+ SHA256:
3
+ metadata.gz: d7898b5512c391163a77d694860db51a5c15c5745031c2b34c0cd181a9bbda37
4
+ data.tar.gz: 87864314b0863331944c604d26c0721db568db238da87923b836d80097531dad
5
5
  SHA512:
6
- metadata.gz: b0d362238781bb50982b7b3f8947b754c3dde755fe4f727197579d943534c717db891b3a197150f2ad975661d12bfc8be66b2e6e9eee9f1395efa6e70cf15a39
7
- data.tar.gz: f5daea2da6036290bca6446936f6d79105578a8106746c809a3887725ba2d7171470451f5c7e0290a8ec4264f7f597af86e77dcb0b01697d697ca35dd433bcc9
6
+ metadata.gz: d468205639de56be5fcf4c4896a823f96760e03e23153b6e09cc9c1bc2779725d84f429a759d67088e622a288a3e002bb528f9e23749cded6416baac38b26614
7
+ data.tar.gz: b8787f4e3ae986aa32ae324cd1e6113081b83cb291ba519b027dea7ee67f0c4a0d9d15e50e38222328d94829735156a525c066cab56966c6e92de25754efc5b4
data/.rubocop.yml CHANGED
@@ -7,6 +7,9 @@ Naming/FileName:
7
7
  Style/Encoding:
8
8
  Enabled: true
9
9
 
10
+ Layout/EndOfLine:
11
+ Enabled: false
12
+
10
13
  Metrics/LineLength:
11
14
  Max: 120
12
15
 
data/.rubocop_todo.yml CHANGED
@@ -34,13 +34,6 @@ Naming/HeredocDelimiterNaming:
34
34
  - 'spec/matchers.rb'
35
35
  - 'winrm-fs.gemspec'
36
36
 
37
- # Offense count: 2
38
- # Cop supports --auto-correct.
39
- # Configuration parameters: AutoCorrect.
40
- Performance/HashEachMethods:
41
- Exclude:
42
- - 'lib/winrm-fs/core/file_transporter.rb'
43
-
44
37
  # Offense count: 1
45
38
  # Configuration parameters: .
46
39
  # SupportedStyles: annotated, template, unannotated
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.0
3
+ - 2.2.0
4
4
  - 2.3.4
5
5
  - 2.4.1
6
6
 
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![Build status](https://ci.appveyor.com/api/projects/status/wm6apa8ojfhfmwsf?svg=true)](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/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rspec/core/rake_task'
4
4
  require 'rubocop/rake_task'
5
5
 
6
6
  # Change to the directory of this file.
7
- Dir.chdir(File.expand_path('../', __FILE__))
7
+ Dir.chdir(File.expand_path(__dir__))
8
8
 
9
9
  # For gem creation and bundling
10
10
  require 'bundler/gem_tasks'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.0
1
+ 1.3.0
data/appveyor.yml CHANGED
@@ -9,7 +9,7 @@ environment:
9
9
  winrm_password: Pass@word1
10
10
 
11
11
  matrix:
12
- - ruby_version: "21"
12
+ - ruby_version: "22"
13
13
  winrm_endpoint: http://localhost:5985/wsman
14
14
 
15
15
  clone_folder: c:\projects\winrm-fs
data/changelog.md CHANGED
@@ -1,4 +1,12 @@
1
1
  # WinRM-fs Gem Changelog
2
+ # 1.3.0
3
+ - Upload from StringIO object
4
+ - Add missing winrm/exceptions require in file_transporter
5
+ - Use correct way to relativize paths of Zip entries
6
+
7
+ # 1.2.1
8
+ - Correctly handle unicode filenames
9
+
2
10
  # 1.2.0
3
11
  - Add ability to download directories
4
12
 
@@ -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
@@ -56,6 +65,7 @@ module WinRM
56
65
  @shell = shell
57
66
  @logger = shell.logger
58
67
  @id_generator = opts.fetch(:id_generator) { -> { SecureRandom.uuid } }
68
+ Zip.unicode_names = true
59
69
  end
60
70
 
61
71
  # Uploads a collection of files and/or directories to the remote host.
@@ -66,17 +76,16 @@ module WinRM
66
76
  # * progress yields block like net-scp progress
67
77
  # * final API: def upload(locals, remote, _options = {}, &_progress)
68
78
  #
69
- # @param locals [Array<String>,String] one or more local file or
70
- # directory paths
79
+ # @param locals [Array<String>,String,StringIO] one or more
80
+ # local file or directory paths, StringIO objects also accepted
71
81
  # @param remote [String] the base destination path on the remote host
72
82
  # @return [Hash] report hash, keyed by the local SHA1 digest
73
83
  def upload(locals, remote)
74
84
  files = nil
75
85
  report = nil
76
86
  remote = remote.to_s
77
-
78
87
  elapsed1 = Benchmark.measure do
79
- files = make_files_hash(Array(locals), remote)
88
+ files = make_files_hash([locals].flatten, remote)
80
89
  report = check_files(files)
81
90
  merge_with_report!(files, report)
82
91
  reconcile_destinations!(files)
@@ -182,16 +191,15 @@ module WinRM
182
191
  # Adds an entry to a files Hash (keyed by local SHA1 digest) for a file.
183
192
  #
184
193
  # @param hash [Hash] hash to be mutated
185
- # @param local [String] file path
194
+ # @param local [String, StringIO] file path or StringIO object
186
195
  # @param remote [String] path to destination on remote host
187
196
  # @api private
188
197
  def add_file_hash!(hash, local, remote)
189
198
  logger.debug "creating hash for file #{remote}"
190
-
191
199
  hash[sha1sum(local)] = {
192
200
  'src' => local,
193
201
  'dst' => remote,
194
- 'size' => File.size(local)
202
+ 'size' => local.is_a?(StringIO) ? local.size : File.size(local)
195
203
  }
196
204
  end
197
205
 
@@ -222,7 +230,7 @@ module WinRM
222
230
  sha1,
223
231
  {
224
232
  'target' => data.fetch('tmpzip', data['dst']),
225
- 'src_basename' => File.basename(data['src']),
233
+ 'src_basename' => data['src'].is_a?(StringIO) ? data['dst'] : File.basename(data['src']),
226
234
  'dst' => data['dst']
227
235
  }
228
236
  ]
@@ -301,33 +309,61 @@ module WinRM
301
309
  # digest. Each file entry has a source and destination set, at a
302
310
  # minimum.
303
311
  #
304
- # @param locals [Array<String>] a collection of local files or
305
- # directories
312
+ # @param locals [Array<String,StringIO>] a collection of local files,
313
+ # directories or StringIO objects
306
314
  # @param remote [String] the base destination path on the remote host
307
315
  # @return [Hash] files hash, keyed by the local SHA1 digest
308
316
  # @api private
309
317
  def make_files_hash(locals, remote)
310
318
  hash = {}
319
+ check_locals_array(locals)
311
320
  locals.each do |local|
312
- local = local.to_s
313
- expanded = File.expand_path(local)
314
- expanded += local[-1] if local.end_with?('/', '\\')
315
-
316
- if File.file?(expanded)
317
- add_file_hash!(hash, expanded, remote)
318
- elsif File.directory?(expanded)
319
- add_directory_hash!(hash, expanded, remote)
321
+ if local.is_a?(StringIO)
322
+ add_file_hash!(hash, local, remote)
320
323
  else
321
- raise Errno::ENOENT, "No such file or directory #{expanded}"
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
322
334
  end
323
335
  end
324
336
  hash
325
337
  end
326
338
 
327
- # @return [String] the SHA1 digest of a local file
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
328
360
  # @api private
329
361
  def sha1sum(local)
330
- Digest::SHA1.file(local).hexdigest
362
+ if local.is_a?(StringIO)
363
+ Digest::SHA1.hexdigest(local.string)
364
+ else
365
+ Digest::SHA1.file(local).hexdigest
366
+ end
331
367
  end
332
368
 
333
369
  # Destructively merges a report Hash into an existing files Hash.
@@ -432,7 +468,7 @@ module WinRM
432
468
  # ClearScriptBlockCache to clear it.
433
469
  $bindingFlags= [Reflection.BindingFlags] "NonPublic,Static"
434
470
  $method = [scriptblock].GetMethod("ClearScriptBlockCache", $bindingFlags)
435
- EOS
471
+ EOS
436
472
  )
437
473
 
438
474
  while input_io.read(read_size, buffer)
@@ -458,7 +494,7 @@ module WinRM
458
494
 
459
495
  # Uploads a local file.
460
496
  #
461
- # @param src [String] path to a local file
497
+ # @param src [String, StringIO] path to a local file or StringIO object
462
498
  # @param dest [String] path to the file on the remote host
463
499
  # @return [Integer,Integer] the number of resulting upload chunks and
464
500
  # the number of bytes transferred to the remote host
@@ -468,8 +504,12 @@ module WinRM
468
504
  chunks = 0
469
505
  bytes = 0
470
506
  elapsed = Benchmark.measure do
471
- File.open(src, 'rb') do |io|
472
- chunks, bytes = stream_upload(io, dest, &block)
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
473
513
  end
474
514
  end
475
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.sub(/#{dir}\//i, '')
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),
@@ -83,7 +83,7 @@ module WinRM
83
83
  # 'C:/Windows/Temp'
84
84
  # @return [String] Full path to the temp directory
85
85
  def temp_dir
86
- @guest_temp ||= begin
86
+ @temp_dir ||= begin
87
87
  (@connection.shell(:powershell) { |e| e.run('$env:TEMP') }).stdout.chomp.tr('\\', '/')
88
88
  end
89
89
  end
@@ -116,7 +116,7 @@ module WinRM
116
116
  private
117
117
 
118
118
  def download_dir(remote_path, local_path, first)
119
- local_path = File.join(local_path, File.basename(remote_path)) if first
119
+ local_path = File.join(local_path, File.basename(remote_path.to_s)) if first
120
120
  FileUtils.mkdir_p(local_path) unless File.directory?(local_path)
121
121
  command = "Get-ChildItem #{remote_path} | Select-Object Name"
122
122
  @connection.shell(:powershell) { |e| e.run(command) }.stdout.strip.split(/\n/).drop(2).each do |file|
@@ -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)
data/spec/spec_helper.rb CHANGED
@@ -9,7 +9,6 @@ module ConnectionHelper
9
9
  def winrm_connection
10
10
  WinRM::Connection.new(config)
11
11
  end
12
- # rubocop:enable AbcSize
13
12
 
14
13
  def config
15
14
  @config ||= begin
data/winrm-fs.gemspec CHANGED
@@ -1,30 +1,30 @@
1
1
  require 'date'
2
2
 
3
- version = File.read(File.expand_path('../VERSION', __FILE__)).strip
3
+ version = File.read(File.expand_path('VERSION', __dir__)).strip
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.platform = Gem::Platform::RUBY
7
7
  s.name = 'winrm-fs'
8
8
  s.version = version
9
- s.date = Date.today.to_s
9
+ s.date = Date.today.to_s
10
10
 
11
11
  s.author = ['Shawn Neal', 'Matt Wrock']
12
12
  s.email = ['sneal@sneal.net', 'matt@mattwrock.com']
13
13
  s.homepage = 'http://github.com/WinRb/winrm-fs'
14
14
 
15
15
  s.summary = 'WinRM File System'
16
- s.description = <<-EOF
16
+ s.description = <<-EOF
17
17
  Ruby library for file system operations via Windows Remote Management
18
18
  EOF
19
19
 
20
20
  s.files = `git ls-files`.split(/\n/)
21
21
  s.require_path = 'lib'
22
- s.rdoc_options = %w[-x test/ -x examples/]
22
+ s.rdoc_options = %w[-x test/ -x examples/]
23
23
  s.extra_rdoc_files = %w[README.md LICENSE]
24
24
 
25
25
  s.bindir = 'bin'
26
26
  s.executables = ['rwinrmcp']
27
- s.required_ruby_version = '>= 2.1.0'
27
+ s.required_ruby_version = '>= 2.2.0'
28
28
  s.add_runtime_dependency 'erubis', '~> 2.7'
29
29
  s.add_runtime_dependency 'logging', ['>= 1.6.1', '< 3.0']
30
30
  s.add_runtime_dependency 'rubyzip', '~> 1.1'
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.2.0
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-01-12 00:00:00.000000000 Z
12
+ date: 2018-08-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: erubis
@@ -189,7 +189,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
189
189
  requirements:
190
190
  - - ">="
191
191
  - !ruby/object:Gem::Version
192
- version: 2.1.0
192
+ version: 2.2.0
193
193
  required_rubygems_version: !ruby/object:Gem::Requirement
194
194
  requirements:
195
195
  - - ">="
@@ -197,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
197
197
  version: '0'
198
198
  requirements: []
199
199
  rubyforge_project:
200
- rubygems_version: 2.6.11
200
+ rubygems_version: 2.7.6
201
201
  signing_key:
202
202
  specification_version: 4
203
203
  summary: WinRM File System