winrm-fs 0.4.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,20 +1,11 @@
1
- $host.ui.RawUI.WindowSize.Width=256
2
- $hash_file = "<%= hash_file %>"
1
+ $hash_file = <%= hash_file %>
3
2
 
4
- Function Cleanup($o) { if (($o -ne $null) -and ($o.GetType().GetMethod("Dispose") -ne $null)) { $o.Dispose() } }
5
-
6
- Function Decode-Base64File($src, $dst) {
7
- Try {
8
- $in = (Get-Item $src).OpenRead()
9
- $b64 = New-Object -TypeName System.Security.Cryptography.FromBase64Transform
10
- $m = [System.Security.Cryptography.CryptoStreamMode]::Read
11
- $d = New-Object -TypeName System.Security.Cryptography.CryptoStream $in,$b64,$m
12
- Copy-Stream $d ($out = [System.IO.File]::OpenWrite($dst))
13
- } Finally { Cleanup $in; Cleanup $out; Cleanup $d }
3
+ Function Cleanup($disposable) {
4
+ if (($disposable -ne $null) -and ($disposable.GetType().GetMethod("Dispose") -ne $null)) {
5
+ $disposable.Dispose()
6
+ }
14
7
  }
15
8
 
16
- Function Copy-Stream($src, $dst) { $b = New-Object Byte[] 4096; while (($i = $src.Read($b, 0, $b.Length)) -ne 0) { $dst.Write($b, 0, $i) } }
17
-
18
9
  Function Check-Files($h) {
19
10
  return $h.GetEnumerator() | ForEach-Object {
20
11
  $dst = Unresolve-Path $_.Value.target
@@ -36,25 +27,23 @@ Function Check-Files($h) {
36
27
 
37
28
  Function Get-MD5Sum($src) {
38
29
  Try {
39
- $c = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
30
+ $c = [System.Security.Cryptography.MD5]::Create()
40
31
  $bytes = $c.ComputeHash(($in = (Get-Item $src).OpenRead()))
41
32
  return ([System.BitConverter]::ToString($bytes)).Replace("-", "").ToLower()
42
- } Finally { Cleanup $c; Cleanup $in }
33
+ }
34
+ Finally {
35
+ Cleanup $c
36
+ Cleanup $in
37
+ }
43
38
  }
44
39
 
45
- Function Invoke-Input($in) {
46
- $in = Unresolve-Path $in
47
- Decode-Base64File $in ($decoded = "$($in).ps1")
48
- $expr = Get-Content $decoded | Out-String
49
- Remove-Item $in,$decoded -Force
50
- try {
51
- return Invoke-Expression "$expr"
40
+ Function Unresolve-Path($path) {
41
+ if ($path -eq $null) {
42
+ return $null
52
43
  }
53
- catch {
54
- throw "There was an error invoking '$expr': `n$($_ | Out-String)"
44
+ else {
45
+ return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
55
46
  }
56
47
  }
57
48
 
58
- Function Unresolve-Path($p) { if ($p -eq $null) { return $null } else { return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p) } }
59
-
60
- Check-Files (Invoke-Input $hash_file) | ConvertTo-Csv -NoTypeInformation
49
+ Check-Files $hash_file | ConvertTo-Csv -NoTypeInformation
@@ -2,7 +2,7 @@ $p = $ExecutionContext.SessionState.Path
2
2
  $path = $p.GetUnresolvedProviderPathFromPSPath("<%= path %>")
3
3
 
4
4
  if (Test-Path $path -PathType Leaf) {
5
- $cryptoProv = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
5
+ $cryptoProv = [System.Security.Cryptography.MD5]::Create()
6
6
  $file = [System.IO.File]::Open($path,
7
7
  [System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
8
8
  $md5 = ([System.BitConverter]::ToString($cryptoProv.ComputeHash($file)))
@@ -0,0 +1,52 @@
1
+ trap {
2
+ $e = $_.Exception
3
+ $e.InvocationInfo.ScriptName
4
+ do {
5
+ $e.Message
6
+ $e = $e.InnerException
7
+ } while ($e)
8
+ break
9
+ }
10
+
11
+ function folder($path){
12
+ $path | ? {-not (test-path $_)} | % {$null = mkdir $_}
13
+ }
14
+
15
+ Function Decode-Files($hash) {
16
+ foreach ($key in $hash.keys) {
17
+ $value = $hash[$key]
18
+ $tzip, $dst = $Value["tmpzip"], $Value["dst"]
19
+ if ($tzip) {Unzip-File $tzip $dst}
20
+ New-Object psobject -Property @{dst=$dst;src_md5=$key;tmpzip=$tzip}
21
+ }
22
+ }
23
+
24
+ Function Unzip-File($src, $dst) {
25
+ $unpack = $src -replace '\.zip'
26
+ $dst_parent = Split-Path -Path $dst -Parent
27
+ if(!(Test-Path $dst_parent)) { $dst = $dst_parent }
28
+ folder $unpack, $dst
29
+ try {
30
+ try{
31
+ [IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)
32
+ }
33
+ catch {
34
+ Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
35
+ [IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)
36
+ }
37
+ }
38
+ catch {
39
+ Try {
40
+ $s = New-Object -ComObject Shell.Application
41
+ ($s.NameSpace($unpack)).CopyHere(($s.NameSpace($src)).Items(), 0x610)
42
+ }
43
+ Finally {
44
+ [void][Runtime.Interopservices.Marshal]::ReleaseComObject($s)
45
+ }
46
+ }
47
+ dir $unpack | cp -dest "$dst/" -force -recurse
48
+ rm $unpack -recurse -force
49
+ }
50
+
51
+ $hash_file = <%= hash_file %>
52
+ Decode-Files $hash_file | ConvertTo-Csv -NoTypeInformation
@@ -1,5 +1,3 @@
1
- auth_type: plaintext
2
- endpoint: "http://192.168.137.20:5985/wsman"
3
- options:
4
- user: vagrant
5
- pass: vagrant
1
+ endpoint: "http://localhost:55985/wsman"
2
+ user: vagrant
3
+ password: vagrant
@@ -5,7 +5,7 @@ describe WinRM::FS::FileManager do
5
5
  let(:dest_dir) { File.join(subject.temp_dir, "winrm_#{rand(2**16)}") }
6
6
  let(:temp_upload_dir) { '$env:TEMP/winrm-upload' }
7
7
  let(:spec_dir) { File.expand_path(File.dirname(File.dirname(__FILE__))) }
8
- let(:this_file) { __FILE__ }
8
+ let(:this_file) { Pathname.new(__FILE__) }
9
9
  let(:service) { winrm_connection }
10
10
 
11
11
  subject { WinRM::FS::FileManager.new(service) }
@@ -40,7 +40,7 @@ describe WinRM::FS::FileManager do
40
40
  end
41
41
 
42
42
  context 'upload file' do
43
- let(:dest_file) { File.join(dest_dir, File.basename(this_file)) }
43
+ let(:dest_file) { Pathname.new(File.join(dest_dir, File.basename(this_file))) }
44
44
 
45
45
  before(:each) do
46
46
  expect(subject.delete(dest_dir)).to be true
@@ -57,6 +57,12 @@ describe WinRM::FS::FileManager do
57
57
  subject.delete('c:/winrmtest.rb')
58
58
  end
59
59
 
60
+ it 'should upload just filename' do
61
+ subject.upload(this_file, 'winrmtest.rb')
62
+ expect(subject).to have_created('winrmtest.rb').with_content(this_file)
63
+ subject.delete('winrmtest.rb')
64
+ end
65
+
60
66
  it 'should upload using relative file path' do
61
67
  subject.upload('./spec/integration/file_manager_spec.rb', dest_file)
62
68
  expect(subject).to have_created(dest_file).with_content(this_file)
@@ -108,8 +114,8 @@ describe WinRM::FS::FileManager do
108
114
  |bytes_copied, total_bytes, local_path, remote_path|
109
115
  expect(total_bytes).to be > 0
110
116
  total_bytes_copied = bytes_copied
111
- expect(local_path).to eq(this_file)
112
- expect(remote_path).to eq(dest_file)
117
+ expect(local_path).to eq(this_file.to_s)
118
+ expect(remote_path).to eq(dest_file.to_s)
113
119
  block_called = true
114
120
  end
115
121
  expect(total_bytes_copied).to eq(total)
data/spec/spec_helper.rb CHANGED
@@ -9,15 +9,14 @@ require_relative 'matchers'
9
9
  module ConnectionHelper
10
10
  # rubocop:disable AbcSize
11
11
  def winrm_connection
12
- WinRM::WinRMWebService.new(
13
- config[:endpoint], config[:auth_type].to_sym, config[:options])
12
+ WinRM::Connection.new(config)
14
13
  end
15
14
  # rubocop:enable AbcSize
16
15
 
17
16
  def config
18
17
  @config ||= begin
19
18
  cfg = symbolize_keys(YAML.load(File.read(winrm_config_path)))
20
- cfg[:options].merge!(basic_auth_only: true) unless cfg[:auth_type].eql? :kerberos
19
+ cfg.merge!(basic_auth_only: true) unless cfg[:transport].eql? :kerberos
21
20
  merge_environment!(cfg)
22
21
  cfg
23
22
  end
@@ -25,18 +24,18 @@ module ConnectionHelper
25
24
 
26
25
  def merge_environment!(config)
27
26
  merge_config_option_from_environment(config, 'user')
28
- merge_config_option_from_environment(config, 'pass')
27
+ merge_config_option_from_environment(config, 'password')
29
28
  merge_config_option_from_environment(config, 'no_ssl_peer_verification')
30
29
  if ENV['use_ssl_peer_fingerprint']
31
30
  config[:options][:ssl_peer_fingerprint] = ENV['winrm_cert']
32
31
  end
33
32
  config[:endpoint] = ENV['winrm_endpoint'] if ENV['winrm_endpoint']
34
- config[:auth_type] = ENV['winrm_auth_type'] if ENV['winrm_auth_type']
33
+ config[:transport] = ENV['winrm_transport'] if ENV['winrm_transport']
35
34
  end
36
35
 
37
36
  def merge_config_option_from_environment(config, key)
38
37
  env_key = 'winrm_' + key
39
- config[:options][key.to_sym] = ENV[env_key] if ENV[env_key]
38
+ config[key.to_sym] = ENV[env_key] if ENV[env_key]
40
39
  end
41
40
 
42
41
  def winrm_config_path
data/winrm-fs.gemspec CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_runtime_dependency 'erubis', '~> 2.7'
30
30
  s.add_runtime_dependency 'logging', ['>= 1.6.1', '< 3.0']
31
31
  s.add_runtime_dependency 'rubyzip', '~> 1.1'
32
- s.add_runtime_dependency 'winrm', '~> 1.5'
32
+ s.add_runtime_dependency 'winrm', '~> 2.0'
33
33
  s.add_development_dependency 'pry'
34
34
  s.add_development_dependency 'rspec', '~> 3.0.0'
35
35
  s.add_development_dependency 'rake', '~> 10.3.2'
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: 0.4.3
4
+ version: 1.0.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: 2016-06-21 00:00:00.000000000 Z
12
+ date: 2016-08-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: erubis
@@ -65,14 +65,14 @@ dependencies:
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.5'
68
+ version: '2.0'
69
69
  type: :runtime
70
70
  prerelease: false
71
71
  version_requirements: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.5'
75
+ version: '2.0'
76
76
  - !ruby/object:Gem::Dependency
77
77
  name: pry
78
78
  requirement: !ruby/object:Gem::Requirement
@@ -129,8 +129,7 @@ dependencies:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
131
  version: 0.28.0
132
- description: |2
133
- Ruby library for file system operations via Windows Remote Management
132
+ description: " Ruby library for file system operations via Windows Remote Management\n"
134
133
  email:
135
134
  - sneal@sneal.net
136
135
  - matt@mattwrock.com
@@ -162,17 +161,16 @@ files:
162
161
  - lib/winrm-fs/scripts/check_files.ps1.erb
163
162
  - lib/winrm-fs/scripts/checksum.ps1.erb
164
163
  - lib/winrm-fs/scripts/create_dir.ps1.erb
165
- - lib/winrm-fs/scripts/decode_files.ps1.erb
166
164
  - lib/winrm-fs/scripts/delete.ps1.erb
167
165
  - lib/winrm-fs/scripts/download.ps1.erb
168
166
  - lib/winrm-fs/scripts/exists.ps1.erb
167
+ - lib/winrm-fs/scripts/extract_files.ps1.erb
169
168
  - lib/winrm-fs/scripts/scripts.rb
170
169
  - spec/config-example.yml
171
170
  - spec/integration/file_manager_spec.rb
172
171
  - spec/integration/tmp_zip_spec.rb
173
172
  - spec/matchers.rb
174
173
  - spec/spec_helper.rb
175
- - spec/unit/file_transporter_spec.rb
176
174
  - spec/unit/tmp_zip_spec.rb
177
175
  - winrm-fs.gemspec
178
176
  homepage: http://github.com/WinRb/winrm-fs
@@ -198,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
196
  version: '0'
199
197
  requirements: []
200
198
  rubyforge_project:
201
- rubygems_version: 2.6.4
199
+ rubygems_version: 2.6.6
202
200
  signing_key:
203
201
  specification_version: 4
204
202
  summary: WinRM File System
@@ -1,58 +0,0 @@
1
- trap {$e = $_.Exception; $e.InvocationInfo.ScriptName; do {$e.Message; $e = $e.InnerException} while ($e); break;}
2
- function Decode-Base64File($src, $dst) {folder (split-path $dst);sc -force -Encoding Byte -Path $dst -Value ([Convert]::FromBase64String([IO.File]::ReadAllLines($src)))}
3
- function Copy-Stream($src, $dst) {$b = New-Object Byte[] 4096; while (($i = $src.Read($b, 0, $b.Length)) -ne 0) { $dst.Write($b, 0, $i) } }
4
- function Resolve-ProviderPath{ $input | % {if ($_){(Resolve-Path $_).ProviderPath} else{$null}} }
5
- function Get-FrameworkVersion { "Full", "Client" | % {([version](gp "HKLM:\Software\Microsoft\NET Framework Setup\NDP\v4\$_").Version)} | select -first 1}
6
- function Test-NETStack($Version){ Get-FrameworkVersion -ge $Version }
7
- function Test-IOCompression {($PSVersionTable.PSVersion.Major -ge 3) -and (Test-NETStack '4.5')}
8
- function folder($path){ $path | ? {-not (test-path $_)} | % {$null = mkdir $_}}
9
- function disposable($o){($o -is [IDisposable]) -and (($o | gm | %{$_.name}) -contains 'Dispose')}
10
- function use($obj, [scriptblock]$sb){try {& $sb} catch [exception]{throw $_} finally {if (disposable $obj) {$obj.Dispose()}} }
11
- set-alias RPP -Value Resolve-ProviderPath
12
-
13
- Function Decode-Files($hash) {
14
- foreach ($key in $hash.keys) {
15
- $value = $hash[$key]
16
- $tmp, $tzip, $dst = $Key, $Value["tmpzip"], $Value["dst"]
17
- if(!$tmp.StartsWith("clean")) {
18
- $sMd5 = (gi $tmp).BaseName.Replace("b64-", "")
19
- $decoded = if ($tzip -ne $null) { $tzip } else { $dst }
20
- Decode-Base64File $tmp $decoded
21
- rm $tmp -Force
22
- $dMd5 = Get-MD5Sum $decoded
23
- $verifies = $sMd5 -like $dMd5
24
- }
25
- if ($tzip) {Unzip-File $tzip $dst}
26
- New-Object psobject -Property @{dst=$dst;verifies=$verifies;src_md5=$sMd5;dst_md5=$dMd5;tmpfile=$tmp;tmpzip=$tzip}
27
- }
28
- }
29
-
30
- Function Get-MD5Sum($src) {
31
- if ($src -and (test-path $src)) {
32
- use ($c = New-Object -TypeName Security.Cryptography.MD5CryptoServiceProvider) {
33
- use ($in = (gi $src).OpenRead()) {([BitConverter]::ToString($c.ComputeHash($in))).Replace("-", "").ToLower()}}
34
- }
35
- }
36
-
37
- Function Invoke-Input($in) {
38
- $in = $in | rpp
39
- $d = "$($in).ps1"
40
- Decode-Base64File $in $d
41
- $expr = gc $d | Out-String
42
- rm $in,$d -Force
43
- iex "$expr"
44
- }
45
-
46
- Function Unzip-File($src, $dst) {
47
- $unpack = $src -replace '\.zip'
48
- $dst_parent = Split-Path -Path $dst -Parent
49
- if(!(Test-Path $dst_parent)) { $dst = $dst_parent }
50
- folder $unpack, $dst
51
- if (Test-IOCompression) {Add-Type -AN System.IO.Compression.FileSystem; [IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)}
52
- else {Try {$s = New-Object -ComObject Shell.Application; ($s.NameSpace($unpack)).CopyHere(($s.NameSpace($src)).Items(), 0x610)} Finally {[void][Runtime.Interopservices.Marshal]::ReleaseComObject($s)}}
53
- dir $unpack | cp -dest "$dst/" -force -recurse
54
- rm $unpack -recurse -force
55
- }
56
-
57
- $hash_file = "<%= hash_file %>"
58
- Decode-Files (Invoke-Input $hash_file) | ConvertTo-Csv -NoTypeInformation
@@ -1,839 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2015, Fletcher Nichol
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- require 'base64'
20
- require 'csv'
21
- require 'stringio'
22
- require 'logger'
23
- require 'winrm'
24
-
25
- require 'winrm-fs/core/file_transporter'
26
-
27
- describe WinRM::FS::Core::FileTransporter do
28
- CheckEntry = Struct.new(
29
- :chk_exists, :src_md5, :dst_md5, :chk_dirty, :verifies)
30
- DecodeEntry = Struct.new(
31
- :dst, :verifies, :src_md5, :dst_md5, :tmpfile, :tmpzip)
32
-
33
- let(:logged_output) { StringIO.new }
34
- let(:logger) { Logger.new(logged_output) }
35
-
36
- let(:randomness) { %w(alpha beta charlie delta).each }
37
- let(:id_generator) { -> { randomness.next } }
38
- let(:winrm_service) { double('winrm_service', logger: logger) }
39
- let(:service) { double('command_executor', service: winrm_service) }
40
- let(:transporter) do
41
- WinRM::FS::Core::FileTransporter.new(
42
- service,
43
- id_generator: id_generator
44
- )
45
- end
46
-
47
- before { @tempfiles = [] }
48
-
49
- after { @tempfiles.each(&:unlink) }
50
-
51
- describe 'when uploading a single file' do
52
- let(:content) { '.' * 12_003 }
53
- let(:local) { create_tempfile('input.txt', content) }
54
- let(:remote) { 'C:\\dest' }
55
- let(:dst) { "#{remote}/#{File.basename(local)}" }
56
- let(:src_md5) { md5sum(local) }
57
- let(:size) { File.size(local) }
58
- let(:cmd_tmpfile) { "%TEMP%\\b64-#{src_md5}.txt" }
59
- let(:ps_tmpfile) { "$env:TEMP\\b64-#{src_md5}.txt" }
60
-
61
- let(:upload) { transporter.upload(local, remote) }
62
-
63
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
64
- def self.common_specs_for_all_single_file_types
65
- it 'truncates a zero-byte hash_file for check_files' do
66
- expect(service).to receive(:run_cmd).with(
67
- regexify(%(echo|set /p=>"%TEMP%\\hash-alpha.txt")))
68
- .and_return(cmd_output)
69
-
70
- upload
71
- end
72
-
73
- it 'uploads the hash_file in chunks for check_files' do
74
- hash = outdent!(<<-HASH.chomp)
75
- @{
76
- "#{src_md5}" = @{
77
- "target" = "#{remote}";
78
- "src_basename" = "#{File.basename(local)}";
79
- "dst" = "#{remote}"
80
- }
81
- }
82
- HASH
83
-
84
- expect(service).to receive(:run_cmd)
85
- .with(%(echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"))
86
- .and_return(cmd_output).once
87
-
88
- upload
89
- end
90
-
91
- it 'sets hash_file and runs the check_files powershell script' do
92
- expect(service).to receive(:run_powershell_script).with(
93
- regexify(%($hash_file = "$env:TEMP\\hash-alpha.txt")) &&
94
- regexify(
95
- 'Check-Files (Invoke-Input $hash_file) | ' \
96
- 'ConvertTo-Csv -NoTypeInformation')
97
- ).and_return(check_output)
98
-
99
- upload
100
- end
101
- end
102
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
103
-
104
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
105
- def self.common_specs_for_all_single_dirty_file_types
106
- it 'truncates a zero-byte tempfile' do
107
- expect(service).to receive(:run_cmd).with(
108
- regexify(%(echo|set /p=>"#{cmd_tmpfile}"))
109
- ).and_return(cmd_output)
110
-
111
- upload
112
- end
113
-
114
- it 'ploads the file in 8k chunks' do
115
- expect(service).to receive(:run_cmd)
116
- .with(%(echo #{base64('.' * 6000)} >> "#{cmd_tmpfile}"))
117
- .and_return(cmd_output).twice
118
- expect(service).to receive(:run_cmd)
119
- .with(%(echo #{base64('.' * 3)} >> "#{cmd_tmpfile}"))
120
- .and_return(cmd_output).once
121
-
122
- upload
123
- end
124
-
125
- describe 'with a small file' do
126
- let(:content) { 'hello, world' }
127
-
128
- it 'uploads the file in base64 encoding' do
129
- expect(service).to receive(:run_cmd)
130
- .with(%(echo #{base64(content)} >> "#{cmd_tmpfile}"))
131
- .and_return(cmd_output)
132
-
133
- upload
134
- end
135
- end
136
-
137
- it 'truncates a zero-byte hash_file for decode_files' do
138
- expect(service).to receive(:run_cmd).with(
139
- regexify(%(echo|set /p=>"%TEMP%\\hash-beta.txt"))
140
- ).and_return(cmd_output)
141
-
142
- upload
143
- end
144
-
145
- it 'uploads the hash_file in chunks for decode_files' do
146
- hash = outdent!(<<-HASH.chomp)
147
- @{
148
- "#{ps_tmpfile}" = @{
149
- "dst" = "#{remote}"
150
- }
151
- }
152
- HASH
153
-
154
- expect(service).to receive(:run_cmd)
155
- .with(%(echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"))
156
- .and_return(cmd_output).once
157
-
158
- upload
159
- end
160
-
161
- it 'sets hash_file and runs the decode_files powershell script' do
162
- expect(service).to receive(:run_powershell_script).with(
163
- regexify(%($hash_file = "$env:TEMP\\hash-beta.txt")) &&
164
- regexify(
165
- 'Decode-Files (Invoke-Input $hash_file) | ' \
166
- 'ConvertTo-Csv -NoTypeInformation')
167
- ).and_return(check_output)
168
-
169
- upload
170
- end
171
- end
172
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
173
-
174
- describe 'for a new file' do
175
- # let(:check_output) do
176
- def check_output
177
- create_check_output([
178
- CheckEntry.new('False', src_md5, nil, 'True', 'False')
179
- ])
180
- end
181
-
182
- let(:cmd_output) do
183
- o = ::WinRM::Output.new
184
- o[:exitcode] = 0
185
- o
186
- end
187
-
188
- # let(:decode_output) do
189
- def decode_output
190
- create_decode_output([
191
- DecodeEntry.new(dst, 'True', src_md5, src_md5, ps_tmpfile, nil)
192
- ])
193
- end
194
-
195
- before do
196
- allow(service).to receive(:run_cmd)
197
- .and_return(cmd_output)
198
-
199
- allow(service).to receive(:run_powershell_script)
200
- .with(/^Check-Files .+ \| ConvertTo-Csv/)
201
- .and_return(check_output)
202
-
203
- allow(service).to receive(:run_powershell_script)
204
- .with(/^Decode-Files .+ \| ConvertTo-Csv/)
205
- .and_return(decode_output)
206
- end
207
-
208
- common_specs_for_all_single_file_types
209
-
210
- common_specs_for_all_single_dirty_file_types
211
-
212
- it 'returns a report hash' do
213
- expect(upload[1]).to eq(
214
- src_md5 => {
215
- 'src' => local,
216
- 'dst' => dst,
217
- 'tmpfile' => ps_tmpfile,
218
- 'tmpzip' => nil,
219
- 'src_md5' => src_md5,
220
- 'dst_md5' => src_md5,
221
- 'chk_exists' => 'False',
222
- 'chk_dirty' => 'True',
223
- 'verifies' => 'True',
224
- 'size' => size,
225
- 'xfered' => size / 3 * 4,
226
- 'chunks' => (size / 6000.to_f).ceil
227
- }
228
- )
229
- end
230
-
231
- describe 'when a failed check command is returned' do
232
- def check_output
233
- o = ::WinRM::Output.new
234
- o[:exitcode] = 10
235
- o[:data].concat([{ stderr: 'Oh noes\n' }])
236
- o
237
- end
238
-
239
- it 'raises a FileTransporterFailed error' do
240
- expect { upload }.to raise_error(
241
- WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
242
- end
243
- end
244
-
245
- describe 'when a failed decode command is returned' do
246
- def decode_output
247
- o = ::WinRM::Output.new
248
- o[:exitcode] = 10
249
- o[:data].concat([{ stderr: 'Oh noes\n' }])
250
- o
251
- end
252
-
253
- it 'raises a FileTransporterFailed error' do
254
- expect { upload }.to raise_error(
255
- WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
256
- end
257
- end
258
- end
259
-
260
- describe 'for an out of date (dirty) file' do
261
- let(:check_output) do
262
- create_check_output([
263
- CheckEntry.new('True', src_md5, 'aabbcc', 'True', 'False')
264
- ])
265
- end
266
-
267
- let(:cmd_output) do
268
- o = ::WinRM::Output.new
269
- o[:exitcode] = 0
270
- o
271
- end
272
-
273
- let(:decode_output) do
274
- create_decode_output([
275
- DecodeEntry.new(dst, 'True', src_md5, src_md5, ps_tmpfile, nil)
276
- ])
277
- end
278
-
279
- before do
280
- allow(service).to receive(:run_cmd)
281
- .and_return(cmd_output)
282
-
283
- allow(service).to receive(:run_powershell_script)
284
- .with(/^Check-Files .+ \| ConvertTo-Csv/)
285
- .and_return(check_output)
286
-
287
- allow(service).to receive(:run_powershell_script)
288
- .with(/^Decode-Files .+ \| ConvertTo-Csv/)
289
- .and_return(decode_output)
290
- end
291
-
292
- common_specs_for_all_single_file_types
293
-
294
- common_specs_for_all_single_dirty_file_types
295
-
296
- it 'returns a report hash' do
297
- expect(upload[1]).to eq(
298
- src_md5 => {
299
- 'src' => local,
300
- 'dst' => dst,
301
- 'tmpfile' => ps_tmpfile,
302
- 'tmpzip' => nil,
303
- 'src_md5' => src_md5,
304
- 'dst_md5' => src_md5,
305
- 'chk_exists' => 'True',
306
- 'chk_dirty' => 'True',
307
- 'verifies' => 'True',
308
- 'size' => size,
309
- 'xfered' => size / 3 * 4,
310
- 'chunks' => (size / 6000.to_f).ceil
311
- }
312
- )
313
- end
314
- end
315
-
316
- describe 'for an up to date (clean) file' do
317
- let(:check_output) do
318
- create_check_output([
319
- CheckEntry.new('True', src_md5, src_md5, 'False', 'True')
320
- ])
321
- end
322
-
323
- let(:cmd_output) do
324
- o = ::WinRM::Output.new
325
- o[:exitcode] = 0
326
- o
327
- end
328
-
329
- before do
330
- allow(service).to receive(:run_cmd)
331
- .and_return(cmd_output)
332
-
333
- allow(service).to receive(:run_powershell_script)
334
- .with(/^Check-Files .+ \| ConvertTo-Csv/)
335
- .and_return(check_output)
336
- end
337
-
338
- common_specs_for_all_single_file_types
339
-
340
- it 'uploads nothing' do
341
- expect(service).not_to receive(:run_cmd).with(/#{remote}/)
342
-
343
- upload
344
- end
345
-
346
- it 'skips the decode_files powershell script' do
347
- expect(service).not_to receive(:run_powershell_script).with(regexify(
348
- 'Decode-Files $files | ConvertTo-Csv -NoTypeInformation')
349
- )
350
-
351
- upload
352
- end
353
-
354
- it 'returns a report hash' do
355
- expect(upload[1]).to eq(
356
- src_md5 => {
357
- 'src' => local,
358
- 'dst' => remote,
359
- 'size' => size,
360
- 'src_md5' => src_md5,
361
- 'dst_md5' => src_md5,
362
- 'chk_exists' => 'True',
363
- 'chk_dirty' => 'False',
364
- 'verifies' => 'True'
365
- }
366
- )
367
- end
368
- end
369
- end
370
-
371
- describe 'when uploading a single directory' do
372
- let(:content) { "I'm a fake zip file" }
373
- let(:local) { Dir.mktmpdir('input') }
374
- let(:remote) { 'C:\\dest' }
375
- let(:src_zip) { create_tempfile('fake.zip', content) }
376
- let(:dst) { remote }
377
- let(:src_md5) { md5sum(src_zip) }
378
- let(:size) { File.size(src_zip) }
379
- let(:cmd_tmpfile) { "%TEMP%\\b64-#{src_md5}.txt" }
380
- let(:ps_tmpfile) { "$env:TEMP\\b64-#{src_md5}.txt" }
381
- let(:ps_tmpzip) { "$env:TEMP\\winrm-upload\\tmpzip-#{src_md5}.zip" }
382
-
383
- let(:tmp_zip) { double('tmp_zip') }
384
-
385
- let(:cmd_output) do
386
- o = ::WinRM::Output.new
387
- o[:exitcode] = 0
388
- o
389
- end
390
-
391
- let(:check_output) do
392
- create_check_output([
393
- CheckEntry.new('False', src_md5, nil, 'True', 'False')
394
- ])
395
- end
396
-
397
- let(:decode_output) do
398
- create_decode_output([
399
- DecodeEntry.new(dst, 'True', src_md5, src_md5, ps_tmpfile, ps_tmpzip)
400
- ])
401
- end
402
-
403
- before do
404
- allow(tmp_zip).to receive(:path).and_return(Pathname(src_zip))
405
- allow(tmp_zip).to receive(:unlink)
406
- allow(WinRM::FS::Core::TmpZip).to receive(:new).with("#{local}/", logger)
407
- .and_return(tmp_zip)
408
-
409
- allow(service).to receive(:run_cmd)
410
- .and_return(cmd_output)
411
-
412
- allow(service).to receive(:run_powershell_script)
413
- .with(/^Check-Files .+ \| ConvertTo-Csv/)
414
- .and_return(check_output)
415
-
416
- allow(service).to receive(:run_powershell_script)
417
- .with(/^Decode-Files .+ \| ConvertTo-Csv/)
418
- .and_return(decode_output)
419
- end
420
-
421
- after do
422
- FileUtils.rm_rf(local)
423
- end
424
-
425
- let(:upload) { transporter.upload("#{local}/", remote) }
426
-
427
- it 'truncates a zero-byte hash_file for check_files' do
428
- expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-alpha.txt"))
429
- ).and_return(cmd_output)
430
-
431
- upload
432
- end
433
-
434
- it 'uploads the hash_file in chunks for check_files' do
435
- hash = outdent!(<<-HASH.chomp)
436
- @{
437
- "#{src_md5}" = @{
438
- "target" = "#{ps_tmpzip}";
439
- "src_basename" = "#{File.basename(local)}";
440
- "dst" = "#{dst}\\#{File.basename(local)}"
441
- }
442
- }
443
- HASH
444
-
445
- expect(service).to receive(:run_cmd)
446
- .with(%(echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"))
447
- .and_return(cmd_output).once
448
-
449
- upload
450
- end
451
-
452
- it 'sets hash_file and runs the check_files powershell script' do
453
- expect(service).to receive(:run_powershell_script).with(
454
- regexify(%($hash_file = "$env:TEMP\\hash-alpha.txt")) &&
455
- regexify(
456
- 'Check-Files (Invoke-Input $hash_file) | ' \
457
- 'ConvertTo-Csv -NoTypeInformation')
458
- ).and_return(check_output)
459
-
460
- upload
461
- end
462
-
463
- it 'truncates a zero-byte tempfile' do
464
- expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"#{cmd_tmpfile}"))
465
- ).and_return(cmd_output)
466
-
467
- upload
468
- end
469
-
470
- it 'uploads the zip file in base64 encoding' do
471
- expect(service).to receive(:run_cmd)
472
- .with(%(echo #{base64(content)} >> "#{cmd_tmpfile}"))
473
- .and_return(cmd_output)
474
-
475
- upload
476
- end
477
-
478
- it 'truncates a zero-byte hash_file for decode_files' do
479
- expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-beta.txt"))
480
- ).and_return(cmd_output)
481
-
482
- upload
483
- end
484
-
485
- it 'uploads the hash_file in chunks for decode_files' do
486
- hash = outdent!(<<-HASH.chomp)
487
- @{
488
- "#{ps_tmpfile}" = @{
489
- "dst" = "#{dst}\\#{File.basename(local)}";
490
- "tmpzip" = "#{ps_tmpzip}"
491
- }
492
- }
493
- HASH
494
-
495
- expect(service).to receive(:run_cmd)
496
- .with(%(echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"))
497
- .and_return(cmd_output).once
498
-
499
- upload
500
- end
501
-
502
- it 'sets hash_file and runs the decode_files powershell script' do
503
- expect(service).to receive(:run_powershell_script).with(
504
- regexify(%($hash_file = "$env:TEMP\\hash-beta.txt")) &&
505
- regexify(
506
- 'Decode-Files (Invoke-Input $hash_file) | ' \
507
- 'ConvertTo-Csv -NoTypeInformation')
508
- ).and_return(check_output)
509
-
510
- upload
511
- end
512
-
513
- it 'returns a report hash' do
514
- expect(upload[1]).to eq(
515
- src_md5 => {
516
- 'src' => "#{local}/",
517
- 'src_zip' => src_zip,
518
- 'dst' => dst,
519
- 'tmpfile' => ps_tmpfile,
520
- 'tmpzip' => ps_tmpzip,
521
- 'src_md5' => src_md5,
522
- 'dst_md5' => src_md5,
523
- 'chk_exists' => 'False',
524
- 'chk_dirty' => 'True',
525
- 'verifies' => 'True',
526
- 'size' => size,
527
- 'xfered' => size / 3 * 4,
528
- 'chunks' => (size / 6000.to_f).ceil
529
- }
530
- )
531
- end
532
-
533
- it 'cleans up the zip file' do
534
- expect(tmp_zip).to receive(:unlink)
535
-
536
- upload
537
- end
538
-
539
- describe 'when a failed check command is returned' do
540
- def check_output
541
- o = ::WinRM::Output.new
542
- o[:exitcode] = 10
543
- o[:data].concat([{ stderr: 'Oh noes\n' }])
544
- o
545
- end
546
-
547
- it 'raises a FileTransporterFailed error' do
548
- expect { upload }.to raise_error(
549
- WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
550
- end
551
- end
552
-
553
- describe 'when a failed decode command is returned' do
554
- def decode_output
555
- o = ::WinRM::Output.new
556
- o[:exitcode] = 10
557
- o[:data].concat([{ stderr: 'Oh noes\n' }])
558
- o
559
- end
560
-
561
- it 'raises a FileTransporterFailed error' do
562
- expect { upload }.to raise_error(
563
- WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
564
- end
565
- end
566
- end
567
-
568
- describe 'when uploading multiple files' do
569
- let(:remote) { 'C:\\Program Files' }
570
-
571
- 1.upto(3).each do |i|
572
- let(:"local#{i}") { create_tempfile("input#{i}.txt", "input#{i}") }
573
- let(:"src#{i}_md5") { md5sum(send("local#{i}")) }
574
- let(:"dst#{i}") { "#{remote}" }
575
- let(:"size#{i}") { File.size(send("local#{i}")) }
576
- let(:"cmd#{i}_tmpfile") { "%TEMP%\\b64-#{send("src#{i}_md5")}.txt" }
577
- let(:"ps#{i}_tmpfile") { "$env:TEMP\\b64-#{send("src#{i}_md5")}.txt" }
578
- end
579
-
580
- let(:check_output) do
581
- create_check_output([
582
- # new
583
- CheckEntry.new('False', src1_md5, nil, 'True', 'False'),
584
- # out-of-date
585
- CheckEntry.new('True', src2_md5, 'aabbcc', 'True', 'False'),
586
- # current
587
- CheckEntry.new('True', src3_md5, src3_md5, 'False', 'True')
588
- ])
589
- end
590
-
591
- let(:cmd_output) do
592
- o = ::WinRM::Output.new
593
- o[:exitcode] = 0
594
- o
595
- end
596
-
597
- let(:decode_output) do
598
- create_decode_output([
599
- DecodeEntry.new(dst1, 'True', src1_md5, src1_md5, ps1_tmpfile, nil),
600
- DecodeEntry.new(dst2, 'True', src2_md5, src2_md5, ps2_tmpfile, nil)
601
- ])
602
- end
603
-
604
- let(:upload) { transporter.upload([local1, local2, local3], remote) }
605
-
606
- before do
607
- allow(service).to receive(:run_cmd)
608
- .and_return(cmd_output)
609
-
610
- allow(service).to receive(:run_powershell_script)
611
- .with(/^Check-Files .+ \| ConvertTo-Csv/)
612
- .and_return(check_output)
613
-
614
- allow(service).to receive(:run_powershell_script)
615
- .with(/^Decode-Files .+ \| ConvertTo-Csv/)
616
- .and_return(decode_output)
617
- end
618
-
619
- it 'truncates a zero-byte hash_file for check_files' do
620
- expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-alpha.txt"))
621
- ).and_return(cmd_output)
622
-
623
- upload
624
- end
625
-
626
- it 'uploads the hash_file in chunks for check_files' do
627
- hash = outdent!(<<-HASH.chomp)
628
- @{
629
- "#{src1_md5}" = @{
630
- "target" = "#{dst1}";
631
- "src_basename" = "#{File.basename(local1)}";
632
- "dst" = "#{dst1}"
633
- };
634
- "#{src2_md5}" = @{
635
- "target" = "#{dst2}";
636
- "src_basename" = "#{File.basename(local2)}";
637
- "dst" = "#{dst2}"
638
- };
639
- "#{src3_md5}" = @{
640
- "target" = "#{dst3}";
641
- "src_basename" = "#{File.basename(local3)}";
642
- "dst" = "#{dst3}"
643
- }
644
- }
645
- HASH
646
-
647
- expect(service).to receive(:run_cmd)
648
- .with(%(echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"))
649
- .and_return(cmd_output).once
650
-
651
- upload
652
- end
653
-
654
- it 'sets hash_file and runs the check_files powershell script' do
655
- expect(service).to receive(:run_powershell_script).with(
656
- regexify(%($hash_file = "$env:TEMP\\hash-alpha.txt")) &&
657
- regexify(
658
- 'Check-Files (Invoke-Input $hash_file) | ' \
659
- 'ConvertTo-Csv -NoTypeInformation')
660
- ).and_return(check_output)
661
-
662
- upload
663
- end
664
-
665
- it 'only uploads dirty files' do
666
- expect(service).to receive(:run_cmd)
667
- .with(%(echo #{base64(IO.read(local1))} >> "#{cmd1_tmpfile}"))
668
- expect(service).to receive(:run_cmd)
669
- .with(%(echo #{base64(IO.read(local2))} >> "#{cmd2_tmpfile}"))
670
- expect(service).not_to receive(:run_cmd)
671
- .with(%(echo #{base64(IO.read(local3))} >> "#{cmd3_tmpfile}"))
672
-
673
- upload
674
- end
675
-
676
- it 'truncates a zero-byte hash_file for decode_files' do
677
- expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-beta.txt"))
678
- ).and_return(cmd_output)
679
-
680
- upload
681
- end
682
-
683
- it 'uploads the hash_file in chunks for decode_files' do
684
- hash = outdent!(<<-HASH.chomp)
685
- @{
686
- "#{ps1_tmpfile}" = @{
687
- "dst" = "#{dst1}"
688
- };
689
- "#{ps2_tmpfile}" = @{
690
- "dst" = "#{dst2}"
691
- }
692
- }
693
- HASH
694
-
695
- expect(service).to receive(:run_cmd)
696
- .with(%(echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"))
697
- .and_return(cmd_output).once
698
-
699
- upload
700
- end
701
-
702
- it 'sets hash_file and runs the decode_files powershell script' do
703
- expect(service).to receive(:run_powershell_script).with(
704
- regexify(%($hash_file = '$env:TEMP\\hash-beta.txt')) &&
705
- regexify(
706
- 'Decode-Files (Invoke-Input $hash_file) | ' \
707
- 'ConvertTo-Csv -NoTypeInformation')
708
- ).and_return(check_output)
709
-
710
- upload
711
- end
712
-
713
- it 'returns a report hash' do
714
- report = upload[1]
715
-
716
- expect(report.fetch(src1_md5)).to eq(
717
- 'src' => local1,
718
- 'dst' => dst1,
719
- 'tmpfile' => ps1_tmpfile,
720
- 'tmpzip' => nil,
721
- 'src_md5' => src1_md5,
722
- 'dst_md5' => src1_md5,
723
- 'chk_exists' => 'False',
724
- 'chk_dirty' => 'True',
725
- 'verifies' => 'True',
726
- 'size' => size1,
727
- 'xfered' => size1 / 3 * 4,
728
- 'chunks' => (size1 / 6000.to_f).ceil
729
- )
730
- expect(report.fetch(src2_md5)).to eq(
731
- 'src' => local2,
732
- 'dst' => dst2,
733
- 'tmpfile' => ps2_tmpfile,
734
- 'tmpzip' => nil,
735
- 'src_md5' => src2_md5,
736
- 'dst_md5' => src2_md5,
737
- 'chk_exists' => 'True',
738
- 'chk_dirty' => 'True',
739
- 'verifies' => 'True',
740
- 'size' => size2,
741
- 'xfered' => size2 / 3 * 4,
742
- 'chunks' => (size2 / 6000.to_f).ceil
743
- )
744
- expect(report.fetch(src3_md5)).to eq(
745
- 'src' => local3,
746
- 'dst' => dst3,
747
- 'src_md5' => src3_md5,
748
- 'dst_md5' => src3_md5,
749
- 'chk_exists' => 'True',
750
- 'chk_dirty' => 'False',
751
- 'verifies' => 'True',
752
- 'size' => size3
753
- )
754
- end
755
-
756
- describe 'when a failed check command is returned' do
757
- def check_output
758
- o = ::WinRM::Output.new
759
- o[:exitcode] = 10
760
- o[:data].concat([{ stderr: "Oh noes\n" }])
761
- o
762
- end
763
-
764
- it 'raises a FileTransporterFailed error' do
765
- expect { upload }.to raise_error(
766
- WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
767
- end
768
- end
769
-
770
- describe 'when a failed decode command is returned' do
771
- def decode_output
772
- o = ::WinRM::Output.new
773
- o[:exitcode] = 10
774
- o[:data].concat([{ stderr: "Oh noes\n" }])
775
- o
776
- end
777
-
778
- it 'raises a FileTransporterFailed error' do
779
- expect { upload }.to raise_error(
780
- WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
781
- end
782
- end
783
- end
784
-
785
- it 'raises an exception when local file or directory is not found' do
786
- expect { transporter.upload('/a/b/c/nope', 'C:\\nopeland') }.to raise_error Errno::ENOENT
787
- end
788
-
789
- def base64(string)
790
- Base64.strict_encode64(string)
791
- end
792
-
793
- def create_check_output(entries)
794
- csv = CSV.generate(force_quotes: true) do |rows|
795
- rows << CheckEntry.new.members.map(&:to_s)
796
- entries.each { |entry| rows << entry.to_a }
797
- end
798
-
799
- o = ::WinRM::Output.new
800
- o[:exitcode] = 0
801
- o[:data].concat(csv.lines.map { |line| { stdout: line } })
802
- o
803
- end
804
-
805
- def create_decode_output(entries)
806
- csv = CSV.generate(force_quotes: true) do |rows|
807
- rows << DecodeEntry.new.members.map(&:to_s)
808
- entries.each { |entry| rows << entry.to_a }
809
- end
810
-
811
- o = ::WinRM::Output.new
812
- o[:exitcode] = 0
813
- o[:data].concat(csv.lines.map { |line| { stdout: line } })
814
- o
815
- end
816
-
817
- def create_tempfile(name, content)
818
- pre, _, ext = name.rpartition('.')
819
- file = Tempfile.open(["#{pre}-", ".#{ext}"])
820
- @tempfiles << file
821
- file.write(content)
822
- file.close
823
- file.path
824
- end
825
-
826
- def md5sum(local)
827
- Digest::MD5.file(local).hexdigest
828
- end
829
-
830
- def outdent!(string)
831
- string.gsub!(/^ {#{string.index(/[^ ]/)}}/, '')
832
- end
833
-
834
- def regexify(str, line = :whole_line)
835
- r = Regexp.escape(str)
836
- r = "^#{r}$" if line == :whole_line
837
- Regexp.new(r)
838
- end
839
- end