winrm-fs 0.4.3 → 1.0.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.
@@ -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