winrm-fs 0.2.3 → 0.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 +9 -5
- data/Rakefile +2 -4
- data/VERSION +1 -1
- data/appveyor.yml +39 -0
- data/changelog.md +9 -0
- data/lib/winrm-fs/core/file_transporter.rb +506 -0
- data/lib/winrm-fs/core/tmp_zip.rb +166 -0
- data/lib/winrm-fs/file_manager.rb +14 -15
- data/lib/winrm-fs/scripts/check_files.ps1.erb +48 -0
- data/lib/winrm-fs/scripts/decode_files.ps1.erb +59 -0
- data/lib/winrm-fs/scripts/download.ps1.erb +2 -1
- data/spec/config-example.yml +1 -1
- data/spec/{file_manager_spec.rb → integration/file_manager_spec.rb} +38 -12
- data/spec/integration/tmp_zip_spec.rb +26 -0
- data/spec/spec_helper.rb +28 -4
- data/spec/unit/file_transporter_spec.rb +819 -0
- data/spec/unit/tmp_zip_spec.rb +79 -0
- data/winrm-fs.gemspec +2 -1
- metadata +27 -12
- data/benchmark.rb +0 -20
- data/lib/winrm-fs/core/command_executor.rb +0 -74
- data/lib/winrm-fs/core/file_uploader.rb +0 -84
- data/lib/winrm-fs/core/temp_zip_file.rb +0 -187
- data/lib/winrm-fs/core/upload_orchestrator.rb +0 -119
- data/lib/winrm-fs/scripts/decode_file.ps1.erb +0 -36
- data/spec/temp_zip_file_spec.rb +0 -55
@@ -0,0 +1,166 @@
|
|
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 'delegate'
|
20
|
+
require 'pathname'
|
21
|
+
require 'tempfile'
|
22
|
+
require 'zip'
|
23
|
+
|
24
|
+
module WinRM
|
25
|
+
module FS
|
26
|
+
module Core
|
27
|
+
# A temporary Zip file for a given directory.
|
28
|
+
#
|
29
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
30
|
+
class TmpZip
|
31
|
+
# Contructs a new Zip file for the given directory.
|
32
|
+
#
|
33
|
+
# There are 2 ways to interpret the directory path:
|
34
|
+
#
|
35
|
+
# * If the directory has no path separator terminator, then the
|
36
|
+
# directory basename will be used as the base directory in the
|
37
|
+
# resulting zip file.
|
38
|
+
# * If the directory has a path separator terminator (such as `/` or
|
39
|
+
# `\\`), then the entries under the directory will be added to the
|
40
|
+
# resulting zip file.
|
41
|
+
#
|
42
|
+
# The following emaples assume a directory tree structure of:
|
43
|
+
#
|
44
|
+
# src
|
45
|
+
# |-- alpha.txt
|
46
|
+
# |-- beta.txt
|
47
|
+
# \-- sub
|
48
|
+
# \-- charlie.txt
|
49
|
+
#
|
50
|
+
# @example Including the base directory in the zip file
|
51
|
+
#
|
52
|
+
# TmpZip.new("/path/to/src")
|
53
|
+
# # produces a zip file with entries:
|
54
|
+
# # - src/alpha.txt
|
55
|
+
# # - src/beta.txt
|
56
|
+
# # - src/sub/charlie.txt
|
57
|
+
#
|
58
|
+
# @example Excluding the base directory in the zip file
|
59
|
+
#
|
60
|
+
# TmpZip.new("/path/to/src/")
|
61
|
+
# # produces a zip file with entries:
|
62
|
+
# # - alpha.txt
|
63
|
+
# # - beta.txt
|
64
|
+
# # - sub/charlie.txt
|
65
|
+
#
|
66
|
+
# @param dir [String,Pathname,#to_s] path to the directory
|
67
|
+
# @param logger [#debug,#debug?] an optional logger/ui object that
|
68
|
+
# responds to `#debug` and `#debug?` (default `nil`)
|
69
|
+
def initialize(dir, logger = nil)
|
70
|
+
@logger = logger || Logging.logger[self]
|
71
|
+
@dir = Pathname.new(dir)
|
72
|
+
@zip_io = Tempfile.open(['tmpzip-', '.zip'], binmode: true)
|
73
|
+
write_zip
|
74
|
+
@zip_io.close
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Pathname] path to zip file
|
78
|
+
def path
|
79
|
+
Pathname.new(zip_io.path) if zip_io.path
|
80
|
+
end
|
81
|
+
|
82
|
+
# Unlinks (deletes) the zip file from the filesystem.
|
83
|
+
def unlink
|
84
|
+
zip_io.unlink
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# @return [Pathname] the directory used to create the Zip file
|
90
|
+
# @api private
|
91
|
+
attr_reader :dir
|
92
|
+
|
93
|
+
# @return [#debug] the logger
|
94
|
+
# @api private
|
95
|
+
attr_reader :logger
|
96
|
+
|
97
|
+
# @return [IO] the Zip file IO
|
98
|
+
# @api private
|
99
|
+
attr_reader :zip_io
|
100
|
+
|
101
|
+
# @return [Array<Pathname] all recursive files under the base
|
102
|
+
# directory, excluding directories
|
103
|
+
# @api private
|
104
|
+
def entries
|
105
|
+
Pathname.glob(dir.join('**/*')).delete_if(&:directory?).sort
|
106
|
+
end
|
107
|
+
|
108
|
+
# (see Logging.log_subject)
|
109
|
+
# @api private
|
110
|
+
def log_subject
|
111
|
+
@log_subject ||= [self.class.to_s.split('::').last, path].join('::')
|
112
|
+
end
|
113
|
+
|
114
|
+
# Adds all file entries to the Zip output stream.
|
115
|
+
#
|
116
|
+
# @param zos [Zip::OutputStream] zip output stream
|
117
|
+
# @api private
|
118
|
+
def produce_zip_entries(zos)
|
119
|
+
entries.each do |entry|
|
120
|
+
entry_path = entry.sub(/#{dir}\//i, '')
|
121
|
+
logger.debug "+++ Adding #{entry_path}"
|
122
|
+
zos.put_next_entry(
|
123
|
+
zip_entry(entry_path),
|
124
|
+
nil, nil, ::Zip::Entry::DEFLATED, Zlib::BEST_COMPRESSION)
|
125
|
+
entry.open('rb') { |src| IO.copy_stream(src, zos) }
|
126
|
+
end
|
127
|
+
logger.debug '=== All files added.'
|
128
|
+
end
|
129
|
+
|
130
|
+
# Writes out a temporary Zip file.
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
def write_zip
|
134
|
+
logger.debug 'Populating files'
|
135
|
+
Zip::OutputStream.write_buffer(NoDupIO.new(zip_io)) do |zos|
|
136
|
+
produce_zip_entries(zos)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def zip_entry(entry_path)
|
141
|
+
Zip::Entry.new(
|
142
|
+
zip_io.path,
|
143
|
+
entry_path.to_s,
|
144
|
+
nil, nil, nil, nil, nil, nil,
|
145
|
+
::Zip::DOSTime.new(2000)
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Simple delegate wrapper to prevent `#dup` calls being made on IO
|
150
|
+
# objects. This is used to bypass an issue in the `Zip::Outputstream`
|
151
|
+
# constructor where an incoming IO is duplicated, leading to races
|
152
|
+
# on flushing the final stream to disk.
|
153
|
+
#
|
154
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
155
|
+
# @api private
|
156
|
+
class NoDupIO < SimpleDelegator
|
157
|
+
# @return [self] returns self and does *not* return a duplicate
|
158
|
+
# object
|
159
|
+
def dup
|
160
|
+
self
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -14,8 +14,9 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
+
require 'winrm'
|
17
18
|
require_relative 'scripts/scripts'
|
18
|
-
require_relative 'core/
|
19
|
+
require_relative 'core/file_transporter'
|
19
20
|
|
20
21
|
module WinRM
|
21
22
|
module FS
|
@@ -25,7 +26,7 @@ module WinRM
|
|
25
26
|
# @param [WinRMWebService] WinRM web service client
|
26
27
|
def initialize(service)
|
27
28
|
@service = service
|
28
|
-
@logger =
|
29
|
+
@logger = service.logger
|
29
30
|
end
|
30
31
|
|
31
32
|
# Gets the MD5 checksum of the specified file if it exists,
|
@@ -34,7 +35,7 @@ module WinRM
|
|
34
35
|
def checksum(path)
|
35
36
|
@logger.debug("checksum: #{path}")
|
36
37
|
script = WinRM::FS::Scripts.render('checksum', path: path)
|
37
|
-
@service.
|
38
|
+
@service.create_executor { |e| e.run_powershell_script(script).stdout.chomp }
|
38
39
|
end
|
39
40
|
|
40
41
|
# Create the specifed directory recursively
|
@@ -43,7 +44,7 @@ module WinRM
|
|
43
44
|
def create_dir(path)
|
44
45
|
@logger.debug("create_dir: #{path}")
|
45
46
|
script = WinRM::FS::Scripts.render('create_dir', path: path)
|
46
|
-
@service.
|
47
|
+
@service.create_executor { |e| e.run_powershell_script(script)[:exitcode] == 0 }
|
47
48
|
end
|
48
49
|
|
49
50
|
# Deletes the file or directory at the specified path
|
@@ -52,7 +53,7 @@ module WinRM
|
|
52
53
|
def delete(path)
|
53
54
|
@logger.debug("deleting: #{path}")
|
54
55
|
script = WinRM::FS::Scripts.render('delete', path: path)
|
55
|
-
@service.
|
56
|
+
@service.create_executor { |e| e.run_powershell_script(script)[:exitcode] == 0 }
|
56
57
|
end
|
57
58
|
|
58
59
|
# Downloads the specified remote file to the specified local path
|
@@ -61,7 +62,7 @@ module WinRM
|
|
61
62
|
def download(remote_path, local_path)
|
62
63
|
@logger.debug("downloading: #{remote_path} -> #{local_path}")
|
63
64
|
script = WinRM::FS::Scripts.render('download', path: remote_path)
|
64
|
-
output = @service.
|
65
|
+
output = @service.create_executor { |e| e.run_powershell_script(script) }
|
65
66
|
return false if output[:exitcode] != 0
|
66
67
|
contents = output.stdout.gsub('\n\r', '')
|
67
68
|
out = Base64.decode64(contents)
|
@@ -75,14 +76,16 @@ module WinRM
|
|
75
76
|
def exists?(path)
|
76
77
|
@logger.debug("exists?: #{path}")
|
77
78
|
script = WinRM::FS::Scripts.render('exists', path: path)
|
78
|
-
@service.
|
79
|
+
@service.create_executor { |e| e.run_powershell_script(script)[:exitcode] == 0 }
|
79
80
|
end
|
80
81
|
|
81
82
|
# Gets the current user's TEMP directory on the remote system, for example
|
82
83
|
# 'C:/Windows/Temp'
|
83
84
|
# @return [String] Full path to the temp directory
|
84
85
|
def temp_dir
|
85
|
-
@guest_temp ||=
|
86
|
+
@guest_temp ||= begin
|
87
|
+
(@service.create_executor { |e| e.run_cmd('echo %TEMP%') }).stdout.chomp.gsub('\\', '/')
|
88
|
+
end
|
86
89
|
end
|
87
90
|
|
88
91
|
# Upload one or more local files and directories to a remote directory
|
@@ -104,13 +107,9 @@ module WinRM
|
|
104
107
|
# @yieldparam [String] Target path on the winrm endpoint
|
105
108
|
# @return [Fixnum] The total number of bytes copied
|
106
109
|
def upload(local_path, remote_path, &block)
|
107
|
-
@
|
108
|
-
|
109
|
-
|
110
|
-
if File.file?(local_path)
|
111
|
-
upload_orchestrator.upload_file(local_path, remote_path, &block)
|
112
|
-
else
|
113
|
-
upload_orchestrator.upload_directory(local_path, remote_path, &block)
|
110
|
+
@service.create_executor do |executor|
|
111
|
+
file_transporter ||= WinRM::FS::Core::FileTransporter.new(executor)
|
112
|
+
file_transporter.upload(local_path, remote_path, &block)[0]
|
114
113
|
end
|
115
114
|
end
|
116
115
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
$hash_file = "<%= hash_file %>"
|
2
|
+
|
3
|
+
Function Cleanup($o) { if (($o -ne $null) -and ($o.GetType().GetMethod("Dispose") -ne $null)) { $o.Dispose() } }
|
4
|
+
|
5
|
+
Function Decode-Base64File($src, $dst) {
|
6
|
+
Try {
|
7
|
+
$in = (Get-Item $src).OpenRead()
|
8
|
+
$b64 = New-Object -TypeName System.Security.Cryptography.FromBase64Transform
|
9
|
+
$m = [System.Security.Cryptography.CryptoStreamMode]::Read
|
10
|
+
$d = New-Object -TypeName System.Security.Cryptography.CryptoStream $in,$b64,$m
|
11
|
+
Copy-Stream $d ($out = [System.IO.File]::OpenWrite($dst))
|
12
|
+
} Finally { Cleanup $in; Cleanup $out; Cleanup $d }
|
13
|
+
}
|
14
|
+
|
15
|
+
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) } }
|
16
|
+
|
17
|
+
Function Check-Files($h) {
|
18
|
+
return $h.GetEnumerator() | ForEach-Object {
|
19
|
+
$dst = Unresolve-Path $_.Key
|
20
|
+
New-Object psobject -Property @{
|
21
|
+
chk_exists = ($exists = Test-Path $dst -PathType Leaf)
|
22
|
+
src_md5 = ($sMd5 = $_.Value)
|
23
|
+
dst_md5 = ($dMd5 = if ($exists) { Get-MD5Sum $dst } else { $null })
|
24
|
+
chk_dirty = ($dirty = if ($sMd5 -ne $dMd5) { $true } else { $false })
|
25
|
+
verifies = if ($dirty -eq $false) { $true } else { $false }
|
26
|
+
}
|
27
|
+
} | Select-Object -Property chk_exists,src_md5,dst_md5,chk_dirty,verifies
|
28
|
+
}
|
29
|
+
|
30
|
+
Function Get-MD5Sum($src) {
|
31
|
+
Try {
|
32
|
+
$c = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
|
33
|
+
$bytes = $c.ComputeHash(($in = (Get-Item $src).OpenRead()))
|
34
|
+
return ([System.BitConverter]::ToString($bytes)).Replace("-", "").ToLower()
|
35
|
+
} Finally { Cleanup $c; Cleanup $in }
|
36
|
+
}
|
37
|
+
|
38
|
+
Function Invoke-Input($in) {
|
39
|
+
$in = Unresolve-Path $in
|
40
|
+
Decode-Base64File $in ($decoded = "$($in).ps1")
|
41
|
+
$expr = Get-Content $decoded | Out-String
|
42
|
+
Remove-Item $in,$decoded -Force
|
43
|
+
return Invoke-Expression "$expr"
|
44
|
+
}
|
45
|
+
|
46
|
+
Function Unresolve-Path($p) { if ($p -eq $null) { return $null } else { return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p) } }
|
47
|
+
|
48
|
+
Check-Files (Invoke-Input $hash_file) | ConvertTo-Csv -NoTypeInformation
|
@@ -0,0 +1,59 @@
|
|
1
|
+
trap {$e = $_.Exception; $e.InvocationInfo.ScriptName; do {$e.Message; $e = $e.InnerException} while ($e); break;}
|
2
|
+
$progresspreference = 'SilentlyContinue'
|
3
|
+
function Decode-Base64File($src, $dst) {folder (split-path $dst);sc -force -Encoding Byte -Path $dst -Value ([Convert]::FromBase64String([IO.File]::ReadAllLines($src)))}
|
4
|
+
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) } }
|
5
|
+
function Resolve-ProviderPath{ $input | % {if ($_){(Resolve-Path $_).ProviderPath} else{$null}} }
|
6
|
+
function Get-FrameworkVersion { "Full", "Client" | % {([version](gp "HKLM:\Software\Microsoft\NET Framework Setup\NDP\v4\$_").Version)} | select -first 1}
|
7
|
+
function Test-NETStack($Version){ Get-FrameworkVersion -ge $Version }
|
8
|
+
function Test-IOCompression {($PSVersionTable.PSVersion.Major -ge 3) -and (Test-NETStack '4.5')}
|
9
|
+
function folder($path){ $path | ? {-not (test-path $_)} | % {$null = mkdir $_}}
|
10
|
+
function disposable($o){($o -is [IDisposable]) -and (($o | gm | %{$_.name}) -contains 'Dispose')}
|
11
|
+
function use($obj, [scriptblock]$sb){try {& $sb} catch [exception]{throw $_} finally {if (disposable $obj) {$obj.Dispose()}} }
|
12
|
+
set-alias RPP -Value Resolve-ProviderPath
|
13
|
+
|
14
|
+
Function Decode-Files($hash) {
|
15
|
+
foreach ($key in $hash.keys) {
|
16
|
+
$value = $hash[$key]
|
17
|
+
$tmp, $tzip, $dst = $Key, $Value["tmpzip"], $Value["dst"]
|
18
|
+
if($tmp -ne "") {
|
19
|
+
$sMd5 = (gi $tmp).BaseName.Replace("b64-", "")
|
20
|
+
$decoded = if ($tzip -ne $null) { $tzip } else { $dst }
|
21
|
+
Decode-Base64File $tmp $decoded
|
22
|
+
rm $tmp -Force
|
23
|
+
$dMd5 = Get-MD5Sum $decoded
|
24
|
+
$verifies = $sMd5 -like $dMd5
|
25
|
+
}
|
26
|
+
if ($tzip) {Unzip-File $tzip $dst}
|
27
|
+
New-Object psobject -Property @{dst=$dst;verifies=$verifies;src_md5=$sMd5;dst_md5=$dMd5;tmpfile=$tmp;tmpzip=$tzip}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
Function Get-MD5Sum($src) {
|
32
|
+
if ($src -and (test-path $src)) {
|
33
|
+
use ($c = New-Object -TypeName Security.Cryptography.MD5CryptoServiceProvider) {
|
34
|
+
use ($in = (gi $src).OpenRead()) {([BitConverter]::ToString($c.ComputeHash($in))).Replace("-", "").ToLower()}}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
Function Invoke-Input($in) {
|
39
|
+
$in = $in | rpp
|
40
|
+
$d = "$($in).ps1"
|
41
|
+
Decode-Base64File $in $d
|
42
|
+
$expr = gc $d | Out-String
|
43
|
+
rm $in,$d -Force
|
44
|
+
iex "$expr"
|
45
|
+
}
|
46
|
+
|
47
|
+
Function Unzip-File($src, $dst) {
|
48
|
+
$unpack = $src -replace '\.zip'
|
49
|
+
$dst_parent = Split-Path -Path $dst -Parent
|
50
|
+
if(!(Test-Path $dst_parent)) { $dst = $dst_parent }
|
51
|
+
folder $unpack, $dst
|
52
|
+
if (Test-IOCompression) {Add-Type -AN System.IO.Compression.FileSystem; [IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)}
|
53
|
+
else {Try {$s = New-Object -ComObject Shell.Application; ($s.NameSpace($unpack)).CopyHere(($s.NameSpace($src)).Items(), 0x610)} Finally {[void][Runtime.Interopservices.Marshal]::ReleaseComObject($s)}}
|
54
|
+
dir $unpack | cp -dest "$dst/" -force -recurse
|
55
|
+
rm $unpack -recurse -force
|
56
|
+
}
|
57
|
+
|
58
|
+
$hash_file = "<%= hash_file %>"
|
59
|
+
Decode-Files (Invoke-Input $hash_file) | ConvertTo-Csv -NoTypeInformation
|
@@ -1,7 +1,8 @@
|
|
1
1
|
$p = $ExecutionContext.SessionState.Path
|
2
2
|
$path = $p.GetUnresolvedProviderPathFromPSPath("<%= path %>")
|
3
3
|
if (Test-Path $path -PathType Leaf) {
|
4
|
-
[System.convert]::ToBase64String([System.IO.File]::ReadAllBytes($path))
|
4
|
+
$bytes = [System.convert]::ToBase64String([System.IO.File]::ReadAllBytes($path))
|
5
|
+
Write-Host $bytes
|
5
6
|
exit 0
|
6
7
|
}
|
7
8
|
exit 1
|
data/spec/config-example.yml
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
require 'pathname'
|
3
3
|
|
4
|
-
describe WinRM::FS::FileManager
|
4
|
+
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
|
-
let(:
|
7
|
+
let(:spec_dir) { File.expand_path(File.dirname(File.dirname(__FILE__))) }
|
8
8
|
let(:this_file) { __FILE__ }
|
9
9
|
let(:service) { winrm_connection }
|
10
10
|
|
@@ -35,7 +35,7 @@ describe WinRM::FS::FileManager, integration: true do
|
|
35
35
|
|
36
36
|
context 'temp_dir' do
|
37
37
|
it 'should return the remote users temp dir' do
|
38
|
-
expect(subject.temp_dir).to match(%r{C:/Users/\
|
38
|
+
expect(subject.temp_dir).to match(%r{C:/Users/\S+/AppData/Local/Temp})
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -58,7 +58,7 @@ describe WinRM::FS::FileManager, integration: true do
|
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'should upload using relative file path' do
|
61
|
-
subject.upload('./spec/file_manager_spec.rb', dest_file)
|
61
|
+
subject.upload('./spec/integration/file_manager_spec.rb', dest_file)
|
62
62
|
expect(subject).to have_created(dest_file).with_content(this_file)
|
63
63
|
end
|
64
64
|
|
@@ -88,14 +88,16 @@ describe WinRM::FS::FileManager, integration: true do
|
|
88
88
|
|
89
89
|
it 'yields progress data' do
|
90
90
|
block_called = false
|
91
|
+
total_bytes_copied = 0
|
91
92
|
total = subject.upload(this_file, dest_file) do \
|
92
93
|
|bytes_copied, total_bytes, local_path, remote_path|
|
93
94
|
expect(total_bytes).to be > 0
|
94
|
-
|
95
|
+
total_bytes_copied = bytes_copied
|
95
96
|
expect(local_path).to eq(this_file)
|
96
97
|
expect(remote_path).to eq(dest_file)
|
97
98
|
block_called = true
|
98
99
|
end
|
100
|
+
expect(total_bytes_copied).to eq(total)
|
99
101
|
expect(block_called).to be true
|
100
102
|
expect(total).to be > 0
|
101
103
|
end
|
@@ -107,7 +109,7 @@ describe WinRM::FS::FileManager, integration: true do
|
|
107
109
|
end
|
108
110
|
|
109
111
|
it 'should upload when content differs' do
|
110
|
-
matchers_file = File.join(
|
112
|
+
matchers_file = File.join(spec_dir, 'matchers.rb')
|
111
113
|
subject.upload(matchers_file, dest_file)
|
112
114
|
bytes_uploaded = subject.upload(this_file, dest_file)
|
113
115
|
expect(bytes_uploaded).to be > 0
|
@@ -119,32 +121,48 @@ describe WinRM::FS::FileManager, integration: true do
|
|
119
121
|
end
|
120
122
|
|
121
123
|
context 'upload empty file' do
|
122
|
-
let(:empty_src_file) { Tempfile.new('empty')
|
124
|
+
let(:empty_src_file) { Tempfile.new('empty') }
|
123
125
|
let(:dest_file) { File.join(dest_dir, 'emptyfile.txt') }
|
124
126
|
|
125
127
|
it 'creates a new empty file' do
|
126
|
-
expect(subject.upload(empty_src_file, dest_file)).to be 0
|
128
|
+
expect(subject.upload(empty_src_file.path, dest_file)).to be 0
|
127
129
|
expect(subject).to have_created(dest_file).with_content('')
|
128
130
|
end
|
129
131
|
|
130
132
|
it 'overwrites an existing file' do
|
131
133
|
expect(subject.upload(this_file, dest_file)).to be > 0
|
132
|
-
expect(subject.upload(empty_src_file, dest_file)).to be 0
|
134
|
+
expect(subject.upload(empty_src_file.path, dest_file)).to be 0
|
133
135
|
expect(subject).to have_created(dest_file).with_content('')
|
134
136
|
end
|
135
137
|
end
|
136
138
|
|
137
139
|
context 'upload directory' do
|
138
|
-
let(:root_dir) { File.expand_path('
|
140
|
+
let(:root_dir) { File.expand_path('../../', File.dirname(__FILE__)) }
|
139
141
|
let(:winrm_fs_dir) { File.join(root_dir, 'lib/winrm-fs') }
|
140
142
|
let(:core_dir) { File.join(root_dir, 'lib/winrm-fs/core') }
|
141
143
|
|
142
|
-
it 'copies the
|
144
|
+
it 'copies the directory contents recursively when directory does not exist' do
|
143
145
|
bytes_uploaded = subject.upload(winrm_fs_dir, dest_dir)
|
144
146
|
expect(bytes_uploaded).to be > 0
|
145
147
|
|
146
148
|
Dir.glob(winrm_fs_dir + '/**/*.rb').each do |host_file|
|
147
|
-
host_file_rel = Pathname.new(host_file).relative_path_from(
|
149
|
+
host_file_rel = Pathname.new(host_file).relative_path_from(
|
150
|
+
Pathname.new(winrm_fs_dir)
|
151
|
+
).to_s
|
152
|
+
remote_file = File.join(dest_dir, host_file_rel)
|
153
|
+
expect(subject).to have_created(remote_file).with_content(host_file)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'copies the directory recursively when directory does exist' do
|
158
|
+
subject.create_dir(dest_dir)
|
159
|
+
bytes_uploaded = subject.upload(winrm_fs_dir, dest_dir)
|
160
|
+
expect(bytes_uploaded).to be > 0
|
161
|
+
|
162
|
+
Dir.glob(winrm_fs_dir + '/**/*.rb').each do |host_file|
|
163
|
+
host_file_rel = Pathname.new(host_file).relative_path_from(
|
164
|
+
Pathname.new(winrm_fs_dir).dirname
|
165
|
+
).to_s
|
148
166
|
remote_file = File.join(dest_dir, host_file_rel)
|
149
167
|
expect(subject).to have_created(remote_file).with_content(host_file)
|
150
168
|
end
|
@@ -156,6 +174,14 @@ describe WinRM::FS::FileManager, integration: true do
|
|
156
174
|
expect(bytes_uploaded).to eq 0
|
157
175
|
end
|
158
176
|
|
177
|
+
it 'unzips the directory when cached content is the same' do
|
178
|
+
subject.upload(winrm_fs_dir, dest_dir)
|
179
|
+
subject.delete(dest_dir)
|
180
|
+
expect(subject.exists?(dest_dir)).to be false
|
181
|
+
subject.upload(winrm_fs_dir, dest_dir)
|
182
|
+
expect(subject.exists?(dest_dir)).to be true
|
183
|
+
end
|
184
|
+
|
159
185
|
it 'copies the directory when content differs' do
|
160
186
|
subject.upload(winrm_fs_dir, dest_dir)
|
161
187
|
bytes_uploaded = subject.upload(core_dir, dest_dir)
|